1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * (C) 2013 Astaro GmbH & Co KG |
4 | */ |
5 | |
6 | #include <linux/module.h> |
7 | #include <linux/skbuff.h> |
8 | #include <net/netfilter/nf_conntrack.h> |
9 | #include <net/netfilter/nf_conntrack_ecache.h> |
10 | #include <net/netfilter/nf_conntrack_labels.h> |
11 | #include <linux/netfilter/x_tables.h> |
12 | |
13 | MODULE_LICENSE("GPL" ); |
14 | MODULE_AUTHOR("Florian Westphal <fw@strlen.de>" ); |
15 | MODULE_DESCRIPTION("Xtables: add/match connection tracking labels" ); |
16 | MODULE_ALIAS("ipt_connlabel" ); |
17 | MODULE_ALIAS("ip6t_connlabel" ); |
18 | |
19 | static bool |
20 | connlabel_mt(const struct sk_buff *skb, struct xt_action_param *par) |
21 | { |
22 | const struct xt_connlabel_mtinfo *info = par->matchinfo; |
23 | enum ip_conntrack_info ctinfo; |
24 | struct nf_conn_labels *labels; |
25 | struct nf_conn *ct; |
26 | bool invert = info->options & XT_CONNLABEL_OP_INVERT; |
27 | |
28 | ct = nf_ct_get(skb, ctinfo: &ctinfo); |
29 | if (ct == NULL) |
30 | return invert; |
31 | |
32 | labels = nf_ct_labels_find(ct); |
33 | if (!labels) |
34 | return invert; |
35 | |
36 | if (test_bit(info->bit, labels->bits)) |
37 | return !invert; |
38 | |
39 | if (info->options & XT_CONNLABEL_OP_SET) { |
40 | if (!test_and_set_bit(nr: info->bit, addr: labels->bits)) |
41 | nf_conntrack_event_cache(event: IPCT_LABEL, ct); |
42 | |
43 | return !invert; |
44 | } |
45 | |
46 | return invert; |
47 | } |
48 | |
49 | static int connlabel_mt_check(const struct xt_mtchk_param *par) |
50 | { |
51 | const int options = XT_CONNLABEL_OP_INVERT | |
52 | XT_CONNLABEL_OP_SET; |
53 | struct xt_connlabel_mtinfo *info = par->matchinfo; |
54 | int ret; |
55 | |
56 | if (info->options & ~options) { |
57 | pr_info_ratelimited("Unknown options in mask %x\n" , |
58 | info->options); |
59 | return -EINVAL; |
60 | } |
61 | |
62 | ret = nf_ct_netns_get(net: par->net, nfproto: par->family); |
63 | if (ret < 0) { |
64 | pr_info_ratelimited("cannot load conntrack support for proto=%u\n" , |
65 | par->family); |
66 | return ret; |
67 | } |
68 | |
69 | ret = nf_connlabels_get(net: par->net, bit: info->bit); |
70 | if (ret < 0) |
71 | nf_ct_netns_put(net: par->net, nfproto: par->family); |
72 | return ret; |
73 | } |
74 | |
75 | static void connlabel_mt_destroy(const struct xt_mtdtor_param *par) |
76 | { |
77 | nf_connlabels_put(net: par->net); |
78 | nf_ct_netns_put(net: par->net, nfproto: par->family); |
79 | } |
80 | |
81 | static struct xt_match connlabels_mt_reg __read_mostly = { |
82 | .name = "connlabel" , |
83 | .family = NFPROTO_UNSPEC, |
84 | .checkentry = connlabel_mt_check, |
85 | .match = connlabel_mt, |
86 | .matchsize = sizeof(struct xt_connlabel_mtinfo), |
87 | .destroy = connlabel_mt_destroy, |
88 | .me = THIS_MODULE, |
89 | }; |
90 | |
91 | static int __init connlabel_mt_init(void) |
92 | { |
93 | return xt_register_match(target: &connlabels_mt_reg); |
94 | } |
95 | |
96 | static void __exit connlabel_mt_exit(void) |
97 | { |
98 | xt_unregister_match(target: &connlabels_mt_reg); |
99 | } |
100 | |
101 | module_init(connlabel_mt_init); |
102 | module_exit(connlabel_mt_exit); |
103 | |