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