1100468e9c05c10fb6872751c1af523b996d6afa9James Morris/*
2100468e9c05c10fb6872751c1af523b996d6afa9James Morris * This module is used to copy security markings from packets
3100468e9c05c10fb6872751c1af523b996d6afa9James Morris * to connections, and restore security markings from connections
4100468e9c05c10fb6872751c1af523b996d6afa9James Morris * back to packets.  This would normally be performed in conjunction
5100468e9c05c10fb6872751c1af523b996d6afa9James Morris * with the SECMARK target and state match.
6100468e9c05c10fb6872751c1af523b996d6afa9James Morris *
7100468e9c05c10fb6872751c1af523b996d6afa9James Morris * Based somewhat on CONNMARK:
8100468e9c05c10fb6872751c1af523b996d6afa9James Morris *   Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
9100468e9c05c10fb6872751c1af523b996d6afa9James Morris *    by Henrik Nordstrom <hno@marasystems.com>
10100468e9c05c10fb6872751c1af523b996d6afa9James Morris *
11560ee653b67074b805f1b661988a72a0e58811a5James Morris * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
12100468e9c05c10fb6872751c1af523b996d6afa9James Morris *
13100468e9c05c10fb6872751c1af523b996d6afa9James Morris * This program is free software; you can redistribute it and/or modify
14100468e9c05c10fb6872751c1af523b996d6afa9James Morris * it under the terms of the GNU General Public License version 2 as
15100468e9c05c10fb6872751c1af523b996d6afa9James Morris * published by the Free Software Foundation.
16100468e9c05c10fb6872751c1af523b996d6afa9James Morris *
17100468e9c05c10fb6872751c1af523b996d6afa9James Morris */
188bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19100468e9c05c10fb6872751c1af523b996d6afa9James Morris#include <linux/module.h>
20100468e9c05c10fb6872751c1af523b996d6afa9James Morris#include <linux/skbuff.h>
21100468e9c05c10fb6872751c1af523b996d6afa9James Morris#include <linux/netfilter/x_tables.h>
22100468e9c05c10fb6872751c1af523b996d6afa9James Morris#include <linux/netfilter/xt_CONNSECMARK.h>
23587aa64163bb14f70098f450abab9410787fce9dPatrick McHardy#include <net/netfilter/nf_conntrack.h>
2437fccd8577d38e249dde71512fb38d2f6a4d9d3cPablo Neira Ayuso#include <net/netfilter/nf_conntrack_ecache.h>
25100468e9c05c10fb6872751c1af523b996d6afa9James Morris
26100468e9c05c10fb6872751c1af523b996d6afa9James MorrisMODULE_LICENSE("GPL");
27100468e9c05c10fb6872751c1af523b996d6afa9James MorrisMODULE_AUTHOR("James Morris <jmorris@redhat.com>");
282ae15b64e6a1608c840c60df38e8e5eef7b2b8c3Jan EngelhardtMODULE_DESCRIPTION("Xtables: target for copying between connection and security mark");
29100468e9c05c10fb6872751c1af523b996d6afa9James MorrisMODULE_ALIAS("ipt_CONNSECMARK");
30100468e9c05c10fb6872751c1af523b996d6afa9James MorrisMODULE_ALIAS("ip6t_CONNSECMARK");
31100468e9c05c10fb6872751c1af523b996d6afa9James Morris
32100468e9c05c10fb6872751c1af523b996d6afa9James Morris/*
33100468e9c05c10fb6872751c1af523b996d6afa9James Morris * If the packet has a security mark and the connection does not, copy
34100468e9c05c10fb6872751c1af523b996d6afa9James Morris * the security mark from the packet to the connection.
35100468e9c05c10fb6872751c1af523b996d6afa9James Morris */
36a47362a226456d8db8207e618324a2278d05d3a7Jan Engelhardtstatic void secmark_save(const struct sk_buff *skb)
37100468e9c05c10fb6872751c1af523b996d6afa9James Morris{
38100468e9c05c10fb6872751c1af523b996d6afa9James Morris	if (skb->secmark) {
39587aa64163bb14f70098f450abab9410787fce9dPatrick McHardy		struct nf_conn *ct;
40100468e9c05c10fb6872751c1af523b996d6afa9James Morris		enum ip_conntrack_info ctinfo;
41100468e9c05c10fb6872751c1af523b996d6afa9James Morris
42587aa64163bb14f70098f450abab9410787fce9dPatrick McHardy		ct = nf_ct_get(skb, &ctinfo);
4337fccd8577d38e249dde71512fb38d2f6a4d9d3cPablo Neira Ayuso		if (ct && !ct->secmark) {
44587aa64163bb14f70098f450abab9410787fce9dPatrick McHardy			ct->secmark = skb->secmark;
45a71996fccce4b2086a26036aa3c915365ca36926Alexey Dobriyan			nf_conntrack_event_cache(IPCT_SECMARK, ct);
4637fccd8577d38e249dde71512fb38d2f6a4d9d3cPablo Neira Ayuso		}
47100468e9c05c10fb6872751c1af523b996d6afa9James Morris	}
48100468e9c05c10fb6872751c1af523b996d6afa9James Morris}
49100468e9c05c10fb6872751c1af523b996d6afa9James Morris
50100468e9c05c10fb6872751c1af523b996d6afa9James Morris/*
51100468e9c05c10fb6872751c1af523b996d6afa9James Morris * If packet has no security mark, and the connection does, restore the
52100468e9c05c10fb6872751c1af523b996d6afa9James Morris * security mark from the connection to the packet.
53100468e9c05c10fb6872751c1af523b996d6afa9James Morris */
54100468e9c05c10fb6872751c1af523b996d6afa9James Morrisstatic void secmark_restore(struct sk_buff *skb)
55100468e9c05c10fb6872751c1af523b996d6afa9James Morris{
56100468e9c05c10fb6872751c1af523b996d6afa9James Morris	if (!skb->secmark) {
573cf93c96af7adf78542d45f8a27f0e5f8704409dJan Engelhardt		const struct nf_conn *ct;
58100468e9c05c10fb6872751c1af523b996d6afa9James Morris		enum ip_conntrack_info ctinfo;
59100468e9c05c10fb6872751c1af523b996d6afa9James Morris
60587aa64163bb14f70098f450abab9410787fce9dPatrick McHardy		ct = nf_ct_get(skb, &ctinfo);
61587aa64163bb14f70098f450abab9410787fce9dPatrick McHardy		if (ct && ct->secmark)
62587aa64163bb14f70098f450abab9410787fce9dPatrick McHardy			skb->secmark = ct->secmark;
63100468e9c05c10fb6872751c1af523b996d6afa9James Morris	}
64100468e9c05c10fb6872751c1af523b996d6afa9James Morris}
65100468e9c05c10fb6872751c1af523b996d6afa9James Morris
66d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic unsigned int
674b560b447df83368df44bd3712c0c39b1d79ba04Jan Engelhardtconnsecmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
68100468e9c05c10fb6872751c1af523b996d6afa9James Morris{
697eb3558655aaa87a3e71a0c065dfaddda521fa6dJan Engelhardt	const struct xt_connsecmark_target_info *info = par->targinfo;
70100468e9c05c10fb6872751c1af523b996d6afa9James Morris
71100468e9c05c10fb6872751c1af523b996d6afa9James Morris	switch (info->mode) {
72100468e9c05c10fb6872751c1af523b996d6afa9James Morris	case CONNSECMARK_SAVE:
73100468e9c05c10fb6872751c1af523b996d6afa9James Morris		secmark_save(skb);
74100468e9c05c10fb6872751c1af523b996d6afa9James Morris		break;
75100468e9c05c10fb6872751c1af523b996d6afa9James Morris
76100468e9c05c10fb6872751c1af523b996d6afa9James Morris	case CONNSECMARK_RESTORE:
77100468e9c05c10fb6872751c1af523b996d6afa9James Morris		secmark_restore(skb);
78100468e9c05c10fb6872751c1af523b996d6afa9James Morris		break;
79100468e9c05c10fb6872751c1af523b996d6afa9James Morris
80100468e9c05c10fb6872751c1af523b996d6afa9James Morris	default:
81100468e9c05c10fb6872751c1af523b996d6afa9James Morris		BUG();
82100468e9c05c10fb6872751c1af523b996d6afa9James Morris	}
83100468e9c05c10fb6872751c1af523b996d6afa9James Morris
84100468e9c05c10fb6872751c1af523b996d6afa9James Morris	return XT_CONTINUE;
85100468e9c05c10fb6872751c1af523b996d6afa9James Morris}
86100468e9c05c10fb6872751c1af523b996d6afa9James Morris
87135367b8f6a18507af6b9a6910a14b5699415309Jan Engelhardtstatic int connsecmark_tg_check(const struct xt_tgchk_param *par)
88100468e9c05c10fb6872751c1af523b996d6afa9James Morris{
89af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	const struct xt_connsecmark_target_info *info = par->targinfo;
904a5a5c73b7cfee46a0b1411903cfa0dea532deecJan Engelhardt	int ret;
91100468e9c05c10fb6872751c1af523b996d6afa9James Morris
92af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	if (strcmp(par->table, "mangle") != 0 &&
93af5d6dc200eb0fcc6fbd3df1ab4d8969004cb37fJan Engelhardt	    strcmp(par->table, "security") != 0) {
948bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt		pr_info("target only valid in the \'mangle\' "
958bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt			"or \'security\' tables, not \'%s\'.\n", par->table);
96d6b00a5345ce4e86e8b00a88bb84a2c0c1f69ddcJan Engelhardt		return -EINVAL;
97560ee653b67074b805f1b661988a72a0e58811a5James Morris	}
98560ee653b67074b805f1b661988a72a0e58811a5James Morris
99100468e9c05c10fb6872751c1af523b996d6afa9James Morris	switch (info->mode) {
100100468e9c05c10fb6872751c1af523b996d6afa9James Morris	case CONNSECMARK_SAVE:
101100468e9c05c10fb6872751c1af523b996d6afa9James Morris	case CONNSECMARK_RESTORE:
102100468e9c05c10fb6872751c1af523b996d6afa9James Morris		break;
103100468e9c05c10fb6872751c1af523b996d6afa9James Morris
104100468e9c05c10fb6872751c1af523b996d6afa9James Morris	default:
1058bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt		pr_info("invalid mode: %hu\n", info->mode);
1064a5a5c73b7cfee46a0b1411903cfa0dea532deecJan Engelhardt		return -EINVAL;
107100468e9c05c10fb6872751c1af523b996d6afa9James Morris	}
108100468e9c05c10fb6872751c1af523b996d6afa9James Morris
1094a5a5c73b7cfee46a0b1411903cfa0dea532deecJan Engelhardt	ret = nf_ct_l3proto_try_module_get(par->family);
110f95c74e33eff5e3fe9798e2dc0a7749150ea3f80Jan Engelhardt	if (ret < 0)
1118bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt		pr_info("cannot load conntrack support for proto=%u\n",
1128bee4bad03c5b601bd6cea123c31025680587cccJan Engelhardt			par->family);
113f95c74e33eff5e3fe9798e2dc0a7749150ea3f80Jan Engelhardt	return ret;
114100468e9c05c10fb6872751c1af523b996d6afa9James Morris}
115100468e9c05c10fb6872751c1af523b996d6afa9James Morris
116a2df1648ba615dd5908e9a1fa7b2f133fa302487Jan Engelhardtstatic void connsecmark_tg_destroy(const struct xt_tgdtor_param *par)
11711078c371e2ecfce011d1dffb67888c6fed1b664Yasuyuki Kozakai{
11892f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	nf_ct_l3proto_module_put(par->family);
11911078c371e2ecfce011d1dffb67888c6fed1b664Yasuyuki Kozakai}
12011078c371e2ecfce011d1dffb67888c6fed1b664Yasuyuki Kozakai
12192f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardtstatic struct xt_target connsecmark_tg_reg __read_mostly = {
12292f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	.name       = "CONNSECMARK",
12392f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	.revision   = 0,
12492f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	.family     = NFPROTO_UNSPEC,
12592f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	.checkentry = connsecmark_tg_check,
12692f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	.destroy    = connsecmark_tg_destroy,
12792f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	.target     = connsecmark_tg,
12892f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	.targetsize = sizeof(struct xt_connsecmark_target_info),
12992f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	.me         = THIS_MODULE,
130100468e9c05c10fb6872751c1af523b996d6afa9James Morris};
131100468e9c05c10fb6872751c1af523b996d6afa9James Morris
132d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic int __init connsecmark_tg_init(void)
133100468e9c05c10fb6872751c1af523b996d6afa9James Morris{
13492f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	return xt_register_target(&connsecmark_tg_reg);
135100468e9c05c10fb6872751c1af523b996d6afa9James Morris}
136100468e9c05c10fb6872751c1af523b996d6afa9James Morris
137d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic void __exit connsecmark_tg_exit(void)
138100468e9c05c10fb6872751c1af523b996d6afa9James Morris{
13992f3b2b1bc968caaabee8cd78bee75ab7c4af74eJan Engelhardt	xt_unregister_target(&connsecmark_tg_reg);
140100468e9c05c10fb6872751c1af523b996d6afa9James Morris}
141100468e9c05c10fb6872751c1af523b996d6afa9James Morris
142d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtmodule_init(connsecmark_tg_init);
143d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtmodule_exit(connsecmark_tg_exit);
144