148b1de4cSPatrick McHardy /* 248b1de4cSPatrick McHardy * Copyright (c) 2013 Patrick McHardy <kaber@trash.net> 348b1de4cSPatrick McHardy * 448b1de4cSPatrick McHardy * This program is free software; you can redistribute it and/or modify 548b1de4cSPatrick McHardy * it under the terms of the GNU General Public License version 2 as 648b1de4cSPatrick McHardy * published by the Free Software Foundation. 748b1de4cSPatrick McHardy */ 848b1de4cSPatrick McHardy 948b1de4cSPatrick McHardy #include <linux/module.h> 1048b1de4cSPatrick McHardy #include <linux/skbuff.h> 1148b1de4cSPatrick McHardy #include <asm/unaligned.h> 1248b1de4cSPatrick McHardy #include <net/tcp.h> 1348b1de4cSPatrick McHardy #include <net/netns/generic.h> 1448b1de4cSPatrick McHardy 1548b1de4cSPatrick McHardy #include <linux/netfilter_ipv4/ip_tables.h> 1648b1de4cSPatrick McHardy #include <linux/netfilter/x_tables.h> 1748b1de4cSPatrick McHardy #include <linux/netfilter/xt_tcpudp.h> 1848b1de4cSPatrick McHardy #include <linux/netfilter/xt_SYNPROXY.h> 1948b1de4cSPatrick McHardy #include <net/netfilter/nf_conntrack.h> 2048b1de4cSPatrick McHardy #include <net/netfilter/nf_conntrack_extend.h> 2148b1de4cSPatrick McHardy #include <net/netfilter/nf_conntrack_seqadj.h> 2248b1de4cSPatrick McHardy #include <net/netfilter/nf_conntrack_synproxy.h> 2348b1de4cSPatrick McHardy 2448b1de4cSPatrick McHardy int synproxy_net_id; 2548b1de4cSPatrick McHardy EXPORT_SYMBOL_GPL(synproxy_net_id); 2648b1de4cSPatrick McHardy 27f4a87e7bSPatrick McHardy bool 2848b1de4cSPatrick McHardy synproxy_parse_options(const struct sk_buff *skb, unsigned int doff, 2948b1de4cSPatrick McHardy const struct tcphdr *th, struct synproxy_options *opts) 3048b1de4cSPatrick McHardy { 3148b1de4cSPatrick McHardy int length = (th->doff * 4) - sizeof(*th); 3248b1de4cSPatrick McHardy u8 buf[40], *ptr; 3348b1de4cSPatrick McHardy 3448b1de4cSPatrick McHardy ptr = skb_header_pointer(skb, doff + sizeof(*th), length, buf); 35f4a87e7bSPatrick McHardy if (ptr == NULL) 36f4a87e7bSPatrick McHardy return false; 3748b1de4cSPatrick McHardy 3848b1de4cSPatrick McHardy opts->options = 0; 3948b1de4cSPatrick McHardy while (length > 0) { 4048b1de4cSPatrick McHardy int opcode = *ptr++; 4148b1de4cSPatrick McHardy int opsize; 4248b1de4cSPatrick McHardy 4348b1de4cSPatrick McHardy switch (opcode) { 4448b1de4cSPatrick McHardy case TCPOPT_EOL: 45f4a87e7bSPatrick McHardy return true; 4648b1de4cSPatrick McHardy case TCPOPT_NOP: 4748b1de4cSPatrick McHardy length--; 4848b1de4cSPatrick McHardy continue; 4948b1de4cSPatrick McHardy default: 5048b1de4cSPatrick McHardy opsize = *ptr++; 5148b1de4cSPatrick McHardy if (opsize < 2) 52f4a87e7bSPatrick McHardy return true; 5348b1de4cSPatrick McHardy if (opsize > length) 54f4a87e7bSPatrick McHardy return true; 5548b1de4cSPatrick McHardy 5648b1de4cSPatrick McHardy switch (opcode) { 5748b1de4cSPatrick McHardy case TCPOPT_MSS: 5848b1de4cSPatrick McHardy if (opsize == TCPOLEN_MSS) { 5948b1de4cSPatrick McHardy opts->mss = get_unaligned_be16(ptr); 6048b1de4cSPatrick McHardy opts->options |= XT_SYNPROXY_OPT_MSS; 6148b1de4cSPatrick McHardy } 6248b1de4cSPatrick McHardy break; 6348b1de4cSPatrick McHardy case TCPOPT_WINDOW: 6448b1de4cSPatrick McHardy if (opsize == TCPOLEN_WINDOW) { 6548b1de4cSPatrick McHardy opts->wscale = *ptr; 6648b1de4cSPatrick McHardy if (opts->wscale > 14) 6748b1de4cSPatrick McHardy opts->wscale = 14; 6848b1de4cSPatrick McHardy opts->options |= XT_SYNPROXY_OPT_WSCALE; 6948b1de4cSPatrick McHardy } 7048b1de4cSPatrick McHardy break; 7148b1de4cSPatrick McHardy case TCPOPT_TIMESTAMP: 7248b1de4cSPatrick McHardy if (opsize == TCPOLEN_TIMESTAMP) { 7348b1de4cSPatrick McHardy opts->tsval = get_unaligned_be32(ptr); 7448b1de4cSPatrick McHardy opts->tsecr = get_unaligned_be32(ptr + 4); 7548b1de4cSPatrick McHardy opts->options |= XT_SYNPROXY_OPT_TIMESTAMP; 7648b1de4cSPatrick McHardy } 7748b1de4cSPatrick McHardy break; 7848b1de4cSPatrick McHardy case TCPOPT_SACK_PERM: 7948b1de4cSPatrick McHardy if (opsize == TCPOLEN_SACK_PERM) 8048b1de4cSPatrick McHardy opts->options |= XT_SYNPROXY_OPT_SACK_PERM; 8148b1de4cSPatrick McHardy break; 8248b1de4cSPatrick McHardy } 8348b1de4cSPatrick McHardy 8448b1de4cSPatrick McHardy ptr += opsize - 2; 8548b1de4cSPatrick McHardy length -= opsize; 8648b1de4cSPatrick McHardy } 8748b1de4cSPatrick McHardy } 88f4a87e7bSPatrick McHardy return true; 8948b1de4cSPatrick McHardy } 9048b1de4cSPatrick McHardy EXPORT_SYMBOL_GPL(synproxy_parse_options); 9148b1de4cSPatrick McHardy 9248b1de4cSPatrick McHardy unsigned int synproxy_options_size(const struct synproxy_options *opts) 9348b1de4cSPatrick McHardy { 9448b1de4cSPatrick McHardy unsigned int size = 0; 9548b1de4cSPatrick McHardy 9648b1de4cSPatrick McHardy if (opts->options & XT_SYNPROXY_OPT_MSS) 9748b1de4cSPatrick McHardy size += TCPOLEN_MSS_ALIGNED; 9848b1de4cSPatrick McHardy if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP) 9948b1de4cSPatrick McHardy size += TCPOLEN_TSTAMP_ALIGNED; 10048b1de4cSPatrick McHardy else if (opts->options & XT_SYNPROXY_OPT_SACK_PERM) 10148b1de4cSPatrick McHardy size += TCPOLEN_SACKPERM_ALIGNED; 10248b1de4cSPatrick McHardy if (opts->options & XT_SYNPROXY_OPT_WSCALE) 10348b1de4cSPatrick McHardy size += TCPOLEN_WSCALE_ALIGNED; 10448b1de4cSPatrick McHardy 10548b1de4cSPatrick McHardy return size; 10648b1de4cSPatrick McHardy } 10748b1de4cSPatrick McHardy EXPORT_SYMBOL_GPL(synproxy_options_size); 10848b1de4cSPatrick McHardy 10948b1de4cSPatrick McHardy void 11048b1de4cSPatrick McHardy synproxy_build_options(struct tcphdr *th, const struct synproxy_options *opts) 11148b1de4cSPatrick McHardy { 11248b1de4cSPatrick McHardy __be32 *ptr = (__be32 *)(th + 1); 11348b1de4cSPatrick McHardy u8 options = opts->options; 11448b1de4cSPatrick McHardy 11548b1de4cSPatrick McHardy if (options & XT_SYNPROXY_OPT_MSS) 11648b1de4cSPatrick McHardy *ptr++ = htonl((TCPOPT_MSS << 24) | 11748b1de4cSPatrick McHardy (TCPOLEN_MSS << 16) | 11848b1de4cSPatrick McHardy opts->mss); 11948b1de4cSPatrick McHardy 12048b1de4cSPatrick McHardy if (options & XT_SYNPROXY_OPT_TIMESTAMP) { 12148b1de4cSPatrick McHardy if (options & XT_SYNPROXY_OPT_SACK_PERM) 12248b1de4cSPatrick McHardy *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | 12348b1de4cSPatrick McHardy (TCPOLEN_SACK_PERM << 16) | 12448b1de4cSPatrick McHardy (TCPOPT_TIMESTAMP << 8) | 12548b1de4cSPatrick McHardy TCPOLEN_TIMESTAMP); 12648b1de4cSPatrick McHardy else 12748b1de4cSPatrick McHardy *ptr++ = htonl((TCPOPT_NOP << 24) | 12848b1de4cSPatrick McHardy (TCPOPT_NOP << 16) | 12948b1de4cSPatrick McHardy (TCPOPT_TIMESTAMP << 8) | 13048b1de4cSPatrick McHardy TCPOLEN_TIMESTAMP); 13148b1de4cSPatrick McHardy 13248b1de4cSPatrick McHardy *ptr++ = htonl(opts->tsval); 13348b1de4cSPatrick McHardy *ptr++ = htonl(opts->tsecr); 13448b1de4cSPatrick McHardy } else if (options & XT_SYNPROXY_OPT_SACK_PERM) 13548b1de4cSPatrick McHardy *ptr++ = htonl((TCPOPT_NOP << 24) | 13648b1de4cSPatrick McHardy (TCPOPT_NOP << 16) | 13748b1de4cSPatrick McHardy (TCPOPT_SACK_PERM << 8) | 13848b1de4cSPatrick McHardy TCPOLEN_SACK_PERM); 13948b1de4cSPatrick McHardy 14048b1de4cSPatrick McHardy if (options & XT_SYNPROXY_OPT_WSCALE) 14148b1de4cSPatrick McHardy *ptr++ = htonl((TCPOPT_NOP << 24) | 14248b1de4cSPatrick McHardy (TCPOPT_WINDOW << 16) | 14348b1de4cSPatrick McHardy (TCPOLEN_WINDOW << 8) | 14448b1de4cSPatrick McHardy opts->wscale); 14548b1de4cSPatrick McHardy } 14648b1de4cSPatrick McHardy EXPORT_SYMBOL_GPL(synproxy_build_options); 14748b1de4cSPatrick McHardy 14848b1de4cSPatrick McHardy void synproxy_init_timestamp_cookie(const struct xt_synproxy_info *info, 14948b1de4cSPatrick McHardy struct synproxy_options *opts) 15048b1de4cSPatrick McHardy { 15148b1de4cSPatrick McHardy opts->tsecr = opts->tsval; 15248b1de4cSPatrick McHardy opts->tsval = tcp_time_stamp & ~0x3f; 15348b1de4cSPatrick McHardy 154c1898c4cSMartin Topholm if (opts->options & XT_SYNPROXY_OPT_WSCALE) { 155c1898c4cSMartin Topholm opts->tsval |= opts->wscale; 156c1898c4cSMartin Topholm opts->wscale = info->wscale; 157c1898c4cSMartin Topholm } else 15848b1de4cSPatrick McHardy opts->tsval |= 0xf; 15948b1de4cSPatrick McHardy 16048b1de4cSPatrick McHardy if (opts->options & XT_SYNPROXY_OPT_SACK_PERM) 16148b1de4cSPatrick McHardy opts->tsval |= 1 << 4; 16248b1de4cSPatrick McHardy 16348b1de4cSPatrick McHardy if (opts->options & XT_SYNPROXY_OPT_ECN) 16448b1de4cSPatrick McHardy opts->tsval |= 1 << 5; 16548b1de4cSPatrick McHardy } 16648b1de4cSPatrick McHardy EXPORT_SYMBOL_GPL(synproxy_init_timestamp_cookie); 16748b1de4cSPatrick McHardy 16848b1de4cSPatrick McHardy void synproxy_check_timestamp_cookie(struct synproxy_options *opts) 16948b1de4cSPatrick McHardy { 17048b1de4cSPatrick McHardy opts->wscale = opts->tsecr & 0xf; 17148b1de4cSPatrick McHardy if (opts->wscale != 0xf) 17248b1de4cSPatrick McHardy opts->options |= XT_SYNPROXY_OPT_WSCALE; 17348b1de4cSPatrick McHardy 17448b1de4cSPatrick McHardy opts->options |= opts->tsecr & (1 << 4) ? XT_SYNPROXY_OPT_SACK_PERM : 0; 17548b1de4cSPatrick McHardy 17648b1de4cSPatrick McHardy opts->options |= opts->tsecr & (1 << 5) ? XT_SYNPROXY_OPT_ECN : 0; 17748b1de4cSPatrick McHardy } 17848b1de4cSPatrick McHardy EXPORT_SYMBOL_GPL(synproxy_check_timestamp_cookie); 17948b1de4cSPatrick McHardy 18048b1de4cSPatrick McHardy unsigned int synproxy_tstamp_adjust(struct sk_buff *skb, 18148b1de4cSPatrick McHardy unsigned int protoff, 18248b1de4cSPatrick McHardy struct tcphdr *th, 18348b1de4cSPatrick McHardy struct nf_conn *ct, 18448b1de4cSPatrick McHardy enum ip_conntrack_info ctinfo, 18548b1de4cSPatrick McHardy const struct nf_conn_synproxy *synproxy) 18648b1de4cSPatrick McHardy { 18748b1de4cSPatrick McHardy unsigned int optoff, optend; 18848b1de4cSPatrick McHardy u32 *ptr, old; 18948b1de4cSPatrick McHardy 19048b1de4cSPatrick McHardy if (synproxy->tsoff == 0) 19148b1de4cSPatrick McHardy return 1; 19248b1de4cSPatrick McHardy 19348b1de4cSPatrick McHardy optoff = protoff + sizeof(struct tcphdr); 19448b1de4cSPatrick McHardy optend = protoff + th->doff * 4; 19548b1de4cSPatrick McHardy 19648b1de4cSPatrick McHardy if (!skb_make_writable(skb, optend)) 19748b1de4cSPatrick McHardy return 0; 19848b1de4cSPatrick McHardy 19948b1de4cSPatrick McHardy while (optoff < optend) { 20048b1de4cSPatrick McHardy unsigned char *op = skb->data + optoff; 20148b1de4cSPatrick McHardy 20248b1de4cSPatrick McHardy switch (op[0]) { 20348b1de4cSPatrick McHardy case TCPOPT_EOL: 20448b1de4cSPatrick McHardy return 1; 20548b1de4cSPatrick McHardy case TCPOPT_NOP: 20648b1de4cSPatrick McHardy optoff++; 20748b1de4cSPatrick McHardy continue; 20848b1de4cSPatrick McHardy default: 20948b1de4cSPatrick McHardy if (optoff + 1 == optend || 21048b1de4cSPatrick McHardy optoff + op[1] > optend || 21148b1de4cSPatrick McHardy op[1] < 2) 21248b1de4cSPatrick McHardy return 0; 21348b1de4cSPatrick McHardy if (op[0] == TCPOPT_TIMESTAMP && 21448b1de4cSPatrick McHardy op[1] == TCPOLEN_TIMESTAMP) { 21548b1de4cSPatrick McHardy if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { 21648b1de4cSPatrick McHardy ptr = (u32 *)&op[2]; 21748b1de4cSPatrick McHardy old = *ptr; 21848b1de4cSPatrick McHardy *ptr = htonl(ntohl(*ptr) - 21948b1de4cSPatrick McHardy synproxy->tsoff); 22048b1de4cSPatrick McHardy } else { 22148b1de4cSPatrick McHardy ptr = (u32 *)&op[6]; 22248b1de4cSPatrick McHardy old = *ptr; 22348b1de4cSPatrick McHardy *ptr = htonl(ntohl(*ptr) + 22448b1de4cSPatrick McHardy synproxy->tsoff); 22548b1de4cSPatrick McHardy } 22648b1de4cSPatrick McHardy inet_proto_csum_replace4(&th->check, skb, 22748b1de4cSPatrick McHardy old, *ptr, 0); 22848b1de4cSPatrick McHardy return 1; 22948b1de4cSPatrick McHardy } 23048b1de4cSPatrick McHardy optoff += op[1]; 23148b1de4cSPatrick McHardy } 23248b1de4cSPatrick McHardy } 23348b1de4cSPatrick McHardy return 1; 23448b1de4cSPatrick McHardy } 23548b1de4cSPatrick McHardy EXPORT_SYMBOL_GPL(synproxy_tstamp_adjust); 23648b1de4cSPatrick McHardy 23748b1de4cSPatrick McHardy static struct nf_ct_ext_type nf_ct_synproxy_extend __read_mostly = { 23848b1de4cSPatrick McHardy .len = sizeof(struct nf_conn_synproxy), 23948b1de4cSPatrick McHardy .align = __alignof__(struct nf_conn_synproxy), 24048b1de4cSPatrick McHardy .id = NF_CT_EXT_SYNPROXY, 24148b1de4cSPatrick McHardy }; 24248b1de4cSPatrick McHardy 24348b1de4cSPatrick McHardy #ifdef CONFIG_PROC_FS 24448b1de4cSPatrick McHardy static void *synproxy_cpu_seq_start(struct seq_file *seq, loff_t *pos) 24548b1de4cSPatrick McHardy { 24648b1de4cSPatrick McHardy struct synproxy_net *snet = synproxy_pernet(seq_file_net(seq)); 24748b1de4cSPatrick McHardy int cpu; 24848b1de4cSPatrick McHardy 24948b1de4cSPatrick McHardy if (*pos == 0) 25048b1de4cSPatrick McHardy return SEQ_START_TOKEN; 25148b1de4cSPatrick McHardy 25248b1de4cSPatrick McHardy for (cpu = *pos - 1; cpu < nr_cpu_ids; cpu++) { 25348b1de4cSPatrick McHardy if (!cpu_possible(cpu)) 25448b1de4cSPatrick McHardy continue; 25548b1de4cSPatrick McHardy *pos = cpu + 1; 25648b1de4cSPatrick McHardy return per_cpu_ptr(snet->stats, cpu); 25748b1de4cSPatrick McHardy } 25848b1de4cSPatrick McHardy 25948b1de4cSPatrick McHardy return NULL; 26048b1de4cSPatrick McHardy } 26148b1de4cSPatrick McHardy 26248b1de4cSPatrick McHardy static void *synproxy_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) 26348b1de4cSPatrick McHardy { 26448b1de4cSPatrick McHardy struct synproxy_net *snet = synproxy_pernet(seq_file_net(seq)); 26548b1de4cSPatrick McHardy int cpu; 26648b1de4cSPatrick McHardy 26748b1de4cSPatrick McHardy for (cpu = *pos; cpu < nr_cpu_ids; cpu++) { 26848b1de4cSPatrick McHardy if (!cpu_possible(cpu)) 26948b1de4cSPatrick McHardy continue; 27048b1de4cSPatrick McHardy *pos = cpu + 1; 27148b1de4cSPatrick McHardy return per_cpu_ptr(snet->stats, cpu); 27248b1de4cSPatrick McHardy } 27348b1de4cSPatrick McHardy 27448b1de4cSPatrick McHardy return NULL; 27548b1de4cSPatrick McHardy } 27648b1de4cSPatrick McHardy 27748b1de4cSPatrick McHardy static void synproxy_cpu_seq_stop(struct seq_file *seq, void *v) 27848b1de4cSPatrick McHardy { 27948b1de4cSPatrick McHardy return; 28048b1de4cSPatrick McHardy } 28148b1de4cSPatrick McHardy 28248b1de4cSPatrick McHardy static int synproxy_cpu_seq_show(struct seq_file *seq, void *v) 28348b1de4cSPatrick McHardy { 28448b1de4cSPatrick McHardy struct synproxy_stats *stats = v; 28548b1de4cSPatrick McHardy 28648b1de4cSPatrick McHardy if (v == SEQ_START_TOKEN) { 28748b1de4cSPatrick McHardy seq_printf(seq, "entries\t\tsyn_received\t" 28848b1de4cSPatrick McHardy "cookie_invalid\tcookie_valid\t" 28948b1de4cSPatrick McHardy "cookie_retrans\tconn_reopened\n"); 29048b1de4cSPatrick McHardy return 0; 29148b1de4cSPatrick McHardy } 29248b1de4cSPatrick McHardy 29348b1de4cSPatrick McHardy seq_printf(seq, "%08x\t%08x\t%08x\t%08x\t%08x\t%08x\n", 0, 29448b1de4cSPatrick McHardy stats->syn_received, 29548b1de4cSPatrick McHardy stats->cookie_invalid, 29648b1de4cSPatrick McHardy stats->cookie_valid, 29748b1de4cSPatrick McHardy stats->cookie_retrans, 29848b1de4cSPatrick McHardy stats->conn_reopened); 29948b1de4cSPatrick McHardy 30048b1de4cSPatrick McHardy return 0; 30148b1de4cSPatrick McHardy } 30248b1de4cSPatrick McHardy 30348b1de4cSPatrick McHardy static const struct seq_operations synproxy_cpu_seq_ops = { 30448b1de4cSPatrick McHardy .start = synproxy_cpu_seq_start, 30548b1de4cSPatrick McHardy .next = synproxy_cpu_seq_next, 30648b1de4cSPatrick McHardy .stop = synproxy_cpu_seq_stop, 30748b1de4cSPatrick McHardy .show = synproxy_cpu_seq_show, 30848b1de4cSPatrick McHardy }; 30948b1de4cSPatrick McHardy 31048b1de4cSPatrick McHardy static int synproxy_cpu_seq_open(struct inode *inode, struct file *file) 31148b1de4cSPatrick McHardy { 31248b1de4cSPatrick McHardy return seq_open_net(inode, file, &synproxy_cpu_seq_ops, 31348b1de4cSPatrick McHardy sizeof(struct seq_net_private)); 31448b1de4cSPatrick McHardy } 31548b1de4cSPatrick McHardy 31648b1de4cSPatrick McHardy static const struct file_operations synproxy_cpu_seq_fops = { 31748b1de4cSPatrick McHardy .owner = THIS_MODULE, 31848b1de4cSPatrick McHardy .open = synproxy_cpu_seq_open, 31948b1de4cSPatrick McHardy .read = seq_read, 32048b1de4cSPatrick McHardy .llseek = seq_lseek, 32148b1de4cSPatrick McHardy .release = seq_release_net, 32248b1de4cSPatrick McHardy }; 32348b1de4cSPatrick McHardy 32448b1de4cSPatrick McHardy static int __net_init synproxy_proc_init(struct net *net) 32548b1de4cSPatrick McHardy { 32648b1de4cSPatrick McHardy if (!proc_create("synproxy", S_IRUGO, net->proc_net_stat, 32748b1de4cSPatrick McHardy &synproxy_cpu_seq_fops)) 32848b1de4cSPatrick McHardy return -ENOMEM; 32948b1de4cSPatrick McHardy return 0; 33048b1de4cSPatrick McHardy } 33148b1de4cSPatrick McHardy 33248b1de4cSPatrick McHardy static void __net_exit synproxy_proc_exit(struct net *net) 33348b1de4cSPatrick McHardy { 33448b1de4cSPatrick McHardy remove_proc_entry("synproxy", net->proc_net_stat); 33548b1de4cSPatrick McHardy } 33648b1de4cSPatrick McHardy #else 33748b1de4cSPatrick McHardy static int __net_init synproxy_proc_init(struct net *net) 33848b1de4cSPatrick McHardy { 33948b1de4cSPatrick McHardy return 0; 34048b1de4cSPatrick McHardy } 34148b1de4cSPatrick McHardy 34248b1de4cSPatrick McHardy static void __net_exit synproxy_proc_exit(struct net *net) 34348b1de4cSPatrick McHardy { 34448b1de4cSPatrick McHardy return; 34548b1de4cSPatrick McHardy } 34648b1de4cSPatrick McHardy #endif /* CONFIG_PROC_FS */ 34748b1de4cSPatrick McHardy 34848b1de4cSPatrick McHardy static int __net_init synproxy_net_init(struct net *net) 34948b1de4cSPatrick McHardy { 35048b1de4cSPatrick McHardy struct synproxy_net *snet = synproxy_pernet(net); 35148b1de4cSPatrick McHardy struct nf_conntrack_tuple t; 35248b1de4cSPatrick McHardy struct nf_conn *ct; 35348b1de4cSPatrick McHardy int err = -ENOMEM; 35448b1de4cSPatrick McHardy 35548b1de4cSPatrick McHardy memset(&t, 0, sizeof(t)); 35648b1de4cSPatrick McHardy ct = nf_conntrack_alloc(net, 0, &t, &t, GFP_KERNEL); 35748b1de4cSPatrick McHardy if (IS_ERR(ct)) { 35848b1de4cSPatrick McHardy err = PTR_ERR(ct); 35948b1de4cSPatrick McHardy goto err1; 36048b1de4cSPatrick McHardy } 36148b1de4cSPatrick McHardy 36248b1de4cSPatrick McHardy if (!nfct_seqadj_ext_add(ct)) 36348b1de4cSPatrick McHardy goto err2; 36448b1de4cSPatrick McHardy if (!nfct_synproxy_ext_add(ct)) 36548b1de4cSPatrick McHardy goto err2; 366f4de4c89SPatrick McHardy __set_bit(IPS_TEMPLATE_BIT, &ct->status); 367f4de4c89SPatrick McHardy __set_bit(IPS_CONFIRMED_BIT, &ct->status); 36848b1de4cSPatrick McHardy 36948b1de4cSPatrick McHardy snet->tmpl = ct; 37048b1de4cSPatrick McHardy 37148b1de4cSPatrick McHardy snet->stats = alloc_percpu(struct synproxy_stats); 37248b1de4cSPatrick McHardy if (snet->stats == NULL) 37348b1de4cSPatrick McHardy goto err2; 37448b1de4cSPatrick McHardy 37548b1de4cSPatrick McHardy err = synproxy_proc_init(net); 37648b1de4cSPatrick McHardy if (err < 0) 37748b1de4cSPatrick McHardy goto err3; 37848b1de4cSPatrick McHardy 37948b1de4cSPatrick McHardy return 0; 38048b1de4cSPatrick McHardy 38148b1de4cSPatrick McHardy err3: 38248b1de4cSPatrick McHardy free_percpu(snet->stats); 38348b1de4cSPatrick McHardy err2: 38448b1de4cSPatrick McHardy nf_conntrack_free(ct); 38548b1de4cSPatrick McHardy err1: 38648b1de4cSPatrick McHardy return err; 38748b1de4cSPatrick McHardy } 38848b1de4cSPatrick McHardy 38948b1de4cSPatrick McHardy static void __net_exit synproxy_net_exit(struct net *net) 39048b1de4cSPatrick McHardy { 39148b1de4cSPatrick McHardy struct synproxy_net *snet = synproxy_pernet(net); 39248b1de4cSPatrick McHardy 39348b1de4cSPatrick McHardy nf_conntrack_free(snet->tmpl); 39448b1de4cSPatrick McHardy synproxy_proc_exit(net); 39548b1de4cSPatrick McHardy free_percpu(snet->stats); 39648b1de4cSPatrick McHardy } 39748b1de4cSPatrick McHardy 39848b1de4cSPatrick McHardy static struct pernet_operations synproxy_net_ops = { 39948b1de4cSPatrick McHardy .init = synproxy_net_init, 40048b1de4cSPatrick McHardy .exit = synproxy_net_exit, 40148b1de4cSPatrick McHardy .id = &synproxy_net_id, 40248b1de4cSPatrick McHardy .size = sizeof(struct synproxy_net), 40348b1de4cSPatrick McHardy }; 40448b1de4cSPatrick McHardy 40548b1de4cSPatrick McHardy static int __init synproxy_core_init(void) 40648b1de4cSPatrick McHardy { 40748b1de4cSPatrick McHardy int err; 40848b1de4cSPatrick McHardy 40948b1de4cSPatrick McHardy err = nf_ct_extend_register(&nf_ct_synproxy_extend); 41048b1de4cSPatrick McHardy if (err < 0) 41148b1de4cSPatrick McHardy goto err1; 41248b1de4cSPatrick McHardy 41348b1de4cSPatrick McHardy err = register_pernet_subsys(&synproxy_net_ops); 41448b1de4cSPatrick McHardy if (err < 0) 41548b1de4cSPatrick McHardy goto err2; 41648b1de4cSPatrick McHardy 41748b1de4cSPatrick McHardy return 0; 41848b1de4cSPatrick McHardy 41948b1de4cSPatrick McHardy err2: 42048b1de4cSPatrick McHardy nf_ct_extend_unregister(&nf_ct_synproxy_extend); 42148b1de4cSPatrick McHardy err1: 42248b1de4cSPatrick McHardy return err; 42348b1de4cSPatrick McHardy } 42448b1de4cSPatrick McHardy 42548b1de4cSPatrick McHardy static void __exit synproxy_core_exit(void) 42648b1de4cSPatrick McHardy { 42748b1de4cSPatrick McHardy unregister_pernet_subsys(&synproxy_net_ops); 42848b1de4cSPatrick McHardy nf_ct_extend_unregister(&nf_ct_synproxy_extend); 42948b1de4cSPatrick McHardy } 43048b1de4cSPatrick McHardy 43148b1de4cSPatrick McHardy module_init(synproxy_core_init); 43248b1de4cSPatrick McHardy module_exit(synproxy_core_exit); 43348b1de4cSPatrick McHardy 43448b1de4cSPatrick McHardy MODULE_LICENSE("GPL"); 43548b1de4cSPatrick McHardy MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 436