1 /*
2  * This module is used to copy security markings from packets
3  * to connections, and restore security markings from connections
4  * back to packets.  This would normally be performed in conjunction
5  * with the SECMARK target and state match.
6  *
7  * Based somewhat on CONNMARK:
8  *   Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
9  *    by Henrik Nordstrom <hno@marasystems.com>
10  *
11  * (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License version 2 as
15  * published by the Free Software Foundation.
16  *
17  */
18 #include <linux/module.h>
19 #include <linux/skbuff.h>
20 #include <linux/netfilter/x_tables.h>
21 #include <linux/netfilter/xt_CONNSECMARK.h>
22 #include <net/netfilter/nf_conntrack_compat.h>
23 
24 #define PFX "CONNSECMARK: "
25 
26 MODULE_LICENSE("GPL");
27 MODULE_AUTHOR("James Morris <jmorris@redhat.com>");
28 MODULE_DESCRIPTION("ip[6]tables CONNSECMARK module");
29 MODULE_ALIAS("ipt_CONNSECMARK");
30 MODULE_ALIAS("ip6t_CONNSECMARK");
31 
32 /*
33  * If the packet has a security mark and the connection does not, copy
34  * the security mark from the packet to the connection.
35  */
36 static void secmark_save(struct sk_buff *skb)
37 {
38 	if (skb->secmark) {
39 		u32 *connsecmark;
40 		enum ip_conntrack_info ctinfo;
41 
42 		connsecmark = nf_ct_get_secmark(skb, &ctinfo);
43 		if (connsecmark && !*connsecmark)
44 			if (*connsecmark != skb->secmark)
45 				*connsecmark = skb->secmark;
46 	}
47 }
48 
49 /*
50  * If packet has no security mark, and the connection does, restore the
51  * security mark from the connection to the packet.
52  */
53 static void secmark_restore(struct sk_buff *skb)
54 {
55 	if (!skb->secmark) {
56 		u32 *connsecmark;
57 		enum ip_conntrack_info ctinfo;
58 
59 		connsecmark = nf_ct_get_secmark(skb, &ctinfo);
60 		if (connsecmark && *connsecmark)
61 			if (skb->secmark != *connsecmark)
62 				skb->secmark = *connsecmark;
63 	}
64 }
65 
66 static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
67 			   const struct net_device *out, unsigned int hooknum,
68 			   const struct xt_target *target,
69 			   const void *targinfo)
70 {
71 	struct sk_buff *skb = *pskb;
72 	const struct xt_connsecmark_target_info *info = targinfo;
73 
74 	switch (info->mode) {
75 	case CONNSECMARK_SAVE:
76 		secmark_save(skb);
77 		break;
78 
79 	case CONNSECMARK_RESTORE:
80 		secmark_restore(skb);
81 		break;
82 
83 	default:
84 		BUG();
85 	}
86 
87 	return XT_CONTINUE;
88 }
89 
90 static int checkentry(const char *tablename, const void *entry,
91 		      const struct xt_target *target, void *targinfo,
92 		      unsigned int targinfosize, unsigned int hook_mask)
93 {
94 	struct xt_connsecmark_target_info *info = targinfo;
95 
96 	switch (info->mode) {
97 	case CONNSECMARK_SAVE:
98 	case CONNSECMARK_RESTORE:
99 		break;
100 
101 	default:
102 		printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode);
103 		return 0;
104 	}
105 
106 	return 1;
107 }
108 
109 static struct xt_target xt_connsecmark_target[] = {
110 	{
111 		.name		= "CONNSECMARK",
112 		.family		= AF_INET,
113 		.checkentry	= checkentry,
114 		.target		= target,
115 		.targetsize	= sizeof(struct xt_connsecmark_target_info),
116 		.table		= "mangle",
117 		.me		= THIS_MODULE,
118 	},
119 	{
120 		.name		= "CONNSECMARK",
121 		.family		= AF_INET6,
122 		.checkentry	= checkentry,
123 		.target		= target,
124 		.targetsize	= sizeof(struct xt_connsecmark_target_info),
125 		.table		= "mangle",
126 		.me		= THIS_MODULE,
127 	},
128 };
129 
130 static int __init xt_connsecmark_init(void)
131 {
132 	need_conntrack();
133 	return xt_register_targets(xt_connsecmark_targets,
134 				   ARRAY_SIZE(xt_connsecmark_targets));
135 }
136 
137 static void __exit xt_connsecmark_fini(void)
138 {
139 	xt_unregister_targets(xt_connsecmark_targets,
140 			      ARRAY_SIZE(xt_connsecmark_targets));
141 }
142 
143 module_init(xt_connsecmark_init);
144 module_exit(xt_connsecmark_fini);
145