Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 03 May 1997 05:55:59 +0800
From:      Peter Wemm <peter@spinner.DIALix.COM>
To:        Craig Leres <leres@ee.lbl.gov>
Cc:        bugs@FreeBSD.ORG
Subject:   Re: reserved port behavior change 
Message-ID:  <199705022156.FAA16845@spinner.DIALix.COM>
In-Reply-To: Your message of "Fri, 02 May 1997 12:37:39 PDT." <199705021937.MAA17182@hot.ee.lbl.gov> 

next in thread | previous in thread | raw e-mail | index | archive | help
Craig Leres wrote:
> At some point between 2.2 and 2.2.1, the last reserved port used by
> in_pcbbind() was changed from 512 to 600. The reason I noticed this is
> because the kernel shell port is 544 and all my kerberos kshell
> applications stopped working. Although I don't want to install them
> suid to root, this makes some of them work.

Huh?  There's some crossed wires somewhere.  The numbers you're referring 
to that in_pcbbind() uses are only used when an application has been 
explicitly modified to request assignment of a reserved port by the kernel 
rather than looping and attempting to bind successive ports in usermode.

The 512 vs. 600 change was the lower limit that the kernel will assign 
with the bind() syscall before wrapping around back up to 1023.  A process 
still *needs* to be root to bind to a port < 1024 just the same as before. 
The applications accepting connections are unchanged, they still test 
against the IPPORT_RESERVED and IPPORT_RESERVED/2 constants, ie 1024 -> 
512.

Besides, the 2.2.0 and 2.2.1 code both have the same values.. (600->1023).

> There's a comment that says something about 512 not being good for
> firewalls. All other versions of Unix I'm aware uses 512 and making
> this change to freebsd means that there will be some applications that
> work everywhere but under freebsd. I suspect even firewall packages
> will have to know the difference between new freebsd, old freebsd and
> everybody else.


The reason this is a problem is because the kernel maintains state between
reserved port bind() calls.  Under the user-mode successive trial
allocation method, each process started at 1023 and worked down.  This is
suspected to be the cause of problems which interact with the TCP TAO cache
 and the resulting very short time_wait states.  ssh and rlogin used to 
hang a lot where one end was allocating port 1023 over and over again, and 
the other end thought that it had a connection to the remote server's port 
1023.

When using the setsockopt() to request that bind() give you a privileged 
port instead of a normal one (assuming you're root), it remembers the last 
port that was allocated.  It won't reuse them until it completely wraps 
around the port sequence space.  This means that it crosses through the 
unix r* port number space.

> This change doesn't seem like a good idea at all... Especially since
> the value can be changed with sysctl; which means the minority of the
> freebsd population that run firewalls and need to have the last
> reserved port be higher than 512 can change it. But changing the
> default from its historic value is a mistake.

The code you point out is only used when binding to a sockaddr_in with a 
sin_port of zero.  Normally that gives you a non-privileged port, unless 
you do this:

int range = IP_PORTRANGE_LOW;
setsockopt(s, IPPROTO_IP, IP_PORTRANGE, &range, sizeof(range));
sin.sin_addr = ...
sin.sin_port = 0;
bind(s, &sin, sizeof(sin))

Traditional code doesn't do this, and is unaffected by the sysctl code
entirely.  Nothing has changed root's ability (and non-root's inability) to
bind to (say) port 544.

> 		Craig
> ------
> ***************
*** 174,191 ****
>   		ushort first, last;
>   		int count;
>   
>   		if (inp->inp_flags & INP_HIGHPORT) {
>   			first = ipport_hifirstauto;	/* sysctl */
>   			last  = ipport_hilastauto;
>   		} else if (inp->inp_flags & INP_LOWPORT) {
>   			if (error = suser(p->p_ucred, &p->p_acflag))
>   				return (EACCES);
> ! 			first = IPPORT_RESERVED - 1;	/* 1023 */
> ! 			last  = IPPORT_RESERVED / 2;	/* traditional - 512 */
> ! 			*lastport = first;		/* restart each time */
>   		} else {
>   			first = ipport_firstauto;	/* sysctl */
>   			last  = ipport_lastauto;
>   		}
>   		/*
>   		 * Simple check to ensure all ports are not used up causing
> --- 201,222 ----
>   		ushort first, last;
>   		int count;
>   
> + 		inp->inp_flags |= INP_ANONPORT;
> + 
>   		if (inp->inp_flags & INP_HIGHPORT) {
>   			first = ipport_hifirstauto;	/* sysctl */
>   			last  = ipport_hilastauto;
> + 			lastport = &inp->inp_pcbinfo->lasthi;
>   		} else if (inp->inp_flags & INP_LOWPORT) {
>   			if (error = suser(p->p_ucred, &p->p_acflag))
>   				return (EACCES);
> ! 			first = ipport_lowfirstauto;	/* 1023 */
> ! 			last  = ipport_lowlastauto;	/* 600 */
> ! 			lastport = &inp->inp_pcbinfo->lastlow;
>   		} else {
>   			first = ipport_firstauto;	/* sysctl */
>   			last  = ipport_lastauto;
> + 			lastport = &inp->inp_pcbinfo->lastport;
>   		}
>   		/*
>   		 * Simple check to ensure all ports are not used up causing

This diff is backwards, isn't it?

Cheers,
-Peter





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199705022156.FAA16845>