1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* IP tables module for matching the value of the IPv4/IPv6 DSCP field |
3 | * |
4 | * (C) 2002 by Harald Welte <laforge@netfilter.org> |
5 | */ |
6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
7 | #include <linux/module.h> |
8 | #include <linux/skbuff.h> |
9 | #include <linux/ip.h> |
10 | #include <linux/ipv6.h> |
11 | #include <net/dsfield.h> |
12 | |
13 | #include <linux/netfilter/x_tables.h> |
14 | #include <linux/netfilter/xt_dscp.h> |
15 | |
16 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>" ); |
17 | MODULE_DESCRIPTION("Xtables: DSCP/TOS field match" ); |
18 | MODULE_LICENSE("GPL" ); |
19 | MODULE_ALIAS("ipt_dscp" ); |
20 | MODULE_ALIAS("ip6t_dscp" ); |
21 | MODULE_ALIAS("ipt_tos" ); |
22 | MODULE_ALIAS("ip6t_tos" ); |
23 | |
24 | static bool |
25 | dscp_mt(const struct sk_buff *skb, struct xt_action_param *par) |
26 | { |
27 | const struct xt_dscp_info *info = par->matchinfo; |
28 | u_int8_t dscp = ipv4_get_dsfield(iph: ip_hdr(skb)) >> XT_DSCP_SHIFT; |
29 | |
30 | return (dscp == info->dscp) ^ !!info->invert; |
31 | } |
32 | |
33 | static bool |
34 | dscp_mt6(const struct sk_buff *skb, struct xt_action_param *par) |
35 | { |
36 | const struct xt_dscp_info *info = par->matchinfo; |
37 | u_int8_t dscp = ipv6_get_dsfield(ipv6h: ipv6_hdr(skb)) >> XT_DSCP_SHIFT; |
38 | |
39 | return (dscp == info->dscp) ^ !!info->invert; |
40 | } |
41 | |
42 | static int dscp_mt_check(const struct xt_mtchk_param *par) |
43 | { |
44 | const struct xt_dscp_info *info = par->matchinfo; |
45 | |
46 | if (info->dscp > XT_DSCP_MAX) |
47 | return -EDOM; |
48 | |
49 | return 0; |
50 | } |
51 | |
52 | static bool tos_mt(const struct sk_buff *skb, struct xt_action_param *par) |
53 | { |
54 | const struct xt_tos_match_info *info = par->matchinfo; |
55 | |
56 | if (xt_family(par) == NFPROTO_IPV4) |
57 | return ((ip_hdr(skb)->tos & info->tos_mask) == |
58 | info->tos_value) ^ !!info->invert; |
59 | else |
60 | return ((ipv6_get_dsfield(ipv6h: ipv6_hdr(skb)) & info->tos_mask) == |
61 | info->tos_value) ^ !!info->invert; |
62 | } |
63 | |
64 | static struct xt_match dscp_mt_reg[] __read_mostly = { |
65 | { |
66 | .name = "dscp" , |
67 | .family = NFPROTO_IPV4, |
68 | .checkentry = dscp_mt_check, |
69 | .match = dscp_mt, |
70 | .matchsize = sizeof(struct xt_dscp_info), |
71 | .me = THIS_MODULE, |
72 | }, |
73 | { |
74 | .name = "dscp" , |
75 | .family = NFPROTO_IPV6, |
76 | .checkentry = dscp_mt_check, |
77 | .match = dscp_mt6, |
78 | .matchsize = sizeof(struct xt_dscp_info), |
79 | .me = THIS_MODULE, |
80 | }, |
81 | { |
82 | .name = "tos" , |
83 | .revision = 1, |
84 | .family = NFPROTO_IPV4, |
85 | .match = tos_mt, |
86 | .matchsize = sizeof(struct xt_tos_match_info), |
87 | .me = THIS_MODULE, |
88 | }, |
89 | { |
90 | .name = "tos" , |
91 | .revision = 1, |
92 | .family = NFPROTO_IPV6, |
93 | .match = tos_mt, |
94 | .matchsize = sizeof(struct xt_tos_match_info), |
95 | .me = THIS_MODULE, |
96 | }, |
97 | }; |
98 | |
99 | static int __init dscp_mt_init(void) |
100 | { |
101 | return xt_register_matches(match: dscp_mt_reg, ARRAY_SIZE(dscp_mt_reg)); |
102 | } |
103 | |
104 | static void __exit dscp_mt_exit(void) |
105 | { |
106 | xt_unregister_matches(match: dscp_mt_reg, ARRAY_SIZE(dscp_mt_reg)); |
107 | } |
108 | |
109 | module_init(dscp_mt_init); |
110 | module_exit(dscp_mt_exit); |
111 | |