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