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 
643db05feaSHerbert Xu static unsigned int target(struct sk_buff *skb, 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 	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 
87e1931b78SJan Engelhardt static bool checkentry(const char *tablename, const void *entry,
88100468e9SJames Morris 		       const struct xt_target *target, void *targinfo,
89efa74165SPatrick McHardy 		       unsigned int hook_mask)
90100468e9SJames Morris {
91a47362a2SJan Engelhardt 	const struct xt_connsecmark_target_info *info = targinfo;
92100468e9SJames Morris 
93100468e9SJames Morris 	switch (info->mode) {
94100468e9SJames Morris 	case CONNSECMARK_SAVE:
95100468e9SJames Morris 	case CONNSECMARK_RESTORE:
96100468e9SJames Morris 		break;
97100468e9SJames Morris 
98100468e9SJames Morris 	default:
99100468e9SJames Morris 		printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode);
100e1931b78SJan Engelhardt 		return false;
101100468e9SJames Morris 	}
102100468e9SJames Morris 
10367b4af29SJan Engelhardt 	if (nf_ct_l3proto_try_module_get(target->family) < 0) {
10467b4af29SJan Engelhardt 		printk(KERN_WARNING "can't load conntrack support for "
10567b4af29SJan Engelhardt 				    "proto=%d\n", target->family);
10667b4af29SJan Engelhardt 		return false;
10767b4af29SJan Engelhardt 	}
108e1931b78SJan Engelhardt 	return true;
109100468e9SJames Morris }
110100468e9SJames Morris 
11111078c37SYasuyuki Kozakai static void
11211078c37SYasuyuki Kozakai destroy(const struct xt_target *target, void *targinfo)
11311078c37SYasuyuki Kozakai {
11411078c37SYasuyuki Kozakai 	nf_ct_l3proto_module_put(target->family);
11511078c37SYasuyuki Kozakai }
11611078c37SYasuyuki Kozakai 
1179f15c530SPatrick McHardy static struct xt_target xt_connsecmark_target[] __read_mostly = {
1184470bbc7SPatrick McHardy 	{
119100468e9SJames Morris 		.name		= "CONNSECMARK",
120100468e9SJames Morris 		.family		= AF_INET,
1214470bbc7SPatrick McHardy 		.checkentry	= checkentry,
12211078c37SYasuyuki Kozakai 		.destroy	= destroy,
123100468e9SJames Morris 		.target		= target,
124100468e9SJames Morris 		.targetsize	= sizeof(struct xt_connsecmark_target_info),
125100468e9SJames Morris 		.table		= "mangle",
126100468e9SJames Morris 		.me		= THIS_MODULE,
1274470bbc7SPatrick McHardy 	},
1284470bbc7SPatrick McHardy 	{
1294470bbc7SPatrick McHardy 		.name		= "CONNSECMARK",
130100468e9SJames Morris 		.family		= AF_INET6,
1314470bbc7SPatrick McHardy 		.checkentry	= checkentry,
13211078c37SYasuyuki Kozakai 		.destroy	= destroy,
1334470bbc7SPatrick McHardy 		.target		= target,
1344470bbc7SPatrick McHardy 		.targetsize	= sizeof(struct xt_connsecmark_target_info),
1354470bbc7SPatrick McHardy 		.table		= "mangle",
1364470bbc7SPatrick McHardy 		.me		= THIS_MODULE,
1374470bbc7SPatrick McHardy 	},
138100468e9SJames Morris };
139100468e9SJames Morris 
140100468e9SJames Morris static int __init xt_connsecmark_init(void)
141100468e9SJames Morris {
14228094864SThomas Graf 	return xt_register_targets(xt_connsecmark_target,
14328094864SThomas Graf 				   ARRAY_SIZE(xt_connsecmark_target));
144100468e9SJames Morris }
145100468e9SJames Morris 
146100468e9SJames Morris static void __exit xt_connsecmark_fini(void)
147100468e9SJames Morris {
14828094864SThomas Graf 	xt_unregister_targets(xt_connsecmark_target,
14928094864SThomas Graf 			      ARRAY_SIZE(xt_connsecmark_target));
150100468e9SJames Morris }
151100468e9SJames Morris 
152100468e9SJames Morris module_init(xt_connsecmark_init);
153100468e9SJames Morris module_exit(xt_connsecmark_fini);
154