Subject: making our tcp/ip a strong-end system
To: None <tech-net@netbsd.org>
From: Luke Mewburn <lukem@netbsd.org>
List: tech-net
Date: 11/10/1998 23:16:10
in PR kern/991, darren reed outlines how to modify netbsd (1.0a) to
enforce the `strong end system' model in tcp/ip. this is where a
packet destined for this machine is not accepted on an interface other
than the one that is configured for that address.

i've taken the ideas in darren's pr (and subsequent followups to it)
and merged them into -current (19981010). before i go and totally
screw the pooch, i was interested in feedback from the tcp gurus
to see if my mods were the appropriate solution.

the patch below adds support for a new sysctl, net.inet.ip.strongendsystem,
which if set to non-zero enforces the semantics described above. you
can hardcode this on by defining IPSTRONGENDSYSTEM to non-zero.

comments/thoughts on this suggested patch? problems people see with
this implementation (especially when you've got a multihomed box
that's routing)?

luke.


Index: if_arp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/if_arp.c,v
retrieving revision 1.53
diff -c -r1.53 if_arp.c
*** if_arp.c	1998/10/01 11:04:24	1.53
--- if_arp.c	1998/11/10 12:10:30
***************
*** 512,517 ****
--- 512,518 ----
  	struct sockaddr sa;
  	struct in_addr isaddr, itaddr, myaddr;
  	int op;
+ 	int oipses;
  
  	ah = mtod(m, struct arphdr *);
  	op = ntohs(ah->ar_op);
***************
*** 539,552 ****
  	 * or any address on the interface to use
  	 * as a dummy address in the rest of this function
  	 */
! 	INADDR_TO_IA(itaddr, ia);
! 	while ((ia != NULL) && ia->ia_ifp != m->m_pkthdr.rcvif)
! 		NEXT_IA_WITH_SAME_ADDR(ia);
! 
  	if (ia == NULL) {
! 		INADDR_TO_IA(isaddr, ia);
! 		while ((ia != NULL) && ia->ia_ifp != m->m_pkthdr.rcvif)
! 			NEXT_IA_WITH_SAME_ADDR(ia);
  
  		if (ia == NULL) {
  			IFP_TO_IA(ifp, ia);
--- 540,554 ----
  	 * or any address on the interface to use
  	 * as a dummy address in the rest of this function
  	 */
! 	oipses = ip_strongendsystem;
! 	ip_strongendsystem = 1;
! 	INADDR_TO_IA(itaddr, ia, m);
! 	ip_strongendsystem = oipses;
  	if (ia == NULL) {
! 		oipses = ip_strongendsystem;
! 		ip_strongendsystem = 1;
! 		INADDR_TO_IA(isaddr, ia, m);
! 		ip_strongendsystem = oipses;
  
  		if (ia == NULL) {
  			IFP_TO_IA(ifp, ia);
Index: in.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.h,v
retrieving revision 1.39
diff -c -r1.39 in.h
*** in.h	1998/09/14 21:15:56	1.39
--- in.h	1998/11/10 12:10:30
***************
*** 297,303 ****
  #define	IPCTL_ANONPORTMAX      11	/* maximum ephemeral port */
  #define	IPCTL_MTUDISCTIMEOUT   12	/* allow path MTU discovery */
  #define	IPCTL_MAXFLOWS         13	/* maximum ip flows allowed */
! #define	IPCTL_MAXID	       14
  
  #define	IPCTL_NAMES { \
  	{ 0, 0 }, \
--- 297,304 ----
  #define	IPCTL_ANONPORTMAX      11	/* maximum ephemeral port */
  #define	IPCTL_MTUDISCTIMEOUT   12	/* allow path MTU discovery */
  #define	IPCTL_MAXFLOWS         13	/* maximum ip flows allowed */
! #define	IPCTL_STRONGENDSYSTEM  14	/* forbid packets on wrong interface */
! #define	IPCTL_MAXID	       15
  
  #define	IPCTL_NAMES { \
  	{ 0, 0 }, \
***************
*** 314,319 ****
--- 315,321 ----
  	{ "anonportmax", CTLTYPE_INT }, \
  	{ "mtudisctimeout", CTLTYPE_INT }, \
  	{ "maxflows", CTLTYPE_INT }, \
+ 	{ "strongendsystem", CTLTYPE_INT }, \
  }
  #endif /* !_XOPEN_SOURCE */
  
Index: in_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_var.h,v
retrieving revision 1.31
diff -c -r1.31 in_var.h
*** in_var.h	1998/09/30 21:52:25	1.31
--- in_var.h	1998/11/10 12:10:30
***************
*** 138,174 ****
  extern  struct in_ifaddrhead in_ifaddr;		/* List head (in ip_input) */
  
  extern	struct	ifqueue	ipintrq;		/* ip packet input queue */
  void	in_socktrim __P((struct sockaddr_in *));
  
  
  /*
   * Macro for finding whether an internet address (in_addr) belongs to one
!  * of our interfaces (in_ifaddr).  NULL if the address isn't ours.
   */
! #define INADDR_TO_IA(addr, ia) \
  	/* struct in_addr addr; */ \
  	/* struct in_ifaddr *ia; */ \
  { \
  	for (ia = IN_IFADDR_HASH((addr).s_addr).lh_first; \
! 	    ia != NULL && !in_hosteq(ia->ia_addr.sin_addr, (addr)); \
! 	    ia = ia->ia_hash.le_next) \
! 		 continue; \
! }
! 
! /*
!  * Macro for finding the next in_ifaddr structure with the same internet
!  * address as ia. Call only with a valid ia pointer.
!  * Will set ia to NULL if none found.
!  */
! 
! #define NEXT_IA_WITH_SAME_ADDR(ia) \
! 	/* struct in_ifaddr *ia; */ \
! { \
! 	struct in_addr addr; \
! 	addr = ia->ia_addr.sin_addr; \
! 	do { \
! 		ia = ia->ia_hash.le_next; \
! 	} while ((ia != NULL) && !in_hosteq(ia->ia_addr.sin_addr, addr)); \
  }
  
  /*
--- 138,169 ----
  extern  struct in_ifaddrhead in_ifaddr;		/* List head (in ip_input) */
  
  extern	struct	ifqueue	ipintrq;		/* ip packet input queue */
+ 
+ extern int	ipforwarding;			/* ip forwarding */
+ extern int	ip_strongendsystem;		/* strong ended system */
+ 
  void	in_socktrim __P((struct sockaddr_in *));
  
  
  /*
   * Macro for finding whether an internet address (in_addr) belongs to one
!  * of our interfaces (in_ifaddr). If necessary, ensure that the packet (mb)
!  * came in on the correct interface.  NULL if the address isn't ours.
   */
! #define INADDR_TO_IA(addr, ia, mb) \
  	/* struct in_addr addr; */ \
  	/* struct in_ifaddr *ia; */ \
+ 	/* struct mbuf *mb; */ \
  { \
  	for (ia = IN_IFADDR_HASH((addr).s_addr).lh_first; \
! 	    ia != NULL; \
! 	    ia = ia->ia_hash.le_next) {\
! 		if (!in_hosteq(ia->ia_addr.sin_addr, (addr))) \
! 			continue; \
! 		if (mb == NULL || \
! 		    !ip_strongendsystem || ia->ia_ifp == mb->m_pkthdr.rcvif) \
! 			break; \
! 	} \
  }
  
  /*
***************
*** 180,187 ****
  	/* struct ifnet *ifp; */ \
  { \
  	register struct in_ifaddr *ia; \
  \
! 	INADDR_TO_IA(addr, ia); \
  	(ifp) = (ia == NULL) ? NULL : ia->ia_ifp; \
  }
  
--- 175,183 ----
  	/* struct ifnet *ifp; */ \
  { \
  	register struct in_ifaddr *ia; \
+ 	register struct mbuf *mb = NULL; \
  \
! 	INADDR_TO_IA(addr, ia, mb); \
  	(ifp) = (ia == NULL) ? NULL : ia->ia_ifp; \
  }
  
Index: ip_icmp.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.30
diff -c -r1.30 ip_icmp.c
*** ip_icmp.c	1998/09/30 21:52:25	1.30
--- ip_icmp.c	1998/11/10 12:10:31
***************
*** 492,498 ****
  	 * or anonymous), use the address which corresponds
  	 * to the incoming interface.
  	 */
! 	INADDR_TO_IA(t, ia);
  	if (ia == NULL && (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST)) {
  		for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first;  
  		    ifa != NULL; ifa = ifa->ifa_list.tqe_next) {
--- 492,498 ----
  	 * or anonymous), use the address which corresponds
  	 * to the incoming interface.
  	 */
! 	INADDR_TO_IA(t, ia, m);
  	if (ia == NULL && (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST)) {
  		for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first;  
  		    ifa != NULL; ifa = ifa->ifa_list.tqe_next) {
Index: ip_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_input.c,v
retrieving revision 1.73
diff -c -r1.73 ip_input.c
*** ip_input.c	1998/10/08 01:41:46	1.73
--- ip_input.c	1998/11/10 12:10:31
***************
*** 128,133 ****
--- 128,136 ----
  #ifndef IPMTUDISCTIMEOUT
  #define IPMTUDISCTIMEOUT (10 * 60)	/* as per RFC 1191 */
  #endif
+ #ifndef IPSTRONGENDSYSTEM
+ #define IPSTRONGENDSYSTEM 0	/* allow packets on wrong interface */
+ #endif
  
  /*
   * Note: DIRECTED_BROADCAST is handled this way so that previous
***************
*** 148,153 ****
--- 151,157 ----
  int	ip_allowsrcrt = IPALLOWSRCRT;
  int	ip_mtudisc = IPMTUDISC;
  u_int	ip_mtudisc_timeout = IPMTUDISCTIMEOUT;
+ int	ip_strongendsystem = IPSTRONGENDSYSTEM;
  #ifdef DIAGNOSTIC
  int	ipprintfs = 0;
  #endif
***************
*** 359,370 ****
  	/*
  	 * Check our list of addresses, to see if the packet is for us.
  	 */
! 	INADDR_TO_IA(ip->ip_dst, ia);
! 	if (ia != NULL) goto ours;
  	if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
  		for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first;
  		    ifa != NULL; ifa = ifa->ifa_list.tqe_next) {
! 			if (ifa->ifa_addr->sa_family != AF_INET) continue;
  			ia = ifatoia(ifa);
  			if (in_hosteq(ip->ip_dst, ia->ia_broadaddr.sin_addr) ||
  			    in_hosteq(ip->ip_dst, ia->ia_netbroadcast) ||
--- 363,376 ----
  	/*
  	 * Check our list of addresses, to see if the packet is for us.
  	 */
! 	INADDR_TO_IA(ip->ip_dst, ia, m);
! 	if (ia != NULL)
! 		goto ours;
  	if (m->m_pkthdr.rcvif->if_flags & IFF_BROADCAST) {
  		for (ifa = m->m_pkthdr.rcvif->if_addrlist.tqh_first;
  		    ifa != NULL; ifa = ifa->ifa_list.tqe_next) {
! 			if (ifa->ifa_addr->sa_family != AF_INET)
! 				continue;
  			ia = ifatoia(ifa);
  			if (in_hosteq(ip->ip_dst, ia->ia_broadaddr.sin_addr) ||
  			    in_hosteq(ip->ip_dst, ia->ia_netbroadcast) ||
***************
*** 1424,1429 ****
--- 1430,1438 ----
  		return (error);
  	    }
  #endif
+ 	case IPCTL_STRONGENDSYSTEM:
+ 		return (sysctl_int(oldp, oldlenp, newp, newlen,
+ 		    &ip_strongendsystem));
  	default:
  		return (EOPNOTSUPP);
  	}
Index: ip_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/ip_var.h,v
retrieving revision 1.36
diff -c -r1.36 ip_var.h
*** ip_var.h	1998/10/08 01:41:46	1.36
--- ip_var.h	1998/11/10 12:10:32
***************
*** 181,198 ****
  extern struct ipstat ipstat;		/* ip statistics */
  extern LIST_HEAD(ipqhead, ipq) ipq;	/* ip reass. queue */
  extern u_int16_t ip_id;			/* ip packet ctr, for ids */
! extern int   ip_defttl;			/* default IP ttl */
! extern int   ipforwarding;		/* ip forwarding */
! extern int   ip_mtudisc;		/* mtu discovery */
! extern u_int ip_mtudisc_timeout;	/* seconds to timeout mtu discovery */
! extern int   anonportmin;		/* minimum ephemeral port */
! extern int   anonportmax;		/* maximum ephemeral port */
  extern struct rttimer_queue *ip_mtudisc_timeout_q;
  #ifdef GATEWAY
! extern int ip_maxflows;
  #endif
  extern struct pool ipqent_pool;
! struct	 inpcb;
  
  int	 ip_ctloutput __P((int, struct socket *, int, int, struct mbuf **));
  int	 ip_dooptions __P((struct mbuf *));
--- 181,197 ----
  extern struct ipstat ipstat;		/* ip statistics */
  extern LIST_HEAD(ipqhead, ipq) ipq;	/* ip reass. queue */
  extern u_int16_t ip_id;			/* ip packet ctr, for ids */
! extern int	ip_defttl;		/* default IP ttl */
! extern int	ip_mtudisc;		/* mtu discovery */
! extern u_int	ip_mtudisc_timeout;	/* seconds to timeout mtu discovery */
! extern int	anonportmin;		/* minimum ephemeral port */
! extern int	anonportmax;		/* maximum ephemeral port */
  extern struct rttimer_queue *ip_mtudisc_timeout_q;
  #ifdef GATEWAY
! extern int	ip_maxflows;
  #endif
  extern struct pool ipqent_pool;
! struct		inpcb;
  
  int	 ip_ctloutput __P((int, struct socket *, int, int, struct mbuf **));
  int	 ip_dooptions __P((struct mbuf *));