[comp.bugs.4bsd] erroneous ICMP error messages in 4.3

hedrick@topaz.RUTGERS.EDU (Charles Hedrick) (01/21/87)

Our network is being flooded by ICMP unreachable messages.  We have
systems that use the new broadcast address of all ones.
Unfortunately, 4.3 recognizes this address only in certain parts of
the code.  Suppose a machine sends a broadcast packet to a UDP port
that we don't have a server on.  ip_input recognizes all ones, and
passes it to udp_usrreq.  udp sees that there is no port, and then
sends ICMP port unreachable.  It should not do this in response to
broadcast messages.  There is an attempt to test for this, but it
calls in_broadcast.  This only tests for the default broadcast
address.  The test should be for all legal broadcast addresses.  Since
similar code appears in several places, I have added a routine
in_any_broadcast.  This extends in_broadcast to include the same set
of addresses that ip_input tests for.  Here are the changes.

WARNING: I have not tested these changes.  I'm about to go to a
conference and don't have time to test a new kernel.  These should
be close enough to show what needs to be done.

*** in.c.HOLD	Thu Nov 20 13:38:42 1986
--- in.c	Tue Jan 20 22:36:46 1987
***************
*** 456,458
  	UNLOCKSEM(&ip_lock);
  	return (0);
  }

--- 456,493 -----
  	UNLOCKSEM(&ip_lock);
  	return (0);
  }
+ 
+ /*
+  * Return 1 if the address is any of the possible broadcast addresses.
+  * in_broadcast is used to recognize things that we intend as broadcasts.
+  * So it only looks at broadaddr on each net.  This one is used to test
+  * incoming addresses, so it must allow any of the various standards.
+  */
+ in_any_broadcast(in)
+ 	struct in_addr in;
+ {
+ 	register struct in_ifaddr *ia;
+ 
+ 	/*
+ 	 * Look through the list of addresses for a match
+ 	 * with a broadcast address.
+ 	 */
+ 	if (in.s_addr == 0 || in.s_addr == 0xffffffff)
+ 	  return(1);
+ 	SPINLOCK(&ip_lock);
+ 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
+ 	  if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
+ 	    if (((struct sockaddr_in *)&ia->ia_broadaddr)->sin_addr.s_addr ==
+ 		in.s_addr)
+ 	      goto isbroad;
+ 	    if (ia->ia_subnet == ntohl(in.s_addr))
+ 	      goto isbroad;
+ 	    if (ia->ia_net == ntohl(in.s_addr))
+ 	      goto isbroad;
+ 	  }
+ 	UNLOCKSEM(&ip_lock);
+ 	return (0);
+ isbroad:		
+ 	UNLOCKSEM(&ip_lock);
+ 	return (1);
+ }
*** ip_input.c.HOLD	Sat Jan 10 06:46:57 1987
--- ip_input.c	Tue Jan 20 22:39:57 1987
***************
*** 1003,1009
  		break;
  	}
  sendicmp:
! 	if (in_broadcast(ip->ip_dst)) {
  		m_freem(dtom(ip));
  		return;
  	}

--- 1003,1010 -----
  		break;
  	}
  sendicmp:
! /* 48 - change in_broadcast to in_any_broadcast */
! 	if (in_any_broadcast(ip->ip_dst)) {
  		m_freem(dtom(ip));
  		return;
  	}
*** tcp_input.c.HOLD	Fri Jan  2 22:09:03 1987
--- tcp_input.c	Tue Jan 20 22:41:08 1987
***************
*** 439,445
  			goto dropwithreset;
  		if ((tiflags & TH_SYN) == 0)
  			goto drop;
! 		if (in_broadcast(ti->ti_dst))
  			goto drop;
  		am = m_get(M_DONTWAIT, MT_SONAME);
  		if (am == NULL)

--- 439,446 -----
  			goto dropwithreset;
  		if ((tiflags & TH_SYN) == 0)
  			goto drop;
! /* 48 - use in_any_broadcast, so we recognize -1, 0, etc. */
! 		if (in_any_broadcast(ti->ti_dst))
  			goto drop;
  		am = m_get(M_DONTWAIT, MT_SONAME);
  		if (am == NULL)
***************
*** 1020,1025
  	 * Make ACK acceptable to originator of segment.
  	 * Don't bother to respond if destination was broadcast.
  	 */
  	if ((tiflags & TH_RST) || in_broadcast(ti->ti_dst))
  		goto drop;
  	if (tiflags & TH_ACK)

--- 1021,1027 -----
  	 * Make ACK acceptable to originator of segment.
  	 * Don't bother to respond if destination was broadcast.
  	 */
+ /* 48 - use in_any_broadcast, to recognize 0 and -1 */
  	if ((tiflags & TH_RST) || in_broadcast(ti->ti_dst))
  		goto drop;
  	if (tiflags & TH_ACK)
*** udp_usrreq.c.HOLD	Fri Jan  2 22:31:21 1987
--- udp_usrreq.c	Tue Jan 20 22:41:51 1987
***************
*** 120,126
  	if (inp == 0) {
  		UNLOCKSEM(&udb.pcb_lock);
  		/* don't send ICMP response for broadcast packet */
! 		if (in_broadcast(ui->ui_dst))
  			goto bad;
  		*(struct ip *)ui = ip;
  		icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT,

--- 120,127 -----
  	if (inp == 0) {
  		UNLOCKSEM(&udb.pcb_lock);
  		/* don't send ICMP response for broadcast packet */
! /* 48 - recognize all broadcast addresses */
! 		if (in_any_broadcast(ui->ui_dst))
  			goto bad;
  		*(struct ip *)ui = ip;
  		icmp_error((struct ip *)ui, ICMP_UNREACH, ICMP_UNREACH_PORT,