netfilter: conntrack: udp: set stream timeout to 2 minutes
[linux-2.6-block.git] / net / netfilter / nf_conntrack_proto_udp.c
CommitLineData
9fb9cbb1
YK
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
f229f6ce 3 * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
9fb9cbb1
YK
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.
9fb9cbb1
YK
8 */
9
10#include <linux/types.h>
9fb9cbb1
YK
11#include <linux/timer.h>
12#include <linux/module.h>
9fb9cbb1
YK
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>
f6180121 19
9fb9cbb1
YK
20#include <linux/netfilter.h>
21#include <linux/netfilter_ipv4.h>
22#include <linux/netfilter_ipv6.h>
605dcad6 23#include <net/netfilter/nf_conntrack_l4proto.h>
f6180121 24#include <net/netfilter/nf_conntrack_ecache.h>
c779e849 25#include <net/netfilter/nf_conntrack_timeout.h>
f01ffbd6 26#include <net/netfilter/nf_log.h>
9d2493f8
CP
27#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
28#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
9fb9cbb1 29
2c9e8637 30static const unsigned int udp_timeouts[UDP_CT_MAX] = {
5a41db94 31 [UDP_CT_UNREPLIED] = 30*HZ,
294304e4 32 [UDP_CT_REPLIED] = 120*HZ,
5a41db94 33};
9fb9cbb1 34
2c8503f5
PNA
35static unsigned int *udp_get_timeouts(struct net *net)
36{
a95a7774 37 return nf_udp_pernet(net)->timeouts;
2c8503f5
PNA
38}
39
83d213fd
FW
40static void udp_error_log(const struct sk_buff *skb,
41 const struct nf_hook_state *state,
42 const char *msg)
43{
44 nf_l4proto_log_invalid(skb, state->net, state->pf,
45 IPPROTO_UDP, "%s", msg);
46}
47
48static bool udp_error(struct sk_buff *skb,
49 unsigned int dataoff,
50 const struct nf_hook_state *state)
51{
52 unsigned int udplen = skb->len - dataoff;
53 const struct udphdr *hdr;
54 struct udphdr _hdr;
55
56 /* Header is too small? */
57 hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
58 if (!hdr) {
59 udp_error_log(skb, state, "short packet");
60 return true;
61 }
62
63 /* Truncated/malformed packets */
64 if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
65 udp_error_log(skb, state, "truncated/malformed packet");
66 return true;
67 }
68
69 /* Packet with no checksum */
70 if (!hdr->check)
71 return false;
72
73 /* Checksum invalid? Ignore.
74 * We skip checking packets on the outgoing path
75 * because the checksum is assumed to be correct.
76 * FIXME: Source route IP option packets --RR */
77 if (state->hook == NF_INET_PRE_ROUTING &&
78 state->net->ct.sysctl_checksum &&
79 nf_checksum(skb, state->hook, dataoff, IPPROTO_UDP, state->pf)) {
80 udp_error_log(skb, state, "bad checksum");
81 return true;
82 }
83
84 return false;
85}
86
9fb9cbb1 87/* Returns verdict for packet, and may modify conntracktype */
c88130bc 88static int udp_packet(struct nf_conn *ct,
83d213fd 89 struct sk_buff *skb,
9fb9cbb1 90 unsigned int dataoff,
93e66024
FW
91 enum ip_conntrack_info ctinfo,
92 const struct nf_hook_state *state)
9fb9cbb1 93{
c779e849
FW
94 unsigned int *timeouts;
95
83d213fd
FW
96 if (udp_error(skb, dataoff, state))
97 return -NF_ACCEPT;
98
c779e849
FW
99 timeouts = nf_ct_timeout_lookup(ct);
100 if (!timeouts)
101 timeouts = udp_get_timeouts(nf_ct_net(ct));
102
d535c8a6
FW
103 if (!nf_ct_is_confirmed(ct))
104 ct->proto.udp.stream_ts = 2 * HZ + jiffies;
105
9fb9cbb1 106 /* If we've seen traffic both ways, this is some kind of UDP
d535c8a6
FW
107 * stream. Set Assured.
108 */
c88130bc 109 if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
d535c8a6
FW
110 unsigned long extra = timeouts[UDP_CT_UNREPLIED];
111
112 /* Still active after two seconds? Extend timeout. */
113 if (time_after(jiffies, ct->proto.udp.stream_ts))
114 extra = timeouts[UDP_CT_REPLIED];
115
116 nf_ct_refresh_acct(ct, ctinfo, skb, extra);
117
9fb9cbb1 118 /* Also, more likely to be important, and not a probe */
c88130bc 119 if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
858b3133 120 nf_conntrack_event_cache(IPCT_ASSURED, ct);
5a41db94
PNA
121 } else {
122 nf_ct_refresh_acct(ct, ctinfo, skb,
2c8503f5 123 timeouts[UDP_CT_UNREPLIED]);
5a41db94 124 }
9fb9cbb1
YK
125 return NF_ACCEPT;
126}
127
e4781421 128#ifdef CONFIG_NF_CT_PROTO_UDPLITE
93e66024
FW
129static void udplite_error_log(const struct sk_buff *skb,
130 const struct nf_hook_state *state,
131 const char *msg)
c4f3db15 132{
93e66024
FW
133 nf_l4proto_log_invalid(skb, state->net, state->pf,
134 IPPROTO_UDPLITE, "%s", msg);
c4f3db15
FW
135}
136
83d213fd
FW
137static bool udplite_error(struct sk_buff *skb,
138 unsigned int dataoff,
139 const struct nf_hook_state *state)
e4781421
FW
140{
141 unsigned int udplen = skb->len - dataoff;
142 const struct udphdr *hdr;
143 struct udphdr _hdr;
144 unsigned int cscov;
145
146 /* Header is too small? */
147 hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
148 if (!hdr) {
93e66024 149 udplite_error_log(skb, state, "short packet");
83d213fd 150 return true;
e4781421
FW
151 }
152
153 cscov = ntohs(hdr->len);
154 if (cscov == 0) {
155 cscov = udplen;
156 } else if (cscov < sizeof(*hdr) || cscov > udplen) {
93e66024 157 udplite_error_log(skb, state, "invalid checksum coverage");
83d213fd 158 return true;
e4781421
FW
159 }
160
161 /* UDPLITE mandates checksums */
162 if (!hdr->check) {
93e66024 163 udplite_error_log(skb, state, "checksum missing");
83d213fd 164 return true;
e4781421
FW
165 }
166
167 /* Checksum invalid? Ignore. */
93e66024
FW
168 if (state->hook == NF_INET_PRE_ROUTING &&
169 state->net->ct.sysctl_checksum &&
170 nf_checksum_partial(skb, state->hook, dataoff, cscov, IPPROTO_UDP,
171 state->pf)) {
172 udplite_error_log(skb, state, "bad checksum");
83d213fd 173 return true;
e4781421
FW
174 }
175
83d213fd 176 return false;
e4781421 177}
e4781421 178
83d213fd
FW
179/* Returns verdict for packet, and may modify conntracktype */
180static int udplite_packet(struct nf_conn *ct,
181 struct sk_buff *skb,
182 unsigned int dataoff,
183 enum ip_conntrack_info ctinfo,
184 const struct nf_hook_state *state)
9fb9cbb1 185{
83d213fd 186 unsigned int *timeouts;
9fb9cbb1 187
83d213fd 188 if (udplite_error(skb, dataoff, state))
9fb9cbb1 189 return -NF_ACCEPT;
9fb9cbb1 190
83d213fd
FW
191 timeouts = nf_ct_timeout_lookup(ct);
192 if (!timeouts)
193 timeouts = udp_get_timeouts(nf_ct_net(ct));
9fb9cbb1 194
83d213fd
FW
195 /* If we've seen traffic both ways, this is some kind of UDP
196 stream. Extend timeout. */
197 if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
198 nf_ct_refresh_acct(ct, ctinfo, skb,
199 timeouts[UDP_CT_REPLIED]);
200 /* Also, more likely to be important, and not a probe */
201 if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status))
202 nf_conntrack_event_cache(IPCT_ASSURED, ct);
203 } else {
204 nf_ct_refresh_acct(ct, ctinfo, skb,
205 timeouts[UDP_CT_UNREPLIED]);
9fb9cbb1 206 }
9fb9cbb1
YK
207 return NF_ACCEPT;
208}
83d213fd 209#endif
9fb9cbb1 210
a874752a 211#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
50978462
PNA
212
213#include <linux/netfilter/nfnetlink.h>
214#include <linux/netfilter/nfnetlink_cttimeout.h>
215
8264deb8
G
216static int udp_timeout_nlattr_to_obj(struct nlattr *tb[],
217 struct net *net, void *data)
50978462
PNA
218{
219 unsigned int *timeouts = data;
a95a7774 220 struct nf_udp_net *un = nf_udp_pernet(net);
50978462 221
c779e849
FW
222 if (!timeouts)
223 timeouts = un->timeouts;
224
50978462 225 /* set default timeouts for UDP. */
8264deb8
G
226 timeouts[UDP_CT_UNREPLIED] = un->timeouts[UDP_CT_UNREPLIED];
227 timeouts[UDP_CT_REPLIED] = un->timeouts[UDP_CT_REPLIED];
50978462
PNA
228
229 if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) {
230 timeouts[UDP_CT_UNREPLIED] =
231 ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_UNREPLIED])) * HZ;
232 }
233 if (tb[CTA_TIMEOUT_UDP_REPLIED]) {
234 timeouts[UDP_CT_REPLIED] =
235 ntohl(nla_get_be32(tb[CTA_TIMEOUT_UDP_REPLIED])) * HZ;
236 }
237 return 0;
238}
239
240static int
241udp_timeout_obj_to_nlattr(struct sk_buff *skb, const void *data)
242{
243 const unsigned int *timeouts = data;
244
3c60a17b
DM
245 if (nla_put_be32(skb, CTA_TIMEOUT_UDP_UNREPLIED,
246 htonl(timeouts[UDP_CT_UNREPLIED] / HZ)) ||
247 nla_put_be32(skb, CTA_TIMEOUT_UDP_REPLIED,
248 htonl(timeouts[UDP_CT_REPLIED] / HZ)))
249 goto nla_put_failure;
50978462
PNA
250 return 0;
251
252nla_put_failure:
253 return -ENOSPC;
254}
255
256static const struct nla_policy
257udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = {
258 [CTA_TIMEOUT_UDP_UNREPLIED] = { .type = NLA_U32 },
259 [CTA_TIMEOUT_UDP_REPLIED] = { .type = NLA_U32 },
260};
a874752a 261#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
50978462 262
933a41e7 263#ifdef CONFIG_SYSCTL
933a41e7
PM
264static struct ctl_table udp_sysctl_table[] = {
265 {
933a41e7 266 .procname = "nf_conntrack_udp_timeout",
933a41e7
PM
267 .maxlen = sizeof(unsigned int),
268 .mode = 0644,
6d9f239a 269 .proc_handler = proc_dointvec_jiffies,
933a41e7
PM
270 },
271 {
933a41e7 272 .procname = "nf_conntrack_udp_timeout_stream",
933a41e7
PM
273 .maxlen = sizeof(unsigned int),
274 .mode = 0644,
6d9f239a 275 .proc_handler = proc_dointvec_jiffies,
933a41e7 276 },
f8572d8f 277 { }
933a41e7
PM
278};
279#endif /* CONFIG_SYSCTL */
280
dee7364e
G
281static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn,
282 struct nf_udp_net *un)
0ce490ad
G
283{
284#ifdef CONFIG_SYSCTL
0ce490ad
G
285 if (pn->ctl_table)
286 return 0;
287 pn->ctl_table = kmemdup(udp_sysctl_table,
288 sizeof(udp_sysctl_table),
289 GFP_KERNEL);
290 if (!pn->ctl_table)
291 return -ENOMEM;
292 pn->ctl_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
293 pn->ctl_table[1].data = &un->timeouts[UDP_CT_REPLIED];
294#endif
295 return 0;
296}
297
ca2ca6e1 298static int udp_init_net(struct net *net)
0ce490ad 299{
a95a7774 300 struct nf_udp_net *un = nf_udp_pernet(net);
dee7364e 301 struct nf_proto_net *pn = &un->pn;
0ce490ad 302
dee7364e
G
303 if (!pn->users) {
304 int i;
0ce490ad 305
dee7364e
G
306 for (i = 0; i < UDP_CT_MAX; i++)
307 un->timeouts[i] = udp_timeouts[i];
0ce490ad 308 }
0ce490ad 309
adf05168 310 return udp_kmemdup_sysctl_table(pn, un);
0ce490ad
G
311}
312
08911475
PNA
313static struct nf_proto_net *udp_get_net_proto(struct net *net)
314{
315 return &net->ct.nf_ct_proto.udp.pn;
316}
317
dd2934a9 318const struct nf_conntrack_l4proto nf_conntrack_l4proto_udp =
9fb9cbb1 319{
605dcad6 320 .l4proto = IPPROTO_UDP,
71d8c47f 321 .allow_clash = true,
9fb9cbb1 322 .packet = udp_packet,
c0cd1156 323#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
fdf70832
PM
324 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
325 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
a400c30e 326 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
f73e924c 327 .nla_policy = nf_ct_port_nla_policy,
c1d10adb 328#endif
a874752a 329#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
50978462
PNA
330 .ctnl_timeout = {
331 .nlattr_to_obj = udp_timeout_nlattr_to_obj,
332 .obj_to_nlattr = udp_timeout_obj_to_nlattr,
333 .nlattr_max = CTA_TIMEOUT_UDP_MAX,
334 .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
335 .nla_policy = udp_timeout_nla_policy,
336 },
a874752a 337#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
dee7364e 338 .init_net = udp_init_net,
08911475 339 .get_net_proto = udp_get_net_proto,
9fb9cbb1
YK
340};
341
e4781421 342#ifdef CONFIG_NF_CT_PROTO_UDPLITE
dd2934a9 343const struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite =
e4781421 344{
e4781421 345 .l4proto = IPPROTO_UDPLITE,
e4781421 346 .allow_clash = true,
83d213fd 347 .packet = udplite_packet,
e4781421
FW
348#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
349 .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
350 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
351 .nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
352 .nla_policy = nf_ct_port_nla_policy,
353#endif
a874752a 354#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
e4781421
FW
355 .ctnl_timeout = {
356 .nlattr_to_obj = udp_timeout_nlattr_to_obj,
357 .obj_to_nlattr = udp_timeout_obj_to_nlattr,
358 .nlattr_max = CTA_TIMEOUT_UDP_MAX,
359 .obj_size = sizeof(unsigned int) * CTA_TIMEOUT_UDP_MAX,
360 .nla_policy = udp_timeout_nla_policy,
361 },
a874752a 362#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
e4781421
FW
363 .init_net = udp_init_net,
364 .get_net_proto = udp_get_net_proto,
365};
e4781421 366#endif