• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/net/ipv4/netfilter/
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