Subject: Re: bin/35479: /usr/sbin/timedc fails
To: None <gnats-bugs@NetBSD.org>
From: Woodchuck <djv@bedford.net>
List: netbsd-bugs
Date: 01/25/2007 11:48:12
On Thu, 25 Jan 2007, Christian Biere wrote:

> The following reply was made to PR bin/35479; it has been noted by GNATS.
> 
> From: Christian Biere <christianbiere@gmx.de>
> To: gnats-bugs@NetBSD.org
> Cc: netbsd-bugs@netbsd.org
> Subject: Re: bin/35479: /usr/sbin/timedc fails
> Date: Thu, 25 Jan 2007 17:13:13 +0100
> 
>  djv@bedford.net wrote:
>  > --- cmds.c.orig	2007-01-24 22:33:51.000000000 -0500
>  > +++ cmds.c	2007-01-24 22:34:30.000000000 -0500
>  > @@ -483,10 +483,11 @@
>  >  		return(-1);
>  >  	}
>  >  
>  > +	memset(&sin, 0, sizeof sin);
>  >  	sin.sin_family = AF_INET;
>  >  	sin.sin_addr.s_addr = 0;
>  >  	for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
>  > -		sin.sin_port = htons((u_short)port);
>  > +		sin.sin_port = port;
>  >  		if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0)
>  >  			break;
>  
>  Sorry, but I don't get this. In how far is htons() a bug here? It certainly
>  never mattered for a big-endian machine but on a little endian machine it
>  definitely does. Albeit I'm having trouble to find this in the documentation,
>  sin_port has to be initialized using big-endian (network byte order). For
>  raw sockets this might differ but this is an UDP socket.
>  
>  > Eliminating the htons call on little-endian machines results in a port
>  > assignment in the 0-1023 range as demanded by some hosts, and as appears to
>  > be the intent of the programmer.
>  
>  I don't see how unless I'm missing something.

I determined the fix empirically.  

Print out sin.sin_port with and without the htons, observe
results of a "clockdiff" command with and without the htons.

On a little-endian (i386) machine, the original code results in a
sin.sin_port value in the 63K range, and subsequent code that probes
the target host for time/udp will fail if the target expects a privileged
port.  perhaps htons belongs *here*, perhaps another one elsewhere is
spurious.  I was unable to find any semantics of the bind(2) call
in the man pages, except for the (irrelevant) UNIX domain.

I no longer have a working big-endian machine for testing, alas.

The OpenBSD version moves all these calls to timedc.c, and makes
the bind call with sin.sin_port set to zero.  The relevant block
of code there is :

	memset(&sin, 0, sizeof sin);
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = INADDR_ANY;
        if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
                fprintf(stderr, "all reserved ports in use\n");
                (void)close(sock_raw);
                exit(1);
        }

Looks I'd better subscribe to bugs@ ;-)

Dave