Blame view

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

1d93a9cba   Jan Engelhardt   [NETFILTER]: x_ta...
25
  static bool
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
26
27
28
29
  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...
30
  	if (l3proto == NFPROTO_IPV4)
6556874dc   Jan Engelhardt   [NETFILTER]: xt_c...
31
  		return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
ee999d8b9   Jan Engelhardt   netfilter: x_tabl...
32
  	else if (l3proto == NFPROTO_IPV6)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
33
34
35
36
37
38
39
40
  		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...
41
                       const struct xt_conntrack_mtinfo2 *info,
76108cea0   Jan Engelhardt   netfilter: Use un...
42
  		     u_int8_t family)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
43
44
45
46
47
48
49
  {
  	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...
50
                       const struct xt_conntrack_mtinfo2 *info,
76108cea0   Jan Engelhardt   netfilter: Use un...
51
  		     u_int8_t family)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
52
53
54
55
56
57
58
  {
  	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...
59
                       const struct xt_conntrack_mtinfo2 *info,
76108cea0   Jan Engelhardt   netfilter: Use un...
60
  		     u_int8_t family)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
61
62
63
64
65
66
67
  {
  	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...
68
                       const struct xt_conntrack_mtinfo2 *info,
76108cea0   Jan Engelhardt   netfilter: Use un...
69
  		     u_int8_t family)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
70
71
72
73
  {
  	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...
74
  static inline bool
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
75
  ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info,
b41649989   Jan Engelhardt   [NETFILTER]: xt_c...
76
77
78
79
80
81
                      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...
82
  	    (nf_ct_protonum(ct) == info->l4proto) ^
b41649989   Jan Engelhardt   [NETFILTER]: xt_c...
83
84
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
  	    !(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...
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
  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...
158
  static bool
62fc80510   Jan Engelhardt   netfilter: xtable...
159
  conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par,
3a0429292   Florian Westphal   netfilter: xtable...
160
               u16 state_mask, u16 status_mask)
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
161
  {
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
162
  	const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
163
164
165
166
167
  	enum ip_conntrack_info ctinfo;
  	const struct nf_conn *ct;
  	unsigned int statebit;
  
  	ct = nf_ct_get(skb, &ctinfo);
cc41c84b7   Florian Westphal   netfilter: kill t...
168
169
170
171
172
  	if (ct)
  		statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
  	else if (ctinfo == IP_CT_UNTRACKED)
  		statebit = XT_CONNTRACK_STATE_UNTRACKED;
  	else
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
173
174
175
176
177
178
179
180
181
  		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...
182
  		if (!!(state_mask & statebit) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
183
184
185
186
187
188
  		    !(info->invert_flags & XT_CONNTRACK_STATE))
  			return false;
  	}
  
  	if (ct == NULL)
  		return info->match_flags & XT_CONNTRACK_STATE;
b41649989   Jan Engelhardt   [NETFILTER]: xt_c...
189
190
  	if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&
  	    (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^
96120d86f   Florian Westphal   netfilter: xt_con...
191
  	    !(info->invert_flags & XT_CONNTRACK_DIRECTION))
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
192
193
194
  		return false;
  
  	if (info->match_flags & XT_CONNTRACK_ORIGSRC)
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
195
  		if (conntrack_mt_origsrc(ct, info, xt_family(par)) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
196
197
198
199
  		    !(info->invert_flags & XT_CONNTRACK_ORIGSRC))
  			return false;
  
  	if (info->match_flags & XT_CONNTRACK_ORIGDST)
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
200
  		if (conntrack_mt_origdst(ct, info, xt_family(par)) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
201
202
203
204
  		    !(info->invert_flags & XT_CONNTRACK_ORIGDST))
  			return false;
  
  	if (info->match_flags & XT_CONNTRACK_REPLSRC)
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
205
  		if (conntrack_mt_replsrc(ct, info, xt_family(par)) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
206
207
208
209
  		    !(info->invert_flags & XT_CONNTRACK_REPLSRC))
  			return false;
  
  	if (info->match_flags & XT_CONNTRACK_REPLDST)
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
210
  		if (conntrack_mt_repldst(ct, info, xt_family(par)) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
211
212
  		    !(info->invert_flags & XT_CONNTRACK_REPLDST))
  			return false;
b017900aa   Patrick McHardy   netfilter: xt_con...
213
214
215
216
217
218
219
  	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...
220

64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
221
  	if ((info->match_flags & XT_CONNTRACK_STATUS) &&
3a0429292   Florian Westphal   netfilter: xtable...
222
  	    (!!(status_mask & ct->status) ^
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
223
224
225
226
  	    !(info->invert_flags & XT_CONNTRACK_STATUS)))
  		return false;
  
  	if (info->match_flags & XT_CONNTRACK_EXPIRES) {
d0b35b93d   Florian Westphal   netfilter: use_nf...
227
  		unsigned long expires = nf_ct_expires(ct) / HZ;
64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
228

64eb12f99   Jan Engelhardt   [NETFILTER]: xt_c...
229
230
231
232
233
234
235
  		if ((expires >= info->expires_min &&
  		    expires <= info->expires_max) ^
  		    !(info->invert_flags & XT_CONNTRACK_EXPIRES))
  			return false;
  	}
  	return true;
  }
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
236
  static bool
62fc80510   Jan Engelhardt   netfilter: xtable...
237
  conntrack_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
238
  {
3a0429292   Florian Westphal   netfilter: xtable...
239
  	const struct xt_conntrack_mtinfo1 *info = par->matchinfo;
d6d3f08b0   Jan Engelhardt   netfilter: xtable...
240

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