bin/62550: [patch] bug in ypset(8) causes attempt to bind to weird IP addresses

Saint Aardvark the Carpeted aardvark at saintaardvarkthecarpeted.com
Sun Feb 8 13:30:16 PST 2004


>Number:         62550
>Category:       bin
>Synopsis:       [patch] bug in ypset(8) causes attempt to bind to weird IP addresses
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Feb 08 13:30:15 PST 2004
>Closed-Date:
>Last-Modified:
>Originator:     Saint Aardvark the Carpeted
>Release:        FreeBSD 4.9-RELEASE i386
>Organization:
>Environment:
System: FreeBSD  4.9-RELEASE FreeBSD 4.9-RELEASE #0: Mon Oct 27 17:51:09 GMT 2003     root at freebsd-stable.sentex.ca:/usr/obj/usr/src/sys/GENERIC i386


	
I've seen this in two separate environments:

	Internal box:  Pentium 4 running 4.8-PRERELEASE on a private
	network (10.0.0.0/24) within another private network
	(192.168.0.0/24); default gateway has two interfaces, and
	forwards traffic from 10.0.0.0/24 to its gateway (192.168.0.1),
	which in turn does NAT and is connected to the Internet

	Pentium 2 ("Dagny") running either 4.8-RELEASE or 4.9-RELEASE
	on private network (10.0.1.0/24) connected to NAT/firewall
	box ("Francisco") with three interfaces (ep1 -- 10.0.1.254
	attached to Dagny via crossover cable; vr0 -- 192.168.23.254
	going to the rest of my home network; xl0 -- external
	interface attached to cable Internet connection)

The first setup is at my job, and is where I first noticed this
behaviour.  I don't have access to it to duplicate it -- I'm just
mentioning it to show that it's not solely my home network.  The
second is my home network, and I'm able to do what I like with it.

>Description:

ypset(8) attempts to bind to strange IP addresses when told to try
binding to NIS server on private IP address (192.168.0.2 in first
example, 192.168.23.254 in second example).  I've seen three different
IP addresses:

	164.110.15.40, which belongs to the Washington State
	Department of Transportation

	132.110.15.40, which belongs to the US Army National Guard
	Bureau

	164.113.15.40, which belongs to the Kansas Research and
	Education Network

(Information from "whois -a <ip address>").

>How-To-Repeat:
	
Francisco:  	ifconfig ep1 10.0.1.254 netmask 255.255.255.0
		domainname foo
		ypserv
		(natd already running)

Dagny:  	ifconfig ep1 10.0.1.1 netmask 255.255.255.0
		route add default 10.0.1.254
		ypset -h localhost -d foo 192.168.23.254

Francisco:	"tcpdump -n -i ep1 port not 22" shows:

	14:14:15.779438 10.0.1.1.1003 > 192.168.23.254.111: udp 56
	14:14:15.782620 10.0.1.254.111 > 10.0.1.1.1003: udp 28
	14:14:15.783349 10.0.1.1.1002 > 164.113.15.40.111: udp 56
	14:14:15.884530 164.113.221.114 > 10.0.1.1: icmp: host 164.113.15.40 unreachable

Packets continue to go to 164.113.15.40 for about a minute; after
this, ypset on Dagny exits with this error message:

	ypset: can't yp_bind, reason: Can't communicate with ypbind

This example is with Dagny running 4.9-RELEASE; the same behaviour
is seen with 4.8-RELEASE except that the strange IP is 132.110.15.40,
and there was no "icmp unreachable" response.  When I first saw
this at work (4.8-PRERELEASE), the strange IP was 164.110.15.40.
None of these numbers are remotely close to any of the private
networks in use, nor to the public IP addresses of the machines
that were connected to the Internet.

I compiled a debug version of ypset and stepped through it with
gdb.  I narrowed it down to this range of code in /usr/src/usr.sbin/ypset/ypset.c:

120          struct hostent *hent;
[snip]
130          sin.sin_addr.s_addr = htonl(0x7f000001);
131  
132          while ((c = getopt(argc, argv, "h:d:")) != -1)
133                  switch (c) {
134                  case 'd':
135                          domainname = optarg;
136                          break;
137                  case 'h':
138                          if ((sin.sin_addr.s_addr = inet_addr(optarg)) == -1) {
139                                  hent = gethostbyname(optarg);
140                                  if (hent == NULL)
141                                          errx(1, "host %s unknown", optarg);
142                                  bcopy(&hent->h_addr_list[0], &sin.sin_addr,
143                                          sizeof sin.sin_addr);
144                          }
145                          break;
146                  default:
147                          usage();
148                  }

The CVS tag for ypset.c was:

	#ifndef lint
	static const char rcsid[] =
	  "$FreeBSD: src/usr.sbin/ypset/ypset.c,v 1.5.2.2 2002/02/15 00:47:00 des Exp $";
	#endif /* not lint */

This chunk goes over the arguments to ypset; pretty much immediately
afterward, it calls bind_tohost() with sin as one of its arguments.

To print hent->h_addr_list[0], I ran this in gdb:

    p (unsigned char)hp->h_addr_list[0][n] 

I changed n from 0 to 3; this printed out the numbers in the IP address,
dotted-quad form without the dots. For example, if h_addr_list had
127.0.0.1, I would see 127, then 0, then 0, then 1. To print out
sin.sin_addr.s_addr, I ran:

    p (unsigned char)((char *)&(sin.sin_addr.s_addr))[n] 

in gdb.  Again, n went from 0 to 3.

The problem seems to come in at lines 142/143:  before this,
sin.sin_addr.s_addr is localhost (as set at line 130), as is
hent->h_addr_list[0][0].  *After* this, it's set with the Weird IP,
bind_tohost() is called, and packets go off to the Weird IP.

Looking through man pages and header files, it looks like
hostent->h_addr_list is an array of pointers to chars (is that the
right term?):

	char **h_addr_list

and so gethostbyname is returning the IP address as the *first entry*
in that list.  It makes sense to me, then, that bcopy should have
h_addr_list[0][0] as its first argument.

>Fix:

If I apply this patch:

--- /usr/src/usr.sbin/ypset/ypset.c	Sun Feb  8 14:10:38 2004
+++ /tmp/ypset.c	Sun Feb  8 14:10:30 2004
@@ -139,7 +139,7 @@
 				hent = gethostbyname(optarg);
 				if (hent == NULL)
 					errx(1, "host %s unknown", optarg);
-				bcopy(&hent->h_addr_list[0], &sin.sin_addr,
+				bcopy(hent->h_addr_list[0], &sin.sin_addr,
 					sizeof sin.sin_addr);
 			}
 			break;

then the Weird IP doesn't show up in sin, and ypset only tries to bind
to the IP address listed in its arguments.

This is against ypset.c with the CVS tag described above, which is
part of 4.9-RELEASE; however, it looks like this line is the same
in 1.13, which is the version in HEAD.

Please let me know if I've missed anything or can provide any more
information.
--- pr ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list