All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: P2P implementation for netfilter NAT
       [not found] <001801c5f6b3$539b1b20$3478fea9@acer21ce70712f>
@ 2005-12-04 10:26 ` Rusty Russell
  2005-12-05  8:03   ` Jesse Peng
  0 siblings, 1 reply; 8+ messages in thread
From: Rusty Russell @ 2005-12-04 10:26 UTC (permalink / raw)
  To: Jesse Peng; +Cc: Harald Welte, netfilter-devel

On Fri, 2005-12-02 at 04:10 +0800, Jesse Peng wrote:
> Dear All
> Here is the patch for p2p implementation.Please reference the links
> below:
> 1.Logic to implement.
> https://lists.netfilter.org/pipermail/netfilter-devel/2004-November/017479.html 
> 2.The Last draft by Dan Kegel.
> http://www.brynosaurus.com/pub/net/p2pnat.pdf
> 
> Hello Rusty
> Like what we discussed as following 2 points
> 1.hash_by_modified_source need be checked and added by conntracks
> being SNATP2Ped.As the checking code is hacked in
> ip_nat_used_tuple,and adding code in ip_nat_setup_info.All incoming
> hairpin or holepunch try be checked and added in the ip_nat_rule_find
> hacking.

> 2.delay tcp timeout for immediate reset by counterparts in case they
> are old version and fail to take hairpin or holepunch reaction.(Maybe
> We don't need do this any more,because that will only terminate our
> initiation,but while they initiate,we are happy to handle the
> holepunch and the hairpin! :) ) .

Hi Jesse,

	Your patch seems incomplete, and anyway it's been mangled by your
mailer.  Sorry I've been slow to respond, but a on a quick read I think
you're going in the right direction.  Perhaps try an attachment?

Thanks!
Rusty.
-- 
A bad analogy is like a leaky screwdriver -- Richard Braakman

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: P2P implementation for netfilter NAT
  2005-12-04 10:26 ` P2P implementation for netfilter NAT Rusty Russell
@ 2005-12-05  8:03   ` Jesse Peng
  2005-12-05  9:48     ` Waiting for user space response in Kernel Mode Guru Prasad
  2006-01-05 15:52     ` P2P implementation for netfilter NAT Jesse Peng
  0 siblings, 2 replies; 8+ messages in thread
From: Jesse Peng @ 2005-12-05  8:03 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Harald Welte, netfilter-devel


----- Original Message ----- 
From: "Rusty Russell" <rusty@rustcorp.com.au>
To: "Jesse Peng" <tzuhsi.peng@msa.hinet.net>
Cc: "Harald Welte" <laforge@netfilter.org>; 
<netfilter-devel@lists.netfilter.org>
Sent: Sunday, December 04, 2005 6:26 PM
Subject: Re: P2P implementation for netfilter NAT


> On Fri, 2005-12-02 at 04:10 +0800, Jesse Peng wrote:
>> Dear All
>> Here is the patch for p2p implementation.Please reference the links
>> below:
>> 1.Logic to implement.
>> https://lists.netfilter.org/pipermail/netfilter-devel/2004-November/017479.html
>> 2.The Last draft by Dan Kegel.
>> http://www.brynosaurus.com/pub/net/p2pnat.pdf
>>
>> Hello Rusty
>> Like what we discussed as following 2 points
>> 1.hash_by_modified_source need be checked and added by conntracks
>> being SNATP2Ped.As the checking code is hacked in
>> ip_nat_used_tuple,and adding code in ip_nat_setup_info.All incoming
>> hairpin or holepunch try be checked and added in the ip_nat_rule_find
>> hacking.
>
>> 2.delay tcp timeout for immediate reset by counterparts in case they
>> are old version and fail to take hairpin or holepunch reaction.(Maybe
>> We don't need do this any more,because that will only terminate our
>> initiation,but while they initiate,we are happy to handle the
>> holepunch and the hairpin! :) ) .
>
> Hi Jesse,
>
> Your patch seems incomplete, and anyway it's been mangled by your
> mailer.  Sorry I've been slow to respond, but a on a quick read I think
> you're going in the right direction.  Perhaps try an attachment?
>
Thanks,Rusty,I'll resend it again!Please check

Regards
Jesse 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Waiting for user space response in Kernel Mode
  2005-12-05  8:03   ` Jesse Peng
@ 2005-12-05  9:48     ` Guru Prasad
  2005-12-05  9:52       ` Pablo Neira Ayuso
  2006-01-05 15:52     ` P2P implementation for netfilter NAT Jesse Peng
  1 sibling, 1 reply; 8+ messages in thread
From: Guru Prasad @ 2005-12-05  9:48 UTC (permalink / raw)
  To: netfilter-devel

I am a newbie to Kernel and Netfilter development.
  
When a new connection with specific parameters (for
example a certain destination IP address) is created,
I would like to indicate this event to a daemon
process in user space which takes some decision before
proceeding. I detect this event from 
ip_conntrack_netlink.c in the following function.
  
  int ctnetlink_conntrack_event(struct notifier_block 
*this,                                     
unsigned long events, void *ptr) -->    "if (events & 
(IPCT_NEW | 
IPCT_RELATED)) {"
  
When I detect a new connection,I tried to use
Wait_queues and call schedule() so that I could wait
on this process before receiving response from user
space, but using this mechanism leads to crashes. It
seems that one can only use this mechanism (wait
queues and schedule)  when a process is executing in
the context of a user space application.  
  
When executing in kernel mode, such as in case when
the ip stack is forwarding packets, how can one wait
for user space response before proceeding?
  
One solution I could think of is to queue the packets
until decision is  received from user space and then
to de-queue everything. 
  
I would like to know if anybody had encountered
similar problem and found a working solution.

Br
Guruprasad


		
__________________________________________ 
Yahoo! DSL – Something to write home about. 
Just $16.99/mo. or less. 
dsl.yahoo.com 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Waiting for user space response in Kernel Mode
  2005-12-05  9:48     ` Waiting for user space response in Kernel Mode Guru Prasad
@ 2005-12-05  9:52       ` Pablo Neira Ayuso
  0 siblings, 0 replies; 8+ messages in thread
From: Pablo Neira Ayuso @ 2005-12-05  9:52 UTC (permalink / raw)
  To: Guru Prasad; +Cc: netfilter-devel

Guru Prasad wrote:
> I am a newbie to Kernel and Netfilter development.
>   
> When a new connection with specific parameters (for
> example a certain destination IP address) is created,
> I would like to indicate this event to a daemon
> process in user space which takes some decision before
> proceeding. I detect this event from 
> ip_conntrack_netlink.c in the following function.
>   
>   int ctnetlink_conntrack_event(struct notifier_block 
> *this,                                     
> unsigned long events, void *ptr) -->    "if (events & 
> (IPCT_NEW | 
> IPCT_RELATED)) {"
>   
> When I detect a new connection,I tried to use
> Wait_queues and call schedule() so that I could wait
> on this process before receiving response from user
> space, but using this mechanism leads to crashes. It
> seems that one can only use this mechanism (wait
> queues and schedule)  when a process is executing in
> the context of a user space application.  

Yes, ctnetlink_conntrack_event is always called from interrupt context.
Don't do that in kernelspace. Use libnetfilter_conntrack and work in
userspace please.

-- 
Pablo

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: P2P implementation for netfilter NAT
  2005-12-05  8:03   ` Jesse Peng
  2005-12-05  9:48     ` Waiting for user space response in Kernel Mode Guru Prasad
@ 2006-01-05 15:52     ` Jesse Peng
  2006-01-08  1:20       ` Rusty Russell
  1 sibling, 1 reply; 8+ messages in thread
From: Jesse Peng @ 2006-01-05 15:52 UTC (permalink / raw)
  To: Jesse Peng, Rusty Russell; +Cc: Harald Welte, netfilter-devel


----- Original Message ----- 
From: "Jesse Peng" <tzuhsi.peng@msa.hinet.net>
To: "Rusty Russell" <rusty@rustcorp.com.au>
Cc: "Harald Welte" <laforge@netfilter.org>; 
<netfilter-devel@lists.netfilter.org>
Sent: Monday, December 05, 2005 4:03 PM
Subject: Re: P2P implementation for netfilter NAT


>
> ----- Original Message ----- 
> From: "Rusty Russell" <rusty@rustcorp.com.au>
> To: "Jesse Peng" <tzuhsi.peng@msa.hinet.net>
> Cc: "Harald Welte" <laforge@netfilter.org>; 
> <netfilter-devel@lists.netfilter.org>
> Sent: Sunday, December 04, 2005 6:26 PM
> Subject: Re: P2P implementation for netfilter NAT
>
>
>> Hi Jesse,
>>
>> Your patch seems incomplete, and anyway it's been mangled by your
>> mailer.  Sorry I've been slow to respond, but a on a quick read I think
>> you're going in the right direction.  Perhaps try an attachment?
>>
> Thanks,Rusty,I'll resend it again!Please check
>
> Regards
> Jesse
Hello Rusty
I resent the patch 1 month ago,but still failed to see it showing on mailing 
list.Sorry,just to make sure if you successfully received the patch,or I 
resend the patch again?

Thanks
Jesse 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: P2P implementation for netfilter NAT
  2006-01-05 15:52     ` P2P implementation for netfilter NAT Jesse Peng
@ 2006-01-08  1:20       ` Rusty Russell
  2006-01-16 16:26         ` Jesse Peng
  0 siblings, 1 reply; 8+ messages in thread
From: Rusty Russell @ 2006-01-08  1:20 UTC (permalink / raw)
  To: Jesse Peng; +Cc: Harald Welte, netfilter-devel


> Hello Rusty
> I resent the patch 1 month ago,but still failed to see it showing on mailing 
> list.Sorry,just to make sure if you successfully received the patch,or I 
> resend the patch again?

Hmm, please resend...

Thanks,
Rusty.
-- 
 ccontrol: http://ozlabs.org/~rusty/ccontrol

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: P2P implementation for netfilter NAT
  2006-01-08  1:20       ` Rusty Russell
@ 2006-01-16 16:26         ` Jesse Peng
  2006-01-18 10:53           ` Jesse Peng
  0 siblings, 1 reply; 8+ messages in thread
From: Jesse Peng @ 2006-01-16 16:26 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Harald Welte, netfilter-devel

[-- Attachment #1: Type: text/plain, Size: 22713 bytes --]

> Hmm, please resend...

Sorry for the late reply,here attatch the patch,Please give advice.

Thanks
Jesse

-------------first part--------------
diff -Nur linux-2.6.13.3/include/linux/netfilter_i
pv4/ip_conntrack.h linux-b/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.6.13.3/include/linux/netfilter_ipv4/ip_conntrack.h  2005-10-04 
07:27
:34.000000000 +0800
+++ linux-b/include/linux/netfilter_ipv4/ip_conntrack.h 2005-11-02 
18:11:00.0000
00000 +0800
@@ -65,6 +65,27 @@
        /* Both together */
        IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+       IPS_SNATP2P_SRC_BIT = 9,
+       IPS_SNATP2P_SRC = (1 << IPS_SNATP2P_SRC_BIT),
+
+       IPS_SNATP2P_DST_BIT = 10,
+       IPS_SNATP2P_DST = (1 << IPS_SNATP2P_DST_BIT),
+
+        /* Both together. */
+       IPS_SNATP2P_MASK = (IPS_SNATP2P_DST | IPS_SNATP2P_SRC),
+
+        IPS_SNATP2P_SRC_DONE_BIT = 11,
+       IPS_SNATP2P_SRC_DONE = (1 << IPS_SNATP2P_SRC_DONE_BIT),
+
+        IPS_SNATP2P_DST_DONE_BIT = 12,
+       IPS_SNATP2P_DST_DONE = (1 << IPS_SNATP2P_DST_DONE_BIT),
+
+        /* Both together. */
+       IPS_SNATP2P_DONE_MASK = (IPS_SNATP2P_DST_DONE | 
IPS_SNATP2P_SRC_DONE),
+#endif
+
 };
 #ifdef __KERNEL__
diff -Nur linux-2.6.13.3/include/linux/netfilter_i
pv4/ip_nat.h linux-b/include/linux/netfilter_ipv4/ip_nat.h
--- linux-2.6.13.3/include/linux/netfilter_ipv4/ip_nat.h        2005-10-04 
07:27
:34.000000000 +0800
+++ linux-b/include/linux/netfilter_ipv4/ip_nat.h       2005-11-07 
21:28:32.0000
00000 +0800
@@ -59,6 +59,10 @@
 {
        struct list_head bysource;
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+    struct list_head by_modified_source;
+#endif
+
        /* Helper (NULL if none). */
        struct ip_nat_helper *helper;
@@ -76,6 +80,11 @@
 extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
                             const struct ip_conntrack *ignored_conntrack);
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+extern int find_appropriate_p2p_dst(const struct ip_conntrack_tuple *tuple,
+                    struct ip_conntrack_tuple *result);
+#endif
+
 /* Calculate relative checksum. */
 extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
                                    u_int32_t newval,
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/Kconf
g linux-b/net/ipv4/netfilter/Kconfig
--- linux-2.6.13.3/net/ipv4/netfilter/Kconfig   2005-10-04 
07:27:34.000000000 +
800
+++ linux-b/net/ipv4/netfilter/Kconfig  2005-11-09 17:11:10.000000000 +0800
@@ -484,6 +484,14 @@
          To compile it as a module, choose M here.  If unsure, say N.
+config IP_NF_TARGET_SNATP2P
+    tristate "SNATP2P target support"
+       depends on IP_NF_NAT
+       help
+         SNATP2P is an implementation for P2P need.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_NF_TARGET_NETMAP
        tristate "NETMAP target support"
        depends on IP_NF_NAT
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/Makef
le linux-b/net/ipv4/netfilter/Makefile
--- linux-2.6.13.3/net/ipv4/netfilter/Makefile  2005-10-04 
07:27:34.000000000 +
800
+++ linux-b/net/ipv4/netfilter/Makefile 2005-11-09 17:13:00.000000000 +0800
@@ -68,6 +68,7 @@
 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+obj-$(CONFIG_IP_NF_TARGET_SNATP2P) += ipt_SNATP2P.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
 obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_co
ntrack_proto_tcp.c linux-b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_conntrack_proto_tcp.c  2005-10-04 
07:2
:34.000000000 +0800
+++ linux-b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2005-11-11 
21:21:34.000
00000 +0800
@@ -979,10 +979,19 @@
            problem case, so we can delete the conntrack
            immediately.  --RR */
         if (th->rst) {
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+            /*maybe we don't need to care this condition 
anymore,Rusty?since we take care of holepunch and hairpin!*/
+            if(conntrack->status & IPS_SNATP2P_SRC_DONE){
+                timeout = 2 MINS;
+                ip_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
+                return NF_DROP;
+            }
+#else
             if (del_timer(&conntrack->timeout))
                 conntrack->timeout.function((unsigned long)
                                 conntrack);
             return NF_ACCEPT;
+#endif
         }
     } else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
            && (old_state == TCP_CONNTRACK_SYN_RECV
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_nat
_core.c linux-b/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_core.c     2005-10-04 
07:27:34.0000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_core.c    2005-11-09 
17:29:24.000000000 +0
800
@@ -1,4 +1,4 @@
 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
@@ -47,6 +47,11 @@
 static unsigned int ip_nat_htable_size;
 static struct list_head *bysource;
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static struct list_head *by_modified_source;
+#endif
+
 struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];

@@ -59,6 +64,16 @@
                            tuple->dst.protonum, 0) % ip_nat_htable_size;
 }
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static inline unsigned int
+hash_by_dst(const struct ip_conntrack_tuple *tuple)
+{
+       /* Original src, to ensure we map it consistently if poss. */
+       return jhash_3words(tuple->dst.ip, tuple->dst.u.all,
+                           tuple->dst.protonum, 0) % ip_nat_htable_size;
+}
+#endif
+
 /* Noone using conntrack by the time this called. */
 static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
 {
@@ -67,6 +82,10 @@
        write_lock_bh(&ip_nat_lock);
        list_del(&conn->nat.info.bysource);
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+        if ((conn->status & IPS_SNATP2P_MASK) && (conn->status & 
IPS_SNATP2P_DONE_MASK))
+                list_del(&conn->nat.info.by_modified_source);
+#endif
        write_unlock_bh(&ip_nat_lock);
 }
@@ -93,6 +112,14 @@
           We could keep a separate hash if this proves too slow. */
        struct ip_conntrack_tuple reply;
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+    if((ignored_conntrack->status & IPS_SNATP2P_SRC)
+                     && !(ignored_conntrack->status & 
IPS_SNATP2P_SRC_DONE))
+        if (modified_src_occupied(tuple,ignored_conntrack))
+            return 1;
+#endif
+
+
        invert_tuplepr(&reply, tuple);
        return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
 }
@@ -160,6 +187,77 @@
        return 0;
 }
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static inline int
+same_modified_src(const struct ip_conntrack *ct,
+        const struct ip_conntrack_tuple *tuple)
+{
+       if (ct->status & IPS_SNATP2P_DST)
+           return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
+                   == tuple->dst.protonum
+                   && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip
+                   == tuple->src.ip
+                   && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all
+                   == tuple->src.u.all);
+       else
+       /*must be ct->status & IPS_SNATP2P_SRC*/
+           return (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
+                   == tuple->dst.protonum
+                   && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
+                   == tuple->src.ip
+                   && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
+                   == tuple->src.u.all);
+}
+
+static int
+modified_src_occupied(const struct ip_conntrack_tuple *tuple,
+                    const struct ip_conntrack *conntrack)
+{
+       unsigned int h = hash_by_src(tuple);
+       struct ip_conntrack *ct;
+
+       read_lock_bh(&ip_nat_lock);
+       list_for_each_entry(ct, &by_modified_source[h], 
nat.info.by_modified_source) {
+               if (same_modified_src(ct, tuple)) {
+                       if (same_src(ct, 
&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple))
+                           /*that's an appropriate source*/
+                           next;
+                       read_unlock_bh(&ip_nat_lock);
+                       return 1;
+               }
+       }
+       read_unlock_bh(&ip_nat_lock);
+       return 0;
+}
+
+int
+find_appropriate_p2p_dst(const struct ip_conntrack_tuple *tuple,
+                    struct ip_conntrack_tuple *result)
+{
+       unsigned int h = hash_by_src(tuple);
+       struct ip_conntrack *ct;
+
+       read_lock_bh(&ip_nat_lock);
+       list_for
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_nat
_rule.c linux-b/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_rule.c     2005-10-04 
07:27:34.0000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_rule.c    2005-11-07 
21:26:44.000000000 +0
800
@@ -267,9 +267,30 @@
        ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);
        if (ret == NF_ACCEPT) {
-               if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
-                       /* NUL mapping */
-                       ret = alloc_null_binding(ct, info, hooknum);
+           if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum))){
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+               if ((HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST)){
+                   struct ip_conntrack_tuple reply_tuple, new_tuple;
+                   invert_tuplepr(&reply_tuple,
+                       &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+                   if (find_appropriate_p2p_dst(&reply_tuple, &new_tuple){
+                       struct ip_nat_range range;
+                       /* This must be a fresh one. */
+                       BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+                       ct->status |= IPS_SNATP2P_DST;
+                       range.flags = (IP_NAT_RANGE_MAP_IPS | 
IP_NAT_RANGE_PROTO_SPECIFIED);
+                       range.min = range.max = new_tuple.dst.u;
+                       range.min_ip = range.max_ip
+                           = new_tuple.dst.ip;
+                       ret = ip_nat_setup_info(ct, &range, 
NF_IP_PRE_ROUTING);
+                   }
+               }
+               if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
+
+#endif
+                /* NUL mapping */
+                           ret = alloc_null_binding(ct, info, hooknum);
+           }
        }
        return ret;
 }
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_na
_standalone.c linux-b/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_standalone.c       2005-10-04 
07:2
:34.000000000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_standalone.c      2005-11-07 
21:28:10.000
00000 +0800
@@ -393,6 +393,9 @@
 module_init(init);
 module_exit(fini);
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+EXPORT_SYMBOL(find_appropriate_p2p_dst);
+#endif
 EXPORT_SYMBOL(ip_nat_setup_info);
 EXPORT_SYMBOL(ip_nat_protocol_register);
 EXPORT_SYMBOL(ip_nat_protocol_unregister);
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ipt_S
ATP2P.c linux-b/net/ipv4/netfilter/ipt_SNATP2P.c
--- linux-2.6.13.3/net/ipv4/netfilter/ipt_SNATP2P.c     1970-01-01 
08:00:00.000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ipt_SNATP2P.c    2005-11-11 
20:12:02.000000000 +
800
@@ -0,0 +1,95 @@
+/* This is a module which is used for source-NAT-P2P.
+ */
+#include <linux/netfilter_ipv4.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+
+static unsigned int ipt_snatp2p_target(struct sk_buff **pskb,
+                                   const struct net_device *in,
+                                   const struct net_device *out,
+                                   unsigned int hooknum,
+                                   const void *targinfo,
+                                   void *userinfo)
+{
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
+       const struct ip_nat_multi_range_compat *mr = targinfo;
+
+       IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
+
+       ct = ip_conntrack_get(*pskb, &ctinfo);
+
+       /* Connection must be valid and new. */
+       IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
+                           || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
+       IP_NF_ASSERT(out);
+       ct->status |= IPS_SNATP2P_SRC;
+       return ip_nat_setup_info(ct, &mr->range[0], hooknum);
+}
+
+static int ipt_snatp2p_checkentry(const char *tablename,
+                              const struct ipt_entry *e,
+                              void *targinfo,
+                              unsigned int targinfosize,
+                              unsigned int hook_mask)
+{
+       struct ip_nat_multi_range_compat *mr = targinfo;
+
+       /* Must be a valid range */
+       if (mr->rangesize != 1) {
+               printk("SNATP2P: multiple ranges no longer supported\n");
+               return 0;
+       }
+
+       if (targinfosize != IPT_ALIGN(sizeof(struct 
ip_nat_multi_range_compat))
 {
+               DEBUGP("SNATP2P: Target size %u wrong for %u ranges\n",
+                      targinfosize, mr->rangesize);
+               return 0;
+       }
+
+       /* Only allow these for NAT. */
+       if (strcmp(tablename, "nat") != 0) {
+               DEBUGP("SNATP2P: wrong table %s\n", tablename);
+               return 0;
+       }
+
+       if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
+               DEBUGP("SNATP2P: hook mask 0x%x bad\n", hook_mask);
+               return 0;
+       }
+       return 1;
+}
+
+static struct ipt_target ipt_snatp2p_reg = {
+       .name           = "SNATP2P",
+       .target         = ipt_snatp2p_target,
+       .checkentry     = ipt_snatp2p_checkentry,
+};
+
+static int __init init(void)
+{
+       if (ipt_register_target(&ipt_snatp2p_reg))
+               return -EINVAL;
+
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_target(&ipt_snatp2p_reg);
+}
+
+module_init(init);
+module_exit(fini);
-------------Second Part------------
diff -Nur iptables-1.3.4/extensions/libi
t_SNATP2P.c iptables-b/extensions/libipt_SNATP2P.c
--- iptables-1.3.4/extensions/libipt_SNATP2P.c  1970-01-01 
08:00:00.000000000 +
800
+++ iptables-b/extensions/libipt_SNATP2P.c      2005-11-09 
17:32:58.000000000 +
800
@@ -0,0 +1,249 @@
+/* Shared library add-on to iptables to add source-NAT-P2P support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+/* Source NAT data consists of a multi-range, indicating where to map
+   to. */
+struct ipt_natinfo
+{
+       struct ipt_entry_target t;
+       struct ip_nat_multi_range mr;
+};
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+       printf(
+"SNATP2P v%s options:\n"
+" --to-source <ipaddr>[-<ipaddr>][:port-port]\n"
+"                              Address to map source to.\n"
+"                              (You can use this more than once)\n\n",
+IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+       { "to-source", 1, 0, '1' },
+       { 0 }
+};
+
+static struct ipt_natinfo *
+append_range(struct ipt_natinfo *info, const struct ip_nat_range *range)
+{
+       unsigned int size;
+
+       /* One rangesize already in struct ipt_natinfo */
+       size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize * 
sizeof(*range));
+
+       info = realloc(info, size);
+       if (!info)
+               exit_error(OTHER_PROBLEM, "Out of memory\n");
+
+       info->t.u.target_size = size;
+       info->mr.range[info->mr.rangesize] = *range;
+       info->mr.rangesize++;
+
+       return info;
+}
+
+/* Ranges expected in network order. */
+static struct ipt_entry_target *
+parse_to(char *arg, int portok, struct ipt_natinfo *info)
+{
+       struct ip_nat_range range;
+       char *colon, *dash, *error;
+       struct in_addr *ip;
+
+       memset(&range, 0, sizeof(range));
+       colon = strchr(arg, ':');
+
+       if (colon) {
+               int port;
+
+               if (!portok)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Need TCP or UDP with port 
specification");
+
+               range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+               port = atoi(colon+1);
+               if (port <= 0 || port > 65535)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Port `%s' not valid\n", colon+1);
+
+               error = strchr(colon+1, ':');
+               if (error)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Invalid port:port syntax - use dash\n");
+
+               dash = strchr(colon, '-');
+               if (!dash) {
+                       range.min.tcp.port
+                               = range.max.tcp.port
+                               = htons(port);
+               } else {
+                       int maxport;
+
+                       maxport = atoi(dash + 1);
+                       if (maxport <= 0 || maxport > 65535)
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Port `%s' not valid\n", dash+1);
+                       if (maxport < port)
+                               /* People are stupid. */
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Port range `%s' funky\n", 
colon+1);
+                       range.min.tcp.port = htons(port);
+                       range.max.tcp.port = htons(maxport);
+               }
+               /* Starts with a colon? No IP info...*/
+               if (colon == arg)
+                       return &(append_range(info, &range)->t);
+               *colon = '\0';
+       }
+
+       range.flags |= IP_NAT_RANGE_MAP_IPS;
+       dash = strchr(arg, '-');
+       if (colon && dash && dash > colon)
+               dash = NULL;
+
+       if (dash)
+               *dash = '\0';
+
+       ip = dotted_to_addr(arg);
+       if (!ip)
+               exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+                          arg);
+       range.min_ip = ip->s_addr;
+       if (dash) {
+               ip = dotted_to_addr(dash+1);
+               if (!ip)
+                       exit_error(PARAMETER_PROBLEM, "Bad IP address 
`%s'\n",
+                                  dash+1);
+               range.max_ip = ip->s_addr;
+       } else
+               range.max_ip = range.min_ip;
+
+       return &(append_range(info, &range)->t);
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ipt_entry *entry,
+      struct ipt_entry_target **target)
+{
+       struct ipt_natinfo *info = (void *)*target;
+       int portok;
+
+       if (entry->ip.proto == IPPROTO_TCP
+           || entry->ip.proto == IPPROTO_UDP
+           || entry->ip.proto == IPPROTO_ICMP)
+               portok = 1;
+       else
+               portok = 0;
+
+       switch (c) {
+       case '1':
+               if (check_inverse(optarg, &invert, NULL, 0))
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Unexpected `!' after --to-source");
+
+               if (*flags) {
+                       if (!kernel_version)
+                               get_kernel_version();
+                       if (kernel_version > LINUX_VERSION(2, 6, 10))
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Multiple --to-source not 
supported"
;
+               }
+               *target = parse_to(optarg, portok, info);
+               *flags = 1;
+               return 1;
+
+       default:
+               return 0;
+       }
+}
+
+/* Final check; must have specfied --to-source. */
+static void final_check(unsigned int flags)
+{
+       if (!flags)
+               exit_error(PARAMETER_PROBLEM,
+                          "You must specify --to-source");
+}
+
+static void print_range(const struct ip_nat_range *r)
+{
+       if (r->flags & IP_NAT_RANGE_MAP_IPS) {
+               struct in_addr a;
+
+               a.s_addr = r->min_ip;
+               printf("%s", addr_to_dotted(&a));
+               if (r->max_ip != r->min_ip) {
+                       a.s_addr = r->max_ip;
+                       printf("-%s", addr_to_dotted(&a));
+               }
+       }
+       if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+               printf(":");
+               printf("%hu", ntohs(r->min.tcp.port));
+               if (r->max.tcp.port != r->min.tcp.port)
+                       printf("-%hu", ntohs(r->max.tcp.port));
+       }
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+      const struct ipt_entry_target *target,
+      int numeric)
+{
+       struct ipt_natinfo *info = (void *)target;
+       unsigned int i = 0;
+
+       printf("to:");
+       for (i = 0; i < info->mr.rangesize; i++) {
+               print_range(&info->mr.range[i]);
+               printf(" ");
+       }
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+       struct ipt_natinfo *info = (void *)target;
+       unsigned int i = 0;
+
+       for (i = 0; i < info->mr.rangesize; i++) {
+               printf("--to-source ");
+               print_range(&info->mr.range[i]);
+               printf(" ");
+       }
+}
+
+static struct iptables_target snatp2p = {
+       .next           = NULL,
+       .name           = "SNATP2P",
+       .version        = IPTABLES_VERSION,
+       .size           = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
+       .userspacesize  = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
+       .help           = &help,
+       .parse          = &parse,
+       .final_check    = &final_check,
+       .print          = &print,
+       .save           = &save,
+       .extra_opts     = opts
+};
+
+void _init(void)
+{
+       register_target(&snatp2p);
+} 

[-- Attachment #2: Netfilter_P2P_Implement_Patch --]
[-- Type: application/octet-stream, Size: 23420 bytes --]

-------------first part--------------
diff -Nur linux-2.6.13.3/include/linux/netfilter_i
pv4/ip_conntrack.h linux-b/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.6.13.3/include/linux/netfilter_ipv4/ip_conntrack.h  2005-10-04 07:27
:34.000000000 +0800
+++ linux-b/include/linux/netfilter_ipv4/ip_conntrack.h 2005-11-02 18:11:00.0000
00000 +0800
@@ -65,6 +65,27 @@

        /* Both together */
        IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+       IPS_SNATP2P_SRC_BIT = 9,
+       IPS_SNATP2P_SRC = (1 << IPS_SNATP2P_SRC_BIT),
+
+       IPS_SNATP2P_DST_BIT = 10,
+       IPS_SNATP2P_DST = (1 << IPS_SNATP2P_DST_BIT),
+
+        /* Both together. */
+       IPS_SNATP2P_MASK = (IPS_SNATP2P_DST | IPS_SNATP2P_SRC),
+
+        IPS_SNATP2P_SRC_DONE_BIT = 11,
+       IPS_SNATP2P_SRC_DONE = (1 << IPS_SNATP2P_SRC_DONE_BIT),
+
+        IPS_SNATP2P_DST_DONE_BIT = 12,
+       IPS_SNATP2P_DST_DONE = (1 << IPS_SNATP2P_DST_DONE_BIT),
+
+        /* Both together. */
+       IPS_SNATP2P_DONE_MASK = (IPS_SNATP2P_DST_DONE | IPS_SNATP2P_SRC_DONE),
+#endif
+
 };

 #ifdef __KERNEL__
diff -Nur linux-2.6.13.3/include/linux/netfilter_i
pv4/ip_nat.h linux-b/include/linux/netfilter_ipv4/ip_nat.h
--- linux-2.6.13.3/include/linux/netfilter_ipv4/ip_nat.h        2005-10-04 07:27
:34.000000000 +0800
+++ linux-b/include/linux/netfilter_ipv4/ip_nat.h       2005-11-07 21:28:32.0000
00000 +0800
@@ -59,6 +59,10 @@
 {
        struct list_head bysource;

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+    struct list_head by_modified_source;
+#endif
+
        /* Helper (NULL if none). */
        struct ip_nat_helper *helper;

@@ -76,6 +80,11 @@
 extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
                             const struct ip_conntrack *ignored_conntrack);

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+extern int find_appropriate_p2p_dst(const struct ip_conntrack_tuple *tuple,
+                    struct ip_conntrack_tuple *result);
+#endif
+
 /* Calculate relative checksum. */
 extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
                                    u_int32_t newval,
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/Kconf
g linux-b/net/ipv4/netfilter/Kconfig
--- linux-2.6.13.3/net/ipv4/netfilter/Kconfig   2005-10-04 07:27:34.000000000 +
800
+++ linux-b/net/ipv4/netfilter/Kconfig  2005-11-09 17:11:10.000000000 +0800
@@ -484,6 +484,14 @@

          To compile it as a module, choose M here.  If unsure, say N.

+config IP_NF_TARGET_SNATP2P
+    tristate "SNATP2P target support"
+       depends on IP_NF_NAT
+       help
+         SNATP2P is an implementation for P2P need.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_NF_TARGET_NETMAP
        tristate "NETMAP target support"
        depends on IP_NF_NAT
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/Makef
le linux-b/net/ipv4/netfilter/Makefile
--- linux-2.6.13.3/net/ipv4/netfilter/Makefile  2005-10-04 07:27:34.000000000 +
800
+++ linux-b/net/ipv4/netfilter/Makefile 2005-11-09 17:13:00.000000000 +0800
@@ -68,6 +68,7 @@
 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+obj-$(CONFIG_IP_NF_TARGET_SNATP2P) += ipt_SNATP2P.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
 obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_co
ntrack_proto_tcp.c linux-b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_conntrack_proto_tcp.c  2005-10-04 07:2
:34.000000000 +0800
+++ linux-b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2005-11-11 21:21:34.000
00000 +0800
@@ -979,10 +979,19 @@
            problem case, so we can delete the conntrack
            immediately.  --RR */
         if (th->rst) {
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+            /*maybe we don't need to care this condition anymore,Rusty?since we take care of holepunch and hairpin!*/
+            if(conntrack->status & IPS_SNATP2P_SRC_DONE){
+                timeout = 2 MINS;
+                ip_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
+                return NF_DROP;
+            }
+#else
             if (del_timer(&conntrack->timeout))
                 conntrack->timeout.function((unsigned long)
                                 conntrack);
             return NF_ACCEPT;
+#endif
         }
     } else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
            && (old_state == TCP_CONNTRACK_SYN_RECV
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_nat
_core.c linux-b/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_core.c     2005-10-04 07:27:34.0000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_core.c    2005-11-09 17:29:24.000000000 +0
800
@@ -1,4 +1,4 @@

 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
@@ -47,6 +47,11 @@
 static unsigned int ip_nat_htable_size;

 static struct list_head *bysource;
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static struct list_head *by_modified_source;
+#endif
+
 struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];


@@ -59,6 +64,16 @@
                            tuple->dst.protonum, 0) % ip_nat_htable_size;
 }

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static inline unsigned int
+hash_by_dst(const struct ip_conntrack_tuple *tuple)
+{
+       /* Original src, to ensure we map it consistently if poss. */
+       return jhash_3words(tuple->dst.ip, tuple->dst.u.all,
+                           tuple->dst.protonum, 0) % ip_nat_htable_size;
+}
+#endif
+
 /* Noone using conntrack by the time this called. */
 static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
 {
@@ -67,6 +82,10 @@

        write_lock_bh(&ip_nat_lock);
        list_del(&conn->nat.info.bysource);
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+        if ((conn->status & IPS_SNATP2P_MASK) && (conn->status & IPS_SNATP2P_DONE_MASK))
+                list_del(&conn->nat.info.by_modified_source);
+#endif
        write_unlock_bh(&ip_nat_lock);
 }

@@ -93,6 +112,14 @@
           We could keep a separate hash if this proves too slow. */
        struct ip_conntrack_tuple reply;

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+    if((ignored_conntrack->status & IPS_SNATP2P_SRC)
+                     && !(ignored_conntrack->status & IPS_SNATP2P_SRC_DONE))
+        if (modified_src_occupied(tuple,ignored_conntrack))
+            return 1;
+#endif
+
+
        invert_tuplepr(&reply, tuple);
        return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
 }
@@ -160,6 +187,77 @@
        return 0;
 }

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static inline int
+same_modified_src(const struct ip_conntrack *ct,
+        const struct ip_conntrack_tuple *tuple)
+{
+       if (ct->status & IPS_SNATP2P_DST)
+           return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
+                   == tuple->dst.protonum
+                   && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip
+                   == tuple->src.ip
+                   && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all
+                   == tuple->src.u.all);
+       else
+       /*must be ct->status & IPS_SNATP2P_SRC*/
+           return (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
+                   == tuple->dst.protonum
+                   && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
+                   == tuple->src.ip
+                   && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
+                   == tuple->src.u.all);
+}
+
+static int
+modified_src_occupied(const struct ip_conntrack_tuple *tuple,
+                    const struct ip_conntrack *conntrack)
+{
+       unsigned int h = hash_by_src(tuple);
+       struct ip_conntrack *ct;
+
+       read_lock_bh(&ip_nat_lock);
+       list_for_each_entry(ct, &by_modified_source[h], nat.info.by_modified_source) {
+               if (same_modified_src(ct, tuple)) {
+                       if (same_src(ct, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple))
+                           /*that's an appropriate source*/
+                           next;
+                       read_unlock_bh(&ip_nat_lock);
+                       return 1;
+               }
+       }
+       read_unlock_bh(&ip_nat_lock);
+       return 0;
+}
+
+int
+find_appropriate_p2p_dst(const struct ip_conntrack_tuple *tuple,
+                    struct ip_conntrack_tuple *result)
+{
+       unsigned int h = hash_by_src(tuple);
+       struct ip_conntrack *ct;
+
+       read_lock_bh(&ip_nat_lock);
+       list_for
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_nat
_rule.c linux-b/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_rule.c     2005-10-04 07:27:34.0000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_rule.c    2005-11-07 21:26:44.000000000 +0
800
@@ -267,9 +267,30 @@
        ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);

        if (ret == NF_ACCEPT) {
-               if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
-                       /* NUL mapping */
-                       ret = alloc_null_binding(ct, info, hooknum);
+           if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum))){
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+               if ((HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST)){
+                   struct ip_conntrack_tuple reply_tuple, new_tuple;
+                   invert_tuplepr(&reply_tuple,
+                       &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+                   if (find_appropriate_p2p_dst(&reply_tuple, &new_tuple){
+                       struct ip_nat_range range;
+                       /* This must be a fresh one. */
+                       BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+                       ct->status |= IPS_SNATP2P_DST;
+                       range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
+                       range.min = range.max = new_tuple.dst.u;
+                       range.min_ip = range.max_ip
+                           = new_tuple.dst.ip;
+                       ret = ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
+                   }
+               }
+               if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
+
+#endif
+                /* NUL mapping */
+                           ret = alloc_null_binding(ct, info, hooknum);
+           }
        }
        return ret;
 }
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_na
_standalone.c linux-b/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_standalone.c       2005-10-04 07:2
:34.000000000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_standalone.c      2005-11-07 21:28:10.000
00000 +0800
@@ -393,6 +393,9 @@
 module_init(init);
 module_exit(fini);

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+EXPORT_SYMBOL(find_appropriate_p2p_dst);
+#endif
 EXPORT_SYMBOL(ip_nat_setup_info);
 EXPORT_SYMBOL(ip_nat_protocol_register);
 EXPORT_SYMBOL(ip_nat_protocol_unregister);
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ipt_S
ATP2P.c linux-b/net/ipv4/netfilter/ipt_SNATP2P.c
--- linux-2.6.13.3/net/ipv4/netfilter/ipt_SNATP2P.c     1970-01-01 08:00:00.000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ipt_SNATP2P.c    2005-11-11 20:12:02.000000000 +
800
@@ -0,0 +1,95 @@
+/* This is a module which is used for source-NAT-P2P.
+ * with concept helped by Rusty Russel <rusty@rustcorp.com.au>
+ * and with code by Jesse Peng <tzuhsi.peng@msa.hinet.net>
+ */
+#include <linux/netfilter_ipv4.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+
+static unsigned int ipt_snatp2p_target(struct sk_buff **pskb,
+                                   const struct net_device *in,
+                                   const struct net_device *out,
+                                   unsigned int hooknum,
+                                   const void *targinfo,
+                                   void *userinfo)
+{
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
+       const struct ip_nat_multi_range_compat *mr = targinfo;
+
+       IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
+
+       ct = ip_conntrack_get(*pskb, &ctinfo);
+
+       /* Connection must be valid and new. */
+       IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
+                           || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
+       IP_NF_ASSERT(out);
+       ct->status |= IPS_SNATP2P_SRC;
+       return ip_nat_setup_info(ct, &mr->range[0], hooknum);
+}
+
+static int ipt_snatp2p_checkentry(const char *tablename,
+                              const struct ipt_entry *e,
+                              void *targinfo,
+                              unsigned int targinfosize,
+                              unsigned int hook_mask)
+{
+       struct ip_nat_multi_range_compat *mr = targinfo;
+
+       /* Must be a valid range */
+       if (mr->rangesize != 1) {
+               printk("SNATP2P: multiple ranges no longer supported\n");
+               return 0;
+       }
+
+       if (targinfosize != IPT_ALIGN(sizeof(struct ip_nat_multi_range_compat))
 {
+               DEBUGP("SNATP2P: Target size %u wrong for %u ranges\n",
+                      targinfosize, mr->rangesize);
+               return 0;
+       }
+
+       /* Only allow these for NAT. */
+       if (strcmp(tablename, "nat") != 0) {
+               DEBUGP("SNATP2P: wrong table %s\n", tablename);
+               return 0;
+       }
+
+       if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
+               DEBUGP("SNATP2P: hook mask 0x%x bad\n", hook_mask);
+               return 0;
+       }
+       return 1;
+}
+
+static struct ipt_target ipt_snatp2p_reg = {
+       .name           = "SNATP2P",
+       .target         = ipt_snatp2p_target,
+       .checkentry     = ipt_snatp2p_checkentry,
+};
+
+static int __init init(void)
+{
+       if (ipt_register_target(&ipt_snatp2p_reg))
+               return -EINVAL;
+
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_target(&ipt_snatp2p_reg);
+}
+
+module_init(init);
+module_exit(fini);

-------------Second Part------------
diff -Nur iptables-1.3.4/extensions/libi
t_SNATP2P.c iptables-b/extensions/libipt_SNATP2P.c
--- iptables-1.3.4/extensions/libipt_SNATP2P.c  1970-01-01 08:00:00.000000000 +
800
+++ iptables-b/extensions/libipt_SNATP2P.c      2005-11-09 17:32:58.000000000 +
800
@@ -0,0 +1,249 @@
+/* Shared library add-on to iptables to add source-NAT-P2P support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+/* Source NAT data consists of a multi-range, indicating where to map
+   to. */
+struct ipt_natinfo
+{
+       struct ipt_entry_target t;
+       struct ip_nat_multi_range mr;
+};
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+       printf(
+"SNATP2P v%s options:\n"
+" --to-source <ipaddr>[-<ipaddr>][:port-port]\n"
+"                              Address to map source to.\n"
+"                              (You can use this more than once)\n\n",
+IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+       { "to-source", 1, 0, '1' },
+       { 0 }
+};
+
+static struct ipt_natinfo *
+append_range(struct ipt_natinfo *info, const struct ip_nat_range *range)
+{
+       unsigned int size;
+
+       /* One rangesize already in struct ipt_natinfo */
+       size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
+
+       info = realloc(info, size);
+       if (!info)
+               exit_error(OTHER_PROBLEM, "Out of memory\n");
+
+       info->t.u.target_size = size;
+       info->mr.range[info->mr.rangesize] = *range;
+       info->mr.rangesize++;
+
+       return info;
+}
+
+/* Ranges expected in network order. */
+static struct ipt_entry_target *
+parse_to(char *arg, int portok, struct ipt_natinfo *info)
+{
+       struct ip_nat_range range;
+       char *colon, *dash, *error;
+       struct in_addr *ip;
+
+       memset(&range, 0, sizeof(range));
+       colon = strchr(arg, ':');
+
+       if (colon) {
+               int port;
+
+               if (!portok)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Need TCP or UDP with port specification");
+
+               range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+               port = atoi(colon+1);
+               if (port <= 0 || port > 65535)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Port `%s' not valid\n", colon+1);
+
+               error = strchr(colon+1, ':');
+               if (error)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Invalid port:port syntax - use dash\n");
+
+               dash = strchr(colon, '-');
+               if (!dash) {
+                       range.min.tcp.port
+                               = range.max.tcp.port
+                               = htons(port);
+               } else {
+                       int maxport;
+
+                       maxport = atoi(dash + 1);
+                       if (maxport <= 0 || maxport > 65535)
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Port `%s' not valid\n", dash+1);
+                       if (maxport < port)
+                               /* People are stupid. */
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Port range `%s' funky\n", colon+1);
+                       range.min.tcp.port = htons(port);
+                       range.max.tcp.port = htons(maxport);
+               }
+               /* Starts with a colon? No IP info...*/
+               if (colon == arg)
+                       return &(append_range(info, &range)->t);
+               *colon = '\0';
+       }
+
+       range.flags |= IP_NAT_RANGE_MAP_IPS;
+       dash = strchr(arg, '-');
+       if (colon && dash && dash > colon)
+               dash = NULL;
+
+       if (dash)
+               *dash = '\0';
+
+       ip = dotted_to_addr(arg);
+       if (!ip)
+               exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+                          arg);
+       range.min_ip = ip->s_addr;
+       if (dash) {
+               ip = dotted_to_addr(dash+1);
+               if (!ip)
+                       exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+                                  dash+1);
+               range.max_ip = ip->s_addr;
+       } else
+               range.max_ip = range.min_ip;
+
+       return &(append_range(info, &range)->t);
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ipt_entry *entry,
+      struct ipt_entry_target **target)
+{
+       struct ipt_natinfo *info = (void *)*target;
+       int portok;
+
+       if (entry->ip.proto == IPPROTO_TCP
+           || entry->ip.proto == IPPROTO_UDP
+           || entry->ip.proto == IPPROTO_ICMP)
+               portok = 1;
+       else
+               portok = 0;
+
+       switch (c) {
+       case '1':
+               if (check_inverse(optarg, &invert, NULL, 0))
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Unexpected `!' after --to-source");
+
+               if (*flags) {
+                       if (!kernel_version)
+                               get_kernel_version();
+                       if (kernel_version > LINUX_VERSION(2, 6, 10))
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Multiple --to-source not supported"
;
+               }
+               *target = parse_to(optarg, portok, info);
+               *flags = 1;
+               return 1;
+
+       default:
+               return 0;
+       }
+}
+
+/* Final check; must have specfied --to-source. */
+static void final_check(unsigned int flags)
+{
+       if (!flags)
+               exit_error(PARAMETER_PROBLEM,
+                          "You must specify --to-source");
+}
+
+static void print_range(const struct ip_nat_range *r)
+{
+       if (r->flags & IP_NAT_RANGE_MAP_IPS) {
+               struct in_addr a;
+
+               a.s_addr = r->min_ip;
+               printf("%s", addr_to_dotted(&a));
+               if (r->max_ip != r->min_ip) {
+                       a.s_addr = r->max_ip;
+                       printf("-%s", addr_to_dotted(&a));
+               }
+       }
+       if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+               printf(":");
+               printf("%hu", ntohs(r->min.tcp.port));
+               if (r->max.tcp.port != r->min.tcp.port)
+                       printf("-%hu", ntohs(r->max.tcp.port));
+       }
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+      const struct ipt_entry_target *target,
+      int numeric)
+{
+       struct ipt_natinfo *info = (void *)target;
+       unsigned int i = 0;
+
+       printf("to:");
+       for (i = 0; i < info->mr.rangesize; i++) {
+               print_range(&info->mr.range[i]);
+               printf(" ");
+       }
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+       struct ipt_natinfo *info = (void *)target;
+       unsigned int i = 0;
+
+       for (i = 0; i < info->mr.rangesize; i++) {
+               printf("--to-source ");
+               print_range(&info->mr.range[i]);
+               printf(" ");
+       }
+}
+
+static struct iptables_target snatp2p = {
+       .next           = NULL,
+       .name           = "SNATP2P",
+       .version        = IPTABLES_VERSION,
+       .size           = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
+       .userspacesize  = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
+       .help           = &help,
+       .parse          = &parse,
+       .final_check    = &final_check,
+       .print          = &print,
+       .save           = &save,
+       .extra_opts     = opts
+};
+
+void _init(void)
+{
+       register_target(&snatp2p);
+}                                            

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: P2P implementation for netfilter NAT
  2006-01-16 16:26         ` Jesse Peng
@ 2006-01-18 10:53           ` Jesse Peng
  0 siblings, 0 replies; 8+ messages in thread
From: Jesse Peng @ 2006-01-18 10:53 UTC (permalink / raw)
  To: Rusty Russell; +Cc: Harald Welte, Scott Shu, netfilter-devel

[-- Attachment #1: Type: text/plain, Size: 27667 bytes --]


----- Original Message ----- 
From: "Jesse Peng" <tzuhsi.peng@msa.hinet.net>
To: "Rusty Russell" <rusty@rustcorp.com.au>
Cc: "Harald Welte" <laforge@netfilter.org>; 
<netfilter-devel@lists.netfilter.org>
Sent: Tuesday, January 17, 2006 12:26 AM
Subject: Re: P2P implementation for netfilter NAT


>> Hmm, please resend...
>
> Sorry for the late reply,here attatch the patch,Please give advice.
>

Hello Rusty

Sorry,you're right,the patch was incomplete.Thanks to Scott Shu,he helped me 
find out where it happens.Hmm,not because mailer server but something wrong 
when I made the patch.Here sending it again,please check!

Thanks
Jesse
-------------first part--------------
diff -Nur linux-2.6.13.3/include/linux/netfilter_i
pv4/ip_conntrack.h linux-b/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.6.13.3/include/linux/netfilter_ipv4/ip_conntrack.h  2005-10-04 
07:27
:34.000000000 +0800
+++ linux-b/include/linux/netfilter_ipv4/ip_conntrack.h 2005-11-02 
18:11:00.0000
00000 +0800
@@ -65,6 +65,27 @@

        /* Both together */
        IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+       IPS_SNATP2P_SRC_BIT = 9,
+       IPS_SNATP2P_SRC = (1 << IPS_SNATP2P_SRC_BIT),
+
+       IPS_SNATP2P_DST_BIT = 10,
+       IPS_SNATP2P_DST = (1 << IPS_SNATP2P_DST_BIT),
+
+        /* Both together. */
+       IPS_SNATP2P_MASK = (IPS_SNATP2P_DST | IPS_SNATP2P_SRC),
+
+        IPS_SNATP2P_SRC_DONE_BIT = 11,
+       IPS_SNATP2P_SRC_DONE = (1 << IPS_SNATP2P_SRC_DONE_BIT),
+
+        IPS_SNATP2P_DST_DONE_BIT = 12,
+       IPS_SNATP2P_DST_DONE = (1 << IPS_SNATP2P_DST_DONE_BIT),
+
+        /* Both together. */
+       IPS_SNATP2P_DONE_MASK = (IPS_SNATP2P_DST_DONE | 
IPS_SNATP2P_SRC_DONE),
+#endif
+
 };

 #ifdef __KERNEL__
diff -Nur linux-2.6.13.3/include/linux/netfilter_i
pv4/ip_nat.h linux-b/include/linux/netfilter_ipv4/ip_nat.h
--- linux-2.6.13.3/include/linux/netfilter_ipv4/ip_nat.h        2005-10-04 
07:27
:34.000000000 +0800
+++ linux-b/include/linux/netfilter_ipv4/ip_nat.h       2005-11-07 
21:28:32.0000
00000 +0800
@@ -59,6 +59,10 @@
 {
        struct list_head bysource;

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+    struct list_head by_modified_source;
+#endif
+
        /* Helper (NULL if none). */
        struct ip_nat_helper *helper;

@@ -76,6 +80,11 @@
 extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
                             const struct ip_conntrack *ignored_conntrack);

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+extern int find_appropriate_p2p_dst(const struct ip_conntrack_tuple *tuple,
+                    struct ip_conntrack_tuple *result);
+#endif
+
 /* Calculate relative checksum. */
 extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
                                    u_int32_t newval,
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/Kconf
g linux-b/net/ipv4/netfilter/Kconfig
--- linux-2.6.13.3/net/ipv4/netfilter/Kconfig   2005-10-04 
07:27:34.000000000 +
800
+++ linux-b/net/ipv4/netfilter/Kconfig  2005-11-09 17:11:10.000000000 +0800
@@ -484,6 +484,14 @@

          To compile it as a module, choose M here.  If unsure, say N.

+config IP_NF_TARGET_SNATP2P
+    tristate "SNATP2P target support"
+       depends on IP_NF_NAT
+       help
+         SNATP2P is an implementation for P2P need.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_NF_TARGET_NETMAP
        tristate "NETMAP target support"
        depends on IP_NF_NAT
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/Makef
le linux-b/net/ipv4/netfilter/Makefile
--- linux-2.6.13.3/net/ipv4/netfilter/Makefile  2005-10-04 
07:27:34.000000000 +
800
+++ linux-b/net/ipv4/netfilter/Makefile 2005-11-09 17:13:00.000000000 +0800
@@ -68,6 +68,7 @@
 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+obj-$(CONFIG_IP_NF_TARGET_SNATP2P) += ipt_SNATP2P.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
 obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_co
ntrack_proto_tcp.c linux-b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_conntrack_proto_tcp.c  2005-10-04 
07:2
:34.000000000 +0800
+++ linux-b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2005-11-11 
21:21:34.000
00000 +0800
@@ -979,10 +979,19 @@
            problem case, so we can delete the conntrack
            immediately.  --RR */
         if (th->rst) {
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+            /*maybe we don't need to care this condition 
anymore,Rusty?since we take care of holepunch and hairpin!*/
+            if(conntrack->status & IPS_SNATP2P_SRC_DONE){
+                timeout = 2 MINS;
+                ip_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
+                return NF_DROP;
+            }
+#else
             if (del_timer(&conntrack->timeout))
                 conntrack->timeout.function((unsigned long)
                                 conntrack);
             return NF_ACCEPT;
+#endif
         }
     } else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
            && (old_state == TCP_CONNTRACK_SYN_RECV
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_nat
_core.c linux-b/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_core.c     2005-10-04 
07:27:34.0000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_core.c    2005-11-09 
17:29:24.000000000 +0
800
@@ -1,4 +1,4 @@

 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
@@ -47,6 +47,11 @@
 static unsigned int ip_nat_htable_size;

 static struct list_head *bysource;
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static struct list_head *by_modified_source;
+#endif
+
 struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];


@@ -59,6 +64,16 @@
                            tuple->dst.protonum, 0) % ip_nat_htable_size;
 }

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static inline unsigned int
+hash_by_dst(const struct ip_conntrack_tuple *tuple)
+{
+       /* Original src, to ensure we map it consistently if poss. */
+       return jhash_3words(tuple->dst.ip, tuple->dst.u.all,
+                           tuple->dst.protonum, 0) % ip_nat_htable_size;
+}
+#endif
+
 /* Noone using conntrack by the time this called. */
 static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
 {
@@ -67,6 +82,10 @@

        write_lock_bh(&ip_nat_lock);
        list_del(&conn->nat.info.bysource);
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+        if ((conn->status & IPS_SNATP2P_MASK) && (conn->status & 
IPS_SNATP2P_DONE_MASK))
+                list_del(&conn->nat.info.by_modified_source);
+#endif
        write_unlock_bh(&ip_nat_lock);
 }

@@ -93,6 +112,14 @@
           We could keep a separate hash if this proves too slow. */
        struct ip_conntrack_tuple reply;

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+    if((ignored_conntrack->status & IPS_SNATP2P_SRC)
+                     && !(ignored_conntrack->status & 
IPS_SNATP2P_SRC_DONE))
+        if (modified_src_occupied(tuple,ignored_conntrack))
+            return 1;
+#endif
+
+
        invert_tuplepr(&reply, tuple);
        return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
 }
@@ -160,6 +187,77 @@
        return 0;
 }

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static inline int
+same_modified_src(const struct ip_conntrack *ct,
+        const struct ip_conntrack_tuple *tuple)
+{
+       if (ct->status & IPS_SNATP2P_DST)
+           return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
+                   == tuple->dst.protonum
+                   && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip
+                   == tuple->src.ip
+                   && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all
+                   == tuple->src.u.all);
+       else
+       /*must be ct->status & IPS_SNATP2P_SRC*/
+           return (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
+                   == tuple->dst.protonum
+                   && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
+                   == tuple->src.ip
+                   && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
+                   == tuple->src.u.all);
+}
+
+static int
+modified_src_occupied(const struct ip_conntrack_tuple *tuple,
+                    const struct ip_conntrack *conntrack)
+{
+       unsigned int h = hash_by_src(tuple);
+       struct ip_conntrack *ct;
+
+       read_lock_bh(&ip_nat_lock);
+       list_for_each_entry(ct, &by_modified_source[h], 
nat.info.by_modified_source) {
+               if (same_modified_src(ct, tuple)) {
+                       if (same_src(ct, 
&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple))
+                           /*that's an appropriate source*/
+                           next;
+                       read_unlock_bh(&ip_nat_lock);
+                       return 1;
+               }
+       }
+       read_unlock_bh(&ip_nat_lock);
+       return 0;
+}
+
+int
+find_appropriate_p2p_dst(const struct ip_conntrack_tuple *tuple,
+                    struct ip_conntrack_tuple *result)
+{
+       unsigned int h = hash_by_src(tuple);
+       struct ip_conntrack *ct;
+
+       read_lock_bh(&ip_nat_lock);
+       list_for_each_entry(ct, &by_modified_source[h], 
nat.info.by_modified_source) {
+               if (same_modified_src(ct, tuple)) {
+                       if (ct->status & IPS_SNATP2P_DST)
+                           invert_tuplepr(result,
+ 
&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+                       else
+                           invert_tuplepr(result,
+ 
&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+                       result->src = tuple->src;
+                       read_unlock_bh(&ip_nat_lock);
+                       return 1;
+
+               }
+       }
+       read_unlock_bh(&ip_nat_lock);
+       return 0;
+}
+
+#endif
+
 /* For [FUTURE] fragmentation handling, we want the least-used
    src-ip/dst-ip/proto triple.  Fairness doesn't come into it.  Thus
    if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
@@ -260,6 +358,11 @@
        struct ip_conntrack_tuple curr_tuple, new_tuple;
        struct ip_nat_info *info = &conntrack->nat.info;
        int have_to_hash = !(conntrack->status & IPS_NAT_DONE_MASK);
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+        int have_to_hash_modified_src = ((conntrack->status & 
IPS_SNATP2P_MASK)
+                     && !(conntrack->status & IPS_SNATP2P_DONE_MASK));
+#endif
        enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);

        IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
@@ -301,11 +404,31 @@
                list_add(&info->bysource, &bysource[srchash]);
                write_unlock_bh(&ip_nat_lock);
        }
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+    if (have_to_hash_modified_src){
+        unsigned int srchash
+            = (conntrack->status & IPS_SNATP2P_SRC) ?
+                hash_by_dst(&conntrack->tuplehash[IP_CT_DIR_REPLY]
+                                   .tuple) : 
hash_by_dst(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+                                       .tuple);
+        write_lock_bh(&ip_nat_lock);
+               list_add(&info->by_modified_source, 
&by_modified_source[srchash]);
+               write_unlock_bh(&ip_nat_lock);
+    }
+#endif
        /* It's done. */
        if (maniptype == IP_NAT_MANIP_DST)
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+                if (conntrack->status & IPS_SNATP2P_DST)
+                       set_bit(IPS_SNATP2P_DST_DONE_BIT, 
&conntrack->status);
+#endif
                set_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status);
        else
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+                if (conntrack->status & IPS_SNATP2P_SRC)
+                       set_bit(IPS_SNATP2P_SRC_DONE_BIT, 
&conntrack->status);
+#endif
                set_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status);

        return NF_ACCEPT;
@@ -507,7 +630,13 @@
        bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size);
        if (!bysource)
                return -ENOMEM;
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+       by_modified_source = vmalloc(sizeof(struct list_head) * 
ip_nat_htable_size);
+       if (!by_modified_source )
+               return -ENOMEM;
+#endif
+
        /* Sew in builtin protocols. */
        write_lock_bh(&ip_nat_lock);
        for (i = 0; i < MAX_IP_NAT_PROTO; i++)
@@ -521,6 +650,11 @@
                INIT_LIST_HEAD(&bysource[i]);
        }

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+       for (i = 0; i < ip_nat_htable_size; i++) {
+               INIT_LIST_HEAD(&by_modified_source[i]);
+       }
+#endif
        /* FIXME: Man, this is a hack.  <SIGH> */
        IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
        ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
@@ -534,7 +668,11 @@
 static int clean_nat(struct ip_conntrack *i, void *data)
 {
        memset(&i->nat, 0, sizeof(i->nat));
-       i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+       i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST | 
IPS_SNATP2P_MASK | IPS_SNATP2P_DONE_MASK);
+#else
+       i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
+#endif
        return 0;
 }

@@ -544,4 +682,7 @@
        ip_ct_iterate_cleanup(&clean_nat, NULL);
        ip_conntrack_destroyed = NULL;
        vfree(bysource);
+#if defined( CONFIG_IP_NF_TARGET_SNATP2P)
+        vfree(by_modified_source);
+#endif
 }

diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_nat
_rule.c linux-b/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_rule.c     2005-10-04 
07:27:34.0000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_rule.c    2005-11-07 
21:26:44.000000000 +0
800
@@ -267,9 +267,30 @@
        ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);

        if (ret == NF_ACCEPT) {
-               if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
-                       /* NUL mapping */
-                       ret = alloc_null_binding(ct, info, hooknum);
+           if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum))){
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+               if ((HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST)){
+                   struct ip_conntrack_tuple reply_tuple, new_tuple;
+                   invert_tuplepr(&reply_tuple,
+                       &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+                   if (find_appropriate_p2p_dst(&reply_tuple, &new_tuple){
+                       struct ip_nat_range range;
+                       /* This must be a fresh one. */
+                       BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+                       ct->status |= IPS_SNATP2P_DST;
+                       range.flags = (IP_NAT_RANGE_MAP_IPS | 
IP_NAT_RANGE_PROTO_SPECIFIED);
+                       range.min = range.max = new_tuple.dst.u;
+                       range.min_ip = range.max_ip
+                           = new_tuple.dst.ip;
+                       ret = ip_nat_setup_info(ct, &range, 
NF_IP_PRE_ROUTING);
+                   }
+               }
+               if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
+
+#endif
+                /* NUL mapping */
+                           ret = alloc_null_binding(ct, info, hooknum);
+           }
        }
        return ret;
 }
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_na
_standalone.c linux-b/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_standalone.c       2005-10-04 
07:2
:34.000000000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_standalone.c      2005-11-07 
21:28:10.000
00000 +0800
@@ -393,6 +393,9 @@
 module_init(init);
 module_exit(fini);

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+EXPORT_SYMBOL(find_appropriate_p2p_dst);
+#endif
 EXPORT_SYMBOL(ip_nat_setup_info);
 EXPORT_SYMBOL(ip_nat_protocol_register);
 EXPORT_SYMBOL(ip_nat_protocol_unregister);
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ipt_S
ATP2P.c linux-b/net/ipv4/netfilter/ipt_SNATP2P.c
--- linux-2.6.13.3/net/ipv4/netfilter/ipt_SNATP2P.c     1970-01-01 
08:00:00.000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ipt_SNATP2P.c    2005-11-11 
20:12:02.000000000 +
800
@@ -0,0 +1,95 @@
+/* This is a module which is used for source-NAT-P2P.
+ * with concept helped by Rusty Russel <rusty@rustcorp.com.au>
+ * and with code by Jesse Peng <tzuhsi.peng@msa.hinet.net>
+ */
+#include <linux/netfilter_ipv4.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+
+static unsigned int ipt_snatp2p_target(struct sk_buff **pskb,
+                                   const struct net_device *in,
+                                   const struct net_device *out,
+                                   unsigned int hooknum,
+                                   const void *targinfo,
+                                   void *userinfo)
+{
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
+       const struct ip_nat_multi_range_compat *mr = targinfo;
+
+       IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
+
+       ct = ip_conntrack_get(*pskb, &ctinfo);
+
+       /* Connection must be valid and new. */
+       IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
+                           || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
+       IP_NF_ASSERT(out);
+       ct->status |= IPS_SNATP2P_SRC;
+       return ip_nat_setup_info(ct, &mr->range[0], hooknum);
+}
+
+static int ipt_snatp2p_checkentry(const char *tablename,
+                              const struct ipt_entry *e,
+                              void *targinfo,
+                              unsigned int targinfosize,
+                              unsigned int hook_mask)
+{
+       struct ip_nat_multi_range_compat *mr = targinfo;
+
+       /* Must be a valid range */
+       if (mr->rangesize != 1) {
+               printk("SNATP2P: multiple ranges no longer supported\n");
+               return 0;
+       }
+
+       if (targinfosize != IPT_ALIGN(sizeof(struct 
ip_nat_multi_range_compat))
 {
+               DEBUGP("SNATP2P: Target size %u wrong for %u ranges\n",
+                      targinfosize, mr->rangesize);
+               return 0;
+       }
+
+       /* Only allow these for NAT. */
+       if (strcmp(tablename, "nat") != 0) {
+               DEBUGP("SNATP2P: wrong table %s\n", tablename);
+               return 0;
+       }
+
+       if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
+               DEBUGP("SNATP2P: hook mask 0x%x bad\n", hook_mask);
+               return 0;
+       }
+       return 1;
+}
+
+static struct ipt_target ipt_snatp2p_reg = {
+       .name           = "SNATP2P",
+       .target         = ipt_snatp2p_target,
+       .checkentry     = ipt_snatp2p_checkentry,
+};
+
+static int __init init(void)
+{
+       if (ipt_register_target(&ipt_snatp2p_reg))
+               return -EINVAL;
+
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_target(&ipt_snatp2p_reg);
+}
+
+module_init(init);
+module_exit(fini);

-------------Second Part------------
diff -Nur iptables-1.3.4/extensions/libi
t_SNATP2P.c iptables-b/extensions/libipt_SNATP2P.c
--- iptables-1.3.4/extensions/libipt_SNATP2P.c  1970-01-01 
08:00:00.000000000 +
800
+++ iptables-b/extensions/libipt_SNATP2P.c      2005-11-09 
17:32:58.000000000 +
800
@@ -0,0 +1,249 @@
+/* Shared library add-on to iptables to add source-NAT-P2P support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+/* Source NAT data consists of a multi-range, indicating where to map
+   to. */
+struct ipt_natinfo
+{
+       struct ipt_entry_target t;
+       struct ip_nat_multi_range mr;
+};
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+       printf(
+"SNATP2P v%s options:\n"
+" --to-source <ipaddr>[-<ipaddr>][:port-port]\n"
+"                              Address to map source to.\n"
+"                              (You can use this more than once)\n\n",
+IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+       { "to-source", 1, 0, '1' },
+       { 0 }
+};
+
+static struct ipt_natinfo *
+append_range(struct ipt_natinfo *info, const struct ip_nat_range *range)
+{
+       unsigned int size;
+
+       /* One rangesize already in struct ipt_natinfo */
+       size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize * 
sizeof(*range));
+
+       info = realloc(info, size);
+       if (!info)
+               exit_error(OTHER_PROBLEM, "Out of memory\n");
+
+       info->t.u.target_size = size;
+       info->mr.range[info->mr.rangesize] = *range;
+       info->mr.rangesize++;
+
+       return info;
+}
+
+/* Ranges expected in network order. */
+static struct ipt_entry_target *
+parse_to(char *arg, int portok, struct ipt_natinfo *info)
+{
+       struct ip_nat_range range;
+       char *colon, *dash, *error;
+       struct in_addr *ip;
+
+       memset(&range, 0, sizeof(range));
+       colon = strchr(arg, ':');
+
+       if (colon) {
+               int port;
+
+               if (!portok)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Need TCP or UDP with port 
specification");
+
+               range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+               port = atoi(colon+1);
+               if (port <= 0 || port > 65535)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Port `%s' not valid\n", colon+1);
+
+               error = strchr(colon+1, ':');
+               if (error)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Invalid port:port syntax - use dash\n");
+
+               dash = strchr(colon, '-');
+               if (!dash) {
+                       range.min.tcp.port
+                               = range.max.tcp.port
+                               = htons(port);
+               } else {
+                       int maxport;
+
+                       maxport = atoi(dash + 1);
+                       if (maxport <= 0 || maxport > 65535)
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Port `%s' not valid\n", dash+1);
+                       if (maxport < port)
+                               /* People are stupid. */
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Port range `%s' funky\n", 
colon+1);
+                       range.min.tcp.port = htons(port);
+                       range.max.tcp.port = htons(maxport);
+               }
+               /* Starts with a colon? No IP info...*/
+               if (colon == arg)
+                       return &(append_range(info, &range)->t);
+               *colon = '\0';
+       }
+
+       range.flags |= IP_NAT_RANGE_MAP_IPS;
+       dash = strchr(arg, '-');
+       if (colon && dash && dash > colon)
+               dash = NULL;
+
+       if (dash)
+               *dash = '\0';
+
+       ip = dotted_to_addr(arg);
+       if (!ip)
+               exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+                          arg);
+       range.min_ip = ip->s_addr;
+       if (dash) {
+               ip = dotted_to_addr(dash+1);
+               if (!ip)
+                       exit_error(PARAMETER_PROBLEM, "Bad IP address 
`%s'\n",
+                                  dash+1);
+               range.max_ip = ip->s_addr;
+       } else
+               range.max_ip = range.min_ip;
+
+       return &(append_range(info, &range)->t);
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ipt_entry *entry,
+      struct ipt_entry_target **target)
+{
+       struct ipt_natinfo *info = (void *)*target;
+       int portok;
+
+       if (entry->ip.proto == IPPROTO_TCP
+           || entry->ip.proto == IPPROTO_UDP
+           || entry->ip.proto == IPPROTO_ICMP)
+               portok = 1;
+       else
+               portok = 0;
+
+       switch (c) {
+       case '1':
+               if (check_inverse(optarg, &invert, NULL, 0))
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Unexpected `!' after --to-source");
+
+               if (*flags) {
+                       if (!kernel_version)
+                               get_kernel_version();
+                       if (kernel_version > LINUX_VERSION(2, 6, 10))
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Multiple --to-source not 
supported"
;
+               }
+               *target = parse_to(optarg, portok, info);
+               *flags = 1;
+               return 1;
+
+       default:
+               return 0;
+       }
+}
+
+/* Final check; must have specfied --to-source. */
+static void final_check(unsigned int flags)
+{
+       if (!flags)
+               exit_error(PARAMETER_PROBLEM,
+                          "You must specify --to-source");
+}
+
+static void print_range(const struct ip_nat_range *r)
+{
+       if (r->flags & IP_NAT_RANGE_MAP_IPS) {
+               struct in_addr a;
+
+               a.s_addr = r->min_ip;
+               printf("%s", addr_to_dotted(&a));
+               if (r->max_ip != r->min_ip) {
+                       a.s_addr = r->max_ip;
+                       printf("-%s", addr_to_dotted(&a));
+               }
+       }
+       if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+               printf(":");
+               printf("%hu", ntohs(r->min.tcp.port));
+               if (r->max.tcp.port != r->min.tcp.port)
+                       printf("-%hu", ntohs(r->max.tcp.port));
+       }
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+      const struct ipt_entry_target *target,
+      int numeric)
+{
+       struct ipt_natinfo *info = (void *)target;
+       unsigned int i = 0;
+
+       printf("to:");
+       for (i = 0; i < info->mr.rangesize; i++) {
+               print_range(&info->mr.range[i]);
+               printf(" ");
+       }
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+       struct ipt_natinfo *info = (void *)target;
+       unsigned int i = 0;
+
+       for (i = 0; i < info->mr.rangesize; i++) {
+               printf("--to-source ");
+               print_range(&info->mr.range[i]);
+               printf(" ");
+       }
+}
+
+static struct iptables_target snatp2p = {
+       .next           = NULL,
+       .name           = "SNATP2P",
+       .version        = IPTABLES_VERSION,
+       .size           = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
+       .userspacesize  = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
+       .help           = &help,
+       .parse          = &parse,
+       .final_check    = &final_check,
+       .print          = &print,
+       .save           = &save,
+       .extra_opts     = opts
+};
+
+void _init(void)
+{
+       register_target(&snatp2p);
+}


[-- Attachment #2: Netfilter_P2P_Implement_Patch --]
[-- Type: application/octet-stream, Size: 27878 bytes --]

-------------first part--------------
diff -Nur linux-2.6.13.3/include/linux/netfilter_i
pv4/ip_conntrack.h linux-b/include/linux/netfilter_ipv4/ip_conntrack.h
--- linux-2.6.13.3/include/linux/netfilter_ipv4/ip_conntrack.h  2005-10-04 07:27
:34.000000000 +0800
+++ linux-b/include/linux/netfilter_ipv4/ip_conntrack.h 2005-11-02 18:11:00.0000
00000 +0800
@@ -65,6 +65,27 @@

        /* Both together */
        IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE | IPS_SRC_NAT_DONE),
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+       IPS_SNATP2P_SRC_BIT = 9,
+       IPS_SNATP2P_SRC = (1 << IPS_SNATP2P_SRC_BIT),
+
+       IPS_SNATP2P_DST_BIT = 10,
+       IPS_SNATP2P_DST = (1 << IPS_SNATP2P_DST_BIT),
+
+        /* Both together. */
+       IPS_SNATP2P_MASK = (IPS_SNATP2P_DST | IPS_SNATP2P_SRC),
+
+        IPS_SNATP2P_SRC_DONE_BIT = 11,
+       IPS_SNATP2P_SRC_DONE = (1 << IPS_SNATP2P_SRC_DONE_BIT),
+
+        IPS_SNATP2P_DST_DONE_BIT = 12,
+       IPS_SNATP2P_DST_DONE = (1 << IPS_SNATP2P_DST_DONE_BIT),
+
+        /* Both together. */
+       IPS_SNATP2P_DONE_MASK = (IPS_SNATP2P_DST_DONE | IPS_SNATP2P_SRC_DONE),
+#endif
+
 };

 #ifdef __KERNEL__
diff -Nur linux-2.6.13.3/include/linux/netfilter_i
pv4/ip_nat.h linux-b/include/linux/netfilter_ipv4/ip_nat.h
--- linux-2.6.13.3/include/linux/netfilter_ipv4/ip_nat.h        2005-10-04 07:27
:34.000000000 +0800
+++ linux-b/include/linux/netfilter_ipv4/ip_nat.h       2005-11-07 21:28:32.0000
00000 +0800
@@ -59,6 +59,10 @@
 {
        struct list_head bysource;

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+    struct list_head by_modified_source;
+#endif
+
        /* Helper (NULL if none). */
        struct ip_nat_helper *helper;

@@ -76,6 +80,11 @@
 extern int ip_nat_used_tuple(const struct ip_conntrack_tuple *tuple,
                             const struct ip_conntrack *ignored_conntrack);

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+extern int find_appropriate_p2p_dst(const struct ip_conntrack_tuple *tuple,
+                    struct ip_conntrack_tuple *result);
+#endif
+
 /* Calculate relative checksum. */
 extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv,
                                    u_int32_t newval,
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/Kconf
g linux-b/net/ipv4/netfilter/Kconfig
--- linux-2.6.13.3/net/ipv4/netfilter/Kconfig   2005-10-04 07:27:34.000000000 +
800
+++ linux-b/net/ipv4/netfilter/Kconfig  2005-11-09 17:11:10.000000000 +0800
@@ -484,6 +484,14 @@

          To compile it as a module, choose M here.  If unsure, say N.

+config IP_NF_TARGET_SNATP2P
+    tristate "SNATP2P target support"
+       depends on IP_NF_NAT
+       help
+         SNATP2P is an implementation for P2P need.
+
+         To compile it as a module, choose M here.  If unsure, say N.
+
 config IP_NF_TARGET_NETMAP
        tristate "NETMAP target support"
        depends on IP_NF_NAT
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/Makef
le linux-b/net/ipv4/netfilter/Makefile
--- linux-2.6.13.3/net/ipv4/netfilter/Makefile  2005-10-04 07:27:34.000000000 +
800
+++ linux-b/net/ipv4/netfilter/Makefile 2005-11-09 17:13:00.000000000 +0800
@@ -68,6 +68,7 @@
 obj-$(CONFIG_IP_NF_TARGET_MARK) += ipt_MARK.o
 obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
 obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
+obj-$(CONFIG_IP_NF_TARGET_SNATP2P) += ipt_SNATP2P.o
 obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
 obj-$(CONFIG_IP_NF_TARGET_SAME) += ipt_SAME.o
 obj-$(CONFIG_IP_NF_TARGET_CLASSIFY) += ipt_CLASSIFY.o
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_co
ntrack_proto_tcp.c linux-b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_conntrack_proto_tcp.c  2005-10-04 07:2
:34.000000000 +0800
+++ linux-b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c 2005-11-11 21:21:34.000
00000 +0800
@@ -979,10 +979,19 @@
            problem case, so we can delete the conntrack
            immediately.  --RR */
         if (th->rst) {
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+            /*maybe we don't need to care this condition anymore,Rusty?since we take care of holepunch and hairpin!*/
+            if(conntrack->status & IPS_SNATP2P_SRC_DONE){
+                timeout = 2 MINS;
+                ip_ct_refresh_acct(conntrack, ctinfo, skb, timeout);
+                return NF_DROP;
+            }
+#else
             if (del_timer(&conntrack->timeout))
                 conntrack->timeout.function((unsigned long)
                                 conntrack);
             return NF_ACCEPT;
+#endif
         }
     } else if (!test_bit(IPS_ASSURED_BIT, &conntrack->status)
            && (old_state == TCP_CONNTRACK_SYN_RECV
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_nat
_core.c linux-b/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_core.c     2005-10-04 07:27:34.0000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_core.c    2005-11-09 17:29:24.000000000 +0
800
@@ -1,4 +1,4 @@

 /* (C) 1999-2001 Paul `Rusty' Russell
  * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
@@ -47,6 +47,11 @@
 static unsigned int ip_nat_htable_size;

 static struct list_head *bysource;
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static struct list_head *by_modified_source;
+#endif
+
 struct ip_nat_protocol *ip_nat_protos[MAX_IP_NAT_PROTO];


@@ -59,6 +64,16 @@
                            tuple->dst.protonum, 0) % ip_nat_htable_size;
 }

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static inline unsigned int
+hash_by_dst(const struct ip_conntrack_tuple *tuple)
+{
+       /* Original src, to ensure we map it consistently if poss. */
+       return jhash_3words(tuple->dst.ip, tuple->dst.u.all,
+                           tuple->dst.protonum, 0) % ip_nat_htable_size;
+}
+#endif
+
 /* Noone using conntrack by the time this called. */
 static void ip_nat_cleanup_conntrack(struct ip_conntrack *conn)
 {
@@ -67,6 +82,10 @@

        write_lock_bh(&ip_nat_lock);
        list_del(&conn->nat.info.bysource);
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+        if ((conn->status & IPS_SNATP2P_MASK) && (conn->status & IPS_SNATP2P_DONE_MASK))
+                list_del(&conn->nat.info.by_modified_source);
+#endif
        write_unlock_bh(&ip_nat_lock);
 }

@@ -93,6 +112,14 @@
           We could keep a separate hash if this proves too slow. */
        struct ip_conntrack_tuple reply;

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+    if((ignored_conntrack->status & IPS_SNATP2P_SRC)
+                     && !(ignored_conntrack->status & IPS_SNATP2P_SRC_DONE))
+        if (modified_src_occupied(tuple,ignored_conntrack))
+            return 1;
+#endif
+
+
        invert_tuplepr(&reply, tuple);
        return ip_conntrack_tuple_taken(&reply, ignored_conntrack);
 }
@@ -160,6 +187,77 @@
        return 0;
 }

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+static inline int
+same_modified_src(const struct ip_conntrack *ct,
+        const struct ip_conntrack_tuple *tuple)
+{
+       if (ct->status & IPS_SNATP2P_DST)
+           return (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum
+                   == tuple->dst.protonum
+                   && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip
+                   == tuple->src.ip
+                   && ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.all
+                   == tuple->src.u.all);
+       else
+       /*must be ct->status & IPS_SNATP2P_SRC*/
+           return (ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum
+                   == tuple->dst.protonum
+                   && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
+                   == tuple->src.ip
+                   && ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all
+                   == tuple->src.u.all);
+}
+
+static int
+modified_src_occupied(const struct ip_conntrack_tuple *tuple,
+                    const struct ip_conntrack *conntrack)
+{
+       unsigned int h = hash_by_src(tuple);
+       struct ip_conntrack *ct;
+
+       read_lock_bh(&ip_nat_lock);
+       list_for_each_entry(ct, &by_modified_source[h], nat.info.by_modified_source) {
+               if (same_modified_src(ct, tuple)) {
+                       if (same_src(ct, &conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple))
+                           /*that's an appropriate source*/
+                           next;
+                       read_unlock_bh(&ip_nat_lock);
+                       return 1;
+               }
+       }
+       read_unlock_bh(&ip_nat_lock);
+       return 0;
+}
+
+int
+find_appropriate_p2p_dst(const struct ip_conntrack_tuple *tuple,
+                    struct ip_conntrack_tuple *result)
+{
+       unsigned int h = hash_by_src(tuple);
+       struct ip_conntrack *ct;
+
+       read_lock_bh(&ip_nat_lock);
+       list_for_each_entry(ct, &by_modified_source[h], nat.info.by_modified_source) {
+               if (same_modified_src(ct, tuple)) {
+                       if (ct->status & IPS_SNATP2P_DST)
+                           invert_tuplepr(result,
+                                      &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+                       else
+                           invert_tuplepr(result,
+                                      &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+                       result->src = tuple->src;
+                       read_unlock_bh(&ip_nat_lock);
+                       return 1;
+
+               }
+       }
+       read_unlock_bh(&ip_nat_lock);
+       return 0;
+}
+
+#endif
+
 /* For [FUTURE] fragmentation handling, we want the least-used
    src-ip/dst-ip/proto triple.  Fairness doesn't come into it.  Thus
    if the range specifies 1.2.3.4 ports 10000-10005 and 1.2.3.5 ports
@@ -260,6 +358,11 @@
        struct ip_conntrack_tuple curr_tuple, new_tuple;
        struct ip_nat_info *info = &conntrack->nat.info;
        int have_to_hash = !(conntrack->status & IPS_NAT_DONE_MASK);
+
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+        int have_to_hash_modified_src = ((conntrack->status & IPS_SNATP2P_MASK)
+                     && !(conntrack->status & IPS_SNATP2P_DONE_MASK));
+#endif
        enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);

        IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING
@@ -301,11 +404,31 @@
                list_add(&info->bysource, &bysource[srchash]);
                write_unlock_bh(&ip_nat_lock);
        }
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+    if (have_to_hash_modified_src){
+        unsigned int srchash
+            = (conntrack->status & IPS_SNATP2P_SRC) ?
+                hash_by_dst(&conntrack->tuplehash[IP_CT_DIR_REPLY]
+                                   .tuple) : hash_by_dst(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
+                                       .tuple);
+        write_lock_bh(&ip_nat_lock);
+               list_add(&info->by_modified_source, &by_modified_source[srchash]);
+               write_unlock_bh(&ip_nat_lock);
+    }
+#endif
        /* It's done. */
        if (maniptype == IP_NAT_MANIP_DST)
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+                if (conntrack->status & IPS_SNATP2P_DST)
+                       set_bit(IPS_SNATP2P_DST_DONE_BIT, &conntrack->status);
+#endif
                set_bit(IPS_DST_NAT_DONE_BIT, &conntrack->status);
        else
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+                if (conntrack->status & IPS_SNATP2P_SRC)
+                       set_bit(IPS_SNATP2P_SRC_DONE_BIT, &conntrack->status);
+#endif
                set_bit(IPS_SRC_NAT_DONE_BIT, &conntrack->status);

        return NF_ACCEPT;
@@ -507,7 +630,13 @@
        bysource = vmalloc(sizeof(struct list_head) * ip_nat_htable_size);
        if (!bysource)
                return -ENOMEM;
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+       by_modified_source = vmalloc(sizeof(struct list_head) * ip_nat_htable_size);
+       if (!by_modified_source )
+               return -ENOMEM;
+#endif
+
        /* Sew in builtin protocols. */
        write_lock_bh(&ip_nat_lock);
        for (i = 0; i < MAX_IP_NAT_PROTO; i++)
@@ -521,6 +650,11 @@
                INIT_LIST_HEAD(&bysource[i]);
        }

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+       for (i = 0; i < ip_nat_htable_size; i++) {
+               INIT_LIST_HEAD(&by_modified_source[i]);
+       }
+#endif
        /* FIXME: Man, this is a hack.  <SIGH> */
        IP_NF_ASSERT(ip_conntrack_destroyed == NULL);
        ip_conntrack_destroyed = &ip_nat_cleanup_conntrack;
@@ -534,7 +668,11 @@
 static int clean_nat(struct ip_conntrack *i, void *data)
 {
        memset(&i->nat, 0, sizeof(i->nat));
-       i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+       i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST | IPS_SNATP2P_MASK | IPS_SNATP2P_DONE_MASK);
+#else
+       i->status &= ~(IPS_NAT_MASK | IPS_NAT_DONE_MASK | IPS_SEQ_ADJUST);
+#endif
        return 0;
 }

@@ -544,4 +682,7 @@
        ip_ct_iterate_cleanup(&clean_nat, NULL);
        ip_conntrack_destroyed = NULL;
        vfree(bysource);
+#if defined( CONFIG_IP_NF_TARGET_SNATP2P)
+        vfree(by_modified_source);
+#endif
 }

diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_nat
_rule.c linux-b/net/ipv4/netfilter/ip_nat_rule.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_rule.c     2005-10-04 07:27:34.0000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_rule.c    2005-11-07 21:26:44.000000000 +0
800
@@ -267,9 +267,30 @@
        ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);

        if (ret == NF_ACCEPT) {
-               if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
-                       /* NUL mapping */
-                       ret = alloc_null_binding(ct, info, hooknum);
+           if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum))){
+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+               if ((HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST)){
+                   struct ip_conntrack_tuple reply_tuple, new_tuple;
+                   invert_tuplepr(&reply_tuple,
+                       &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+                   if (find_appropriate_p2p_dst(&reply_tuple, &new_tuple){
+                       struct ip_nat_range range;
+                       /* This must be a fresh one. */
+                       BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+                       ct->status |= IPS_SNATP2P_DST;
+                       range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
+                       range.min = range.max = new_tuple.dst.u;
+                       range.min_ip = range.max_ip
+                           = new_tuple.dst.ip;
+                       ret = ip_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
+                   }
+               }
+               if (!ip_nat_initialized(ct, HOOK2MANIP(hooknum)))
+
+#endif
+                /* NUL mapping */
+                           ret = alloc_null_binding(ct, info, hooknum);
+           }
        }
        return ret;
 }
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ip_na
_standalone.c linux-b/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.6.13.3/net/ipv4/netfilter/ip_nat_standalone.c       2005-10-04 07:2
:34.000000000 +0800
+++ linux-b/net/ipv4/netfilter/ip_nat_standalone.c      2005-11-07 21:28:10.000
00000 +0800
@@ -393,6 +393,9 @@
 module_init(init);
 module_exit(fini);

+#if defined(CONFIG_IP_NF_TARGET_SNATP2P)
+EXPORT_SYMBOL(find_appropriate_p2p_dst);
+#endif
 EXPORT_SYMBOL(ip_nat_setup_info);
 EXPORT_SYMBOL(ip_nat_protocol_register);
 EXPORT_SYMBOL(ip_nat_protocol_unregister);
diff -Nur linux-2.6.13.3/net/ipv4/netfilter/ipt_S
ATP2P.c linux-b/net/ipv4/netfilter/ipt_SNATP2P.c
--- linux-2.6.13.3/net/ipv4/netfilter/ipt_SNATP2P.c     1970-01-01 08:00:00.000
00000 +0800
+++ linux-b/net/ipv4/netfilter/ipt_SNATP2P.c    2005-11-11 20:12:02.000000000 +
800
@@ -0,0 +1,95 @@
+/* This is a module which is used for source-NAT-P2P.
+ * with concept helped by Rusty Russel <rusty@rustcorp.com.au>
+ * and with code by Jesse Peng <tzuhsi.peng@msa.hinet.net>
+ */
+#include <linux/netfilter_ipv4.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+
+static unsigned int ipt_snatp2p_target(struct sk_buff **pskb,
+                                   const struct net_device *in,
+                                   const struct net_device *out,
+                                   unsigned int hooknum,
+                                   const void *targinfo,
+                                   void *userinfo)
+{
+       struct ip_conntrack *ct;
+       enum ip_conntrack_info ctinfo;
+       const struct ip_nat_multi_range_compat *mr = targinfo;
+
+       IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
+
+       ct = ip_conntrack_get(*pskb, &ctinfo);
+
+       /* Connection must be valid and new. */
+       IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED
+                           || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY));
+       IP_NF_ASSERT(out);
+       ct->status |= IPS_SNATP2P_SRC;
+       return ip_nat_setup_info(ct, &mr->range[0], hooknum);
+}
+
+static int ipt_snatp2p_checkentry(const char *tablename,
+                              const struct ipt_entry *e,
+                              void *targinfo,
+                              unsigned int targinfosize,
+                              unsigned int hook_mask)
+{
+       struct ip_nat_multi_range_compat *mr = targinfo;
+
+       /* Must be a valid range */
+       if (mr->rangesize != 1) {
+               printk("SNATP2P: multiple ranges no longer supported\n");
+               return 0;
+       }
+
+       if (targinfosize != IPT_ALIGN(sizeof(struct ip_nat_multi_range_compat))
 {
+               DEBUGP("SNATP2P: Target size %u wrong for %u ranges\n",
+                      targinfosize, mr->rangesize);
+               return 0;
+       }
+
+       /* Only allow these for NAT. */
+       if (strcmp(tablename, "nat") != 0) {
+               DEBUGP("SNATP2P: wrong table %s\n", tablename);
+               return 0;
+       }
+
+       if (hook_mask & ~(1 << NF_IP_POST_ROUTING)) {
+               DEBUGP("SNATP2P: hook mask 0x%x bad\n", hook_mask);
+               return 0;
+       }
+       return 1;
+}
+
+static struct ipt_target ipt_snatp2p_reg = {
+       .name           = "SNATP2P",
+       .target         = ipt_snatp2p_target,
+       .checkentry     = ipt_snatp2p_checkentry,
+};
+
+static int __init init(void)
+{
+       if (ipt_register_target(&ipt_snatp2p_reg))
+               return -EINVAL;
+
+       return 0;
+}
+
+static void __exit fini(void)
+{
+       ipt_unregister_target(&ipt_snatp2p_reg);
+}
+
+module_init(init);
+module_exit(fini);

-------------Second Part------------
diff -Nur iptables-1.3.4/extensions/libi
t_SNATP2P.c iptables-b/extensions/libipt_SNATP2P.c
--- iptables-1.3.4/extensions/libipt_SNATP2P.c  1970-01-01 08:00:00.000000000 +
800
+++ iptables-b/extensions/libipt_SNATP2P.c      2005-11-09 17:32:58.000000000 +
800
@@ -0,0 +1,249 @@
+/* Shared library add-on to iptables to add source-NAT-P2P support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+
+/* Source NAT data consists of a multi-range, indicating where to map
+   to. */
+struct ipt_natinfo
+{
+       struct ipt_entry_target t;
+       struct ip_nat_multi_range mr;
+};
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+       printf(
+"SNATP2P v%s options:\n"
+" --to-source <ipaddr>[-<ipaddr>][:port-port]\n"
+"                              Address to map source to.\n"
+"                              (You can use this more than once)\n\n",
+IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+       { "to-source", 1, 0, '1' },
+       { 0 }
+};
+
+static struct ipt_natinfo *
+append_range(struct ipt_natinfo *info, const struct ip_nat_range *range)
+{
+       unsigned int size;
+
+       /* One rangesize already in struct ipt_natinfo */
+       size = IPT_ALIGN(sizeof(*info) + info->mr.rangesize * sizeof(*range));
+
+       info = realloc(info, size);
+       if (!info)
+               exit_error(OTHER_PROBLEM, "Out of memory\n");
+
+       info->t.u.target_size = size;
+       info->mr.range[info->mr.rangesize] = *range;
+       info->mr.rangesize++;
+
+       return info;
+}
+
+/* Ranges expected in network order. */
+static struct ipt_entry_target *
+parse_to(char *arg, int portok, struct ipt_natinfo *info)
+{
+       struct ip_nat_range range;
+       char *colon, *dash, *error;
+       struct in_addr *ip;
+
+       memset(&range, 0, sizeof(range));
+       colon = strchr(arg, ':');
+
+       if (colon) {
+               int port;
+
+               if (!portok)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Need TCP or UDP with port specification");
+
+               range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+
+               port = atoi(colon+1);
+               if (port <= 0 || port > 65535)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Port `%s' not valid\n", colon+1);
+
+               error = strchr(colon+1, ':');
+               if (error)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Invalid port:port syntax - use dash\n");
+
+               dash = strchr(colon, '-');
+               if (!dash) {
+                       range.min.tcp.port
+                               = range.max.tcp.port
+                               = htons(port);
+               } else {
+                       int maxport;
+
+                       maxport = atoi(dash + 1);
+                       if (maxport <= 0 || maxport > 65535)
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Port `%s' not valid\n", dash+1);
+                       if (maxport < port)
+                               /* People are stupid. */
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Port range `%s' funky\n", colon+1);
+                       range.min.tcp.port = htons(port);
+                       range.max.tcp.port = htons(maxport);
+               }
+               /* Starts with a colon? No IP info...*/
+               if (colon == arg)
+                       return &(append_range(info, &range)->t);
+               *colon = '\0';
+       }
+
+       range.flags |= IP_NAT_RANGE_MAP_IPS;
+       dash = strchr(arg, '-');
+       if (colon && dash && dash > colon)
+               dash = NULL;
+
+       if (dash)
+               *dash = '\0';
+
+       ip = dotted_to_addr(arg);
+       if (!ip)
+               exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+                          arg);
+       range.min_ip = ip->s_addr;
+       if (dash) {
+               ip = dotted_to_addr(dash+1);
+               if (!ip)
+                       exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
+                                  dash+1);
+               range.max_ip = ip->s_addr;
+       } else
+               range.max_ip = range.min_ip;
+
+       return &(append_range(info, &range)->t);
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ipt_entry *entry,
+      struct ipt_entry_target **target)
+{
+       struct ipt_natinfo *info = (void *)*target;
+       int portok;
+
+       if (entry->ip.proto == IPPROTO_TCP
+           || entry->ip.proto == IPPROTO_UDP
+           || entry->ip.proto == IPPROTO_ICMP)
+               portok = 1;
+       else
+               portok = 0;
+
+       switch (c) {
+       case '1':
+               if (check_inverse(optarg, &invert, NULL, 0))
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Unexpected `!' after --to-source");
+
+               if (*flags) {
+                       if (!kernel_version)
+                               get_kernel_version();
+                       if (kernel_version > LINUX_VERSION(2, 6, 10))
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Multiple --to-source not supported"
;
+               }
+               *target = parse_to(optarg, portok, info);
+               *flags = 1;
+               return 1;
+
+       default:
+               return 0;
+       }
+}
+
+/* Final check; must have specfied --to-source. */
+static void final_check(unsigned int flags)
+{
+       if (!flags)
+               exit_error(PARAMETER_PROBLEM,
+                          "You must specify --to-source");
+}
+
+static void print_range(const struct ip_nat_range *r)
+{
+       if (r->flags & IP_NAT_RANGE_MAP_IPS) {
+               struct in_addr a;
+
+               a.s_addr = r->min_ip;
+               printf("%s", addr_to_dotted(&a));
+               if (r->max_ip != r->min_ip) {
+                       a.s_addr = r->max_ip;
+                       printf("-%s", addr_to_dotted(&a));
+               }
+       }
+       if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) {
+               printf(":");
+               printf("%hu", ntohs(r->min.tcp.port));
+               if (r->max.tcp.port != r->min.tcp.port)
+                       printf("-%hu", ntohs(r->max.tcp.port));
+       }
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+      const struct ipt_entry_target *target,
+      int numeric)
+{
+       struct ipt_natinfo *info = (void *)target;
+       unsigned int i = 0;
+
+       printf("to:");
+       for (i = 0; i < info->mr.rangesize; i++) {
+               print_range(&info->mr.range[i]);
+               printf(" ");
+       }
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+       struct ipt_natinfo *info = (void *)target;
+       unsigned int i = 0;
+
+       for (i = 0; i < info->mr.rangesize; i++) {
+               printf("--to-source ");
+               print_range(&info->mr.range[i]);
+               printf(" ");
+       }
+}
+
+static struct iptables_target snatp2p = {
+       .next           = NULL,
+       .name           = "SNATP2P",
+       .version        = IPTABLES_VERSION,
+       .size           = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
+       .userspacesize  = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
+       .help           = &help,
+       .parse          = &parse,
+       .final_check    = &final_check,
+       .print          = &print,
+       .save           = &save,
+       .extra_opts     = opts
+};
+
+void _init(void)
+{
+       register_target(&snatp2p);
+}                                            

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2006-01-18 10:53 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <001801c5f6b3$539b1b20$3478fea9@acer21ce70712f>
2005-12-04 10:26 ` P2P implementation for netfilter NAT Rusty Russell
2005-12-05  8:03   ` Jesse Peng
2005-12-05  9:48     ` Waiting for user space response in Kernel Mode Guru Prasad
2005-12-05  9:52       ` Pablo Neira Ayuso
2006-01-05 15:52     ` P2P implementation for netfilter NAT Jesse Peng
2006-01-08  1:20       ` Rusty Russell
2006-01-16 16:26         ` Jesse Peng
2006-01-18 10:53           ` Jesse Peng

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.