* 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.