1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2100468e9SJames Morris /*
3100468e9SJames Morris * This module is used to copy security markings from packets
4100468e9SJames Morris * to connections, and restore security markings from connections
5100468e9SJames Morris * back to packets. This would normally be performed in conjunction
6100468e9SJames Morris * with the SECMARK target and state match.
7100468e9SJames Morris *
8100468e9SJames Morris * Based somewhat on CONNMARK:
950935339SAlexander A. Klimov * Copyright (C) 2002,2004 MARA Systems AB <https://www.marasystems.com>
10100468e9SJames Morris * by Henrik Nordstrom <hno@marasystems.com>
11100468e9SJames Morris *
12560ee653SJames Morris * (C) 2006,2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
13100468e9SJames Morris */
148bee4badSJan Engelhardt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15100468e9SJames Morris #include <linux/module.h>
16100468e9SJames Morris #include <linux/skbuff.h>
17100468e9SJames Morris #include <linux/netfilter/x_tables.h>
18100468e9SJames Morris #include <linux/netfilter/xt_CONNSECMARK.h>
19587aa641SPatrick McHardy #include <net/netfilter/nf_conntrack.h>
2037fccd85SPablo Neira Ayuso #include <net/netfilter/nf_conntrack_ecache.h>
21100468e9SJames Morris
22100468e9SJames Morris MODULE_LICENSE("GPL");
23100468e9SJames Morris MODULE_AUTHOR("James Morris <jmorris@redhat.com>");
242ae15b64SJan Engelhardt MODULE_DESCRIPTION("Xtables: target for copying between connection and security mark");
25100468e9SJames Morris MODULE_ALIAS("ipt_CONNSECMARK");
26100468e9SJames Morris MODULE_ALIAS("ip6t_CONNSECMARK");
27100468e9SJames Morris
28100468e9SJames Morris /*
29100468e9SJames Morris * If the packet has a security mark and the connection does not, copy
30100468e9SJames Morris * the security mark from the packet to the connection.
31100468e9SJames Morris */
secmark_save(const struct sk_buff * skb)32a47362a2SJan Engelhardt static void secmark_save(const struct sk_buff *skb)
33100468e9SJames Morris {
34100468e9SJames Morris if (skb->secmark) {
35587aa641SPatrick McHardy struct nf_conn *ct;
36100468e9SJames Morris enum ip_conntrack_info ctinfo;
37100468e9SJames Morris
38587aa641SPatrick McHardy ct = nf_ct_get(skb, &ctinfo);
3937fccd85SPablo Neira Ayuso if (ct && !ct->secmark) {
40587aa641SPatrick McHardy ct->secmark = skb->secmark;
41a71996fcSAlexey Dobriyan nf_conntrack_event_cache(IPCT_SECMARK, ct);
4237fccd85SPablo Neira Ayuso }
43100468e9SJames Morris }
44100468e9SJames Morris }
45100468e9SJames Morris
46100468e9SJames Morris /*
47100468e9SJames Morris * If packet has no security mark, and the connection does, restore the
48100468e9SJames Morris * security mark from the connection to the packet.
49100468e9SJames Morris */
secmark_restore(struct sk_buff * skb)50100468e9SJames Morris static void secmark_restore(struct sk_buff *skb)
51100468e9SJames Morris {
52100468e9SJames Morris if (!skb->secmark) {
533cf93c96SJan Engelhardt const struct nf_conn *ct;
54100468e9SJames Morris enum ip_conntrack_info ctinfo;
55100468e9SJames Morris
56587aa641SPatrick McHardy ct = nf_ct_get(skb, &ctinfo);
57587aa641SPatrick McHardy if (ct && ct->secmark)
58587aa641SPatrick McHardy skb->secmark = ct->secmark;
59100468e9SJames Morris }
60100468e9SJames Morris }
61100468e9SJames Morris
62d3c5ee6dSJan Engelhardt static unsigned int
connsecmark_tg(struct sk_buff * skb,const struct xt_action_param * par)634b560b44SJan Engelhardt connsecmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
64100468e9SJames Morris {
657eb35586SJan Engelhardt const struct xt_connsecmark_target_info *info = par->targinfo;
66100468e9SJames Morris
67100468e9SJames Morris switch (info->mode) {
68100468e9SJames Morris case CONNSECMARK_SAVE:
69100468e9SJames Morris secmark_save(skb);
70100468e9SJames Morris break;
71100468e9SJames Morris
72100468e9SJames Morris case CONNSECMARK_RESTORE:
73100468e9SJames Morris secmark_restore(skb);
74100468e9SJames Morris break;
75100468e9SJames Morris
76100468e9SJames Morris default:
77100468e9SJames Morris BUG();
78100468e9SJames Morris }
79100468e9SJames Morris
80100468e9SJames Morris return XT_CONTINUE;
81100468e9SJames Morris }
82100468e9SJames Morris
connsecmark_tg_check(const struct xt_tgchk_param * par)83135367b8SJan Engelhardt static int connsecmark_tg_check(const struct xt_tgchk_param *par)
84100468e9SJames Morris {
85af5d6dc2SJan Engelhardt const struct xt_connsecmark_target_info *info = par->targinfo;
864a5a5c73SJan Engelhardt int ret;
87100468e9SJames Morris
88af5d6dc2SJan Engelhardt if (strcmp(par->table, "mangle") != 0 &&
89af5d6dc2SJan Engelhardt strcmp(par->table, "security") != 0) {
90cc48baefSFlorian Westphal pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n",
91cc48baefSFlorian Westphal par->table);
92d6b00a53SJan Engelhardt return -EINVAL;
93560ee653SJames Morris }
94560ee653SJames Morris
95100468e9SJames Morris switch (info->mode) {
96100468e9SJames Morris case CONNSECMARK_SAVE:
97100468e9SJames Morris case CONNSECMARK_RESTORE:
98100468e9SJames Morris break;
99100468e9SJames Morris
100100468e9SJames Morris default:
101b2606644SFlorian Westphal pr_info_ratelimited("invalid mode: %hu\n", info->mode);
1024a5a5c73SJan Engelhardt return -EINVAL;
103100468e9SJames Morris }
104100468e9SJames Morris
105ecb2421bSFlorian Westphal ret = nf_ct_netns_get(par->net, par->family);
106f95c74e3SJan Engelhardt if (ret < 0)
107b2606644SFlorian Westphal pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
1088bee4badSJan Engelhardt par->family);
1094a5a5c73SJan Engelhardt return ret;
11067b4af29SJan Engelhardt }
111100468e9SJames Morris
connsecmark_tg_destroy(const struct xt_tgdtor_param * par)112a2df1648SJan Engelhardt static void connsecmark_tg_destroy(const struct xt_tgdtor_param *par)
11311078c37SYasuyuki Kozakai {
114ecb2421bSFlorian Westphal nf_ct_netns_put(par->net, par->family);
11511078c37SYasuyuki Kozakai }
11611078c37SYasuyuki Kozakai
11792f3b2b1SJan Engelhardt static struct xt_target connsecmark_tg_reg __read_mostly = {
118100468e9SJames Morris .name = "CONNSECMARK",
11992f3b2b1SJan Engelhardt .revision = 0,
12092f3b2b1SJan Engelhardt .family = NFPROTO_UNSPEC,
121d3c5ee6dSJan Engelhardt .checkentry = connsecmark_tg_check,
122d3c5ee6dSJan Engelhardt .destroy = connsecmark_tg_destroy,
123d3c5ee6dSJan Engelhardt .target = connsecmark_tg,
124100468e9SJames Morris .targetsize = sizeof(struct xt_connsecmark_target_info),
125100468e9SJames Morris .me = THIS_MODULE,
126100468e9SJames Morris };
127100468e9SJames Morris
connsecmark_tg_init(void)128d3c5ee6dSJan Engelhardt static int __init connsecmark_tg_init(void)
129100468e9SJames Morris {
13092f3b2b1SJan Engelhardt return xt_register_target(&connsecmark_tg_reg);
131100468e9SJames Morris }
132100468e9SJames Morris
connsecmark_tg_exit(void)133d3c5ee6dSJan Engelhardt static void __exit connsecmark_tg_exit(void)
134100468e9SJames Morris {
13592f3b2b1SJan Engelhardt xt_unregister_target(&connsecmark_tg_reg);
136100468e9SJames Morris }
137100468e9SJames Morris
138d3c5ee6dSJan Engelhardt module_init(connsecmark_tg_init);
139d3c5ee6dSJan Engelhardt module_exit(connsecmark_tg_exit);
140