ypset(8) attempts to bind to Weird IP (and possible solution)
Saint Aardvark the Carpeted
aardvark at saintaardvarkthecarpeted.com
Sun Jan 18 13:26:05 PST 2004
A while back I came across some strange behaviour with ypset(8). I was
having trouble at work making a host bind to our NIS server, so I thought
I'd try using ypset. When running these commands:
domainname [domain]
ypbind
ypset -h localhost -d [domain] 192.168.0.254
and watching network traffic with tcpdump, I found UDP packets going
off to port 111 on an IP address I'd never seen before: 164.110.15.40.
As far as I could tell, it was trying to bind to the Weird IP (tm)
instead of our NIS server.
The domainname didn't seem to matter or change things; I tried both
the domain we use at work, and "foo" without any change in behaviour.
The same goes for the IP address I had specified, which was that of the
local NIS server. The Weird IP was was completely unrelated to the local
network (192.168.0.0/24), and turns out to belong to the Washington
State Department of Transportation (!). I tried this again at home,
and exactly the same behaviour was seen.
A couple days ago I decided to track this down, and found nearly the
same behaviour; the difference is that this time, the Weird IP was
132.110.15.40, which turns out to belong to the US Army National Guard
Bureau (!!). Again, that IP address is *completely* different from
anything on my local network or my public IP address.
This is all using 4.8-RELEASE; however, the relevant code for ypset
appears to be the same in 4.9-RELEASE. Each test was done on a box
that had one interface, IP address 10.0.0.1, going to a gateway box
(10.0.0.254) with an external IP (192.168.0.100 at work, 192.168.23.254
at home). I varied the IP addresses at home, but saw the same behaviour
each time.
To make a long story short, I compiled a debug version of ypset and stepped
through it with gdb. I narrowed it down to this range of code:
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 }
This chunk goes over the arguments to ypset; pretty much immediately
afterward, it calls bind_tohost() with sin as one of its arguments.
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.
ObDisclaimer: I Am Not A Programmer, and my knowledge of C is pretty
slim. But: if I change lines 142/143 to:
bcopy(&hent->h_addr_list[0][0], &sin.sin_addr, sizeof sin.sin_addr);
then the Weird IP doesn't show up in sin, and ypset only tries to bind
to the IP address listed in its arguments.
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.
*But*, as I mentioned, I'm no programmer. I find it hard to believe
that I could pick up a mistake that simple, especially when I'm not
at all familiar with using sockets, or that this simple-seeming fix
wouldn't introduce more problems.
So -- what's going on? Is this a real bug, or have I misunderstood
something?
Please let me know if I've left anything out, or if there's a better
place to ask this question.
Thanks for your time, everyone!
--
Saint Aardvark the Carpeted
aardvark at saintaardvarkthecarpeted.com
Because the plural of Anecdote is Myth.
More information about the freebsd-questions
mailing list