Blame view

net/netfilter/xt_conntrack.c 9.6 KB
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
1
2
3
  /*
   *	xt_conntrack - Netfilter module to match connection tracking
   *	information. (Superset of Rusty's minimalistic state match.)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   *
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
5
6
   *	(C) 2001  Marc Boucher (marc@mbsi.ca).
   *	Copyright © CC Computer Consultants GmbH, 2007 - 2008
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
   *
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
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.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
   */
8bee4bad0   Jan Engelhardt   netfilter: xt ext...
12
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
  #include <linux/module.h>
  #include <linux/skbuff.h>
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
15
  #include <net/ipv6.h>
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
16
17
  #include <linux/netfilter/x_tables.h>
  #include <linux/netfilter/xt_conntrack.h>
587aa6416   Patrick McHardy   [NETFILTER]: Remo...
18
  #include <net/netfilter/nf_conntrack.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
9e05ec4b1   Jan Engelhardt   netfilter: xtable...
22
  MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
2ae15b64e   Jan Engelhardt   [NETFILTER]: Upda...
23
  MODULE_DESCRIPTION("Xtables: connection tracking state match");
2e4e6a17a   Harald Welte   [NETFILTER] x_tab...
24
  MODULE_ALIAS("ipt_conntrack");
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
25
  MODULE_ALIAS("ip6t_conntrack");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26

1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
27
  static bool
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
28
29
30
31
  conntrack_addrcmp(const union nf_inet_addr *kaddr,
                    const union nf_inet_addr *uaddr,
                    const union nf_inet_addr *umask, unsigned int l3proto)
  {
ee999d8b9   Jan Engelhardt   netfilter: x_tabl...
32
  	if (l3proto == NFPROTO_IPV4)
6556874dc   Jan Engelhardt   [NETFILTER]: xt_c...
33
  		return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
ee999d8b9   Jan Engelhardt   netfilter: x_tabl...
34
  	else if (l3proto == NFPROTO_IPV6)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
35
36
37
38
39
40
41
42
  		return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
  		       &uaddr->in6) == 0;
  	else
  		return false;
  }
  
  static inline bool
  conntrack_mt_origsrc(const struct nf_conn *ct,
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
43
                       const struct xt_conntrack_mtinfo2 *info,
76108cea0   Jan Engelhardt   netfilter: Use un...
44
  		     u_int8_t family)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
45
46
47
48
49
50
51
  {
  	return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
  	       &info->origsrc_addr, &info->origsrc_mask, family);
  }
  
  static inline bool
  conntrack_mt_origdst(const struct nf_conn *ct,
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
52
                       const struct xt_conntrack_mtinfo2 *info,
76108cea0   Jan Engelhardt   netfilter: Use un...
53
  		     u_int8_t family)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
54
55
56
57
58
59
60
  {
  	return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3,
  	       &info->origdst_addr, &info->origdst_mask, family);
  }
  
  static inline bool
  conntrack_mt_replsrc(const struct nf_conn *ct,
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
61
                       const struct xt_conntrack_mtinfo2 *info,
76108cea0   Jan Engelhardt   netfilter: Use un...
62
  		     u_int8_t family)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
63
64
65
66
67
68
69
  {
  	return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3,
  	       &info->replsrc_addr, &info->replsrc_mask, family);
  }
  
  static inline bool
  conntrack_mt_repldst(const struct nf_conn *ct,
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
70
                       const struct xt_conntrack_mtinfo2 *info,
76108cea0   Jan Engelhardt   netfilter: Use un...
71
  		     u_int8_t family)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
72
73
74
75
  {
  	return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3,
  	       &info->repldst_addr, &info->repldst_mask, family);
  }
b41649989   Jan Engelhardt   [NETFILTER]: xt_c...
76
  static inline bool
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
77
  ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info,
b41649989   Jan Engelhardt   [NETFILTER]: xt_c...
78
79
80
81
82
83
                      const struct nf_conn *ct)
  {
  	const struct nf_conntrack_tuple *tuple;
  
  	tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
  	if ((info->match_flags & XT_CONNTRACK_PROTO) &&
5e8fbe2ac   Patrick McHardy   [NETFILTER]: nf_c...
84
  	    (nf_ct_protonum(ct) == info->l4proto) ^
b41649989   Jan Engelhardt   [NETFILTER]: xt_c...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
  	    !(info->invert_flags & XT_CONNTRACK_PROTO))
  		return false;
  
  	/* Shortcut to match all recognized protocols by using ->src.all. */
  	if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
  	    (tuple->src.u.all == info->origsrc_port) ^
  	    !(info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT))
  		return false;
  
  	if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
  	    (tuple->dst.u.all == info->origdst_port) ^
  	    !(info->invert_flags & XT_CONNTRACK_ORIGDST_PORT))
  		return false;
  
  	tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
  
  	if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
  	    (tuple->src.u.all == info->replsrc_port) ^
  	    !(info->invert_flags & XT_CONNTRACK_REPLSRC_PORT))
  		return false;
  
  	if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
  	    (tuple->dst.u.all == info->repldst_port) ^
  	    !(info->invert_flags & XT_CONNTRACK_REPLDST_PORT))
  		return false;
  
  	return true;
  }
b017900aa   Patrick McHardy   netfilter: xt_con...
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
  static inline bool
  port_match(u16 min, u16 max, u16 port, bool invert)
  {
  	return (port >= min && port <= max) ^ invert;
  }
  
  static inline bool
  ct_proto_port_check_v3(const struct xt_conntrack_mtinfo3 *info,
  		       const struct nf_conn *ct)
  {
  	const struct nf_conntrack_tuple *tuple;
  
  	tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
  	if ((info->match_flags & XT_CONNTRACK_PROTO) &&
  	    (nf_ct_protonum(ct) == info->l4proto) ^
  	    !(info->invert_flags & XT_CONNTRACK_PROTO))
  		return false;
  
  	/* Shortcut to match all recognized protocols by using ->src.all. */
  	if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
  	    !port_match(info->origsrc_port, info->origsrc_port_high,
  			ntohs(tuple->src.u.all),
  			info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT))
  		return false;
  
  	if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
  	    !port_match(info->origdst_port, info->origdst_port_high,
  			ntohs(tuple->dst.u.all),
  			info->invert_flags & XT_CONNTRACK_ORIGDST_PORT))
  		return false;
  
  	tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
  
  	if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
  	    !port_match(info->replsrc_port, info->replsrc_port_high,
  			ntohs(tuple->src.u.all),
  			info->invert_flags & XT_CONNTRACK_REPLSRC_PORT))
  		return false;
  
  	if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
  	    !port_match(info->repldst_port, info->repldst_port_high,
  			ntohs(tuple->dst.u.all),
  			info->invert_flags & XT_CONNTRACK_REPLDST_PORT))
  		return false;
  
  	return true;
  }
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
160
  static bool
62fc80510   Jan Engelhardt   netfilter: xtable...
161
  conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par,
3a0429292   Florian Westphal   netfilter: xtable...
162
               u16 state_mask, u16 status_mask)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
163
  {
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
164
  	const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
165
166
167
168
169
  	enum ip_conntrack_info ctinfo;
  	const struct nf_conn *ct;
  	unsigned int statebit;
  
  	ct = nf_ct_get(skb, &ctinfo);
5bfddbd46   Eric Dumazet   netfilter: nf_con...
170
171
172
173
174
175
  	if (ct) {
  		if (nf_ct_is_untracked(ct))
  			statebit = XT_CONNTRACK_STATE_UNTRACKED;
  		else
  			statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
  	} else
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
176
177
178
179
180
181
182
183
184
  		statebit = XT_CONNTRACK_STATE_INVALID;
  
  	if (info->match_flags & XT_CONNTRACK_STATE) {
  		if (ct != NULL) {
  			if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
  				statebit |= XT_CONNTRACK_STATE_SNAT;
  			if (test_bit(IPS_DST_NAT_BIT, &ct->status))
  				statebit |= XT_CONNTRACK_STATE_DNAT;
  		}
3a0429292   Florian Westphal   netfilter: xtable...
185
  		if (!!(state_mask & statebit) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
186
187
188
189
190
191
  		    !(info->invert_flags & XT_CONNTRACK_STATE))
  			return false;
  	}
  
  	if (ct == NULL)
  		return info->match_flags & XT_CONNTRACK_STATE;
b41649989   Jan Engelhardt   [NETFILTER]: xt_c...
192
193
  	if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&
  	    (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^
96120d86f   Florian Westphal   netfilter: xt_con...
194
  	    !(info->invert_flags & XT_CONNTRACK_DIRECTION))
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
195
196
197
  		return false;
  
  	if (info->match_flags & XT_CONNTRACK_ORIGSRC)
92f3b2b1b   Jan Engelhardt   netfilter: xtable...
198
  		if (conntrack_mt_origsrc(ct, info, par->family) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
199
200
201
202
  		    !(info->invert_flags & XT_CONNTRACK_ORIGSRC))
  			return false;
  
  	if (info->match_flags & XT_CONNTRACK_ORIGDST)
92f3b2b1b   Jan Engelhardt   netfilter: xtable...
203
  		if (conntrack_mt_origdst(ct, info, par->family) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
204
205
206
207
  		    !(info->invert_flags & XT_CONNTRACK_ORIGDST))
  			return false;
  
  	if (info->match_flags & XT_CONNTRACK_REPLSRC)
92f3b2b1b   Jan Engelhardt   netfilter: xtable...
208
  		if (conntrack_mt_replsrc(ct, info, par->family) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
209
210
211
212
  		    !(info->invert_flags & XT_CONNTRACK_REPLSRC))
  			return false;
  
  	if (info->match_flags & XT_CONNTRACK_REPLDST)
92f3b2b1b   Jan Engelhardt   netfilter: xtable...
213
  		if (conntrack_mt_repldst(ct, info, par->family) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
214
215
  		    !(info->invert_flags & XT_CONNTRACK_REPLDST))
  			return false;
b017900aa   Patrick McHardy   netfilter: xt_con...
216
217
218
219
220
221
222
  	if (par->match->revision != 3) {
  		if (!ct_proto_port_check(info, ct))
  			return false;
  	} else {
  		if (!ct_proto_port_check_v3(par->matchinfo, ct))
  			return false;
  	}
b41649989   Jan Engelhardt   [NETFILTER]: xt_c...
223

64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
224
  	if ((info->match_flags & XT_CONNTRACK_STATUS) &&
3a0429292   Florian Westphal   netfilter: xtable...
225
  	    (!!(status_mask & ct->status) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
  	    !(info->invert_flags & XT_CONNTRACK_STATUS)))
  		return false;
  
  	if (info->match_flags & XT_CONNTRACK_EXPIRES) {
  		unsigned long expires = 0;
  
  		if (timer_pending(&ct->timeout))
  			expires = (ct->timeout.expires - jiffies) / HZ;
  		if ((expires >= info->expires_min &&
  		    expires <= info->expires_max) ^
  		    !(info->invert_flags & XT_CONNTRACK_EXPIRES))
  			return false;
  	}
  	return true;
  }
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
241
  static bool
62fc80510   Jan Engelhardt   netfilter: xtable...
242
  conntrack_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
243
  {
3a0429292   Florian Westphal   netfilter: xtable...
244
  	const struct xt_conntrack_mtinfo1 *info = par->matchinfo;
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
245

3a0429292   Florian Westphal   netfilter: xtable...
246
247
248
249
  	return conntrack_mt(skb, par, info->state_mask, info->status_mask);
  }
  
  static bool
62fc80510   Jan Engelhardt   netfilter: xtable...
250
  conntrack_mt_v2(const struct sk_buff *skb, struct xt_action_param *par)
3a0429292   Florian Westphal   netfilter: xtable...
251
252
253
254
  {
  	const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
  
  	return conntrack_mt(skb, par, info->state_mask, info->status_mask);
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
255
  }
b017900aa   Patrick McHardy   netfilter: xt_con...
256
257
258
259
260
261
262
  static bool
  conntrack_mt_v3(const struct sk_buff *skb, struct xt_action_param *par)
  {
  	const struct xt_conntrack_mtinfo3 *info = par->matchinfo;
  
  	return conntrack_mt(skb, par, info->state_mask, info->status_mask);
  }
b0f38452f   Jan Engelhardt   netfilter: xtable...
263
  static int conntrack_mt_check(const struct xt_mtchk_param *par)
b9f78f9fc   Pablo Neira Ayuso   [NETFILTER]: nf_c...
264
  {
4a5a5c73b   Jan Engelhardt   netfilter: xtable...
265
266
267
  	int ret;
  
  	ret = nf_ct_l3proto_try_module_get(par->family);
f95c74e33   Jan Engelhardt   netfilter: xtable...
268
  	if (ret < 0)
8bee4bad0   Jan Engelhardt   netfilter: xt ext...
269
270
271
  		pr_info("cannot load conntrack support for proto=%u
  ",
  			par->family);
f95c74e33   Jan Engelhardt   netfilter: xtable...
272
  	return ret;
b9f78f9fc   Pablo Neira Ayuso   [NETFILTER]: nf_c...
273
  }
6be3d8598   Jan Engelhardt   netfilter: xtable...
274
  static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
b9f78f9fc   Pablo Neira Ayuso   [NETFILTER]: nf_c...
275
  {
92f3b2b1b   Jan Engelhardt   netfilter: xtable...
276
  	nf_ct_l3proto_module_put(par->family);
b9f78f9fc   Pablo Neira Ayuso   [NETFILTER]: nf_c...
277
  }
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
278
279
280
  static struct xt_match conntrack_mt_reg[] __read_mostly = {
  	{
  		.name       = "conntrack",
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
281
  		.revision   = 1,
92f3b2b1b   Jan Engelhardt   netfilter: xtable...
282
  		.family     = NFPROTO_UNSPEC,
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
283
  		.matchsize  = sizeof(struct xt_conntrack_mtinfo1),
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
284
  		.match      = conntrack_mt_v1,
3a0429292   Florian Westphal   netfilter: xtable...
285
286
  		.checkentry = conntrack_mt_check,
  		.destroy    = conntrack_mt_destroy,
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
287
288
289
290
291
292
293
  		.me         = THIS_MODULE,
  	},
  	{
  		.name       = "conntrack",
  		.revision   = 2,
  		.family     = NFPROTO_UNSPEC,
  		.matchsize  = sizeof(struct xt_conntrack_mtinfo2),
3a0429292   Florian Westphal   netfilter: xtable...
294
  		.match      = conntrack_mt_v2,
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
295
296
297
298
  		.checkentry = conntrack_mt_check,
  		.destroy    = conntrack_mt_destroy,
  		.me         = THIS_MODULE,
  	},
b017900aa   Patrick McHardy   netfilter: xt_con...
299
300
301
302
303
304
305
306
307
308
  	{
  		.name       = "conntrack",
  		.revision   = 3,
  		.family     = NFPROTO_UNSPEC,
  		.matchsize  = sizeof(struct xt_conntrack_mtinfo3),
  		.match      = conntrack_mt_v3,
  		.checkentry = conntrack_mt_check,
  		.destroy    = conntrack_mt_destroy,
  		.me         = THIS_MODULE,
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  };
d3c5ee6d5   Jan Engelhardt   [NETFILTER]: x_ta...
310
  static int __init conntrack_mt_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  {
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
312
313
  	return xt_register_matches(conntrack_mt_reg,
  	       ARRAY_SIZE(conntrack_mt_reg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  }
d3c5ee6d5   Jan Engelhardt   [NETFILTER]: x_ta...
315
  static void __exit conntrack_mt_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
  {
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
317
  	xt_unregister_matches(conntrack_mt_reg, ARRAY_SIZE(conntrack_mt_reg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
  }
d3c5ee6d5   Jan Engelhardt   [NETFILTER]: x_ta...
319
320
  module_init(conntrack_mt_init);
  module_exit(conntrack_mt_exit);