1100468e9SJames Morris /* 2100468e9SJames Morris * This module is used to copy security markings from packets 3100468e9SJames Morris * to connections, and restore security markings from connections 4100468e9SJames Morris * back to packets. This would normally be performed in conjunction 5100468e9SJames Morris * with the SECMARK target and state match. 6100468e9SJames Morris * 7100468e9SJames Morris * Based somewhat on CONNMARK: 8100468e9SJames Morris * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> 9100468e9SJames Morris * by Henrik Nordstrom <hno@marasystems.com> 10100468e9SJames Morris * 11100468e9SJames Morris * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com> 12100468e9SJames Morris * 13100468e9SJames Morris * This program is free software; you can redistribute it and/or modify 14100468e9SJames Morris * it under the terms of the GNU General Public License version 2 as 15100468e9SJames Morris * published by the Free Software Foundation. 16100468e9SJames Morris * 17100468e9SJames Morris */ 18100468e9SJames Morris #include <linux/module.h> 19100468e9SJames Morris #include <linux/skbuff.h> 20100468e9SJames Morris #include <linux/netfilter/x_tables.h> 21100468e9SJames Morris #include <linux/netfilter/xt_CONNSECMARK.h> 22587aa641SPatrick McHardy #include <net/netfilter/nf_conntrack.h> 23100468e9SJames Morris 24100468e9SJames Morris #define PFX "CONNSECMARK: " 25100468e9SJames Morris 26100468e9SJames Morris MODULE_LICENSE("GPL"); 27100468e9SJames Morris MODULE_AUTHOR("James Morris <jmorris@redhat.com>"); 28100468e9SJames Morris MODULE_DESCRIPTION("ip[6]tables CONNSECMARK module"); 29100468e9SJames Morris MODULE_ALIAS("ipt_CONNSECMARK"); 30100468e9SJames Morris MODULE_ALIAS("ip6t_CONNSECMARK"); 31100468e9SJames Morris 32100468e9SJames Morris /* 33100468e9SJames Morris * If the packet has a security mark and the connection does not, copy 34100468e9SJames Morris * the security mark from the packet to the connection. 35100468e9SJames Morris */ 36100468e9SJames Morris static void secmark_save(struct sk_buff *skb) 37100468e9SJames Morris { 38100468e9SJames Morris if (skb->secmark) { 39587aa641SPatrick McHardy struct nf_conn *ct; 40100468e9SJames Morris enum ip_conntrack_info ctinfo; 41100468e9SJames Morris 42587aa641SPatrick McHardy ct = nf_ct_get(skb, &ctinfo); 43587aa641SPatrick McHardy if (ct && !ct->secmark) 44587aa641SPatrick McHardy ct->secmark = skb->secmark; 45100468e9SJames Morris } 46100468e9SJames Morris } 47100468e9SJames Morris 48100468e9SJames Morris /* 49100468e9SJames Morris * If packet has no security mark, and the connection does, restore the 50100468e9SJames Morris * security mark from the connection to the packet. 51100468e9SJames Morris */ 52100468e9SJames Morris static void secmark_restore(struct sk_buff *skb) 53100468e9SJames Morris { 54100468e9SJames Morris if (!skb->secmark) { 55587aa641SPatrick McHardy struct nf_conn *ct; 56100468e9SJames Morris enum ip_conntrack_info ctinfo; 57100468e9SJames Morris 58587aa641SPatrick McHardy ct = nf_ct_get(skb, &ctinfo); 59587aa641SPatrick McHardy if (ct && ct->secmark) 60587aa641SPatrick McHardy skb->secmark = ct->secmark; 61100468e9SJames Morris } 62100468e9SJames Morris } 63100468e9SJames Morris 64100468e9SJames Morris static unsigned int target(struct sk_buff **pskb, const struct net_device *in, 65100468e9SJames Morris const struct net_device *out, unsigned int hooknum, 66100468e9SJames Morris const struct xt_target *target, 67fe1cb108SPatrick McHardy const void *targinfo) 68100468e9SJames Morris { 69100468e9SJames Morris struct sk_buff *skb = *pskb; 70100468e9SJames Morris const struct xt_connsecmark_target_info *info = targinfo; 71100468e9SJames Morris 72100468e9SJames Morris switch (info->mode) { 73100468e9SJames Morris case CONNSECMARK_SAVE: 74100468e9SJames Morris secmark_save(skb); 75100468e9SJames Morris break; 76100468e9SJames Morris 77100468e9SJames Morris case CONNSECMARK_RESTORE: 78100468e9SJames Morris secmark_restore(skb); 79100468e9SJames Morris break; 80100468e9SJames Morris 81100468e9SJames Morris default: 82100468e9SJames Morris BUG(); 83100468e9SJames Morris } 84100468e9SJames Morris 85100468e9SJames Morris return XT_CONTINUE; 86100468e9SJames Morris } 87100468e9SJames Morris 88e1931b78SJan Engelhardt static bool checkentry(const char *tablename, const void *entry, 89100468e9SJames Morris const struct xt_target *target, void *targinfo, 90efa74165SPatrick McHardy unsigned int hook_mask) 91100468e9SJames Morris { 92100468e9SJames Morris struct xt_connsecmark_target_info *info = targinfo; 93100468e9SJames Morris 9411078c37SYasuyuki Kozakai if (nf_ct_l3proto_try_module_get(target->family) < 0) { 9511078c37SYasuyuki Kozakai printk(KERN_WARNING "can't load conntrack support for " 9611078c37SYasuyuki Kozakai "proto=%d\n", target->family); 97e1931b78SJan Engelhardt return false; 9811078c37SYasuyuki Kozakai } 99100468e9SJames Morris switch (info->mode) { 100100468e9SJames Morris case CONNSECMARK_SAVE: 101100468e9SJames Morris case CONNSECMARK_RESTORE: 102100468e9SJames Morris break; 103100468e9SJames Morris 104100468e9SJames Morris default: 105100468e9SJames Morris printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode); 106e1931b78SJan Engelhardt return false; 107100468e9SJames Morris } 108100468e9SJames Morris 109e1931b78SJan Engelhardt return true; 110100468e9SJames Morris } 111100468e9SJames Morris 11211078c37SYasuyuki Kozakai static void 11311078c37SYasuyuki Kozakai destroy(const struct xt_target *target, void *targinfo) 11411078c37SYasuyuki Kozakai { 11511078c37SYasuyuki Kozakai nf_ct_l3proto_module_put(target->family); 11611078c37SYasuyuki Kozakai } 11711078c37SYasuyuki Kozakai 1184470bbc7SPatrick McHardy static struct xt_target xt_connsecmark_target[] = { 1194470bbc7SPatrick McHardy { 120100468e9SJames Morris .name = "CONNSECMARK", 121100468e9SJames Morris .family = AF_INET, 1224470bbc7SPatrick McHardy .checkentry = checkentry, 12311078c37SYasuyuki Kozakai .destroy = destroy, 124100468e9SJames Morris .target = target, 125100468e9SJames Morris .targetsize = sizeof(struct xt_connsecmark_target_info), 126100468e9SJames Morris .table = "mangle", 127100468e9SJames Morris .me = THIS_MODULE, 1284470bbc7SPatrick McHardy }, 1294470bbc7SPatrick McHardy { 1304470bbc7SPatrick McHardy .name = "CONNSECMARK", 131100468e9SJames Morris .family = AF_INET6, 1324470bbc7SPatrick McHardy .checkentry = checkentry, 13311078c37SYasuyuki Kozakai .destroy = destroy, 1344470bbc7SPatrick McHardy .target = target, 1354470bbc7SPatrick McHardy .targetsize = sizeof(struct xt_connsecmark_target_info), 1364470bbc7SPatrick McHardy .table = "mangle", 1374470bbc7SPatrick McHardy .me = THIS_MODULE, 1384470bbc7SPatrick McHardy }, 139100468e9SJames Morris }; 140100468e9SJames Morris 141100468e9SJames Morris static int __init xt_connsecmark_init(void) 142100468e9SJames Morris { 14328094864SThomas Graf return xt_register_targets(xt_connsecmark_target, 14428094864SThomas Graf ARRAY_SIZE(xt_connsecmark_target)); 145100468e9SJames Morris } 146100468e9SJames Morris 147100468e9SJames Morris static void __exit xt_connsecmark_fini(void) 148100468e9SJames Morris { 14928094864SThomas Graf xt_unregister_targets(xt_connsecmark_target, 15028094864SThomas Graf ARRAY_SIZE(xt_connsecmark_target)); 151100468e9SJames Morris } 152100468e9SJames Morris 153100468e9SJames Morris module_init(xt_connsecmark_init); 154100468e9SJames Morris module_exit(xt_connsecmark_fini); 155