Hello,
Here's a patch from Guilaumme Morin that updates my previous 'send icmp unreach* with fake source IP' patch, so that on top of being able to specify manually which fake source IP should be set on the icmp unreach, it is now possible to fake the source IP dynamically (using the dest of the original packet as the fake source IP), as per explained in this thread : http://lists.samba.org/pipermail/netfilter/2002-February/020237.html I've reformated the patch so it will apply on the latest CVS tree. Have a nice day, Fabrice. -- Fabrice MARIE Senior R&D Engineer Celestix Networks http://www.celestix.com/ "Silly hacker, root is for administrators" -Unknown
diff -uNr -x CVS cvs/netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch --- cvs/netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch 2002-02-26 21:31:56.000000000 +0800 +++ netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch 2002-05-22 12:06:45.000000000 +0800 @@ -1,48 +1,77 @@ ---- original/linux/include/linux/netfilter_ipv4/ipt_REJECT.h Sat Jul 15 03:20:23 2000 -+++ linux/include/linux/netfilter_ipv4/ipt_REJECT.h Thu Nov 15 16:56:23 2001 -@@ -14,6 +14,7 @@ +diff -uNr linux-2.4.18-vanilla/include/linux/netfilter_ipv4/ipt_REJECT.h linux/include/linux/netfilter_ipv4/ipt_REJECT.h +--- linux-2.4.18-vanilla/include/linux/netfilter_ipv4/ipt_REJECT.h Mon May 20 15:07:13 2002 ++++ linux/include/linux/netfilter_ipv4/ipt_REJECT.h Mon May 20 14:01:03 2002 +@@ -12,8 +12,11 @@ + IPT_TCP_RESET + }; ++#define IPT_REJECT_FAKE_TO_DESTINATION 0x0000000100000000 ++ struct ipt_reject_info { enum ipt_reject_with with; /* reject type */ -+ u_int32_t fake_source_address; /* fake source address, 0 if no fake */ ++ u_int64_t fake_source_address; /* fake source address, 0 if no fake */ }; -#endif /*_IPT_REJECT_H*/ +#endif /* _IPT_REJECT_H */ ---- original/linux/net/ipv4/netfilter/ipt_REJECT.c Sat Oct 6 23:50:28 2001 -+++ linux/net/ipv4/netfilter/ipt_REJECT.c Thu Nov 15 16:57:52 2001 +diff -uNr linux-2.4.18-vanilla/net/ipv4/netfilter/ipt_REJECT.c linux/net/ipv4/netfilter/ipt_REJECT.c +--- linux-2.4.18-vanilla/net/ipv4/netfilter/ipt_REJECT.c Mon May 20 15:07:13 2002 ++++ linux/net/ipv4/netfilter/ipt_REJECT.c Mon May 20 14:52:22 2002 @@ -1,6 +1,7 @@ /* * This is a module which is used for rejecting packets. * Added support for customized reject packets (Jozsef Kadlecsik). -+ * Added support for fake source IP in icmp-unreach (Fabrice MARIE). ++ * Added support for fake source IP in icmp-unreach (Fabrice MARIE & Guillaume MORIN). */ #include <linux/config.h> #include <linux/module.h> -@@ -150,7 +151,7 @@ +@@ -150,12 +151,12 @@ kfree_skb(nskb); } -static void send_unreach(struct sk_buff *skb_in, int code) -+static void send_unreach(struct sk_buff *skb_in, int code, u_int32_t fake_source_address) ++static void send_unreach(struct sk_buff *skb_in, int code, u_int64_t fake_source_address) { struct iphdr *iph; struct icmphdr *icmph; -@@ -243,7 +244,12 @@ + struct sk_buff *nskb; +- u32 saddr; ++ u32 saddr,packet_daddr; + u8 tos; + int hh_len, length; + struct rtable *rt = (struct rtable*)skb_in->dst; +@@ -197,7 +198,7 @@ + return; + } + +- saddr = iph->daddr; ++ packet_daddr = saddr = iph->daddr; + if (!(rt->rt_flags & RTCF_LOCAL)) + saddr = 0; + +@@ -243,7 +244,20 @@ iph->ttl = MAXTTL; ip_select_ident(iph, &rt->u.dst, NULL); iph->protocol=IPPROTO_ICMP; - iph->saddr=rt->rt_src; + -+ /* fake source IP if we have to */ -+ if (fake_source_address != 0) -+ iph->saddr=fake_source_address; -+ else ++ /* fake source IP if we have to ++ ++ if fake_source_address == IPT_REJECT_FAKE_TO_DESTINATION, we fake ++ the source ip from the packet destination address dynamically ++ */ ++ if (fake_source_address != 0) { ++ if (fake_source_address == IPT_REJECT_FAKE_TO_DESTINATION) ++ iph->saddr = packet_daddr; ++ else ++ iph->saddr=fake_source_address; ++ } else + iph->saddr=rt->rt_src; ++ iph->daddr=rt->rt_dst; iph->check=0; iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); -@@ -290,22 +296,22 @@ +@@ -290,22 +304,22 @@ must return an absolute verdict. --RR */ switch (reject->with) { case IPT_ICMP_NET_UNREACHABLE: @@ -71,7 +100,7 @@ break; case IPT_TCP_RESET: send_reset(*pskb, hooknum == NF_IP_LOCAL_IN); -@@ -350,6 +356,11 @@ +@@ -350,6 +364,11 @@ if (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & IPT_INV_PROTO)) { DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n"); diff -uNr -x CVS cvs/netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch.help netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch.help --- cvs/netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch.help 2002-05-22 13:55:13.000000000 +0800 +++ netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch.help 2002-05-22 13:24:42.000000000 +0800 @@ -5,11 +5,19 @@ from a fake source IP address. Example : -# iptables -A INPUT -p tcp -d 202.156.58.79 --dport http -j REJECT --fake-source 10.1.1.1 +# iptables -A FORWARD -p tcp -d 202.156.58.79 --dport http -j REJECT --fake-source 10.1.1.1 # iptables --list -n -Chain INPUT (policy ACCEPT) +Chain FORWARD (policy ACCEPT) target prot opt source destination REJECT tcp -- 0.0.0.0/0 202.156.58.79 tcp dpt:80 reject-with icmp-port-unreachable faked from 10.1.1.1 +Now you can also make that the icmp-unreach seems to come from the destination host : + +# iptables -A FORWARD -p tcp -d 202.156.58.0/24 --dport domain -j REJECT --fake-source-with-dest +# iptables --list +Chain FORWARD (policy ACCEPT) +target prot opt source destination +REJECT tcp -- anywhere 202.156.58.0/24 tcp dpt:domain reject-with icmp-port-unreachable faked from packet destination address + ***** WARNING ***** This patch also patch the userspace directory which means that you you have to recompile and reinstall the iptables package after that. diff -uNr -x CVS cvs/netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch.userspace netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch.userspace --- cvs/netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch.userspace 2002-02-26 21:31:56.000000000 +0800 +++ netfilter/userspace/patch-o-matic/extra/ipt_REJECT-fake-source.patch.userspace 2002-05-22 13:58:12.000000000 +0800 @@ -1,5 +1,5 @@ ---- extensions/libipt_REJECT.c Thu Nov 15 18:08:42 2001 -+++ extensions/libipt_REJECT.c Thu Nov 15 17:28:03 2001 +--- extensions/libipt_REJECT.c Thu Nov 15 18:08:42 2001 ++++ extensions/libipt_REJECT.c Thu Nov 15 17:28:03 2001 @@ -6,10 +6,17 @@ #include <string.h> #include <stdlib.h> @@ -27,7 +27,7 @@ /* Function which prints out usage message. */ static void -@@ -62,12 +69,15 @@ +@@ -62,12 +69,19 @@ "REJECT options:\n" "--reject-with type drop input packet and send back\n" " a reply packet according to type:\n"); @@ -35,16 +35,20 @@ print_reject_types(); + printf( +"--fake-source ip_address fake the source address of the packet to\n" -+" be ip_address (do not use with tcp-reset!)\n"); ++" be ip_address (do not use with tcp-reset!)\n" ++"--fake-source-with-dest fake the source address with the destination\n" ++" address of the matched packet (useful for\n" ++" port unreachable ICMP message)\n"); } static struct option opts[] = { { "reject-with", 1, 0, '1' }, + { "fake-source", 1, 0, '2' }, ++ { "fake-source-with-dest", 0, 0, '3' }, { 0 } }; -@@ -79,6 +89,7 @@ +@@ -79,6 +93,7 @@ /* default */ reject->with = IPT_ICMP_PORT_UNREACHABLE; @@ -52,7 +56,7 @@ /* Can't cache this */ *nfcache |= NFC_UNKNOWN; -@@ -94,6 +105,7 @@ +@@ -94,6 +109,7 @@ struct ipt_reject_info *reject = (struct ipt_reject_info *)(*target)->data; unsigned int limit = sizeof(reject_table)/sizeof(struct reject_names); unsigned int i; @@ -60,7 +64,7 @@ switch(c) { case '1': -@@ -113,6 +125,24 @@ +@@ -113,6 +129,38 @@ fprintf(stderr, "--reject-with echo-reply no longer" " supported\n"); exit_error(PARAMETER_PROBLEM, "unknown reject type `%s'",optarg); @@ -70,6 +74,11 @@ + + break; + case '2': ++ if (reject->fake_source_address == IPT_REJECT_FAKE_TO_DESTINATION) { ++ exit_error(PARAMETER_PROBLEM, ++ "Cannot use --fake-source-with-dest and " ++ "--fake-source together"); ++ } + if (invert) + exit_error(PARAMETER_PROBLEM, + "unexpected '!' with --fake-source"); @@ -82,24 +91,45 @@ + reject->fake_source_address = ip->s_addr; + return 1; + break; ++ case '3': ++ if (reject->fake_source_address) { ++ exit_error(PARAMETER_PROBLEM, ++ "Cannot use --fake-source-with-dest and " ++ "--fake-source together"); ++ } ++ reject->fake_source_address = IPT_REJECT_FAKE_TO_DESTINATION; ++ return 1; ++ break; default: /* Fall through */ - } -@@ -139,6 +169,8 @@ + break; +@@ -140,6 +188,14 @@ break; } printf("reject-with %s ", reject_table[i].name); -+ if (reject->fake_source_address != 0) -+ printf("faked from %u.%u.%u.%u ", NIPQUAD(reject->fake_source_address)); ++ if (reject->fake_source_address != 0) { ++ if (reject->fake_source_address == IPT_REJECT_FAKE_TO_DESTINATION) ++ printf("faked from packet destination address"); ++ else { ++ u_int32_t fake_addr = reject->fake_source_address; ++ printf("faked from %d.%d.%d.%d ", NIPQUAD(fake_addr)); ++ } ++ } } - + /* Saves ipt_reject in parsable form to stdout. */ -@@ -153,6 +185,8 @@ +@@ -154,6 +210,14 @@ break; printf("--reject-with %s ", reject_table[i].name); -+ if (reject->fake_source_address != 0) -+ printf("--fake-source %u.%u.%u.%u ", NIPQUAD(reject->fake_source_address)); ++ if (reject->fake_source_address != 0) { ++ if (reject->fake_source_address == IPT_REJECT_FAKE_TO_DESTINATION) ++ printf("--fake-source-with-dest "); ++ else { ++ u_int32_t fake_addr = reject->fake_source_address; ++ printf("--fake-source %u.%u.%u.%u ", NIPQUAD(fake_addr)); ++ } ++ } } static