[comp.bugs.4bsd] Fix for dropping of 4.3BSD IP options

dpz@rutgers.rutgers.edu (David P. Zimmerman) (01/09/89)

The problem:

4.3BSD drops the IP options on the floor when it turns an ICMP request
into a reply.  This doesn't make things easy, especially for doing
useful things like ping with record route.

The fix:

Apply these two patches.  The first is for sys/netinet/ip_input.c, the
second is for sys/netinet/ip_icmp.c.

No, it isn't backwards compatible with the original way
ip_stripoptions(ip, real_mbuf) worked, but nothing was using it that
way anyway.  Looked like a half-solution waiting for a problem.
ip_stripoptions(ip, (struct mbuf *)0)) still works normally.

						David


:	This is a shell archive.
:	Remove everything above this line and
:	run the following text with /bin/sh to create:
:	ip_input.c.diff
:	ip_icmp.c.diff
: This archive created: Mon Jan  9 05:51:11 1989
cat << 'SHAR_EOF' > ip_input.c.diff
*** /tmp/geta4604	Mon Jan  9 05:10:02 1989
--- /tmp/getb4604	Mon Jan  9 05:10:02 1989
***************
*** 783,798 ****
  	register int i;
  	register struct mbuf *m;
  	register caddr_t opts;
! 	int olen;
  
  	olen = (ip->ip_hl<<2) - sizeof (struct ip);
  	m = dtom(ip);
  	opts = (caddr_t)(ip + 1);
  	if (mopt) {
! 		mopt->m_len = olen;
! 		mopt->m_off = MMINOFF;
! 		bcopy(opts, mtod(mopt, caddr_t), (unsigned)olen);
! 	}
  	i = m->m_len - (sizeof (struct ip) + olen);
  	bcopy(opts  + olen, opts, (unsigned)i);
  	m->m_len -= olen;
--- 783,834 ----
  	register int i;
  	register struct mbuf *m;
  	register caddr_t opts;
! 	int olen, optsoff = 0;
  
  	olen = (ip->ip_hl<<2) - sizeof (struct ip);
  	m = dtom(ip);
  	opts = (caddr_t)(ip + 1);
+ 
  	if (mopt) {
! 
! /*  If m_len is 0, we're dealing with an option set which ip_srcroute
! **  found no source routing in.  So, we've got an empty mbuf, into the
! **  beginning of which we have to coerce a "first hop" address.  In a
! **  packet with no source routing, this would be the destination
! **  address.  Otherwise, m_len is real, and we're just appending to
! **  the mbuf coming out of ip_srcroute.  */
! 
! 	  if (!mopt->m_len) {
! 	    mopt->m_len = sizeof(struct in_addr);
! 	    bcopy(&ip->ip_dst, mtod(mopt, caddr_t), mopt->m_len);
! 	  }
! 
! /*  Push the rest of the options in.  We don't have to worry about the
! **  other IP level options like we do the source routing, so just
! **  search for them and insert them into the mbuf.  Notice that
! **  anything dealing with source routing is ignored, since you would
! **  want to do that in ip_srcroute instead.  */
! 
! 	  while (optsoff + 1 <= olen)
! 	    switch(opts[optsoff]) {
! 	    case IPOPT_LSRR:
! 	    case IPOPT_SSRR:
! 			       optsoff += opts[optsoff + IPOPT_OLEN];
! 			       break;
! 	    case IPOPT_EOL:
! 	    case IPOPT_NOP:
! 			       mopt->m_dat[mopt->m_len++] = opts[optsoff++];
! 			       break;
! 	    default:
! 			       bcopy(&opts[optsoff], &mopt->m_dat[mopt->m_len],
! 				     opts[optsoff + IPOPT_OLEN]);
! 			       mopt->m_len += opts[optsoff + IPOPT_OLEN];
! 			       optsoff += opts[optsoff + IPOPT_OLEN];
! 			       break;
! 	    }
! 	  mopt->m_off = MMINOFF;
! 	}  
! 
  	i = m->m_len - (sizeof (struct ip) + olen);
  	bcopy(opts  + olen, opts, (unsigned)i);
  	m->m_len -= olen;
SHAR_EOF
cat << 'SHAR_EOF' > ip_icmp.c.diff
*** /tmp/geta4590	Mon Jan  9 05:09:27 1989
--- /tmp/getb4590	Mon Jan  9 05:09:27 1989
***************
*** 376,386 ****
  	if (optlen > 0) {
  		/*
  		 * Retrieve any source routing from the incoming packet
! 		 * and strip out other options.  Adjust the IP length.
  		 */
  		opts = ip_srcroute();
  		ip->ip_len -= optlen;
- 		ip_stripoptions(ip, (struct mbuf *)0);
  	}
  	icmp_send(ip, opts);
  	if (opts)
--- 376,393 ----
  	if (optlen > 0) {
  		/*
  		 * Retrieve any source routing from the incoming packet
! 		 * and merge in the other non-routing options.
! 		 * Adjust the IP length.
  		 */
  		opts = ip_srcroute();
+ 		if (!opts) 
+ 		  if (opts = m_get(M_DONTWAIT, MT_SOOPTS))
+ 		    opts->m_len = 0;
+ 		if (opts)
+ 		  ip_stripoptions(ip, opts);
+ 		else  /* admit defeat */
+ 		  ip_stripoptions(ip, (struct mbuf *)0);
  		ip->ip_len -= optlen;
  	}
  	icmp_send(ip, opts);
  	if (opts)
SHAR_EOF
:	End of shell archive
exit 0
-- 
David P. Zimmerman, the Dorm Networking Pilot Project, the UUCP Project, etc
dpz@dorm.rutgers.edu          rutgers!dpz          dpzimmerman@zodiac.bitnet