diff -ur v2.6.4/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt --- v2.6.4/linux/Documentation/filesystems/proc.txt 2004-03-11 23:45:34.000000000 +0200 +++ linux/Documentation/filesystems/proc.txt 2004-03-12 01:26:36.182665480 +0200 @@ -1587,6 +1587,18 @@ (external addresses can still be spoofed), without the need for additional firewall rules. +forward_shared +-------------- + +Integer value determines if a source validation should allow forwarding of +packets with local source address. 1 means yes, 0 means no. By default the +flag is disabled and such packets are not forwarded. + +If you enable this flag on internal network, the router will forward packets +from internal hosts with shared IP addresses no matter how the rp_filter is +set. This flag is activated only if it is enabled both in specific device +section and in "all" section. + secure_redirects ---------------- diff -ur v2.6.4/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt --- v2.6.4/linux/Documentation/networking/ip-sysctl.txt 2004-03-11 23:45:35.000000000 +0200 +++ linux/Documentation/networking/ip-sysctl.txt 2004-03-12 01:26:36.183665328 +0200 @@ -403,6 +403,17 @@ forwarding - BOOLEAN Enable IP forwarding on this interface. +forward_shared - BOOLEAN + Integer value determines if a source validation should allow + forwarding of packets with local source address. 1 means yes, + 0 means no. By default the flag is disabled and such packets + are not forwarded. + + If you enable this flag on internal network, the router will forward + packets from internal hosts with shared IP addresses no matter how + the rp_filter is set. This flag is activated only if it is + enabled both in specific device section and in "all" section. + mc_forwarding - BOOLEAN Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE and a multicast routing daemon is required. diff -ur v2.6.4/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h --- v2.6.4/linux/include/linux/inetdevice.h 2004-03-11 23:48:02.000000000 +0200 +++ linux/include/linux/inetdevice.h 2004-03-12 01:26:36.184665176 +0200 @@ -24,6 +24,7 @@ int no_xfrm; int no_policy; int force_igmp_version; + int forward_shared; void *sysctl; }; @@ -76,6 +77,8 @@ #define IN_DEV_ARP_ANNOUNCE(in_dev) (max(ipv4_devconf.arp_announce, (in_dev)->cnf.arp_announce)) #define IN_DEV_ARP_IGNORE(in_dev) (max(ipv4_devconf.arp_ignore, (in_dev)->cnf.arp_ignore)) +#define IN_DEV_FORWARD_SHARED(in_dev) ((in_dev)->cnf.forward_shared && ipv4_devconf.forward_shared) + struct in_ifaddr { struct in_ifaddr *ifa_next; diff -ur v2.6.4/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.6.4/linux/include/linux/sysctl.h 2004-03-11 23:48:06.000000000 +0200 +++ linux/include/linux/sysctl.h 2004-03-12 01:26:59.935054568 +0200 @@ -374,6 +374,7 @@ NET_IPV4_CONF_FORCE_IGMP_VERSION=17, NET_IPV4_CONF_ARP_ANNOUNCE=18, NET_IPV4_CONF_ARP_IGNORE=19, + NET_IPV4_CONF_FORWARD_SHARED=20, }; /* /proc/sys/net/ipv4/netfilter */ diff -ur v2.6.4/linux/include/net/ip_fib.h linux/include/net/ip_fib.h --- v2.6.4/linux/include/net/ip_fib.h 2003-08-23 19:43:12.000000000 +0300 +++ linux/include/net/ip_fib.h 2004-03-12 01:26:36.185665024 +0200 @@ -207,7 +207,7 @@ extern int inet_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg); extern int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb); extern int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, - struct net_device *dev, u32 *spec_dst, u32 *itag); + struct net_device *dev, u32 *spec_dst, u32 *itag, int our); extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res); /* Exported by fib_semantics.c */ diff -ur v2.6.4/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v2.6.4/linux/net/ipv4/devinet.c 2004-03-11 23:48:15.000000000 +0200 +++ linux/net/ipv4/devinet.c 2004-03-12 01:27:20.050996480 +0200 @@ -1210,7 +1210,7 @@ static struct devinet_sysctl_table { struct ctl_table_header *sysctl_header; - ctl_table devinet_vars[20]; + ctl_table devinet_vars[21]; ctl_table devinet_dev[2]; ctl_table devinet_conf_dir[2]; ctl_table devinet_proto_dir[2]; @@ -1346,6 +1346,14 @@ .proc_handler = &proc_dointvec, }, { + .ctl_name = NET_IPV4_CONF_FORWARD_SHARED, + .procname = "forward_shared", + .data = &ipv4_devconf.forward_shared, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = NET_IPV4_CONF_NOXFRM, .procname = "disable_xfrm", .data = &ipv4_devconf.no_xfrm, diff -ur v2.6.4/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c --- v2.6.4/linux/net/ipv4/fib_frontend.c 2003-10-10 01:16:29.000000000 +0300 +++ linux/net/ipv4/fib_frontend.c 2004-03-12 01:26:36.188664568 +0200 @@ -159,7 +159,8 @@ */ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif, - struct net_device *dev, u32 *spec_dst, u32 *itag) + struct net_device *dev, u32 *spec_dst, u32 *itag, + int our) { struct in_device *in_dev; struct flowi fl = { .nl_u = { .ip4_u = @@ -170,6 +171,7 @@ struct fib_result res; int no_addr, rpf; int ret; + int fwdsh = 0; no_addr = rpf = 0; read_lock(&inetdev_lock); @@ -177,6 +179,7 @@ if (in_dev) { no_addr = in_dev->ifa_list == NULL; rpf = IN_DEV_RPFILTER(in_dev); + fwdsh = IN_DEV_FORWARD_SHARED(in_dev); } read_unlock(&inetdev_lock); @@ -185,7 +188,12 @@ if (fib_lookup(&fl, &res)) goto last_resort; - if (res.type != RTN_UNICAST) + if (fwdsh) { + fwdsh = (res.type == RTN_LOCAL && !our); + if (fwdsh) + rpf = 0; + } + if (res.type != RTN_UNICAST && !fwdsh) goto e_inval_res; *spec_dst = FIB_RES_PREFSRC(res); fib_combine_itag(itag, &res); @@ -205,6 +213,8 @@ if (rpf) goto e_inval; fl.oif = dev->ifindex; + if (fwdsh) + fl.iif = loopback_dev.ifindex; ret = 0; if (fib_lookup(&fl, &res) == 0) { diff -ur v2.6.4/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.6.4/linux/net/ipv4/route.c 2004-03-11 23:48:17.000000000 +0200 +++ linux/net/ipv4/route.c 2004-03-12 01:26:36.189664416 +0200 @@ -1454,7 +1454,7 @@ goto e_inval; spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); } else if (fib_validate_source(saddr, 0, tos, 0, - dev, &spec_dst, &itag) < 0) + dev, &spec_dst, &itag, our) < 0) goto e_inval; rth = dst_alloc(&ipv4_dst_ops); @@ -1619,7 +1619,7 @@ int result; result = fib_validate_source(saddr, daddr, tos, loopback_dev.ifindex, - dev, &spec_dst, &itag); + dev, &spec_dst, &itag, 1); if (result < 0) goto martian_source; if (result) @@ -1646,7 +1646,7 @@ } err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(res), dev, - &spec_dst, &itag); + &spec_dst, &itag, 0); if (err < 0) goto martian_source; @@ -1734,7 +1734,7 @@ spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); else { err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, - &itag); + &itag, 1); if (err < 0) goto martian_source; if (err)