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>
22100468e9SJames Morris #include <net/netfilter/nf_conntrack_compat.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) {
39100468e9SJames Morris 		u32 *connsecmark;
40100468e9SJames Morris 		enum ip_conntrack_info ctinfo;
41100468e9SJames Morris 
42100468e9SJames Morris 		connsecmark = nf_ct_get_secmark(skb, &ctinfo);
43100468e9SJames Morris 		if (connsecmark && !*connsecmark)
44100468e9SJames Morris 			if (*connsecmark != skb->secmark)
45100468e9SJames Morris 				*connsecmark = skb->secmark;
46100468e9SJames Morris 	}
47100468e9SJames Morris }
48100468e9SJames Morris 
49100468e9SJames Morris /*
50100468e9SJames Morris  * If packet has no security mark, and the connection does, restore the
51100468e9SJames Morris  * security mark from the connection to the packet.
52100468e9SJames Morris  */
53100468e9SJames Morris static void secmark_restore(struct sk_buff *skb)
54100468e9SJames Morris {
55100468e9SJames Morris 	if (!skb->secmark) {
56100468e9SJames Morris 		u32 *connsecmark;
57100468e9SJames Morris 		enum ip_conntrack_info ctinfo;
58100468e9SJames Morris 
59100468e9SJames Morris 		connsecmark = nf_ct_get_secmark(skb, &ctinfo);
60100468e9SJames Morris 		if (connsecmark && *connsecmark)
61100468e9SJames Morris 			if (skb->secmark != *connsecmark)
62100468e9SJames Morris 				skb->secmark = *connsecmark;
63100468e9SJames Morris 	}
64100468e9SJames Morris }
65100468e9SJames Morris 
66100468e9SJames Morris static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
67100468e9SJames Morris 			   const struct net_device *out, unsigned int hooknum,
68100468e9SJames Morris 			   const struct xt_target *target,
69fe1cb108SPatrick McHardy 			   const void *targinfo)
70100468e9SJames Morris {
71100468e9SJames Morris 	struct sk_buff *skb = *pskb;
72100468e9SJames Morris 	const struct xt_connsecmark_target_info *info = targinfo;
73100468e9SJames Morris 
74100468e9SJames Morris 	switch (info->mode) {
75100468e9SJames Morris 	case CONNSECMARK_SAVE:
76100468e9SJames Morris 		secmark_save(skb);
77100468e9SJames Morris 		break;
78100468e9SJames Morris 
79100468e9SJames Morris 	case CONNSECMARK_RESTORE:
80100468e9SJames Morris 		secmark_restore(skb);
81100468e9SJames Morris 		break;
82100468e9SJames Morris 
83100468e9SJames Morris 	default:
84100468e9SJames Morris 		BUG();
85100468e9SJames Morris 	}
86100468e9SJames Morris 
87100468e9SJames Morris 	return XT_CONTINUE;
88100468e9SJames Morris }
89100468e9SJames Morris 
90100468e9SJames Morris static int checkentry(const char *tablename, const void *entry,
91100468e9SJames Morris 		      const struct xt_target *target, void *targinfo,
92efa74165SPatrick McHardy 		      unsigned int hook_mask)
93100468e9SJames Morris {
94100468e9SJames Morris 	struct xt_connsecmark_target_info *info = targinfo;
95100468e9SJames Morris 
96100468e9SJames Morris 	switch (info->mode) {
97100468e9SJames Morris 	case CONNSECMARK_SAVE:
98100468e9SJames Morris 	case CONNSECMARK_RESTORE:
99100468e9SJames Morris 		break;
100100468e9SJames Morris 
101100468e9SJames Morris 	default:
102100468e9SJames Morris 		printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode);
103100468e9SJames Morris 		return 0;
104100468e9SJames Morris 	}
105100468e9SJames Morris 
106100468e9SJames Morris 	return 1;
107100468e9SJames Morris }
108100468e9SJames Morris 
1094470bbc7SPatrick McHardy static struct xt_target xt_connsecmark_target[] = {
1104470bbc7SPatrick McHardy 	{
111100468e9SJames Morris 		.name		= "CONNSECMARK",
112100468e9SJames Morris 		.family		= AF_INET,
1134470bbc7SPatrick McHardy 		.checkentry	= checkentry,
114100468e9SJames Morris 		.target		= target,
115100468e9SJames Morris 		.targetsize	= sizeof(struct xt_connsecmark_target_info),
116100468e9SJames Morris 		.table		= "mangle",
117100468e9SJames Morris 		.me		= THIS_MODULE,
1184470bbc7SPatrick McHardy 	},
1194470bbc7SPatrick McHardy 	{
1204470bbc7SPatrick McHardy 		.name		= "CONNSECMARK",
121100468e9SJames Morris 		.family		= AF_INET6,
1224470bbc7SPatrick McHardy 		.checkentry	= checkentry,
1234470bbc7SPatrick McHardy 		.target		= target,
1244470bbc7SPatrick McHardy 		.targetsize	= sizeof(struct xt_connsecmark_target_info),
1254470bbc7SPatrick McHardy 		.table		= "mangle",
1264470bbc7SPatrick McHardy 		.me		= THIS_MODULE,
1274470bbc7SPatrick McHardy 	},
128100468e9SJames Morris };
129100468e9SJames Morris 
130100468e9SJames Morris static int __init xt_connsecmark_init(void)
131100468e9SJames Morris {
132100468e9SJames Morris 	need_conntrack();
1334470bbc7SPatrick McHardy 	return xt_register_targets(xt_connsecmark_targets,
1344470bbc7SPatrick McHardy 				   ARRAY_SIZE(xt_connsecmark_targets));
135100468e9SJames Morris }
136100468e9SJames Morris 
137100468e9SJames Morris static void __exit xt_connsecmark_fini(void)
138100468e9SJames Morris {
1394470bbc7SPatrick McHardy 	xt_unregister_targets(xt_connsecmark_targets,
1404470bbc7SPatrick McHardy 			      ARRAY_SIZE(xt_connsecmark_targets));
141100468e9SJames Morris }
142100468e9SJames Morris 
143100468e9SJames Morris module_init(xt_connsecmark_init);
144100468e9SJames Morris module_exit(xt_connsecmark_fini);
145