[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openbsd-bugs
Subject:    kernel/883: ip_nat fights with multihomed net
From:       Geoff Steckel <gwes () oat ! com>
Date:       1999-07-25 14:20:57
[Download RAW message or body]


>Number:         883
>Category:       kernel
>Synopsis:       ipnat mapping fails on multihomed network
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    bugs
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Jul 25 13:20:02 MDT 1999
>Last-Modified:
>Originator:     Geoff Steckel
>Organization:
Omnivore Technology
net
>Release:        2.5
>Environment:
	
	System      : OpenBSD 2.5
	Architecture: OpenBSD.i386
	Machine     : i386
>Description:
ip_nat.c attempts to recognize outgoing packets which correspond
to a connection initiated from outside by comparing destination interface
address and port #s.  This fails on a multihomed host/net if the
default outbound interface is not the same as the interface on which
the incoming connection request was received.  Instead, a new port
number will be assigned and a new nat structure created.  This results
in connections in the SYN_SENT state which are hung.

>How-To-Repeat:
Set up a host with two interfaces pointing to two gateways to another network.
route default -gateway gw1

From another machine, attempt to telnet to victim host via the
address for if2.  The connection will hang "half-established".

>Fix:
Change if_nat.{c,h} to allow multiple equivalent interfaces in
rdr and map ipnat entries.  Use a syntax of
    interfacename[,interfacename...]
so that no changes need be made to ipnat other than recompilation
and documentation.

The deltas between the original ipnat.{c,h} and what I'm running
with follow.  The last time I looked, the "current" versions of these
files have not changed since 2.5.


*** ip_nat.h	Tue Jul 13 18:27:33 1999
--- ip_nat.h.orig	Tue Jul 13 14:31:20 1999
***************
*** 63,77 ****
  	struct	nat	*nat_next;
  	struct	nat	*nat_hnext[2];
  	struct	nat	**nat_hstart[2];
! 	void	**nat_ifpp;		/* potentially matching interfaces */
! 	int	nat_ifpn ;		/* # of potential interfaces */
  	int	nat_dir;
  } nat_t;
  
  typedef	struct	ipnat	{
  	struct	ipnat	*in_next;
! 	u_int	in_ifpn ;			/* # interfaces in array */
! 	void	**in_ifpp;			/* interface pointer array */
  	void	*in_apr;			/* proxy structure ptr */
  	u_int	in_space;
  	u_int	in_use;
--- 63,75 ----
  	struct	nat	*nat_next;
  	struct	nat	*nat_hnext[2];
  	struct	nat	**nat_hstart[2];
! 	void	*nat_ifp;
  	int	nat_dir;
  } nat_t;
  
  typedef	struct	ipnat	{
  	struct	ipnat	*in_next;
! 	void	*in_ifp;			/* interface pointer */
  	void	*in_apr;			/* proxy structure ptr */
  	u_int	in_space;
  	u_int	in_use;
*** ip_nat.c	Sun Jul 25 14:13:36 1999
--- ip_nat.c.orig	Tue Jul 13 14:31:13 1999
***************
*** 214,226 ****
  #if defined(_KERNEL) && !SOLARIS
  	int s;
  #endif
- 	int i ;
- 	char *p, *q ;
- 	char namebuf[32] ;
  
  	nat = NULL;     /* XXX gcc -Wuninitialized */
  	KMALLOC(nt, ipnat_t *, sizeof(*nt));
- 	nt->in_ifpp = NULL ;
  	if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT))
  		IRCOPY(data, (char *)&natd, sizeof(natd));
  
--- 214,222 ----
***************
*** 257,285 ****
  			break;
  		}
  		bcopy((char *)nat, (char *)n, sizeof(*n));
! 		/*
! 		 * count interface names & allocate array of ptrs
! 		 */
! 		for (i = 1, p = n->in_ifname ; p && *p ; p++, i++) {
! 			p = memchr(p, ',', strlen(p)) ;
! 			if (!p)
! 				break ;
! 		}
! 		n->in_ifpn = i ;
! 		KMALLOC(n->in_ifpp, void **, i * sizeof (void *)) ;
! 		for (i = 0, p = n->in_ifname ; i < n->in_ifpn ; i++) {
! 			q = memchr(p, ',', strlen(p)) ;
! 			if (q) {
! 				strncpy(namebuf, p, q - p) ;
! 				namebuf[q - p] = '\0' ;
! 			}
! 			else
! 				strcpy(namebuf, p) ;
! 			n->in_ifpp[i] = (void *)GETUNIT(namebuf) ;
! 			if (!n->in_ifpp[i])
! 				n->in_ifpp[i] = (void *)-1;
! 			p = q + 1 ;
! 		}
  		if (n->in_plabel[0] != '\0') {
  			n->in_apr = ap_match(n->in_p, n->in_plabel);
  			if (!n->in_apr) {
--- 253,261 ----
  			break;
  		}
  		bcopy((char *)nat, (char *)n, sizeof(*n));
! 		n->in_ifp = (void *)GETUNIT(n->in_ifname);
! 		if (!n->in_ifp)
! 			n->in_ifp = (void *)-1;
  		if (n->in_plabel[0] != '\0') {
  			n->in_apr = ap_match(n->in_p, n->in_plabel);
  			if (!n->in_apr) {
***************
*** 326,332 ****
  		if (!n->in_use) {
  			if (n->in_apr)
  				ap_free(n->in_apr);
- 			KFREE(n->in_ifpp) ;
  			KFREE(n);
  			nat_stats.ns_rules--;
  		} else {
--- 302,307 ----
***************
*** 387,397 ****
  	}
  	RWLOCK_EXIT(&ipf_nat);			/* READ/WRITE */
  	SPL_X(s);
! 	if (nt) {
! 		if (nt->in_ifpp)
! 			KFREE(nt->in_ifpp) ;
  		KFREE(nt);
- 	}
  	return error;
  }
  
--- 362,369 ----
  	}
  	RWLOCK_EXIT(&ipf_nat);			/* READ/WRITE */
  	SPL_X(s);
! 	if (nt)
  		KFREE(nt);
  	return error;
  }
  
***************
*** 430,436 ****
  		if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) {
  			if (ipn->in_apr)
  				ap_free(ipn->in_apr);
- 			KFREE(ipn->in_ifpp) ;
  			KFREE(ipn);
  			nat_stats.ns_rules--;
  		}
--- 402,407 ----
***************
*** 485,491 ****
  		if (!n->in_use) {
  			if (n->in_apr)
  				ap_free(n->in_apr);
- 			KFREE(n->in_ifpp) ;
  			KFREE(n);
  			nat_stats.ns_rules--;
  		} else {
--- 456,461 ----
***************
*** 591,607 ****
  	}
  
  	/* Give me a new nat */
! 	KMALLOC(nat, nat_t *, sizeof(*nat) + np->in_ifpn * sizeof (void *));
  	if (nat == NULL)
  		return NULL;
  	bzero((char *)nat, sizeof(*nat));
  	nat->nat_flags = flags;
  
- 	nat->nat_ifpp = (void **) (nat + 1) ;
- 	nat->nat_ifpn = np->in_ifpn ;
- 	bcopy((char *) np->in_ifpp, (char *) nat->nat_ifpp,
- 			np->in_ifpn * sizeof (void *)) ;
- 
  	/*
  	 * Search the current table for a match.
  	 */
--- 561,573 ----
  	}
  
  	/* Give me a new nat */
! 	KMALLOC(nat, nat_t *, sizeof(*nat));
  	if (nat == NULL)
  		return NULL;
+ 
  	bzero((char *)nat, sizeof(*nat));
  	nat->nat_flags = flags;
  
  	/*
  	 * Search the current table for a match.
  	 */
***************
*** 776,784 ****
  	nat->nat_ptr = np;
  	nat->nat_bytes = 0;
  	nat->nat_pkts = 0;
- #if 0
  	nat->nat_ifp = fin->fin_ifp;
- #endif
  	nat->nat_dir = direction;
  	nat->nat_age = fr_defnatage;
  	if (direction == NAT_OUTBOUND) {
--- 742,748 ----
***************
*** 953,979 ****
  #endif
  {
  	register nat_t *nat;
- 	int i ;
  
  	flags &= IPN_TCPUDP;
  
  	nat = nat_table[1][mapdst.s_addr % NAT_SIZE];
! 	for (; nat; nat = nat->nat_hnext[1]) {
! 		if (ifp) {
! 			for (i = 0 ; i < nat->nat_ifpn ; i++)
! 				if (ifp == nat->nat_ifpp[i])
! 					goto match ;
! 			continue ;
! 		}
! match:
! 		if (
  		    nat->nat_oip.s_addr == src.s_addr &&
  		    nat->nat_outip.s_addr == mapdst.s_addr &&
  		    flags == nat->nat_flags && (!flags ||
  		     (nat->nat_oport == sport &&
  		      nat->nat_outport == mapdport)))
  			return nat;
- 	}
  	return NULL;
  }
  
--- 917,934 ----
  #endif
  {
  	register nat_t *nat;
  
  	flags &= IPN_TCPUDP;
  
  	nat = nat_table[1][mapdst.s_addr % NAT_SIZE];
! 	for (; nat; nat = nat->nat_hnext[1])
! 		if ((!ifp || ifp == nat->nat_ifp) &&
  		    nat->nat_oip.s_addr == src.s_addr &&
  		    nat->nat_outip.s_addr == mapdst.s_addr &&
  		    flags == nat->nat_flags && (!flags ||
  		     (nat->nat_oport == sport &&
  		      nat->nat_outport == mapdport)))
  			return nat;
  	return NULL;
  }
  
***************
*** 995,1014 ****
  #endif
  {
  	register nat_t *nat;
- 	int i ;
  
  	flags &= IPN_TCPUDP;
  
  	nat = nat_table[0][src.s_addr % NAT_SIZE];
  	for (; nat; nat = nat->nat_hnext[0]) {
! 		if (ifp) {
! 			for (i = 0 ; i < nat->nat_ifpn ; i++)
! 				if (ifp == nat->nat_ifpp[i])
! 					goto match ;
! 			continue ;
! 		}
! match:
! 		if (
  		    nat->nat_inip.s_addr == src.s_addr &&
  		    nat->nat_oip.s_addr == dst.s_addr &&
  		    flags == nat->nat_flags && (!flags ||
--- 950,961 ----
  #endif
  {
  	register nat_t *nat;
  
  	flags &= IPN_TCPUDP;
  
  	nat = nat_table[0][src.s_addr % NAT_SIZE];
  	for (; nat; nat = nat->nat_hnext[0]) {
! 		if ((!ifp || ifp == nat->nat_ifp) &&
  		    nat->nat_inip.s_addr == src.s_addr &&
  		    nat->nat_oip.s_addr == dst.s_addr &&
  		    flags == nat->nat_flags && (!flags ||
***************
*** 1035,1061 ****
  #endif
  {
  	register nat_t *nat;
- 	int i ;
  
  	flags &= IPN_TCPUDP;
  
  	nat = nat_table[1][mapsrc.s_addr % NAT_SIZE];
! 	for (; nat; nat = nat->nat_hnext[0]) {
! 		if (ifp) {
! 			for (i = 0 ; i < nat->nat_ifpn ; i++)
! 				if (ifp == nat->nat_ifpp[i])
! 					goto match ;
! 			continue ;
! 		}
! match:
! 		if (
  		    nat->nat_oip.s_addr == dst.s_addr &&
  		    nat->nat_outip.s_addr == mapsrc.s_addr &&
  		    flags == nat->nat_flags && (!flags ||
  		     (nat->nat_outport == mapsport &&
  		      nat->nat_oport == dport)))
  			return nat;
- 	}
  	return NULL;
  }
  
--- 982,999 ----
  #endif
  {
  	register nat_t *nat;
  
  	flags &= IPN_TCPUDP;
  
  	nat = nat_table[1][mapsrc.s_addr % NAT_SIZE];
! 	for (; nat; nat = nat->nat_hnext[0])
! 		if ((!ifp || ifp == nat->nat_ifp) &&
  		    nat->nat_oip.s_addr == dst.s_addr &&
  		    nat->nat_outip.s_addr == mapsrc.s_addr &&
  		    flags == nat->nat_flags && (!flags ||
  		     (nat->nat_outport == mapsport &&
  		      nat->nat_oport == dport)))
  			return nat;
  	return NULL;
  }
  
***************
*** 1099,1105 ****
  	frentry_t *fr;
  	nat_t *nat;
  	int natadd = 1;
- 	int i ;
  
  	if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) &&
  	    fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1)
--- 1037,1042 ----
***************
*** 1135,1147 ****
  		 * If there is no current entry in the nat table for this IP#,
  		 * create one for it (if there is a matching rule).
  		 */
! 		for (np = nat_list; np; np = np->in_next) {
! 			for (i = 0 ; i < np->in_ifpn ; i++)
! 				if (ifp == np->in_ifpp[i])
! 					goto match ;
! 			continue ;
! match:
! 			if (np->in_space &&
  			    (!np->in_flags || (np->in_flags & nflags)) &&
  			    ((ipa & np->in_inmsk) == np->in_inip) &&
  			    ((np->in_redir & NAT_MAP) ||
--- 1072,1079 ----
  		 * If there is no current entry in the nat table for this IP#,
  		 * create one for it (if there is a matching rule).
  		 */
! 		for (np = nat_list; np; np = np->in_next)
! 			if ((np->in_ifp == ifp) && np->in_space &&
  			    (!np->in_flags || (np->in_flags & nflags)) &&
  			    ((ipa & np->in_inmsk) == np->in_inip) &&
  			    ((np->in_redir & NAT_MAP) ||
***************
*** 1165,1171 ****
  #endif
  				break;
  			}
- 		}
  		MUTEX_DOWNGRADE(&ipf_nat);
  	}
  
--- 1097,1102 ----
***************
*** 1254,1260 ****
  	u_short sport = 0, dport = 0, *csump = NULL;
  	nat_t *nat;
  	int nflags = 0, natadd = 1;
- 	int i ;
  
  	if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
  		if (ip->ip_p == IPPROTO_TCP)
--- 1185,1190 ----
***************
*** 1287,1299 ****
  		 * If there is no current entry in the nat table for this IP#,
  		 * create one for it (if there is a matching rule).
  		 */
! 		for (np = nat_list; np; np = np->in_next) {
! 			for (i = 0 ; i < np->in_ifpn ; i++)
! 				if (np->in_ifpp[i] == ifp)
! 					goto match ;
! 			continue ;
! match:
! 			if (
  			    (!np->in_flags || (nflags & np->in_flags)) &&
  			    ((in.s_addr & np->in_outmsk) == np->in_outip) &&
  			    (np->in_redir & NAT_REDIRECT) &&
--- 1217,1224 ----
  		 * If there is no current entry in the nat table for this IP#,
  		 * create one for it (if there is a matching rule).
  		 */
! 		for (np = nat_list; np; np = np->in_next)
! 			if ((np->in_ifp == ifp) &&
  			    (!np->in_flags || (nflags & np->in_flags)) &&
  			    ((in.s_addr & np->in_outmsk) == np->in_outip) &&
  			    (np->in_redir & NAT_REDIRECT) &&
***************
*** 1307,1313 ****
  #endif
  				break;
  			}
- 		}
  		MUTEX_DOWNGRADE(&ipf_nat);
  	}
  	if (nat) {
--- 1232,1237 ----
***************
*** 1426,1432 ****
  
  
  /*
-  * Adjust mappings on change of IP address
   */
  #ifdef __STDC__
  void ip_natsync(void *ifp)
--- 1350,1355 ----
***************
*** 1442,1454 ****
  #if defined(_KERNEL) && !SOLARIS
  	int s;
  #endif
- 	int i ;
  
  	SPL_NET(s);
  	WRITE_ENTER(&ipf_nat);
  	for (nat = nat_instances; nat; nat = nat->nat_next)
! 		for (i = 0 ; i < nat->nat_ifpn ; i++)
! 		    if ((ifp == nat->nat_ifpp[i]) && (np = nat->nat_ptr))
  			if ((np->in_outmsk == 0xffffffff) && !np->in_nip) {
  				/*
  				 * Change the map-to address to be the same
--- 1365,1375 ----
  #if defined(_KERNEL) && !SOLARIS
  	int s;
  #endif
  
  	SPL_NET(s);
  	WRITE_ENTER(&ipf_nat);
  	for (nat = nat_instances; nat; nat = nat->nat_next)
! 		if ((ifp == nat->nat_ifp) && (np = nat->nat_ptr))
  			if ((np->in_outmsk == 0xffffffff) && !np->in_nip) {
  				/*
  				 * Change the map-to address to be the same

>Audit-Trail:
>Unformatted:

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic