allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / net / ipv4 / netfilter / ipt_TRIGGER.c
bloba17b7dfcb1c37fbf7080592e81f0b70153d38e64
1 /* Kernel module to match the port-ranges, trigger related port-ranges,
2 * and alters the destination to a local IP address.
4 * Copyright (C) 2003, CyberTAN Corporation
5 * All Rights Reserved.
7 * Description:
8 * This is kernel module for port-triggering.
10 * The module follows the Netfilter framework, called extended packet
11 * matching modules.
13 * History:
15 * 2008.07: code cleaning by Delta Networks Inc.
19 #include <linux/types.h>
20 #include <linux/skbuff.h>
21 #include <linux/version.h>
22 #include <linux/ip.h>
23 #include <linux/tcp.h>
24 #include <net/sock.h>
25 #include <linux/timer.h>
26 #include <linux/module.h>
27 #include <linux/netfilter.h>
28 #include <linux/netdevice.h>
29 #include <linux/if.h>
30 #include <linux/inetdevice.h>
31 #include <net/protocol.h>
32 #include <net/checksum.h>
34 #include <linux/netfilter_ipv4.h>
35 #include <linux/netfilter_ipv4/ip_tables.h>
37 #include <net/netfilter/nf_nat.h>
38 #include <net/netfilter/nf_nat_helper.h>
39 #include <net/netfilter/nf_conntrack_core.h>
40 #include <net/netfilter/nf_conntrack_helper.h>
41 #include <net/netfilter/nf_conntrack_expect.h>
43 #ifdef CONFIG_NF_NAT_NEEDED
44 #include <net/netfilter/nf_nat_rule.h>
45 #else
46 #include <linux/netfilter_ipv4/ip_nat_rule.h>
47 #endif
48 #include <linux/netfilter_ipv4/ipt_TRIGGER.h>
50 /* This rwlock protects the main hash table, protocol/helper/expected
51 * registrations, conntrack timers
53 static DEFINE_RWLOCK(trigger_lock);
55 #include <linux/list.h>
57 #if 0
58 #define DEBUGP printk
59 #else
60 #define DEBUGP(format, args...)
61 #endif
63 #define LIST_FIND(head, cmpfn, type, args...) \
64 ({ \
65 const struct list_head *__i, *__j = NULL; \
67 read_lock_bh(&trigger_lock); \
68 list_for_each(__i, (head)) \
69 if (cmpfn((const type)__i , ## args)) { \
70 __j = __i; \
71 break; \
72 } \
73 read_unlock_bh(&trigger_lock); \
74 (type)__j; \
77 struct ipt_trigger {
78 struct list_head list; /* Trigger list */
79 struct timer_list timeout; /* Timer for list destroying */
80 u_int32_t srcip; /* Outgoing source address */
81 u_int16_t mproto; /* Trigger protocol */
82 u_int16_t rproto; /* Related protocol */
83 struct ipt_trigger_ports ports; /* Trigger and related ports */
84 u_int8_t reply; /* Confirm a reply connection */
87 static LIST_HEAD(trigger_list);
89 static void trigger_timer_refresh(struct ipt_trigger *trig)
91 DEBUGP("%s: mport=%u-%u\n", __FUNCTION__, trig->ports.mport[0], trig->ports.mport[1]);
92 NF_CT_ASSERT(trig);
93 write_lock_bh(&trigger_lock);
95 /* Need del_timer for race avoidance (may already be dying). */
96 if (del_timer(&trig->timeout)) {
97 trig->timeout.expires = jiffies + (TRIGGER_TIMEOUT * HZ);
98 add_timer(&trig->timeout);
101 write_unlock_bh(&trigger_lock);
104 static void __del_trigger(struct ipt_trigger *trig)
106 DEBUGP("%s: mport=%u-%u\n", __FUNCTION__, trig->ports.mport[0], trig->ports.mport[1]);
107 NF_CT_ASSERT(trig);
109 /* delete from 'trigger_list' */
110 list_del(&trig->list);
111 kfree(trig);
114 static int ip_ct_kill_triggered(struct nf_conn *i, void *ifindex)
116 u_int16_t proto, dport;
117 struct ipt_trigger *trig;
119 if (!(i->status & IPS_TRIGGER))
120 return 0;
122 trig = ifindex;
123 proto = i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
124 dport = ntohs(i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all);
126 if (trig->rproto == proto || trig->rproto == 0)
127 return (trig->ports.rport[0] <= dport && trig->ports.rport[1] >= dport);
128 else
129 return 0;
132 static void trigger_timeout(unsigned long ul_trig)
134 struct ipt_trigger *trig= (void *) ul_trig;
136 DEBUGP("%s: mport=%u-%u\n", __FUNCTION__, trig->ports.mport[0], trig->ports.mport[1]);
138 nf_ct_iterate_cleanup(ip_ct_kill_triggered, (void *)trig);
140 write_lock_bh(&trigger_lock);
141 __del_trigger(trig);
142 write_unlock_bh(&trigger_lock);
145 static void trigger_flush(void)
147 struct list_head *cur_item, *tmp_item;
149 DEBUGP("%s\n", __FUNCTION__);
150 write_lock_bh(&trigger_lock);
151 list_for_each_safe(cur_item, tmp_item, &trigger_list) {
152 struct ipt_trigger *trig = (void *)cur_item;
154 DEBUGP("%s: list_for_each_safe(): %p.\n", __FUNCTION__, trig);
155 del_timer(&trig->timeout);
156 nf_ct_iterate_cleanup(ip_ct_kill_triggered, (void *)trig);
157 __del_trigger(trig);
159 write_unlock_bh(&trigger_lock);
163 * Service-Name OutBound InBound
164 * 1. TMD UDP:1000 TCP/UDP:2000..2010
165 * 2. WOKAO UDP:1000 TCP/UDP:3000..3010
166 * 3. net2phone-1 UDP:6801 TCP:30000..30000
167 * 4. net2phone-2 UDP:6801 UDP:30000..30000
169 * For supporting to use the same outgoing port to trigger different port rules,
170 * it should check the inbound protocol and port range value. If all conditions
171 * are matched, it is a same trigger item, else it needs to create a new one.
173 static inline int trigger_out_matched(const struct ipt_trigger *i,
174 const u_int16_t proto, const u_int16_t dport,
175 const struct ipt_trigger_info *info)
177 return
178 i->mproto == proto &&
179 i->ports.mport[0] <= dport &&
180 i->ports.mport[1] >= dport &&
181 i->rproto == info->proto &&
182 i->ports.rport[0] == info->ports.rport[0] &&
183 i->ports.rport[1] == info->ports.rport[1];
186 static unsigned int
187 trigger_out(struct sk_buff *skb, const void *targinfo)
189 const struct ipt_trigger_info *info = targinfo;
190 struct ipt_trigger *trig;
191 struct iphdr *iph = ip_hdr(skb);
192 struct tcphdr *tcph = (void *)iph + (iph->ihl << 2); /* Might be TCP, UDP */
194 /* Check if the trigger range has already existed in 'trigger_list'. */
195 trig = LIST_FIND(&trigger_list,
196 trigger_out_matched,
197 struct ipt_trigger *,
198 iph->protocol, ntohs(tcph->dest), info);
200 if (trig != NULL) {
201 DEBUGP("Tirgger Out Refresh: %u.%u.%u.%u %u\n", NIPQUAD(iph->saddr),
202 ntohs(tcph->dest));
203 /* Yeah, it exists. We need to update(delay) the destroying timer. */
204 trigger_timer_refresh(trig);
205 /* In order to allow multiple hosts use the same port range, we update
206 the 'saddr' after previous trigger has a reply connection. */
207 #if 0
208 if (trig->reply) {
209 trig->srcip = iph->saddr;
210 trig->reply = 0;
212 #else
214 * Well, CD-Router verifies Port-Triggering to support multiple LAN hosts can
215 * use trigger ports after mappings are aged out. It tests as bellowing ...
217 * net2phone-1 UDP:6801 TCP:30000..30000
218 * net2phone-2 UDP:6801 UDP:3000..3000
220 * 1. 192.168.1.2 --> UDP:6801 --> verify TCP:30000 opened ?
221 * 2. waiting for all trigger port mappings to be deleted.
222 * 3. 192.168.1.3 --> UDP:6801 --> verify TCP:30000 opened ?
224 * 4. 192.168.1.2 --> UDP:6801 --> verify UDP:3000 opened ?
225 * 5. waiting for all trigger port mappings to be deleted.
226 * 6. 192.168.1.3 --> UDP:6801 --> verify UDP:3000 opened ?
228 * Between steps 3 and 4, it doesn't wait time out, and on step 3, it has created
229 * two trigger items: [A]. TCP:30000 ('reply' = 1); B). UDP:3000 ('reply' = 0). so
230 * on step 4, it can't update the 'srcip' value from '192.168.1.3' to '192.168.1.2'.
231 * For passing test, and let the customer be happy, we ... ^_^, it is not so bad.
233 trig->srcip = iph->saddr;
234 #endif
236 else {
237 /* Create new trigger */
238 trig = (struct ipt_trigger *)kzalloc(sizeof(struct ipt_trigger), GFP_ATOMIC);
239 if (trig == NULL) {
240 DEBUGP("No memory for adding Tigger!\n");
241 return IPT_CONTINUE;
244 INIT_LIST_HEAD(&trig->list);
245 init_timer(&trig->timeout);
246 trig->timeout.data = (unsigned long)trig;
247 trig->timeout.function = trigger_timeout;
248 trig->timeout.expires = jiffies + (TRIGGER_TIMEOUT * HZ);
250 trig->srcip = iph->saddr;
251 trig->mproto = iph->protocol;
252 trig->rproto = info->proto;
253 trig->reply = 0;
254 memcpy(&trig->ports, &info->ports, sizeof(struct ipt_trigger_ports));
256 /* add to global table of trigger and start timer. */
257 write_lock_bh(&trigger_lock);
258 list_add(&trig->list, &trigger_list);
259 add_timer(&trig->timeout);
260 write_unlock_bh(&trigger_lock);
263 return IPT_CONTINUE; /* We don't block any packet. */
266 static inline int trigger_in_matched(const struct ipt_trigger *i,
267 const u_int16_t proto, const u_int16_t dport)
269 u_int16_t rproto = i->rproto ? : proto;
271 return ((rproto == proto) && (i->ports.rport[0] <= dport)
272 && (i->ports.rport[1] >= dport));
275 static unsigned int
276 trigger_in(struct sk_buff *skb)
278 struct ipt_trigger *trig;
279 struct nf_conn *ct;
280 enum ip_conntrack_info ctinfo;
281 struct iphdr *iph;
282 struct tcphdr *tcph;
284 ct = nf_ct_get(skb, &ctinfo);
285 if ((ct == NULL) || !(ct->status & IPS_TRIGGER))
286 return IPT_CONTINUE;
288 iph = ip_hdr(skb);
289 tcph = (void *)iph + (iph->ihl << 2); /* Might be TCP, UDP */
291 /* Check if the trigger-ed range has already existed in 'trigger_list'. */
292 trig = LIST_FIND(&trigger_list,
293 trigger_in_matched,
294 struct ipt_trigger *,
295 iph->protocol, ntohs(tcph->dest));
297 if (trig != NULL) {
298 DEBUGP("Trigger In: from %u.%u.%u.%u, destination port %u\n",
299 NIPQUAD(iph->saddr), ntohs(tcph->dest));
300 /* Yeah, it exists. We need to update(delay) the destroying timer. */
301 trigger_timer_refresh(trig);
303 return NF_ACCEPT; /* Accept it, or the imcoming packet could be
304 dropped in the FORWARD chain */
307 return IPT_CONTINUE; /* Our job is the interception. */
310 static unsigned int
311 trigger_dnat(struct sk_buff *skb, unsigned int hooknum)
313 struct ipt_trigger *trig;
314 struct iphdr *iph;
315 struct tcphdr *tcph;
316 struct nf_conn *ct;
317 enum ip_conntrack_info ctinfo;
318 struct nf_nat_range newrange;
320 iph = ip_hdr(skb);
321 tcph = (void *)iph + (iph->ihl << 2); /* Might be TCP, UDP */
323 NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING);
324 /* Check if the trigger-ed range has already existed in 'trigger_list'. */
325 trig = LIST_FIND(&trigger_list,
326 trigger_in_matched,
327 struct ipt_trigger *,
328 iph->protocol, ntohs(tcph->dest));
330 if (trig == NULL || trig->srcip == 0)
331 return IPT_CONTINUE; /* We don't block any packet. */
333 trig->reply = 1; /* Confirm there has been a reply connection. */
334 ct = nf_ct_get(skb, &ctinfo);
335 NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW));
337 DEBUGP("Trigger DNAT: %u.%u.%u.%u ", NIPQUAD(trig->srcip));
338 NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
340 /* Alter the destination of imcoming packet. */
341 newrange = ((struct nf_nat_range)
342 { IP_NAT_RANGE_MAP_IPS,
343 trig->srcip, trig->srcip,
344 { 0 }, { 0 }
347 ct->status |= IPS_TRIGGER;
349 /* Hand modified range to generic setup. */
350 return nf_nat_setup_info(ct, &newrange, hooknum);
353 static inline int trigger_refresh_matched(const struct ipt_trigger *i,
354 u_int16_t proto, u_int16_t sport)
356 u_int16_t rproto = i->rproto ? : proto;
358 return
359 rproto == proto &&
360 i->ports.rport[0] <= sport &&
361 i->ports.rport[1] >= sport;
364 static unsigned int trigger_refresh(struct sk_buff *skb)
366 struct iphdr *iph;
367 struct tcphdr *tcph;
368 struct ipt_trigger *trig;
369 struct nf_conn *ct;
370 enum ip_conntrack_info ctinfo;
372 ct = nf_ct_get(skb, &ctinfo);
373 if ((ct == NULL) || !(ct->status & IPS_TRIGGER))
374 return IPT_CONTINUE;
376 iph = ip_hdr(skb);
377 tcph = (void *)iph + (iph->ihl << 2); /* Might be TCP, UDP */
379 trig = LIST_FIND(&trigger_list,
380 trigger_refresh_matched,
381 struct ipt_trigger *,
382 iph->protocol, tcph->source);
383 if (trig != NULL) {
384 DEBUGP("Trigger Refresh: from %u.%u.%u.%u, %u\n",
385 NIPQUAD(iph->saddr), ntohs(tcph->source));
386 trigger_timer_refresh(trig);
389 return IPT_CONTINUE;
392 static unsigned int
393 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
394 target(struct sk_buff *skb,
395 const struct net_device *in,
396 const struct net_device *out,
397 unsigned int hooknum,
398 const struct xt_target *target,
399 const void *targinfo)
400 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
401 target(struct sk_buff *skb,
402 const struct net_device *in,
403 const struct net_device *out,
404 unsigned int hooknum,
405 const struct xt_target *target,
406 const void *targinfo)
407 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
408 target(struct sk_buff *skb,
409 const struct xt_target_param *par)
410 #endif
412 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
413 const struct ipt_trigger_info *info = targinfo;
414 #else
415 const struct ipt_trigger_info *info = par->targinfo;
416 const struct net_device *in = par->in;
417 const struct net_device *out = par->out;
418 unsigned int hooknum = par->hooknum;
419 #endif
420 const struct iphdr *iph = ip_hdr(skb);
422 /* DEBUGP("%s: type = %s\n", __FUNCTION__,
423 (info->type == IPT_TRIGGER_DNAT) ? "dnat" :
424 (info->type == IPT_TRIGGER_IN) ? "in" : "out"); */
426 /* The Port-trigger only supports TCP and UDP. */
427 if ((iph->protocol != IPPROTO_TCP) && (iph->protocol != IPPROTO_UDP))
428 return IPT_CONTINUE;
430 if (info->type == IPT_TRIGGER_OUT)
431 return trigger_out(skb, targinfo);
432 else if (info->type == IPT_TRIGGER_IN)
433 return trigger_in(skb);
434 else if (info->type == IPT_TRIGGER_DNAT)
435 return trigger_dnat(skb, hooknum);
436 else if (info->type == IPT_TRIGGER_REFRESH)
437 return trigger_refresh(skb);
439 return IPT_CONTINUE;
442 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
443 static int
444 checkentry(const char *tablename,
445 const void *e,
446 const struct xt_target *target,
447 void *targinfo,
448 unsigned int hook_mask)
449 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
450 static bool
451 checkentry(const char *tablename,
452 const void *e,
453 const struct xt_target *target,
454 void *targinfo,
455 unsigned int hook_mask)
456 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
457 static bool
458 checkentry(const struct xt_tgchk_param *par)
459 #endif
461 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
462 unsigned int hook_mask = par->hook_mask;
463 const struct ipt_trigger_info *info = par->targinfo;
464 const char *tablename = par->table;
465 #else
466 const struct ipt_trigger_info *info = targinfo;
467 #endif
469 if ((strcmp(tablename, "mangle") == 0)) {
470 DEBUGP("trigger_check: bad table `%s'.\n", tablename);
471 return 0;
473 if (info->proto) {
474 if (info->proto != IPPROTO_TCP && info->proto != IPPROTO_UDP) {
475 DEBUGP("trigger_check: bad proto %d.\n", info->proto);
476 return 0;
479 if (info->type == IPT_TRIGGER_OUT) {
480 if (!info->ports.mport[0] || !info->ports.rport[0]) {
481 DEBUGP("trigger_check: Try 'iptables -j TRIGGER -h' for help.\n");
482 return 0;
486 /* Empty the 'trigger_list' */
487 trigger_flush();
489 return 1;
492 static struct ipt_target redirect_reg = {
493 .name = "TRIGGER",
494 .family = AF_INET,
495 .target = target,
496 .targetsize = sizeof(struct ipt_trigger_info),
497 .checkentry = checkentry,
498 .hooks = (1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_FORWARD),
499 .me = THIS_MODULE,
502 static int __init init(void)
504 return xt_register_target(&redirect_reg);
507 static void __exit fini(void)
509 xt_unregister_target(&redirect_reg);
510 trigger_flush();
513 module_init(init);
514 module_exit(fini);