2007年5月9日 星期三

Netfilter P2P issues

Netfilter P2P issues
Patch:
http://lists.netfilter.org/pipermail/netfilter-devel/2006-January/023084.html
Coding hint:
http://lists.netfilter.org/pipermail/netfilter-devel/2005-December/022584.html
Theory:
http://lists.netfilter.org/pipermail/netfilter-devel/2004-November/017479.html

-------------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 at 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. */
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 at rustcorp.com.au>
+ * and with code by Jesse Peng <tzuhsi.peng at msa.hinet.net>
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* 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 [-][: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 <>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 <>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
+};file:///C:/Documents%20and%20Settings/Vincent/Application%20Data/Microsoft/Internet%20Explorer/Quick%20Launch/CuteFTP%208%20Professional.lnk
+
+void _init(void)
+{
+ register_target(&snatp2p);
+}





NAT implementation in the linux
http://lists.netfilter.org/pipermail/netfilter-devel/2004-November/017457.html

For connection/packet PROTO-SRCIP:SPT=>DSTIP:DPT:

1) Look up user-defined rules to decide what range to NAT this to
(default is if no rule). We support ranges.

2) Look up a a "bysource" hash table of (PROTO, SRCIP, SPT). If another
connection from the same endpoint is found, and the same mapping gives a
connection within the range, try that. If that mapping creates a unique
reply (ie. there's no PROTO-DSTIP:DPT=>mapped SRCIP:mapped SPT in our
"conntrack" hash table), we're done.

3) Try a mapping which doesn't change SPT, ie. just changing the SRCIP
to each IP address in the range. If that mapping creates a unique
reply, we're done.

4) Try altering the SPT as well (we attempt to keep high ports high,
etc). If this fails, we drop the connection.

Consider two machines A and B being NATed through N to servers Sa, Sb
and Sc respectively (rule says NAT source to N):

A:45000 -> Sa:80 <=> N:45000 -> Sa:80 (rule 3)
B:45000 -> Sb:80 <=> N:45000 -> Sb:80 (rule 3)
A:45000 -> Sc:80 <=> N:45000 -> Sc:80 (rule 2)
B:45000 -> Sc:80 <=> N:45001 -> Sc:80 (rule 2 clash, rule 4)

4 則留言:

匿名 提到...

您好..我想請問有關Netfilter P2P issues這篇文章的問題..如果您願意分享見解...可以麻煩您回信到 ms9107@cis.scu.edu.tw 嗎..謝謝

Linux Worker 提到...

有什麼問題可以直接post到版上, 大家一起討論:)

匿名 提到...

謝謝你的回應...請問Post到板上...指得是哪裡呢...另外還有比這個更新的Patch嗎...謝謝

Linux Worker 提到...

就直接貼在目前的blog即可, 我並不確定是否有更新的patch