Blame view

net/netfilter/xt_ecn.c 4.3 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
af0d29cd2   Patrick McHardy   netfilter: xtable...
2
3
  /*
   * Xtables module for matching the value of the IPv4/IPv6 and TCP ECN bits
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   * (C) 2002 by Harald Welte <laforge@gnumonks.org>
af0d29cd2   Patrick McHardy   netfilter: xtable...
6
   * (C) 2011 Patrick McHardy <kaber@trash.net>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
   */
ff67e4e42   Jan Engelhardt   netfilter: xt ext...
8
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
6709dbbb1   Jan Engelhardt   [NETFILTER]: {ip,...
9
10
  #include <linux/in.h>
  #include <linux/ip.h>
c9bdd4b52   Arnaldo Carvalho de Melo   [IP]: Introduce i...
11
  #include <net/ip.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/tcp.h>
6709dbbb1   Jan Engelhardt   [NETFILTER]: {ip,...
15
  #include <linux/netfilter/x_tables.h>
a4c6f9d36   Jan Engelhardt   netfilter: xtable...
16
  #include <linux/netfilter/xt_ecn.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <linux/netfilter_ipv4/ip_tables.h>
af0d29cd2   Patrick McHardy   netfilter: xtable...
18
  #include <linux/netfilter_ipv6/ip6_tables.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  
  MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
af0d29cd2   Patrick McHardy   netfilter: xtable...
21
  MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  MODULE_LICENSE("GPL");
d446a8202   Jan Engelhardt   netfilter: xtable...
23
  MODULE_ALIAS("ipt_ecn");
af0d29cd2   Patrick McHardy   netfilter: xtable...
24
  MODULE_ALIAS("ip6t_ecn");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25

af0d29cd2   Patrick McHardy   netfilter: xtable...
26
  static bool match_tcp(const struct sk_buff *skb, struct xt_action_param *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  {
af0d29cd2   Patrick McHardy   netfilter: xtable...
28
  	const struct xt_ecn_info *einfo = par->matchinfo;
a47362a22   Jan Engelhardt   [NETFILTER]: add ...
29
30
  	struct tcphdr _tcph;
  	const struct tcphdr *th;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
  
  	/* In practice, TCP match does this, so can't fail.  But let's
  	 * be good citizens.
  	 */
af0d29cd2   Patrick McHardy   netfilter: xtable...
35
  	th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
42c344a3b   Jan Engelhardt   netfilter: xtable...
36
  	if (th == NULL)
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
37
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38

a4c6f9d36   Jan Engelhardt   netfilter: xtable...
39
40
  	if (einfo->operation & XT_ECN_OP_MATCH_ECE) {
  		if (einfo->invert & XT_ECN_OP_MATCH_ECE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  			if (th->ece == 1)
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
42
  				return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
  		} else {
  			if (th->ece == 0)
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
45
  				return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  		}
  	}
a4c6f9d36   Jan Engelhardt   netfilter: xtable...
48
49
  	if (einfo->operation & XT_ECN_OP_MATCH_CWR) {
  		if (einfo->invert & XT_ECN_OP_MATCH_CWR) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  			if (th->cwr == 1)
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
51
  				return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
  		} else {
  			if (th->cwr == 0)
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
54
  				return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
  		}
  	}
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
57
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  }
af0d29cd2   Patrick McHardy   netfilter: xtable...
59
60
61
62
63
64
65
66
  static inline bool match_ip(const struct sk_buff *skb,
  			    const struct xt_ecn_info *einfo)
  {
  	return ((ip_hdr(skb)->tos & XT_ECN_IP_MASK) == einfo->ip_ect) ^
  	       !!(einfo->invert & XT_ECN_OP_MATCH_IP);
  }
  
  static bool ecn_mt4(const struct sk_buff *skb, struct xt_action_param *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  {
a4c6f9d36   Jan Engelhardt   netfilter: xtable...
68
  	const struct xt_ecn_info *info = par->matchinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69

42c344a3b   Jan Engelhardt   netfilter: xtable...
70
71
  	if (info->operation & XT_ECN_OP_MATCH_IP && !match_ip(skb, info))
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72

42c344a3b   Jan Engelhardt   netfilter: xtable...
73
74
75
  	if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
  	    !match_tcp(skb, par))
  		return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
77
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  }
af0d29cd2   Patrick McHardy   netfilter: xtable...
79
  static int ecn_mt_check4(const struct xt_mtchk_param *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  {
a4c6f9d36   Jan Engelhardt   netfilter: xtable...
81
  	const struct xt_ecn_info *info = par->matchinfo;
9b4fce7a3   Jan Engelhardt   netfilter: xtable...
82
  	const struct ipt_ip *ip = par->entryinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

a4c6f9d36   Jan Engelhardt   netfilter: xtable...
84
  	if (info->operation & XT_ECN_OP_MATCH_MASK)
bd414ee60   Jan Engelhardt   netfilter: xtable...
85
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86

a4c6f9d36   Jan Engelhardt   netfilter: xtable...
87
  	if (info->invert & XT_ECN_OP_MATCH_MASK)
bd414ee60   Jan Engelhardt   netfilter: xtable...
88
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89

a4c6f9d36   Jan Engelhardt   netfilter: xtable...
90
  	if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
58d5a0257   Patrick McHardy   netfilter: ipt_ec...
91
  	    (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) {
b26066447   Florian Westphal   netfilter: x_tabl...
92
93
  		pr_info_ratelimited("cannot match TCP bits for non-tcp packets
  ");
bd414ee60   Jan Engelhardt   netfilter: xtable...
94
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  	}
bd414ee60   Jan Engelhardt   netfilter: xtable...
96
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  }
af0d29cd2   Patrick McHardy   netfilter: xtable...
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
  static inline bool match_ipv6(const struct sk_buff *skb,
  			      const struct xt_ecn_info *einfo)
  {
  	return (((ipv6_hdr(skb)->flow_lbl[0] >> 4) & XT_ECN_IP_MASK) ==
  	        einfo->ip_ect) ^
  	       !!(einfo->invert & XT_ECN_OP_MATCH_IP);
  }
  
  static bool ecn_mt6(const struct sk_buff *skb, struct xt_action_param *par)
  {
  	const struct xt_ecn_info *info = par->matchinfo;
  
  	if (info->operation & XT_ECN_OP_MATCH_IP && !match_ipv6(skb, info))
  		return false;
  
  	if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
  	    !match_tcp(skb, par))
  		return false;
  
  	return true;
  }
  
  static int ecn_mt_check6(const struct xt_mtchk_param *par)
  {
  	const struct xt_ecn_info *info = par->matchinfo;
  	const struct ip6t_ip6 *ip = par->entryinfo;
  
  	if (info->operation & XT_ECN_OP_MATCH_MASK)
  		return -EINVAL;
  
  	if (info->invert & XT_ECN_OP_MATCH_MASK)
  		return -EINVAL;
  
  	if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
  	    (ip->proto != IPPROTO_TCP || ip->invflags & IP6T_INV_PROTO)) {
b26066447   Florian Westphal   netfilter: x_tabl...
133
134
  		pr_info_ratelimited("cannot match TCP bits for non-tcp packets
  ");
af0d29cd2   Patrick McHardy   netfilter: xtable...
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static struct xt_match ecn_mt_reg[] __read_mostly = {
  	{
  		.name		= "ecn",
  		.family		= NFPROTO_IPV4,
  		.match		= ecn_mt4,
  		.matchsize	= sizeof(struct xt_ecn_info),
  		.checkentry	= ecn_mt_check4,
  		.me		= THIS_MODULE,
  	},
  	{
  		.name		= "ecn",
  		.family		= NFPROTO_IPV6,
  		.match		= ecn_mt6,
  		.matchsize	= sizeof(struct xt_ecn_info),
  		.checkentry	= ecn_mt_check6,
  		.me		= THIS_MODULE,
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  };
d3c5ee6d5   Jan Engelhardt   [NETFILTER]: x_ta...
159
  static int __init ecn_mt_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  {
af0d29cd2   Patrick McHardy   netfilter: xtable...
161
  	return xt_register_matches(ecn_mt_reg, ARRAY_SIZE(ecn_mt_reg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  }
d3c5ee6d5   Jan Engelhardt   [NETFILTER]: x_ta...
163
  static void __exit ecn_mt_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  {
af0d29cd2   Patrick McHardy   netfilter: xtable...
165
  	xt_unregister_matches(ecn_mt_reg, ARRAY_SIZE(ecn_mt_reg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  }
d3c5ee6d5   Jan Engelhardt   [NETFILTER]: x_ta...
167
168
  module_init(ecn_mt_init);
  module_exit(ecn_mt_exit);