1/* 2 * Automatic port forwarding target. When this target is entered, a 3 * related connection to a port in the reply direction will be 4 * expected. This connection may be mapped to a different port. 5 * 6 * Copyright (C) 2015, Broadcom Corporation. All Rights Reserved. 7 * 8 * Permission to use, copy, modify, and/or distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 17 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 18 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 * 20 * $Id: nf_nat_autofw.c,v 1.1 2008-10-02 03:40:29 $ 21 */ 22 23#include <linux/config.h> 24#include <linux/types.h> 25#include <linux/ip.h> 26#include <linux/timer.h> 27#include <linux/module.h> 28#include <linux/netfilter.h> 29#include <net/protocol.h> 30#include <net/checksum.h> 31#include <net/tcp.h> 32 33#include <linux/netfilter_ipv4.h> 34#include <linux/netfilter_ipv4/ip_tables.h> 35#include <net/netfilter/nf_nat_rule.h> 36#include <linux/netfilter/x_tables.h> 37 38#include <net/netfilter/nf_conntrack_expect.h> 39#include <net/netfilter/nf_conntrack_helper.h> 40#include <linux/netfilter_ipv4/ip_autofw.h> 41 42DEFINE_RWLOCK(nf_nat_autofw_lock); 43 44#define DEBUGP(format, args...) 45 46static int 47autofw_help(struct sk_buff **pskb, 48 unsigned int protoff, 49 struct nf_conn *ct, 50 enum ip_conntrack_info ctinfo) 51{ 52 return 1; 53} 54 55static void 56autofw_expect(struct nf_conn *ct, struct nf_conntrack_expect *exp) 57{ 58 struct nf_nat_range pre_range; 59 u_int32_t newdstip, newsrcip; 60 u_int16_t port; 61 int ret; 62 struct nf_conn_help *help; 63 struct nf_conn *exp_ct = exp->master; 64 struct nf_conntrack_expect *newexp; 65 int count; 66 67 /* expect has been removed from expect list, but expect isn't free yet. */ 68 help = nfct_help(exp_ct); 69 DEBUGP("autofw_nat_expected: got "); 70 NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 71 72 spin_lock_bh(&nf_nat_autofw_lock); 73 74 port = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all); 75 newdstip = exp->tuple.dst.u3.ip; 76 newsrcip = exp->tuple.src.u3.ip; 77 if (port < ntohs(help->help.ct_autofw_info.dport[0]) || 78 port > ntohs(help->help.ct_autofw_info.dport[1])) { 79 spin_unlock_bh(&nf_nat_autofw_lock); 80 return; 81 } 82 83 /* Only need to do PRE_ROUTING */ 84 port -= ntohs(help->help.ct_autofw_info.dport[0]); 85 port += ntohs(help->help.ct_autofw_info.to[0]); 86 pre_range.flags = IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED; 87 pre_range.min_ip = pre_range.max_ip = newdstip; 88 pre_range.min.all = pre_range.max.all = htons(port); 89 nf_nat_setup_info(ct, &pre_range, NF_IP_PRE_ROUTING); 90 91 spin_unlock_bh(&nf_nat_autofw_lock); 92 93 /* Add expect again */ 94 95 /* alloc will set exp->master = exp_ct */ 96 newexp = nf_conntrack_expect_alloc(exp_ct); 97 if (!newexp) 98 return; 99 100 newexp->tuple.src.u3.ip = exp->tuple.src.u3.ip; 101 newexp->tuple.dst.protonum = exp->tuple.dst.protonum; 102 newexp->mask.src.u3.ip = 0xFFFFFFFF; 103 newexp->mask.dst.protonum = 0xFF; 104 105 newexp->tuple.dst.u3.ip = exp->tuple.dst.u3.ip; 106 newexp->mask.dst.u3.ip = 0x0; 107 108 for (count = 1; count < NF_CT_TUPLE_L3SIZE; count++) { 109 newexp->tuple.src.u3.all[count] = 0x0; 110 newexp->tuple.dst.u3.all[count] = 0x0; 111 } 112 113 newexp->mask.dst.u.all = 0x0; 114 newexp->mask.src.u.all = 0x0; 115 newexp->mask.src.l3num = 0x0; 116 117 newexp->expectfn = autofw_expect; 118 newexp->helper = NULL; 119 newexp->flags = 0; 120 121 /* 122 * exp->timeout.expires will set as 123 * (jiffies + helper->timeout * HZ), when insert exp. 124 */ 125 ret = nf_conntrack_expect_related(newexp); 126 if (ret == 0) 127 nf_conntrack_expect_put(newexp); 128} 129 130 131static struct nf_conntrack_helper autofw_helper; 132 133static unsigned int 134autofw_target(struct sk_buff **pskb, 135 const struct net_device *in, 136 const struct net_device *out, 137 unsigned int hooknum, 138 const struct xt_target *target, 139 const void *targinfo) 140{ 141 const struct ip_autofw_info *info = targinfo; 142 const struct iphdr *iph = ip_hdr(*pskb); 143 int ret; 144 struct nf_conntrack_helper *helper; 145 struct nf_conntrack_expect *exp; 146 struct nf_conn *ct; 147 enum ip_conntrack_info ctinfo; 148 struct nf_conn_help *help; 149 int count; 150 151 ct = nf_ct_get(*pskb, &ctinfo); 152 if (!ct) 153 goto out; 154 155 helper = __nf_conntrack_helper_find_byname("autofw"); 156 if (!helper) 157 goto out; 158 159 help = nfct_help(ct); 160 help->helper = helper; 161 162 /* alloc will set exp->master = ct */ 163 exp = nf_conntrack_expect_alloc(ct); 164 if (!exp) 165 goto out; 166 167 helper->me = THIS_MODULE; 168 helper->timeout = 5 * 60; 169 170 exp->tuple.src.u3.ip = iph->daddr; 171 exp->tuple.dst.protonum = info->proto; 172 exp->mask.src.u3.ip = 0xFFFFFFFF; 173 exp->mask.dst.protonum = 0xFF; 174 175 exp->tuple.dst.u3.ip = iph->saddr; 176 exp->mask.dst.u3.ip = 0x0; 177 178 for (count = 1; count < NF_CT_TUPLE_L3SIZE; count++) { 179 exp->tuple.src.u3.all[count] = 0x0; 180 exp->tuple.dst.u3.all[count] = 0x0; 181 } 182 183 exp->mask.dst.u.all = 0x0; 184 exp->mask.src.u.all = 0x0; 185 exp->mask.src.l3num = 0x0; 186 187 exp->expectfn = autofw_expect; 188 exp->helper = NULL; 189 exp->flags = 0; 190 191 /* 192 * exp->timeout.expires will set as 193 * (jiffies + helper->timeout * HZ), when insert exp. 194 */ 195 ret = nf_conntrack_expect_related(exp); 196 if (ret != 0) 197 goto out; 198 199 nf_conntrack_expect_put(exp); 200 201 help->help.ct_autofw_info.dport[0] = info->dport[0]; 202 help->help.ct_autofw_info.dport[1] = info->dport[1]; 203 help->help.ct_autofw_info.to[0] = info->to[0]; 204 help->help.ct_autofw_info.to[1] = info->to[1]; 205 206out: 207 return IPT_CONTINUE; 208} 209 210static int 211autofw_check(const char *tablename, 212 const void *e, 213 const struct xt_target *target, 214 void *targinfo, 215 unsigned int hook_mask) 216{ 217 218 const struct ip_autofw_info *info = targinfo; 219 220 if (info->proto != IPPROTO_TCP && info->proto != IPPROTO_UDP) { 221 DEBUGP("autofw_check: bad proto %d.\n", info->proto); 222 return 0; 223 } 224 225 return 1; 226} 227 228static struct xt_target autofw = { 229 .name = "autofw", 230 .family = AF_INET, 231 .target = autofw_target, 232 .targetsize = sizeof(struct ip_autofw_info), 233 .table = "nat", 234 .hooks = 1 << NF_IP_PRE_ROUTING, 235 .checkentry = autofw_check, 236 .me = THIS_MODULE 237}; 238 239static int __init ip_autofw_init(void) 240{ 241 int ret; 242 243 autofw_helper.name = "autofw"; 244 autofw_helper.tuple.dst.u3.ip = 0xFFFFFFFF; 245 autofw_helper.tuple.dst.protonum = 0xFF; 246 autofw_helper.mask.dst.u3.ip = 0xFFFFFFFF; 247 autofw_helper.mask.dst.protonum = 0xFF; 248 autofw_helper.tuple.src.u3.ip = 0xFFFFFFFF; 249 autofw_helper.me = THIS_MODULE; 250 autofw_helper.timeout = 5 * 60; 251 autofw_helper.help = autofw_help; 252 253 ret = nf_conntrack_helper_register(&autofw_helper); 254 if (ret) 255 nf_conntrack_helper_unregister(&autofw_helper); 256 257 return xt_register_target(&autofw); 258} 259 260static void __exit ip_autofw_fini(void) 261{ 262 xt_unregister_target(&autofw); 263} 264 265module_init(ip_autofw_init); 266module_exit(ip_autofw_fini); 267