Subject: kern/898: enable strict control of ip input
To: None <gnats-admin@NetBSD.ORG>
From: Simon J. Gerraty <sjg@zen.void.oz.au>
List: netbsd-bugs
Date: 03/23/1995 01:35:04
>Number:         898
>Category:       kern
>Synopsis:       patch to prevent ip packets being delivered to other than receiving interface
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Thu Mar 23 01:35:02 1995
>Originator:     Simon J. Gerraty
>Organization:
Zen Programming...
>Release:        1.0
>Environment:
	
System: NetBSD zen.void.oz.au 1.0 NetBSD 1.0 (ZEN) #6: Tue Dec 13 09:55:20 EST 1994 root@zen.void.oz.au:/usr/src/sys/arch/i386/compile/ZEN i386


>Description:
	
In the following config:

	(bad_guy) 1.1 ------ 1.2 [NetBSD] 2.2 ------ (good_guys)

"bad_guy" can set a route to address 2.2 via 1.1 and reach a service
which NetBSD is trying to only offer to "good_guys".

The simple patch below, makes NetBSD check whether the dest address
2.2 belongs to the interface the packet arrived on (or came from a
loopback interface) and if not, simply drops it.

This then allows NetBSD to offer different service sets on different
interfaces. 

The patch below is against --current ip_input.c, I've used
ipforwarding < 0 to control this, but that it probably not a good idea
(folk who really want this will not want anyone to be able to turn it
off), but is useful for experimenting with it.   I use

sysctl -w net.inet.ip.forwarding=-1

before starting inetd (modified to bind to specific addrs not *.23
say).

>How-To-Repeat:
	<code/input/activities to reproduce the problem (multiple
lines)>

>Fix:
	

*** ip_input.c.~1~	Wed Jun 29 20:31:01 1994
--- ip_input.c	Thu Mar 23 12:54:56 1995
***************
*** 241,248 ****
  	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
  #define	satosin(sa)	((struct sockaddr_in *)(sa))
  
! 		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr)
  			goto ours;
  		if (
  #ifdef	DIRECTED_BROADCAST
  		    ia->ia_ifp == m->m_pkthdr.rcvif &&
--- 241,262 ----
  	for (ia = in_ifaddr; ia; ia = ia->ia_next) {
  #define	satosin(sa)	((struct sockaddr_in *)(sa))
  
! 		if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) {
! 			/* one of our addresses */
! 			if (ipforwarding >= 0)
  				goto ours;
+ 			/*
+ 			 * ipforwarding < 0 means only accept
+ 			 * packets to addresses belonging to the interface
+ 			 * or it arrived on the loopback interface.
+ 			 */
+ 			if (ia->ia_ifp == m->m_pkthdr.rcvif ||
+ 			    m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK)
+ 				goto ours;
+ 			/* nope, someone playing games with us */
+ 			ipstat.ips_cantforward++;
+ 			goto bad;
+ 		}
  		if (
  #ifdef	DIRECTED_BROADCAST
  		    ia->ia_ifp == m->m_pkthdr.rcvif &&
***************
*** 330,336 ****
  	/*
  	 * Not for us; forward if possible and desirable.
  	 */
! 	if (ipforwarding == 0) {
  		ipstat.ips_cantforward++;
  		m_freem(m);
  	} else
--- 344,350 ----
  	/*
  	 * Not for us; forward if possible and desirable.
  	 */
! 	if (ipforwarding <= 0) {
  		ipstat.ips_cantforward++;
  		m_freem(m);
  	} else
>Audit-Trail:
>Unformatted: