Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nf_conntrack_proto_udplite.c
Go to the documentation of this file.
1 /* (C) 1999-2001 Paul `Rusty' Russell
2  * (C) 2002-2004 Netfilter Core Team <[email protected]>
3  * (C) 2007 Patrick McHardy <[email protected]>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  */
9 
10 #include <linux/types.h>
11 #include <linux/timer.h>
12 #include <linux/module.h>
13 #include <linux/udp.h>
14 #include <linux/seq_file.h>
15 #include <linux/skbuff.h>
16 #include <linux/ipv6.h>
17 #include <net/ip6_checksum.h>
18 #include <net/checksum.h>
19 
20 #include <linux/netfilter.h>
21 #include <linux/netfilter_ipv4.h>
22 #include <linux/netfilter_ipv6.h>
25 #include <net/netfilter/nf_log.h>
26 
31 };
32 
33 static unsigned int udplite_timeouts[UDPLITE_CT_MAX] = {
34  [UDPLITE_CT_UNREPLIED] = 30*HZ,
35  [UDPLITE_CT_REPLIED] = 180*HZ,
36 };
37 
38 static int udplite_net_id __read_mostly;
39 struct udplite_net {
40  struct nf_proto_net pn;
41  unsigned int timeouts[UDPLITE_CT_MAX];
42 };
43 
44 static inline struct udplite_net *udplite_pernet(struct net *net)
45 {
46  return net_generic(net, udplite_net_id);
47 }
48 
49 static bool udplite_pkt_to_tuple(const struct sk_buff *skb,
50  unsigned int dataoff,
51  struct nf_conntrack_tuple *tuple)
52 {
53  const struct udphdr *hp;
54  struct udphdr _hdr;
55 
56  hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
57  if (hp == NULL)
58  return false;
59 
60  tuple->src.u.udp.port = hp->source;
61  tuple->dst.u.udp.port = hp->dest;
62  return true;
63 }
64 
65 static bool udplite_invert_tuple(struct nf_conntrack_tuple *tuple,
66  const struct nf_conntrack_tuple *orig)
67 {
68  tuple->src.u.udp.port = orig->dst.u.udp.port;
69  tuple->dst.u.udp.port = orig->src.u.udp.port;
70  return true;
71 }
72 
73 /* Print out the per-protocol part of the tuple. */
74 static int udplite_print_tuple(struct seq_file *s,
75  const struct nf_conntrack_tuple *tuple)
76 {
77  return seq_printf(s, "sport=%hu dport=%hu ",
78  ntohs(tuple->src.u.udp.port),
79  ntohs(tuple->dst.u.udp.port));
80 }
81 
82 static unsigned int *udplite_get_timeouts(struct net *net)
83 {
84  return udplite_pernet(net)->timeouts;
85 }
86 
87 /* Returns verdict for packet, and may modify conntracktype */
88 static int udplite_packet(struct nf_conn *ct,
89  const struct sk_buff *skb,
90  unsigned int dataoff,
91  enum ip_conntrack_info ctinfo,
92  u_int8_t pf,
93  unsigned int hooknum,
94  unsigned int *timeouts)
95 {
96  /* If we've seen traffic both ways, this is some kind of UDP
97  stream. Extend timeout. */
98  if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
99  nf_ct_refresh_acct(ct, ctinfo, skb,
100  timeouts[UDPLITE_CT_REPLIED]);
101  /* Also, more likely to be important, and not a probe */
103  nf_conntrack_event_cache(IPCT_ASSURED, ct);
104  } else {
105  nf_ct_refresh_acct(ct, ctinfo, skb,
106  timeouts[UDPLITE_CT_UNREPLIED]);
107  }
108  return NF_ACCEPT;
109 }
110 
111 /* Called when a new connection for this protocol found. */
112 static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb,
113  unsigned int dataoff, unsigned int *timeouts)
114 {
115  return true;
116 }
117 
118 static int udplite_error(struct net *net, struct nf_conn *tmpl,
119  struct sk_buff *skb,
120  unsigned int dataoff,
121  enum ip_conntrack_info *ctinfo,
122  u_int8_t pf,
123  unsigned int hooknum)
124 {
125  unsigned int udplen = skb->len - dataoff;
126  const struct udphdr *hdr;
127  struct udphdr _hdr;
128  unsigned int cscov;
129 
130  /* Header is too small? */
131  hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
132  if (hdr == NULL) {
133  if (LOG_INVALID(net, IPPROTO_UDPLITE))
134  nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
135  "nf_ct_udplite: short packet ");
136  return -NF_ACCEPT;
137  }
138 
139  cscov = ntohs(hdr->len);
140  if (cscov == 0)
141  cscov = udplen;
142  else if (cscov < sizeof(*hdr) || cscov > udplen) {
143  if (LOG_INVALID(net, IPPROTO_UDPLITE))
144  nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
145  "nf_ct_udplite: invalid checksum coverage ");
146  return -NF_ACCEPT;
147  }
148 
149  /* UDPLITE mandates checksums */
150  if (!hdr->check) {
151  if (LOG_INVALID(net, IPPROTO_UDPLITE))
152  nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
153  "nf_ct_udplite: checksum missing ");
154  return -NF_ACCEPT;
155  }
156 
157  /* Checksum invalid? Ignore. */
158  if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
159  nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP,
160  pf)) {
161  if (LOG_INVALID(net, IPPROTO_UDPLITE))
162  nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
163  "nf_ct_udplite: bad UDPLite checksum ");
164  return -NF_ACCEPT;
165  }
166 
167  return NF_ACCEPT;
168 }
169 
170 #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
171 
172 #include <linux/netfilter/nfnetlink.h>
174 
175 static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[],
176  struct net *net, void *data)
177 {
178  unsigned int *timeouts = data;
179  struct udplite_net *un = udplite_pernet(net);
180 
181  /* set default timeouts for UDPlite. */
184 
186  timeouts[UDPLITE_CT_UNREPLIED] =
187  ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_UNREPLIED])) * HZ;
188  }
189  if (tb[CTA_TIMEOUT_UDPLITE_REPLIED]) {
190  timeouts[UDPLITE_CT_REPLIED] =
191  ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDPLITE_REPLIED])) * HZ;
192  }
193  return 0;
194 }
195 
196 static int
197 udplite_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
198 {
199  const unsigned int *timeouts = data;
200 
201  if (nla_put_be32(skb, CTA_TIMEOUT_UDPLITE_UNREPLIED,
202  htonl(timeouts[UDPLITE_CT_UNREPLIED] / HZ)) ||
203  nla_put_be32(skb, CTA_TIMEOUT_UDPLITE_REPLIED,
204  htonl(timeouts[UDPLITE_CT_REPLIED] / HZ)))
205  goto nla_put_failure;
206  return 0;
207 
208 nla_put_failure:
209  return -ENOSPC;
210 }
211 
212 static const struct nla_policy
213 udplite_timeout_nla_policy[CTA_TIMEOUT_UDPLITE_MAX+1] = {
215  [CTA_TIMEOUT_UDPLITE_REPLIED] = { .type = NLA_U32 },
216 };
217 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
218 
219 #ifdef CONFIG_SYSCTL
220 static struct ctl_table udplite_sysctl_table[] = {
221  {
222  .procname = "nf_conntrack_udplite_timeout",
223  .maxlen = sizeof(unsigned int),
224  .mode = 0644,
226  },
227  {
228  .procname = "nf_conntrack_udplite_timeout_stream",
229  .maxlen = sizeof(unsigned int),
230  .mode = 0644,
232  },
233  { }
234 };
235 #endif /* CONFIG_SYSCTL */
236 
237 static int udplite_kmemdup_sysctl_table(struct nf_proto_net *pn,
238  struct udplite_net *un)
239 {
240 #ifdef CONFIG_SYSCTL
241  if (pn->ctl_table)
242  return 0;
243 
244  pn->ctl_table = kmemdup(udplite_sysctl_table,
245  sizeof(udplite_sysctl_table),
246  GFP_KERNEL);
247  if (!pn->ctl_table)
248  return -ENOMEM;
249 
250  pn->ctl_table[0].data = &un->timeouts[UDPLITE_CT_UNREPLIED];
251  pn->ctl_table[1].data = &un->timeouts[UDPLITE_CT_REPLIED];
252 #endif
253  return 0;
254 }
255 
256 static int udplite_init_net(struct net *net, u_int16_t proto)
257 {
258  struct udplite_net *un = udplite_pernet(net);
259  struct nf_proto_net *pn = &un->pn;
260 
261  if (!pn->users) {
262  int i;
263 
264  for (i = 0 ; i < UDPLITE_CT_MAX; i++)
265  un->timeouts[i] = udplite_timeouts[i];
266  }
267 
268  return udplite_kmemdup_sysctl_table(pn, un);
269 }
270 
271 static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
272 {
273  .l3proto = PF_INET,
274  .l4proto = IPPROTO_UDPLITE,
275  .name = "udplite",
276  .pkt_to_tuple = udplite_pkt_to_tuple,
277  .invert_tuple = udplite_invert_tuple,
278  .print_tuple = udplite_print_tuple,
279  .packet = udplite_packet,
280  .get_timeouts = udplite_get_timeouts,
281  .new = udplite_new,
282  .error = udplite_error,
283 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
284  .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
285  .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
286  .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
287  .nla_policy = nf_ct_port_nla_policy,
288 #endif
289 #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
290  .ctnl_timeout = {
291  .nlattr_to_obj = udplite_timeout_nlattr_to_obj,
292  .obj_to_nlattr = udplite_timeout_obj_to_nlattr,
293  .nlattr_max = CTA_TIMEOUT_UDPLITE_MAX,
294  .obj_size = sizeof(unsigned int) *
296  .nla_policy = udplite_timeout_nla_policy,
297  },
298 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
299  .net_id = &udplite_net_id,
300  .init_net = udplite_init_net,
301 };
302 
303 static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
304 {
305  .l3proto = PF_INET6,
306  .l4proto = IPPROTO_UDPLITE,
307  .name = "udplite",
308  .pkt_to_tuple = udplite_pkt_to_tuple,
309  .invert_tuple = udplite_invert_tuple,
310  .print_tuple = udplite_print_tuple,
311  .packet = udplite_packet,
312  .get_timeouts = udplite_get_timeouts,
313  .new = udplite_new,
314  .error = udplite_error,
315 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
316  .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
317  .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
318  .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
319  .nla_policy = nf_ct_port_nla_policy,
320 #endif
321 #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
322  .ctnl_timeout = {
323  .nlattr_to_obj = udplite_timeout_nlattr_to_obj,
324  .obj_to_nlattr = udplite_timeout_obj_to_nlattr,
325  .nlattr_max = CTA_TIMEOUT_UDPLITE_MAX,
326  .obj_size = sizeof(unsigned int) *
328  .nla_policy = udplite_timeout_nla_policy,
329  },
330 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
331  .net_id = &udplite_net_id,
332  .init_net = udplite_init_net,
333 };
334 
335 static int udplite_net_init(struct net *net)
336 {
337  int ret = 0;
338 
340  &nf_conntrack_l4proto_udplite4);
341  if (ret < 0) {
342  pr_err("nf_conntrack_l4proto_udplite4 :protocol register failed.\n");
343  goto out;
344  }
346  &nf_conntrack_l4proto_udplite6);
347  if (ret < 0) {
348  pr_err("nf_conntrack_l4proto_udplite4 :protocol register failed.\n");
349  goto cleanup_udplite4;
350  }
351  return 0;
352 
353 cleanup_udplite4:
354  nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite4);
355 out:
356  return ret;
357 }
358 
359 static void udplite_net_exit(struct net *net)
360 {
361  nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite6);
362  nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite4);
363 }
364 
365 static struct pernet_operations udplite_net_ops = {
366  .init = udplite_net_init,
367  .exit = udplite_net_exit,
368  .id = &udplite_net_id,
369  .size = sizeof(struct udplite_net),
370 };
371 
372 static int __init nf_conntrack_proto_udplite_init(void)
373 {
374  return register_pernet_subsys(&udplite_net_ops);
375 }
376 
377 static void __exit nf_conntrack_proto_udplite_exit(void)
378 {
379  unregister_pernet_subsys(&udplite_net_ops);
380 }
381 
382 module_init(nf_conntrack_proto_udplite_init);
383 module_exit(nf_conntrack_proto_udplite_exit);
384 
385 MODULE_LICENSE("GPL");