Merge remote-tracking branch 'torvalds/master' into perf/core
[linux-2.6-microblaze.git] / net / netfilter / nf_synproxy_core.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
4  */
5
6 #include <linux/module.h>
7 #include <linux/skbuff.h>
8 #include <asm/unaligned.h>
9 #include <net/tcp.h>
10 #include <net/netns/generic.h>
11 #include <linux/proc_fs.h>
12
13 #include <linux/netfilter_ipv6.h>
14 #include <linux/netfilter/nf_synproxy.h>
15
16 #include <net/netfilter/nf_conntrack.h>
17 #include <net/netfilter/nf_conntrack_ecache.h>
18 #include <net/netfilter/nf_conntrack_extend.h>
19 #include <net/netfilter/nf_conntrack_seqadj.h>
20 #include <net/netfilter/nf_conntrack_synproxy.h>
21 #include <net/netfilter/nf_conntrack_zones.h>
22 #include <net/netfilter/nf_synproxy.h>
23
24 unsigned int synproxy_net_id;
25 EXPORT_SYMBOL_GPL(synproxy_net_id);
26
27 bool
28 synproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
29                        const struct tcphdr *th, struct synproxy_options *opts)
30 {
31         int length = (th->doff * 4) - sizeof(*th);
32         u8 buf[40], *ptr;
33
34         if (unlikely(length < 0))
35                 return false;
36
37         ptr = skb_header_pointer(skb, doff + sizeof(*th), length, buf);
38         if (ptr == NULL)
39                 return false;
40
41         opts->options = 0;
42         while (length > 0) {
43                 int opcode = *ptr++;
44                 int opsize;
45
46                 switch (opcode) {
47                 case TCPOPT_EOL:
48                         return true;
49                 case TCPOPT_NOP:
50                         length--;
51                         continue;
52                 default:
53                         if (length < 2)
54                                 return true;
55                         opsize = *ptr++;
56                         if (opsize < 2)
57                                 return true;
58                         if (opsize > length)
59                                 return true;
60
61                         switch (opcode) {
62                         case TCPOPT_MSS:
63                                 if (opsize == TCPOLEN_MSS) {
64                                         opts->mss_option = get_unaligned_be16(ptr);
65                                         opts->options |= NF_SYNPROXY_OPT_MSS;
66                                 }
67                                 break;
68                         case TCPOPT_WINDOW:
69                                 if (opsize == TCPOLEN_WINDOW) {
70                                         opts->wscale = *ptr;
71                                         if (opts->wscale > TCP_MAX_WSCALE)
72                                                 opts->wscale = TCP_MAX_WSCALE;
73                                         opts->options |= NF_SYNPROXY_OPT_WSCALE;
74                                 }
75                                 break;
76                         case TCPOPT_TIMESTAMP:
77                                 if (opsize == TCPOLEN_TIMESTAMP) {
78                                         opts->tsval = get_unaligned_be32(ptr);
79                                         opts->tsecr = get_unaligned_be32(ptr + 4);
80                                         opts->options |= NF_SYNPROXY_OPT_TIMESTAMP;
81                                 }
82                                 break;
83                         case TCPOPT_SACK_PERM:
84                                 if (opsize == TCPOLEN_SACK_PERM)
85                                         opts->options |= NF_SYNPROXY_OPT_SACK_PERM;
86                                 break;
87                         }
88
89                         ptr += opsize - 2;
90                         length -= opsize;
91                 }
92         }
93         return true;
94 }
95 EXPORT_SYMBOL_GPL(synproxy_parse_options);
96
97 static unsigned int
98 synproxy_options_size(const struct synproxy_options *opts)
99 {
100         unsigned int size = 0;
101
102         if (opts->options & NF_SYNPROXY_OPT_MSS)
103                 size += TCPOLEN_MSS_ALIGNED;
104         if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
105                 size += TCPOLEN_TSTAMP_ALIGNED;
106         else if (opts->options & NF_SYNPROXY_OPT_SACK_PERM)
107                 size += TCPOLEN_SACKPERM_ALIGNED;
108         if (opts->options & NF_SYNPROXY_OPT_WSCALE)
109                 size += TCPOLEN_WSCALE_ALIGNED;
110
111         return size;
112 }
113
114 static void
115 synproxy_build_options(struct tcphdr *th, const struct synproxy_options *opts)
116 {
117         __be32 *ptr = (__be32 *)(th + 1);
118         u8 options = opts->options;
119
120         if (options & NF_SYNPROXY_OPT_MSS)
121                 *ptr++ = htonl((TCPOPT_MSS << 24) |
122                                (TCPOLEN_MSS << 16) |
123                                opts->mss_option);
124
125         if (options & NF_SYNPROXY_OPT_TIMESTAMP) {
126                 if (options & NF_SYNPROXY_OPT_SACK_PERM)
127                         *ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
128                                        (TCPOLEN_SACK_PERM << 16) |
129                                        (TCPOPT_TIMESTAMP << 8) |
130                                        TCPOLEN_TIMESTAMP);
131                 else
132                         *ptr++ = htonl((TCPOPT_NOP << 24) |
133                                        (TCPOPT_NOP << 16) |
134                                        (TCPOPT_TIMESTAMP << 8) |
135                                        TCPOLEN_TIMESTAMP);
136
137                 *ptr++ = htonl(opts->tsval);
138                 *ptr++ = htonl(opts->tsecr);
139         } else if (options & NF_SYNPROXY_OPT_SACK_PERM)
140                 *ptr++ = htonl((TCPOPT_NOP << 24) |
141                                (TCPOPT_NOP << 16) |
142                                (TCPOPT_SACK_PERM << 8) |
143                                TCPOLEN_SACK_PERM);
144
145         if (options & NF_SYNPROXY_OPT_WSCALE)
146                 *ptr++ = htonl((TCPOPT_NOP << 24) |
147                                (TCPOPT_WINDOW << 16) |
148                                (TCPOLEN_WINDOW << 8) |
149                                opts->wscale);
150 }
151
152 void synproxy_init_timestamp_cookie(const struct nf_synproxy_info *info,
153                                     struct synproxy_options *opts)
154 {
155         opts->tsecr = opts->tsval;
156         opts->tsval = tcp_time_stamp_raw() & ~0x3f;
157
158         if (opts->options & NF_SYNPROXY_OPT_WSCALE) {
159                 opts->tsval |= opts->wscale;
160                 opts->wscale = info->wscale;
161         } else
162                 opts->tsval |= 0xf;
163
164         if (opts->options & NF_SYNPROXY_OPT_SACK_PERM)
165                 opts->tsval |= 1 << 4;
166
167         if (opts->options & NF_SYNPROXY_OPT_ECN)
168                 opts->tsval |= 1 << 5;
169 }
170 EXPORT_SYMBOL_GPL(synproxy_init_timestamp_cookie);
171
172 static void
173 synproxy_check_timestamp_cookie(struct synproxy_options *opts)
174 {
175         opts->wscale = opts->tsecr & 0xf;
176         if (opts->wscale != 0xf)
177                 opts->options |= NF_SYNPROXY_OPT_WSCALE;
178
179         opts->options |= opts->tsecr & (1 << 4) ? NF_SYNPROXY_OPT_SACK_PERM : 0;
180
181         opts->options |= opts->tsecr & (1 << 5) ? NF_SYNPROXY_OPT_ECN : 0;
182 }
183
184 static unsigned int
185 synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff,
186                        struct tcphdr *th, struct nf_conn *ct,
187                        enum ip_conntrack_info ctinfo,
188                        const struct nf_conn_synproxy *synproxy)
189 {
190         unsigned int optoff, optend;
191         __be32 *ptr, old;
192
193         if (synproxy->tsoff == 0)
194                 return 1;
195
196         optoff = protoff + sizeof(struct tcphdr);
197         optend = protoff + th->doff * 4;
198
199         if (skb_ensure_writable(skb, optend))
200                 return 0;
201
202         while (optoff < optend) {
203                 unsigned char *op = skb->data + optoff;
204
205                 switch (op[0]) {
206                 case TCPOPT_EOL:
207                         return 1;
208                 case TCPOPT_NOP:
209                         optoff++;
210                         continue;
211                 default:
212                         if (optoff + 1 == optend ||
213                             optoff + op[1] > optend ||
214                             op[1] < 2)
215                                 return 0;
216                         if (op[0] == TCPOPT_TIMESTAMP &&
217                             op[1] == TCPOLEN_TIMESTAMP) {
218                                 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
219                                         ptr = (__be32 *)&op[2];
220                                         old = *ptr;
221                                         *ptr = htonl(ntohl(*ptr) -
222                                                      synproxy->tsoff);
223                                 } else {
224                                         ptr = (__be32 *)&op[6];
225                                         old = *ptr;
226                                         *ptr = htonl(ntohl(*ptr) +
227                                                      synproxy->tsoff);
228                                 }
229                                 inet_proto_csum_replace4(&th->check, skb,
230                                                          old, *ptr, false);
231                                 return 1;
232                         }
233                         optoff += op[1];
234                 }
235         }
236         return 1;
237 }
238
239 static struct nf_ct_ext_type nf_ct_synproxy_extend __read_mostly = {
240         .len            = sizeof(struct nf_conn_synproxy),
241         .align          = __alignof__(struct nf_conn_synproxy),
242         .id             = NF_CT_EXT_SYNPROXY,
243 };
244
245 #ifdef CONFIG_PROC_FS
246 static void *synproxy_cpu_seq_start(struct seq_file *seq, loff_t *pos)
247 {
248         struct synproxy_net *snet = synproxy_pernet(seq_file_net(seq));
249         int cpu;
250
251         if (*pos == 0)
252                 return SEQ_START_TOKEN;
253
254         for (cpu = *pos - 1; cpu < nr_cpu_ids; cpu++) {
255                 if (!cpu_possible(cpu))
256                         continue;
257                 *pos = cpu + 1;
258                 return per_cpu_ptr(snet->stats, cpu);
259         }
260
261         return NULL;
262 }
263
264 static void *synproxy_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
265 {
266         struct synproxy_net *snet = synproxy_pernet(seq_file_net(seq));
267         int cpu;
268
269         for (cpu = *pos; cpu < nr_cpu_ids; cpu++) {
270                 if (!cpu_possible(cpu))
271                         continue;
272                 *pos = cpu + 1;
273                 return per_cpu_ptr(snet->stats, cpu);
274         }
275         (*pos)++;
276         return NULL;
277 }
278
279 static void synproxy_cpu_seq_stop(struct seq_file *seq, void *v)
280 {
281         return;
282 }
283
284 static int synproxy_cpu_seq_show(struct seq_file *seq, void *v)
285 {
286         struct synproxy_stats *stats = v;
287
288         if (v == SEQ_START_TOKEN) {
289                 seq_puts(seq, "entries\t\tsyn_received\t"
290                               "cookie_invalid\tcookie_valid\t"
291                               "cookie_retrans\tconn_reopened\n");
292                 return 0;
293         }
294
295         seq_printf(seq, "%08x\t%08x\t%08x\t%08x\t%08x\t%08x\n", 0,
296                    stats->syn_received,
297                    stats->cookie_invalid,
298                    stats->cookie_valid,
299                    stats->cookie_retrans,
300                    stats->conn_reopened);
301
302         return 0;
303 }
304
305 static const struct seq_operations synproxy_cpu_seq_ops = {
306         .start          = synproxy_cpu_seq_start,
307         .next           = synproxy_cpu_seq_next,
308         .stop           = synproxy_cpu_seq_stop,
309         .show           = synproxy_cpu_seq_show,
310 };
311
312 static int __net_init synproxy_proc_init(struct net *net)
313 {
314         if (!proc_create_net("synproxy", 0444, net->proc_net_stat,
315                         &synproxy_cpu_seq_ops, sizeof(struct seq_net_private)))
316                 return -ENOMEM;
317         return 0;
318 }
319
320 static void __net_exit synproxy_proc_exit(struct net *net)
321 {
322         remove_proc_entry("synproxy", net->proc_net_stat);
323 }
324 #else
325 static int __net_init synproxy_proc_init(struct net *net)
326 {
327         return 0;
328 }
329
330 static void __net_exit synproxy_proc_exit(struct net *net)
331 {
332         return;
333 }
334 #endif /* CONFIG_PROC_FS */
335
336 static int __net_init synproxy_net_init(struct net *net)
337 {
338         struct synproxy_net *snet = synproxy_pernet(net);
339         struct nf_conn *ct;
340         int err = -ENOMEM;
341
342         ct = nf_ct_tmpl_alloc(net, &nf_ct_zone_dflt, GFP_KERNEL);
343         if (!ct)
344                 goto err1;
345
346         if (!nfct_seqadj_ext_add(ct))
347                 goto err2;
348         if (!nfct_synproxy_ext_add(ct))
349                 goto err2;
350
351         __set_bit(IPS_CONFIRMED_BIT, &ct->status);
352         nf_conntrack_get(&ct->ct_general);
353         snet->tmpl = ct;
354
355         snet->stats = alloc_percpu(struct synproxy_stats);
356         if (snet->stats == NULL)
357                 goto err2;
358
359         err = synproxy_proc_init(net);
360         if (err < 0)
361                 goto err3;
362
363         return 0;
364
365 err3:
366         free_percpu(snet->stats);
367 err2:
368         nf_ct_tmpl_free(ct);
369 err1:
370         return err;
371 }
372
373 static void __net_exit synproxy_net_exit(struct net *net)
374 {
375         struct synproxy_net *snet = synproxy_pernet(net);
376
377         nf_ct_put(snet->tmpl);
378         synproxy_proc_exit(net);
379         free_percpu(snet->stats);
380 }
381
382 static struct pernet_operations synproxy_net_ops = {
383         .init           = synproxy_net_init,
384         .exit           = synproxy_net_exit,
385         .id             = &synproxy_net_id,
386         .size           = sizeof(struct synproxy_net),
387 };
388
389 static int __init synproxy_core_init(void)
390 {
391         int err;
392
393         err = nf_ct_extend_register(&nf_ct_synproxy_extend);
394         if (err < 0)
395                 goto err1;
396
397         err = register_pernet_subsys(&synproxy_net_ops);
398         if (err < 0)
399                 goto err2;
400
401         return 0;
402
403 err2:
404         nf_ct_extend_unregister(&nf_ct_synproxy_extend);
405 err1:
406         return err;
407 }
408
409 static void __exit synproxy_core_exit(void)
410 {
411         unregister_pernet_subsys(&synproxy_net_ops);
412         nf_ct_extend_unregister(&nf_ct_synproxy_extend);
413 }
414
415 module_init(synproxy_core_init);
416 module_exit(synproxy_core_exit);
417
418 static struct iphdr *
419 synproxy_build_ip(struct net *net, struct sk_buff *skb, __be32 saddr,
420                   __be32 daddr)
421 {
422         struct iphdr *iph;
423
424         skb_reset_network_header(skb);
425         iph = skb_put(skb, sizeof(*iph));
426         iph->version    = 4;
427         iph->ihl        = sizeof(*iph) / 4;
428         iph->tos        = 0;
429         iph->id         = 0;
430         iph->frag_off   = htons(IP_DF);
431         iph->ttl        = net->ipv4.sysctl_ip_default_ttl;
432         iph->protocol   = IPPROTO_TCP;
433         iph->check      = 0;
434         iph->saddr      = saddr;
435         iph->daddr      = daddr;
436
437         return iph;
438 }
439
440 static void
441 synproxy_send_tcp(struct net *net,
442                   const struct sk_buff *skb, struct sk_buff *nskb,
443                   struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
444                   struct iphdr *niph, struct tcphdr *nth,
445                   unsigned int tcp_hdr_size)
446 {
447         nth->check = ~tcp_v4_check(tcp_hdr_size, niph->saddr, niph->daddr, 0);
448         nskb->ip_summed   = CHECKSUM_PARTIAL;
449         nskb->csum_start  = (unsigned char *)nth - nskb->head;
450         nskb->csum_offset = offsetof(struct tcphdr, check);
451
452         skb_dst_set_noref(nskb, skb_dst(skb));
453         nskb->protocol = htons(ETH_P_IP);
454         if (ip_route_me_harder(net, nskb->sk, nskb, RTN_UNSPEC))
455                 goto free_nskb;
456
457         if (nfct) {
458                 nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
459                 nf_conntrack_get(nfct);
460         }
461
462         ip_local_out(net, nskb->sk, nskb);
463         return;
464
465 free_nskb:
466         kfree_skb(nskb);
467 }
468
469 void
470 synproxy_send_client_synack(struct net *net,
471                             const struct sk_buff *skb, const struct tcphdr *th,
472                             const struct synproxy_options *opts)
473 {
474         struct sk_buff *nskb;
475         struct iphdr *iph, *niph;
476         struct tcphdr *nth;
477         unsigned int tcp_hdr_size;
478         u16 mss = opts->mss_encode;
479
480         iph = ip_hdr(skb);
481
482         tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
483         nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
484                          GFP_ATOMIC);
485         if (!nskb)
486                 return;
487         skb_reserve(nskb, MAX_TCP_HEADER);
488
489         niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
490
491         skb_reset_transport_header(nskb);
492         nth = skb_put(nskb, tcp_hdr_size);
493         nth->source     = th->dest;
494         nth->dest       = th->source;
495         nth->seq        = htonl(__cookie_v4_init_sequence(iph, th, &mss));
496         nth->ack_seq    = htonl(ntohl(th->seq) + 1);
497         tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
498         if (opts->options & NF_SYNPROXY_OPT_ECN)
499                 tcp_flag_word(nth) |= TCP_FLAG_ECE;
500         nth->doff       = tcp_hdr_size / 4;
501         nth->window     = 0;
502         nth->check      = 0;
503         nth->urg_ptr    = 0;
504
505         synproxy_build_options(nth, opts);
506
507         synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
508                           IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
509 }
510 EXPORT_SYMBOL_GPL(synproxy_send_client_synack);
511
512 static void
513 synproxy_send_server_syn(struct net *net,
514                          const struct sk_buff *skb, const struct tcphdr *th,
515                          const struct synproxy_options *opts, u32 recv_seq)
516 {
517         struct synproxy_net *snet = synproxy_pernet(net);
518         struct sk_buff *nskb;
519         struct iphdr *iph, *niph;
520         struct tcphdr *nth;
521         unsigned int tcp_hdr_size;
522
523         iph = ip_hdr(skb);
524
525         tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
526         nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
527                          GFP_ATOMIC);
528         if (!nskb)
529                 return;
530         skb_reserve(nskb, MAX_TCP_HEADER);
531
532         niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
533
534         skb_reset_transport_header(nskb);
535         nth = skb_put(nskb, tcp_hdr_size);
536         nth->source     = th->source;
537         nth->dest       = th->dest;
538         nth->seq        = htonl(recv_seq - 1);
539         /* ack_seq is used to relay our ISN to the synproxy hook to initialize
540          * sequence number translation once a connection tracking entry exists.
541          */
542         nth->ack_seq    = htonl(ntohl(th->ack_seq) - 1);
543         tcp_flag_word(nth) = TCP_FLAG_SYN;
544         if (opts->options & NF_SYNPROXY_OPT_ECN)
545                 tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
546         nth->doff       = tcp_hdr_size / 4;
547         nth->window     = th->window;
548         nth->check      = 0;
549         nth->urg_ptr    = 0;
550
551         synproxy_build_options(nth, opts);
552
553         synproxy_send_tcp(net, skb, nskb, &snet->tmpl->ct_general, IP_CT_NEW,
554                           niph, nth, tcp_hdr_size);
555 }
556
557 static void
558 synproxy_send_server_ack(struct net *net,
559                          const struct ip_ct_tcp *state,
560                          const struct sk_buff *skb, const struct tcphdr *th,
561                          const struct synproxy_options *opts)
562 {
563         struct sk_buff *nskb;
564         struct iphdr *iph, *niph;
565         struct tcphdr *nth;
566         unsigned int tcp_hdr_size;
567
568         iph = ip_hdr(skb);
569
570         tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
571         nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
572                          GFP_ATOMIC);
573         if (!nskb)
574                 return;
575         skb_reserve(nskb, MAX_TCP_HEADER);
576
577         niph = synproxy_build_ip(net, nskb, iph->daddr, iph->saddr);
578
579         skb_reset_transport_header(nskb);
580         nth = skb_put(nskb, tcp_hdr_size);
581         nth->source     = th->dest;
582         nth->dest       = th->source;
583         nth->seq        = htonl(ntohl(th->ack_seq));
584         nth->ack_seq    = htonl(ntohl(th->seq) + 1);
585         tcp_flag_word(nth) = TCP_FLAG_ACK;
586         nth->doff       = tcp_hdr_size / 4;
587         nth->window     = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
588         nth->check      = 0;
589         nth->urg_ptr    = 0;
590
591         synproxy_build_options(nth, opts);
592
593         synproxy_send_tcp(net, skb, nskb, NULL, 0, niph, nth, tcp_hdr_size);
594 }
595
596 static void
597 synproxy_send_client_ack(struct net *net,
598                          const struct sk_buff *skb, const struct tcphdr *th,
599                          const struct synproxy_options *opts)
600 {
601         struct sk_buff *nskb;
602         struct iphdr *iph, *niph;
603         struct tcphdr *nth;
604         unsigned int tcp_hdr_size;
605
606         iph = ip_hdr(skb);
607
608         tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
609         nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
610                          GFP_ATOMIC);
611         if (!nskb)
612                 return;
613         skb_reserve(nskb, MAX_TCP_HEADER);
614
615         niph = synproxy_build_ip(net, nskb, iph->saddr, iph->daddr);
616
617         skb_reset_transport_header(nskb);
618         nth = skb_put(nskb, tcp_hdr_size);
619         nth->source     = th->source;
620         nth->dest       = th->dest;
621         nth->seq        = htonl(ntohl(th->seq) + 1);
622         nth->ack_seq    = th->ack_seq;
623         tcp_flag_word(nth) = TCP_FLAG_ACK;
624         nth->doff       = tcp_hdr_size / 4;
625         nth->window     = htons(ntohs(th->window) >> opts->wscale);
626         nth->check      = 0;
627         nth->urg_ptr    = 0;
628
629         synproxy_build_options(nth, opts);
630
631         synproxy_send_tcp(net, skb, nskb, skb_nfct(skb),
632                           IP_CT_ESTABLISHED_REPLY, niph, nth, tcp_hdr_size);
633 }
634
635 bool
636 synproxy_recv_client_ack(struct net *net,
637                          const struct sk_buff *skb, const struct tcphdr *th,
638                          struct synproxy_options *opts, u32 recv_seq)
639 {
640         struct synproxy_net *snet = synproxy_pernet(net);
641         int mss;
642
643         mss = __cookie_v4_check(ip_hdr(skb), th, ntohl(th->ack_seq) - 1);
644         if (mss == 0) {
645                 this_cpu_inc(snet->stats->cookie_invalid);
646                 return false;
647         }
648
649         this_cpu_inc(snet->stats->cookie_valid);
650         opts->mss_option = mss;
651         opts->options |= NF_SYNPROXY_OPT_MSS;
652
653         if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
654                 synproxy_check_timestamp_cookie(opts);
655
656         synproxy_send_server_syn(net, skb, th, opts, recv_seq);
657         return true;
658 }
659 EXPORT_SYMBOL_GPL(synproxy_recv_client_ack);
660
661 unsigned int
662 ipv4_synproxy_hook(void *priv, struct sk_buff *skb,
663                    const struct nf_hook_state *nhs)
664 {
665         struct net *net = nhs->net;
666         struct synproxy_net *snet = synproxy_pernet(net);
667         enum ip_conntrack_info ctinfo;
668         struct nf_conn *ct;
669         struct nf_conn_synproxy *synproxy;
670         struct synproxy_options opts = {};
671         const struct ip_ct_tcp *state;
672         struct tcphdr *th, _th;
673         unsigned int thoff;
674
675         ct = nf_ct_get(skb, &ctinfo);
676         if (!ct)
677                 return NF_ACCEPT;
678
679         synproxy = nfct_synproxy(ct);
680         if (!synproxy)
681                 return NF_ACCEPT;
682
683         if (nf_is_loopback_packet(skb) ||
684             ip_hdr(skb)->protocol != IPPROTO_TCP)
685                 return NF_ACCEPT;
686
687         thoff = ip_hdrlen(skb);
688         th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
689         if (!th)
690                 return NF_DROP;
691
692         state = &ct->proto.tcp;
693         switch (state->state) {
694         case TCP_CONNTRACK_CLOSE:
695                 if (th->rst && CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) {
696                         nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
697                                                       ntohl(th->seq) + 1);
698                         break;
699                 }
700
701                 if (!th->syn || th->ack ||
702                     CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
703                         break;
704
705                 /* Reopened connection - reset the sequence number and timestamp
706                  * adjustments, they will get initialized once the connection is
707                  * reestablished.
708                  */
709                 nf_ct_seqadj_init(ct, ctinfo, 0);
710                 synproxy->tsoff = 0;
711                 this_cpu_inc(snet->stats->conn_reopened);
712                 fallthrough;
713         case TCP_CONNTRACK_SYN_SENT:
714                 if (!synproxy_parse_options(skb, thoff, th, &opts))
715                         return NF_DROP;
716
717                 if (!th->syn && th->ack &&
718                     CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
719                         /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
720                          * therefore we need to add 1 to make the SYN sequence
721                          * number match the one of first SYN.
722                          */
723                         if (synproxy_recv_client_ack(net, skb, th, &opts,
724                                                      ntohl(th->seq) + 1)) {
725                                 this_cpu_inc(snet->stats->cookie_retrans);
726                                 consume_skb(skb);
727                                 return NF_STOLEN;
728                         } else {
729                                 return NF_DROP;
730                         }
731                 }
732
733                 synproxy->isn = ntohl(th->ack_seq);
734                 if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP)
735                         synproxy->its = opts.tsecr;
736
737                 nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
738                 break;
739         case TCP_CONNTRACK_SYN_RECV:
740                 if (!th->syn || !th->ack)
741                         break;
742
743                 if (!synproxy_parse_options(skb, thoff, th, &opts))
744                         return NF_DROP;
745
746                 if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP) {
747                         synproxy->tsoff = opts.tsval - synproxy->its;
748                         nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
749                 }
750
751                 opts.options &= ~(NF_SYNPROXY_OPT_MSS |
752                                   NF_SYNPROXY_OPT_WSCALE |
753                                   NF_SYNPROXY_OPT_SACK_PERM);
754
755                 swap(opts.tsval, opts.tsecr);
756                 synproxy_send_server_ack(net, state, skb, th, &opts);
757
758                 nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
759                 nf_conntrack_event_cache(IPCT_SEQADJ, ct);
760
761                 swap(opts.tsval, opts.tsecr);
762                 synproxy_send_client_ack(net, skb, th, &opts);
763
764                 consume_skb(skb);
765                 return NF_STOLEN;
766         default:
767                 break;
768         }
769
770         synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
771         return NF_ACCEPT;
772 }
773 EXPORT_SYMBOL_GPL(ipv4_synproxy_hook);
774
775 static const struct nf_hook_ops ipv4_synproxy_ops[] = {
776         {
777                 .hook           = ipv4_synproxy_hook,
778                 .pf             = NFPROTO_IPV4,
779                 .hooknum        = NF_INET_LOCAL_IN,
780                 .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
781         },
782         {
783                 .hook           = ipv4_synproxy_hook,
784                 .pf             = NFPROTO_IPV4,
785                 .hooknum        = NF_INET_POST_ROUTING,
786                 .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
787         },
788 };
789
790 int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net)
791 {
792         int err;
793
794         if (snet->hook_ref4 == 0) {
795                 err = nf_register_net_hooks(net, ipv4_synproxy_ops,
796                                             ARRAY_SIZE(ipv4_synproxy_ops));
797                 if (err)
798                         return err;
799         }
800
801         snet->hook_ref4++;
802         return 0;
803 }
804 EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init);
805
806 void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net)
807 {
808         snet->hook_ref4--;
809         if (snet->hook_ref4 == 0)
810                 nf_unregister_net_hooks(net, ipv4_synproxy_ops,
811                                         ARRAY_SIZE(ipv4_synproxy_ops));
812 }
813 EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini);
814
815 #if IS_ENABLED(CONFIG_IPV6)
816 static struct ipv6hdr *
817 synproxy_build_ip_ipv6(struct net *net, struct sk_buff *skb,
818                        const struct in6_addr *saddr,
819                        const struct in6_addr *daddr)
820 {
821         struct ipv6hdr *iph;
822
823         skb_reset_network_header(skb);
824         iph = skb_put(skb, sizeof(*iph));
825         ip6_flow_hdr(iph, 0, 0);
826         iph->hop_limit  = net->ipv6.devconf_all->hop_limit;
827         iph->nexthdr    = IPPROTO_TCP;
828         iph->saddr      = *saddr;
829         iph->daddr      = *daddr;
830
831         return iph;
832 }
833
834 static void
835 synproxy_send_tcp_ipv6(struct net *net,
836                        const struct sk_buff *skb, struct sk_buff *nskb,
837                        struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo,
838                        struct ipv6hdr *niph, struct tcphdr *nth,
839                        unsigned int tcp_hdr_size)
840 {
841         struct dst_entry *dst;
842         struct flowi6 fl6;
843         int err;
844
845         nth->check = ~tcp_v6_check(tcp_hdr_size, &niph->saddr, &niph->daddr, 0);
846         nskb->ip_summed   = CHECKSUM_PARTIAL;
847         nskb->csum_start  = (unsigned char *)nth - nskb->head;
848         nskb->csum_offset = offsetof(struct tcphdr, check);
849
850         memset(&fl6, 0, sizeof(fl6));
851         fl6.flowi6_proto = IPPROTO_TCP;
852         fl6.saddr = niph->saddr;
853         fl6.daddr = niph->daddr;
854         fl6.fl6_sport = nth->source;
855         fl6.fl6_dport = nth->dest;
856         security_skb_classify_flow((struct sk_buff *)skb,
857                                    flowi6_to_flowi_common(&fl6));
858         err = nf_ip6_route(net, &dst, flowi6_to_flowi(&fl6), false);
859         if (err) {
860                 goto free_nskb;
861         }
862
863         dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
864         if (IS_ERR(dst))
865                 goto free_nskb;
866
867         skb_dst_set(nskb, dst);
868
869         if (nfct) {
870                 nf_ct_set(nskb, (struct nf_conn *)nfct, ctinfo);
871                 nf_conntrack_get(nfct);
872         }
873
874         ip6_local_out(net, nskb->sk, nskb);
875         return;
876
877 free_nskb:
878         kfree_skb(nskb);
879 }
880
881 void
882 synproxy_send_client_synack_ipv6(struct net *net,
883                                  const struct sk_buff *skb,
884                                  const struct tcphdr *th,
885                                  const struct synproxy_options *opts)
886 {
887         struct sk_buff *nskb;
888         struct ipv6hdr *iph, *niph;
889         struct tcphdr *nth;
890         unsigned int tcp_hdr_size;
891         u16 mss = opts->mss_encode;
892
893         iph = ipv6_hdr(skb);
894
895         tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
896         nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
897                          GFP_ATOMIC);
898         if (!nskb)
899                 return;
900         skb_reserve(nskb, MAX_TCP_HEADER);
901
902         niph = synproxy_build_ip_ipv6(net, nskb, &iph->daddr, &iph->saddr);
903
904         skb_reset_transport_header(nskb);
905         nth = skb_put(nskb, tcp_hdr_size);
906         nth->source     = th->dest;
907         nth->dest       = th->source;
908         nth->seq        = htonl(nf_ipv6_cookie_init_sequence(iph, th, &mss));
909         nth->ack_seq    = htonl(ntohl(th->seq) + 1);
910         tcp_flag_word(nth) = TCP_FLAG_SYN | TCP_FLAG_ACK;
911         if (opts->options & NF_SYNPROXY_OPT_ECN)
912                 tcp_flag_word(nth) |= TCP_FLAG_ECE;
913         nth->doff       = tcp_hdr_size / 4;
914         nth->window     = 0;
915         nth->check      = 0;
916         nth->urg_ptr    = 0;
917
918         synproxy_build_options(nth, opts);
919
920         synproxy_send_tcp_ipv6(net, skb, nskb, skb_nfct(skb),
921                                IP_CT_ESTABLISHED_REPLY, niph, nth,
922                                tcp_hdr_size);
923 }
924 EXPORT_SYMBOL_GPL(synproxy_send_client_synack_ipv6);
925
926 static void
927 synproxy_send_server_syn_ipv6(struct net *net, const struct sk_buff *skb,
928                               const struct tcphdr *th,
929                               const struct synproxy_options *opts, u32 recv_seq)
930 {
931         struct synproxy_net *snet = synproxy_pernet(net);
932         struct sk_buff *nskb;
933         struct ipv6hdr *iph, *niph;
934         struct tcphdr *nth;
935         unsigned int tcp_hdr_size;
936
937         iph = ipv6_hdr(skb);
938
939         tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
940         nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
941                          GFP_ATOMIC);
942         if (!nskb)
943                 return;
944         skb_reserve(nskb, MAX_TCP_HEADER);
945
946         niph = synproxy_build_ip_ipv6(net, nskb, &iph->saddr, &iph->daddr);
947
948         skb_reset_transport_header(nskb);
949         nth = skb_put(nskb, tcp_hdr_size);
950         nth->source     = th->source;
951         nth->dest       = th->dest;
952         nth->seq        = htonl(recv_seq - 1);
953         /* ack_seq is used to relay our ISN to the synproxy hook to initialize
954          * sequence number translation once a connection tracking entry exists.
955          */
956         nth->ack_seq    = htonl(ntohl(th->ack_seq) - 1);
957         tcp_flag_word(nth) = TCP_FLAG_SYN;
958         if (opts->options & NF_SYNPROXY_OPT_ECN)
959                 tcp_flag_word(nth) |= TCP_FLAG_ECE | TCP_FLAG_CWR;
960         nth->doff       = tcp_hdr_size / 4;
961         nth->window     = th->window;
962         nth->check      = 0;
963         nth->urg_ptr    = 0;
964
965         synproxy_build_options(nth, opts);
966
967         synproxy_send_tcp_ipv6(net, skb, nskb, &snet->tmpl->ct_general,
968                                IP_CT_NEW, niph, nth, tcp_hdr_size);
969 }
970
971 static void
972 synproxy_send_server_ack_ipv6(struct net *net, const struct ip_ct_tcp *state,
973                               const struct sk_buff *skb,
974                               const struct tcphdr *th,
975                               const struct synproxy_options *opts)
976 {
977         struct sk_buff *nskb;
978         struct ipv6hdr *iph, *niph;
979         struct tcphdr *nth;
980         unsigned int tcp_hdr_size;
981
982         iph = ipv6_hdr(skb);
983
984         tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
985         nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
986                          GFP_ATOMIC);
987         if (!nskb)
988                 return;
989         skb_reserve(nskb, MAX_TCP_HEADER);
990
991         niph = synproxy_build_ip_ipv6(net, nskb, &iph->daddr, &iph->saddr);
992
993         skb_reset_transport_header(nskb);
994         nth = skb_put(nskb, tcp_hdr_size);
995         nth->source     = th->dest;
996         nth->dest       = th->source;
997         nth->seq        = htonl(ntohl(th->ack_seq));
998         nth->ack_seq    = htonl(ntohl(th->seq) + 1);
999         tcp_flag_word(nth) = TCP_FLAG_ACK;
1000         nth->doff       = tcp_hdr_size / 4;
1001         nth->window     = htons(state->seen[IP_CT_DIR_ORIGINAL].td_maxwin);
1002         nth->check      = 0;
1003         nth->urg_ptr    = 0;
1004
1005         synproxy_build_options(nth, opts);
1006
1007         synproxy_send_tcp_ipv6(net, skb, nskb, NULL, 0, niph, nth,
1008                                tcp_hdr_size);
1009 }
1010
1011 static void
1012 synproxy_send_client_ack_ipv6(struct net *net, const struct sk_buff *skb,
1013                               const struct tcphdr *th,
1014                               const struct synproxy_options *opts)
1015 {
1016         struct sk_buff *nskb;
1017         struct ipv6hdr *iph, *niph;
1018         struct tcphdr *nth;
1019         unsigned int tcp_hdr_size;
1020
1021         iph = ipv6_hdr(skb);
1022
1023         tcp_hdr_size = sizeof(*nth) + synproxy_options_size(opts);
1024         nskb = alloc_skb(sizeof(*niph) + tcp_hdr_size + MAX_TCP_HEADER,
1025                          GFP_ATOMIC);
1026         if (!nskb)
1027                 return;
1028         skb_reserve(nskb, MAX_TCP_HEADER);
1029
1030         niph = synproxy_build_ip_ipv6(net, nskb, &iph->saddr, &iph->daddr);
1031
1032         skb_reset_transport_header(nskb);
1033         nth = skb_put(nskb, tcp_hdr_size);
1034         nth->source     = th->source;
1035         nth->dest       = th->dest;
1036         nth->seq        = htonl(ntohl(th->seq) + 1);
1037         nth->ack_seq    = th->ack_seq;
1038         tcp_flag_word(nth) = TCP_FLAG_ACK;
1039         nth->doff       = tcp_hdr_size / 4;
1040         nth->window     = htons(ntohs(th->window) >> opts->wscale);
1041         nth->check      = 0;
1042         nth->urg_ptr    = 0;
1043
1044         synproxy_build_options(nth, opts);
1045
1046         synproxy_send_tcp_ipv6(net, skb, nskb, skb_nfct(skb),
1047                                IP_CT_ESTABLISHED_REPLY, niph, nth,
1048                                tcp_hdr_size);
1049 }
1050
1051 bool
1052 synproxy_recv_client_ack_ipv6(struct net *net,
1053                               const struct sk_buff *skb,
1054                               const struct tcphdr *th,
1055                               struct synproxy_options *opts, u32 recv_seq)
1056 {
1057         struct synproxy_net *snet = synproxy_pernet(net);
1058         int mss;
1059
1060         mss = nf_cookie_v6_check(ipv6_hdr(skb), th, ntohl(th->ack_seq) - 1);
1061         if (mss == 0) {
1062                 this_cpu_inc(snet->stats->cookie_invalid);
1063                 return false;
1064         }
1065
1066         this_cpu_inc(snet->stats->cookie_valid);
1067         opts->mss_option = mss;
1068         opts->options |= NF_SYNPROXY_OPT_MSS;
1069
1070         if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP)
1071                 synproxy_check_timestamp_cookie(opts);
1072
1073         synproxy_send_server_syn_ipv6(net, skb, th, opts, recv_seq);
1074         return true;
1075 }
1076 EXPORT_SYMBOL_GPL(synproxy_recv_client_ack_ipv6);
1077
1078 unsigned int
1079 ipv6_synproxy_hook(void *priv, struct sk_buff *skb,
1080                    const struct nf_hook_state *nhs)
1081 {
1082         struct net *net = nhs->net;
1083         struct synproxy_net *snet = synproxy_pernet(net);
1084         enum ip_conntrack_info ctinfo;
1085         struct nf_conn *ct;
1086         struct nf_conn_synproxy *synproxy;
1087         struct synproxy_options opts = {};
1088         const struct ip_ct_tcp *state;
1089         struct tcphdr *th, _th;
1090         __be16 frag_off;
1091         u8 nexthdr;
1092         int thoff;
1093
1094         ct = nf_ct_get(skb, &ctinfo);
1095         if (!ct)
1096                 return NF_ACCEPT;
1097
1098         synproxy = nfct_synproxy(ct);
1099         if (!synproxy)
1100                 return NF_ACCEPT;
1101
1102         if (nf_is_loopback_packet(skb))
1103                 return NF_ACCEPT;
1104
1105         nexthdr = ipv6_hdr(skb)->nexthdr;
1106         thoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
1107                                  &frag_off);
1108         if (thoff < 0 || nexthdr != IPPROTO_TCP)
1109                 return NF_ACCEPT;
1110
1111         th = skb_header_pointer(skb, thoff, sizeof(_th), &_th);
1112         if (!th)
1113                 return NF_DROP;
1114
1115         state = &ct->proto.tcp;
1116         switch (state->state) {
1117         case TCP_CONNTRACK_CLOSE:
1118                 if (th->rst && CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) {
1119                         nf_ct_seqadj_init(ct, ctinfo, synproxy->isn -
1120                                                       ntohl(th->seq) + 1);
1121                         break;
1122                 }
1123
1124                 if (!th->syn || th->ack ||
1125                     CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
1126                         break;
1127
1128                 /* Reopened connection - reset the sequence number and timestamp
1129                  * adjustments, they will get initialized once the connection is
1130                  * reestablished.
1131                  */
1132                 nf_ct_seqadj_init(ct, ctinfo, 0);
1133                 synproxy->tsoff = 0;
1134                 this_cpu_inc(snet->stats->conn_reopened);
1135                 fallthrough;
1136         case TCP_CONNTRACK_SYN_SENT:
1137                 if (!synproxy_parse_options(skb, thoff, th, &opts))
1138                         return NF_DROP;
1139
1140                 if (!th->syn && th->ack &&
1141                     CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
1142                         /* Keep-Alives are sent with SEG.SEQ = SND.NXT-1,
1143                          * therefore we need to add 1 to make the SYN sequence
1144                          * number match the one of first SYN.
1145                          */
1146                         if (synproxy_recv_client_ack_ipv6(net, skb, th, &opts,
1147                                                           ntohl(th->seq) + 1)) {
1148                                 this_cpu_inc(snet->stats->cookie_retrans);
1149                                 consume_skb(skb);
1150                                 return NF_STOLEN;
1151                         } else {
1152                                 return NF_DROP;
1153                         }
1154                 }
1155
1156                 synproxy->isn = ntohl(th->ack_seq);
1157                 if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP)
1158                         synproxy->its = opts.tsecr;
1159
1160                 nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
1161                 break;
1162         case TCP_CONNTRACK_SYN_RECV:
1163                 if (!th->syn || !th->ack)
1164                         break;
1165
1166                 if (!synproxy_parse_options(skb, thoff, th, &opts))
1167                         return NF_DROP;
1168
1169                 if (opts.options & NF_SYNPROXY_OPT_TIMESTAMP) {
1170                         synproxy->tsoff = opts.tsval - synproxy->its;
1171                         nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
1172                 }
1173
1174                 opts.options &= ~(NF_SYNPROXY_OPT_MSS |
1175                                   NF_SYNPROXY_OPT_WSCALE |
1176                                   NF_SYNPROXY_OPT_SACK_PERM);
1177
1178                 swap(opts.tsval, opts.tsecr);
1179                 synproxy_send_server_ack_ipv6(net, state, skb, th, &opts);
1180
1181                 nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
1182                 nf_conntrack_event_cache(IPCT_SEQADJ, ct);
1183
1184                 swap(opts.tsval, opts.tsecr);
1185                 synproxy_send_client_ack_ipv6(net, skb, th, &opts);
1186
1187                 consume_skb(skb);
1188                 return NF_STOLEN;
1189         default:
1190                 break;
1191         }
1192
1193         synproxy_tstamp_adjust(skb, thoff, th, ct, ctinfo, synproxy);
1194         return NF_ACCEPT;
1195 }
1196 EXPORT_SYMBOL_GPL(ipv6_synproxy_hook);
1197
1198 static const struct nf_hook_ops ipv6_synproxy_ops[] = {
1199         {
1200                 .hook           = ipv6_synproxy_hook,
1201                 .pf             = NFPROTO_IPV6,
1202                 .hooknum        = NF_INET_LOCAL_IN,
1203                 .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
1204         },
1205         {
1206                 .hook           = ipv6_synproxy_hook,
1207                 .pf             = NFPROTO_IPV6,
1208                 .hooknum        = NF_INET_POST_ROUTING,
1209                 .priority       = NF_IP_PRI_CONNTRACK_CONFIRM - 1,
1210         },
1211 };
1212
1213 int
1214 nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net)
1215 {
1216         int err;
1217
1218         if (snet->hook_ref6 == 0) {
1219                 err = nf_register_net_hooks(net, ipv6_synproxy_ops,
1220                                             ARRAY_SIZE(ipv6_synproxy_ops));
1221                 if (err)
1222                         return err;
1223         }
1224
1225         snet->hook_ref6++;
1226         return 0;
1227 }
1228 EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init);
1229
1230 void
1231 nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net)
1232 {
1233         snet->hook_ref6--;
1234         if (snet->hook_ref6 == 0)
1235                 nf_unregister_net_hooks(net, ipv6_synproxy_ops,
1236                                         ARRAY_SIZE(ipv6_synproxy_ops));
1237 }
1238 EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini);
1239 #endif /* CONFIG_IPV6 */
1240
1241 MODULE_LICENSE("GPL");
1242 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
1243 MODULE_DESCRIPTION("nftables SYNPROXY expression support");