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
8 * This is kernel module for port-triggering.
10 * The module follows the Netfilter framework, called extended packet
15 * 2008.07: code cleaning by Delta Networks Inc.
19 #include <linux/types.h>
20 #include <linux/skbuff.h>
21 #include <linux/version.h>
23 #include <linux/tcp.h>
25 #include <linux/timer.h>
26 #include <linux/module.h>
27 #include <linux/netfilter.h>
28 #include <linux/netdevice.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>
46 #include <linux/netfilter_ipv4/ip_nat_rule.h>
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>
60 #define DEBUGP(format, args...)
63 #define LIST_FIND(head, cmpfn, type, args...) \
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)) { \
73 read_unlock_bh(&trigger_lock); \
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]);
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]);
109 /* delete from 'trigger_list' */
110 list_del(&trig
->list
);
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
))
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
);
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
);
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
);
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
)
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];
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
,
197 struct ipt_trigger
*,
198 iph
->protocol
, ntohs(tcph
->dest
), info
);
201 DEBUGP("Tirgger Out Refresh: %u.%u.%u.%u %u\n", NIPQUAD(iph
->saddr
),
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. */
209 trig
->srcip
= iph
->saddr
;
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
;
237 /* Create new trigger */
238 trig
= (struct ipt_trigger
*)kzalloc(sizeof(struct ipt_trigger
), GFP_ATOMIC
);
240 DEBUGP("No memory for adding Tigger!\n");
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
;
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
));
276 trigger_in(struct sk_buff
*skb
)
278 struct ipt_trigger
*trig
;
280 enum ip_conntrack_info ctinfo
;
284 ct
= nf_ct_get(skb
, &ctinfo
);
285 if ((ct
== NULL
) || !(ct
->status
& IPS_TRIGGER
))
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
,
294 struct ipt_trigger
*,
295 iph
->protocol
, ntohs(tcph
->dest
));
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. */
311 trigger_dnat(struct sk_buff
*skb
, unsigned int hooknum
)
313 struct ipt_trigger
*trig
;
317 enum ip_conntrack_info ctinfo
;
318 struct nf_nat_range newrange
;
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
,
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
,
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
;
360 i
->ports
.rport
[0] <= sport
&&
361 i
->ports
.rport
[1] >= sport
;
364 static unsigned int trigger_refresh(struct sk_buff
*skb
)
368 struct ipt_trigger
*trig
;
370 enum ip_conntrack_info ctinfo
;
372 ct
= nf_ct_get(skb
, &ctinfo
);
373 if ((ct
== NULL
) || !(ct
->status
& IPS_TRIGGER
))
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
);
384 DEBUGP("Trigger Refresh: from %u.%u.%u.%u, %u\n",
385 NIPQUAD(iph
->saddr
), ntohs(tcph
->source
));
386 trigger_timer_refresh(trig
);
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
)
412 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
413 const struct ipt_trigger_info
*info
= targinfo
;
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
;
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
))
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
);
442 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
444 checkentry(const char *tablename
,
446 const struct xt_target
*target
,
448 unsigned int hook_mask
)
449 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
451 checkentry(const char *tablename
,
453 const struct xt_target
*target
,
455 unsigned int hook_mask
)
456 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
458 checkentry(const struct xt_tgchk_param
*par
)
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
;
466 const struct ipt_trigger_info
*info
= targinfo
;
469 if ((strcmp(tablename
, "mangle") == 0)) {
470 DEBUGP("trigger_check: bad table `%s'.\n", tablename
);
474 if (info
->proto
!= IPPROTO_TCP
&& info
->proto
!= IPPROTO_UDP
) {
475 DEBUGP("trigger_check: bad proto %d.\n", info
->proto
);
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");
486 /* Empty the 'trigger_list' */
492 static struct ipt_target redirect_reg
= {
496 .targetsize
= sizeof(struct ipt_trigger_info
),
497 .checkentry
= checkentry
,
498 .hooks
= (1 << NF_IP_PRE_ROUTING
) | (1 << NF_IP_FORWARD
),
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
);