diff -ur v2.6.3/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt --- v2.6.3/linux/Documentation/filesystems/proc.txt 2003-09-27 23:14:56.000000000 +0300 +++ linux/Documentation/filesystems/proc.txt 2004-02-19 01:41:46.933376104 +0200 @@ -1578,6 +1578,16 @@ (external addresses can still be spoofed), without the need for additional firewall rules. +rp_filter_mask +-------------- + +Integer value representing bitmask of the mediums for which the reverse path +protection is disabled. If the source validation results in reverse path to +interface with medium_id value in the 1..31 range the access is allowed if the +corresponding bit is set in the bitmask. The bitmask value is considered only +when rp_filter is enabled. By default the bitmask is empty preserving the +original rp_filter semantic. + secure_redirects ---------------- diff -ur v2.6.3/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt --- v2.6.3/linux/Documentation/networking/ip-sysctl.txt 2004-02-19 00:13:33.000000000 +0200 +++ linux/Documentation/networking/ip-sysctl.txt 2004-02-19 01:41:46.933376104 +0200 @@ -507,6 +507,16 @@ Alpha 1/1024s. See the HZ define in /usr/include/asm/param.h for the exact value on your system. +rp_filter_mask - INTEGER + + Integer value representing bitmask of the mediums for which the + reverse path protection is disabled. If the source validation + results in reverse path to interface with medium_id value in + the 1..31 range the access is allowed if the corresponding bit + is set in the bitmask. The bitmask value is considered only when + rp_filter is enabled. By default the bitmask is empty preserving + the original rp_filter semantic. + Alexey Kuznetsov. kuznet@ms2.inr.ac.ru diff -ur v2.6.3/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h --- v2.6.3/linux/include/linux/inetdevice.h 2004-02-19 00:13:38.000000000 +0200 +++ linux/include/linux/inetdevice.h 2004-02-19 01:42:10.026865360 +0200 @@ -22,6 +22,7 @@ int no_xfrm; int no_policy; int force_igmp_version; + int rp_filter_mask; void *sysctl; }; @@ -63,6 +64,7 @@ #define IN_DEV_SEC_REDIRECTS(in_dev) (ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects) #define IN_DEV_IDTAG(in_dev) ((in_dev)->cnf.tag) #define IN_DEV_MEDIUM_ID(in_dev) ((in_dev)->cnf.medium_id) +#define IN_DEV_RPFILTER_MASK(in_dev) ((in_dev)->cnf.rp_filter_mask) #define IN_DEV_RX_REDIRECTS(in_dev) \ ((IN_DEV_FORWARD(in_dev) && \ diff -ur v2.6.3/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.6.3/linux/include/linux/sysctl.h 2004-02-19 00:13:38.000000000 +0200 +++ linux/include/linux/sysctl.h 2004-02-19 01:42:34.375163856 +0200 @@ -362,6 +362,7 @@ NET_IPV4_CONF_NOXFRM=15, NET_IPV4_CONF_NOPOLICY=16, NET_IPV4_CONF_FORCE_IGMP_VERSION=17, + NET_IPV4_CONF_RP_FILTER_MASK=18, }; /* /proc/sys/net/ipv4/netfilter */ diff -ur v2.6.3/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v2.6.3/linux/net/ipv4/devinet.c 2004-02-19 00:13:38.000000000 +0200 +++ linux/net/ipv4/devinet.c 2004-02-19 01:43:13.300246344 +0200 @@ -1132,7 +1132,7 @@ static struct devinet_sysctl_table { struct ctl_table_header *sysctl_header; - ctl_table devinet_vars[18]; + ctl_table devinet_vars[19]; ctl_table devinet_dev[2]; ctl_table devinet_conf_dir[2]; ctl_table devinet_proto_dir[2]; @@ -1220,6 +1220,14 @@ .proc_handler = &proc_dointvec, }, { + .ctl_name = NET_IPV4_CONF_RP_FILTER_MASK, + .procname = "rp_filter_mask", + .data = &ipv4_devconf.rp_filter_mask, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = NET_IPV4_CONF_BOOTP_RELAY, .procname = "bootp_relay", .data = &ipv4_devconf.bootp_relay, diff -ur v2.6.3/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c --- v2.6.3/linux/net/ipv4/fib_frontend.c 2003-10-10 01:16:29.000000000 +0300 +++ linux/net/ipv4/fib_frontend.c 2004-02-19 01:41:51.358703352 +0200 @@ -169,6 +169,7 @@ .iif = oif }; struct fib_result res; int no_addr, rpf; + unsigned rpf_mask = 0; int ret; no_addr = rpf = 0; @@ -177,6 +178,7 @@ if (in_dev) { no_addr = in_dev->ifa_list == NULL; rpf = IN_DEV_RPFILTER(in_dev); + rpf_mask = IN_DEV_RPFILTER_MASK(in_dev); } read_unlock(&inetdev_lock); @@ -199,6 +201,17 @@ fib_res_put(&res); return ret; } + if (rpf_mask && rpf) { + int omi = 0; + + read_lock(&inetdev_lock); + in_dev = __in_dev_get(FIB_RES_DEV(res)); + if (in_dev) + omi = IN_DEV_MEDIUM_ID(in_dev); + read_unlock(&inetdev_lock); + if (omi >= 1 && omi <= 31 && ((1 << omi) & rpf_mask)) + rpf = 0; + } fib_res_put(&res); if (no_addr) goto last_resort;