Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
xt_conntrack.c
Go to the documentation of this file.
1 /*
2  * xt_conntrack - Netfilter module to match connection tracking
3  * information. (Superset of Rusty's minimalistic state match.)
4  *
5  * (C) 2001 Marc Boucher ([email protected]).
6  * Copyright © CC Computer Consultants GmbH, 2007 - 2008
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13 #include <linux/module.h>
14 #include <linux/skbuff.h>
15 #include <net/ipv6.h>
16 #include <linux/netfilter/x_tables.h>
19 
20 MODULE_LICENSE("GPL");
21 MODULE_AUTHOR("Marc Boucher <[email protected]>");
22 MODULE_AUTHOR("Jan Engelhardt <[email protected]>");
23 MODULE_DESCRIPTION("Xtables: connection tracking state match");
24 MODULE_ALIAS("ipt_conntrack");
25 MODULE_ALIAS("ip6t_conntrack");
26 
27 static bool
28 conntrack_addrcmp(const union nf_inet_addr *kaddr,
29  const union nf_inet_addr *uaddr,
30  const union nf_inet_addr *umask, unsigned int l3proto)
31 {
32  if (l3proto == NFPROTO_IPV4)
33  return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
34  else if (l3proto == NFPROTO_IPV6)
35  return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
36  &uaddr->in6) == 0;
37  else
38  return false;
39 }
40 
41 static inline bool
42 conntrack_mt_origsrc(const struct nf_conn *ct,
43  const struct xt_conntrack_mtinfo2 *info,
45 {
46  return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
47  &info->origsrc_addr, &info->origsrc_mask, family);
48 }
49 
50 static inline bool
51 conntrack_mt_origdst(const struct nf_conn *ct,
52  const struct xt_conntrack_mtinfo2 *info,
54 {
55  return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3,
56  &info->origdst_addr, &info->origdst_mask, family);
57 }
58 
59 static inline bool
60 conntrack_mt_replsrc(const struct nf_conn *ct,
61  const struct xt_conntrack_mtinfo2 *info,
63 {
64  return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3,
65  &info->replsrc_addr, &info->replsrc_mask, family);
66 }
67 
68 static inline bool
69 conntrack_mt_repldst(const struct nf_conn *ct,
70  const struct xt_conntrack_mtinfo2 *info,
72 {
73  return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3,
74  &info->repldst_addr, &info->repldst_mask, family);
75 }
76 
77 static inline bool
78 ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info,
79  const struct nf_conn *ct)
80 {
81  const struct nf_conntrack_tuple *tuple;
82 
83  tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
84  if ((info->match_flags & XT_CONNTRACK_PROTO) &&
85  (nf_ct_protonum(ct) == info->l4proto) ^
87  return false;
88 
89  /* Shortcut to match all recognized protocols by using ->src.all. */
90  if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
91  (tuple->src.u.all == info->origsrc_port) ^
93  return false;
94 
95  if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
96  (tuple->dst.u.all == info->origdst_port) ^
98  return false;
99 
100  tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
101 
102  if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
103  (tuple->src.u.all == info->replsrc_port) ^
105  return false;
106 
107  if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
108  (tuple->dst.u.all == info->repldst_port) ^
110  return false;
111 
112  return true;
113 }
114 
115 static inline bool
116 port_match(u16 min, u16 max, u16 port, bool invert)
117 {
118  return (port >= min && port <= max) ^ invert;
119 }
120 
121 static inline bool
122 ct_proto_port_check_v3(const struct xt_conntrack_mtinfo3 *info,
123  const struct nf_conn *ct)
124 {
125  const struct nf_conntrack_tuple *tuple;
126 
127  tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
128  if ((info->match_flags & XT_CONNTRACK_PROTO) &&
129  (nf_ct_protonum(ct) == info->l4proto) ^
130  !(info->invert_flags & XT_CONNTRACK_PROTO))
131  return false;
132 
133  /* Shortcut to match all recognized protocols by using ->src.all. */
134  if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
135  !port_match(info->origsrc_port, info->origsrc_port_high,
136  ntohs(tuple->src.u.all),
138  return false;
139 
140  if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
141  !port_match(info->origdst_port, info->origdst_port_high,
142  ntohs(tuple->dst.u.all),
144  return false;
145 
146  tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
147 
148  if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
149  !port_match(info->replsrc_port, info->replsrc_port_high,
150  ntohs(tuple->src.u.all),
152  return false;
153 
154  if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
155  !port_match(info->repldst_port, info->repldst_port_high,
156  ntohs(tuple->dst.u.all),
158  return false;
159 
160  return true;
161 }
162 
163 static bool
164 conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par,
165  u16 state_mask, u16 status_mask)
166 {
167  const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
168  enum ip_conntrack_info ctinfo;
169  const struct nf_conn *ct;
170  unsigned int statebit;
171 
172  ct = nf_ct_get(skb, &ctinfo);
173 
174  if (ct) {
175  if (nf_ct_is_untracked(ct))
176  statebit = XT_CONNTRACK_STATE_UNTRACKED;
177  else
178  statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
179  } else
180  statebit = XT_CONNTRACK_STATE_INVALID;
181 
182  if (info->match_flags & XT_CONNTRACK_STATE) {
183  if (ct != NULL) {
184  if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
185  statebit |= XT_CONNTRACK_STATE_SNAT;
186  if (test_bit(IPS_DST_NAT_BIT, &ct->status))
187  statebit |= XT_CONNTRACK_STATE_DNAT;
188  }
189  if (!!(state_mask & statebit) ^
190  !(info->invert_flags & XT_CONNTRACK_STATE))
191  return false;
192  }
193 
194  if (ct == NULL)
195  return info->match_flags & XT_CONNTRACK_STATE;
196  if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&
197  (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^
199  return false;
200 
201  if (info->match_flags & XT_CONNTRACK_ORIGSRC)
202  if (conntrack_mt_origsrc(ct, info, par->family) ^
204  return false;
205 
206  if (info->match_flags & XT_CONNTRACK_ORIGDST)
207  if (conntrack_mt_origdst(ct, info, par->family) ^
209  return false;
210 
211  if (info->match_flags & XT_CONNTRACK_REPLSRC)
212  if (conntrack_mt_replsrc(ct, info, par->family) ^
214  return false;
215 
216  if (info->match_flags & XT_CONNTRACK_REPLDST)
217  if (conntrack_mt_repldst(ct, info, par->family) ^
219  return false;
220 
221  if (par->match->revision != 3) {
222  if (!ct_proto_port_check(info, ct))
223  return false;
224  } else {
225  if (!ct_proto_port_check_v3(par->matchinfo, ct))
226  return false;
227  }
228 
229  if ((info->match_flags & XT_CONNTRACK_STATUS) &&
230  (!!(status_mask & ct->status) ^
231  !(info->invert_flags & XT_CONNTRACK_STATUS)))
232  return false;
233 
234  if (info->match_flags & XT_CONNTRACK_EXPIRES) {
235  unsigned long expires = 0;
236 
237  if (timer_pending(&ct->timeout))
238  expires = (ct->timeout.expires - jiffies) / HZ;
239  if ((expires >= info->expires_min &&
240  expires <= info->expires_max) ^
242  return false;
243  }
244  return true;
245 }
246 
247 static bool
248 conntrack_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
249 {
250  const struct xt_conntrack_mtinfo1 *info = par->matchinfo;
251 
252  return conntrack_mt(skb, par, info->state_mask, info->status_mask);
253 }
254 
255 static bool
256 conntrack_mt_v2(const struct sk_buff *skb, struct xt_action_param *par)
257 {
258  const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
259 
260  return conntrack_mt(skb, par, info->state_mask, info->status_mask);
261 }
262 
263 static bool
264 conntrack_mt_v3(const struct sk_buff *skb, struct xt_action_param *par)
265 {
266  const struct xt_conntrack_mtinfo3 *info = par->matchinfo;
267 
268  return conntrack_mt(skb, par, info->state_mask, info->status_mask);
269 }
270 
271 static int conntrack_mt_check(const struct xt_mtchk_param *par)
272 {
273  int ret;
274 
276  if (ret < 0)
277  pr_info("cannot load conntrack support for proto=%u\n",
278  par->family);
279  return ret;
280 }
281 
282 static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
283 {
285 }
286 
287 static struct xt_match conntrack_mt_reg[] __read_mostly = {
288  {
289  .name = "conntrack",
290  .revision = 1,
291  .family = NFPROTO_UNSPEC,
292  .matchsize = sizeof(struct xt_conntrack_mtinfo1),
293  .match = conntrack_mt_v1,
294  .checkentry = conntrack_mt_check,
295  .destroy = conntrack_mt_destroy,
296  .me = THIS_MODULE,
297  },
298  {
299  .name = "conntrack",
300  .revision = 2,
301  .family = NFPROTO_UNSPEC,
302  .matchsize = sizeof(struct xt_conntrack_mtinfo2),
303  .match = conntrack_mt_v2,
304  .checkentry = conntrack_mt_check,
305  .destroy = conntrack_mt_destroy,
306  .me = THIS_MODULE,
307  },
308  {
309  .name = "conntrack",
310  .revision = 3,
311  .family = NFPROTO_UNSPEC,
312  .matchsize = sizeof(struct xt_conntrack_mtinfo3),
313  .match = conntrack_mt_v3,
314  .checkentry = conntrack_mt_check,
315  .destroy = conntrack_mt_destroy,
316  .me = THIS_MODULE,
317  },
318 };
319 
320 static int __init conntrack_mt_init(void)
321 {
322  return xt_register_matches(conntrack_mt_reg,
323  ARRAY_SIZE(conntrack_mt_reg));
324 }
325 
326 static void __exit conntrack_mt_exit(void)
327 {
328  xt_unregister_matches(conntrack_mt_reg, ARRAY_SIZE(conntrack_mt_reg));
329 }
330 
331 module_init(conntrack_mt_init);
332 module_exit(conntrack_mt_exit);