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 */ 36a47362a2SJan Engelhardt static void secmark_save(const 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 64d3c5ee6dSJan Engelhardt static unsigned int 65d3c5ee6dSJan Engelhardt connsecmark_tg(struct sk_buff *skb, const struct net_device *in, 66100468e9SJames Morris const struct net_device *out, unsigned int hooknum, 67d3c5ee6dSJan Engelhardt const struct xt_target *target, const void *targinfo) 68100468e9SJames Morris { 69100468e9SJames Morris const struct xt_connsecmark_target_info *info = targinfo; 70100468e9SJames Morris 71100468e9SJames Morris switch (info->mode) { 72100468e9SJames Morris case CONNSECMARK_SAVE: 73100468e9SJames Morris secmark_save(skb); 74100468e9SJames Morris break; 75100468e9SJames Morris 76100468e9SJames Morris case CONNSECMARK_RESTORE: 77100468e9SJames Morris secmark_restore(skb); 78100468e9SJames Morris break; 79100468e9SJames Morris 80100468e9SJames Morris default: 81100468e9SJames Morris BUG(); 82100468e9SJames Morris } 83100468e9SJames Morris 84100468e9SJames Morris return XT_CONTINUE; 85100468e9SJames Morris } 86100468e9SJames Morris 87d3c5ee6dSJan Engelhardt static bool 88d3c5ee6dSJan Engelhardt connsecmark_tg_check(const char *tablename, const void *entry, 89100468e9SJames Morris const struct xt_target *target, void *targinfo, 90efa74165SPatrick McHardy unsigned int hook_mask) 91100468e9SJames Morris { 92a47362a2SJan Engelhardt const struct xt_connsecmark_target_info *info = targinfo; 93100468e9SJames Morris 94100468e9SJames Morris switch (info->mode) { 95100468e9SJames Morris case CONNSECMARK_SAVE: 96100468e9SJames Morris case CONNSECMARK_RESTORE: 97100468e9SJames Morris break; 98100468e9SJames Morris 99100468e9SJames Morris default: 100100468e9SJames Morris printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode); 101e1931b78SJan Engelhardt return false; 102100468e9SJames Morris } 103100468e9SJames Morris 10467b4af29SJan Engelhardt if (nf_ct_l3proto_try_module_get(target->family) < 0) { 10567b4af29SJan Engelhardt printk(KERN_WARNING "can't load conntrack support for " 10667b4af29SJan Engelhardt "proto=%d\n", target->family); 10767b4af29SJan Engelhardt return false; 10867b4af29SJan Engelhardt } 109e1931b78SJan Engelhardt return true; 110100468e9SJames Morris } 111100468e9SJames Morris 11211078c37SYasuyuki Kozakai static void 113d3c5ee6dSJan Engelhardt connsecmark_tg_destroy(const struct xt_target *target, void *targinfo) 11411078c37SYasuyuki Kozakai { 11511078c37SYasuyuki Kozakai nf_ct_l3proto_module_put(target->family); 11611078c37SYasuyuki Kozakai } 11711078c37SYasuyuki Kozakai 118d3c5ee6dSJan Engelhardt static struct xt_target connsecmark_tg_reg[] __read_mostly = { 1194470bbc7SPatrick McHardy { 120100468e9SJames Morris .name = "CONNSECMARK", 121100468e9SJames Morris .family = AF_INET, 122d3c5ee6dSJan Engelhardt .checkentry = connsecmark_tg_check, 123d3c5ee6dSJan Engelhardt .destroy = connsecmark_tg_destroy, 124d3c5ee6dSJan Engelhardt .target = connsecmark_tg, 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, 132d3c5ee6dSJan Engelhardt .checkentry = connsecmark_tg_check, 133d3c5ee6dSJan Engelhardt .destroy = connsecmark_tg_destroy, 134d3c5ee6dSJan Engelhardt .target = connsecmark_tg, 1354470bbc7SPatrick McHardy .targetsize = sizeof(struct xt_connsecmark_target_info), 1364470bbc7SPatrick McHardy .table = "mangle", 1374470bbc7SPatrick McHardy .me = THIS_MODULE, 1384470bbc7SPatrick McHardy }, 139100468e9SJames Morris }; 140100468e9SJames Morris 141d3c5ee6dSJan Engelhardt static int __init connsecmark_tg_init(void) 142100468e9SJames Morris { 143d3c5ee6dSJan Engelhardt return xt_register_targets(connsecmark_tg_reg, 144d3c5ee6dSJan Engelhardt ARRAY_SIZE(connsecmark_tg_reg)); 145100468e9SJames Morris } 146100468e9SJames Morris 147d3c5ee6dSJan Engelhardt static void __exit connsecmark_tg_exit(void) 148100468e9SJames Morris { 149d3c5ee6dSJan Engelhardt xt_unregister_targets(connsecmark_tg_reg, 150d3c5ee6dSJan Engelhardt ARRAY_SIZE(connsecmark_tg_reg)); 151100468e9SJames Morris } 152100468e9SJames Morris 153d3c5ee6dSJan Engelhardt module_init(connsecmark_tg_init); 154d3c5ee6dSJan Engelhardt module_exit(connsecmark_tg_exit); 155