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