Blame view

net/netfilter/xt_ecn.c 4.43 KB
af0d29cd2   Patrick McHardy   netfilter: xtable...
1
2
  /*
   * Xtables module for matching the value of the IPv4/IPv6 and TCP ECN bits
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   * (C) 2002 by Harald Welte <laforge@gnumonks.org>
af0d29cd2   Patrick McHardy   netfilter: xtable...
5
   * (C) 2011 Patrick McHardy <kaber@trash.net>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
ff67e4e42   Jan Engelhardt   netfilter: xt ext...
11
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
6709dbbb1   Jan Engelhardt   [NETFILTER]: {ip,...
12
13
  #include <linux/in.h>
  #include <linux/ip.h>
c9bdd4b52   Arnaldo Carvalho de Melo   [IP]: Introduce i...
14
  #include <net/ip.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/tcp.h>
6709dbbb1   Jan Engelhardt   [NETFILTER]: {ip,...
18
  #include <linux/netfilter/x_tables.h>
a4c6f9d36   Jan Engelhardt   netfilter: xtable...
19
  #include <linux/netfilter/xt_ecn.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/netfilter_ipv4/ip_tables.h>
af0d29cd2   Patrick McHardy   netfilter: xtable...
21
  #include <linux/netfilter_ipv6/ip6_tables.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
  
  MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
af0d29cd2   Patrick McHardy   netfilter: xtable...
24
  MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  MODULE_LICENSE("GPL");
d446a8202   Jan Engelhardt   netfilter: xtable...
26
  MODULE_ALIAS("ipt_ecn");
af0d29cd2   Patrick McHardy   netfilter: xtable...
27
  MODULE_ALIAS("ip6t_ecn");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

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

a4c6f9d36   Jan Engelhardt   netfilter: xtable...
42
43
  	if (einfo->operation & XT_ECN_OP_MATCH_ECE) {
  		if (einfo->invert & XT_ECN_OP_MATCH_ECE) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  			if (th->ece == 1)
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
45
  				return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
  		} else {
  			if (th->ece == 0)
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
48
  				return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
  		}
  	}
a4c6f9d36   Jan Engelhardt   netfilter: xtable...
51
52
  	if (einfo->operation & XT_ECN_OP_MATCH_CWR) {
  		if (einfo->invert & XT_ECN_OP_MATCH_CWR) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  			if (th->cwr == 1)
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
54
  				return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
  		} else {
  			if (th->cwr == 0)
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
57
  				return false;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  		}
  	}
1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
60
  	return true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  }
af0d29cd2   Patrick McHardy   netfilter: xtable...
62
63
64
65
66
67
68
69
  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
70
  {
a4c6f9d36   Jan Engelhardt   netfilter: xtable...
71
  	const struct xt_ecn_info *info = par->matchinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72

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

42c344a3b   Jan Engelhardt   netfilter: xtable...
76
77
78
  	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
79

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

a4c6f9d36   Jan Engelhardt   netfilter: xtable...
87
  	if (info->operation & 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->invert & XT_ECN_OP_MATCH_MASK)
bd414ee60   Jan Engelhardt   netfilter: xtable...
91
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

a4c6f9d36   Jan Engelhardt   netfilter: xtable...
93
  	if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
58d5a0257   Patrick McHardy   netfilter: ipt_ec...
94
  	    (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) {
ff67e4e42   Jan Engelhardt   netfilter: xt ext...
95
96
  		pr_info("cannot match TCP bits in rule for non-tcp packets
  ");
bd414ee60   Jan Engelhardt   netfilter: xtable...
97
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  	}
bd414ee60   Jan Engelhardt   netfilter: xtable...
99
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  }
af0d29cd2   Patrick McHardy   netfilter: xtable...
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
  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)) {
  		pr_info("cannot match TCP bits in rule for non-tcp packets
  ");
  		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
161
  };
d3c5ee6d5   Jan Engelhardt   [NETFILTER]: x_ta...
162
  static int __init ecn_mt_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  {
af0d29cd2   Patrick McHardy   netfilter: xtable...
164
  	return xt_register_matches(ecn_mt_reg, ARRAY_SIZE(ecn_mt_reg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
  }
d3c5ee6d5   Jan Engelhardt   [NETFILTER]: x_ta...
166
  static void __exit ecn_mt_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  {
af0d29cd2   Patrick McHardy   netfilter: xtable...
168
  	xt_unregister_matches(ecn_mt_reg, ARRAY_SIZE(ecn_mt_reg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  }
d3c5ee6d5   Jan Engelhardt   [NETFILTER]: x_ta...
170
171
  module_init(ecn_mt_init);
  module_exit(ecn_mt_exit);