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