add the following, derived from FreeBSD:

* IP_PORTRANGE socket option, which controls how the ephemeral ports
  are allocated. it takes the following settings:
	IP_PORTRANGE_DEFAULT	use anonportmin (49152) -> anonportmax (65535)
	IP_PORTRANGE_HIGH	as IP_PORTRANGE_DEFAULT (retained for FreeBSD
				compat reasons, where these are separate)
	IP_PORTRANGE_LOW	use 600 -> 1023. only works if uid==0.
* in_pcb flag INP_ANONPORT. set if port was allocated ephmerally
This commit is contained in:
lukem 1998-01-07 22:51:22 +00:00
parent cf89ccf13e
commit c80b4400e5
4 changed files with 112 additions and 13 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: in.h,v 1.31 1998/01/05 09:52:02 lukem Exp $ */
/* $NetBSD: in.h,v 1.32 1998/01/07 22:51:22 lukem Exp $ */
/*
* Copyright (c) 1982, 1986, 1990, 1993
@ -68,12 +68,37 @@
/*
* Local port number conventions:
* Ports < IPPORT_RESERVED are reserved for privileged processes (e.g. root).
* IPPORT_ANONMIN <= Ports <= IPPORT_ANONMAX are for dynamic connections.
*
* Ports < IPPORT_RESERVED are reserved for privileged processes (e.g. root),
* unless a kernel is compiled with IPNOPRIVPORTS defined.
*
* When a user does a bind(2) or connect(2) with a port number of zero,
* a non-conflicting local port address is chosen.
*
* The default range is IPPORT_ANONMIX to IPPORT_ANONMAX, although
* that is settable by sysctl(3); net.inet.ip.anonportmin and
* net.inet.ip.anonportmax respectively.
*
* A user may set the IPPROTO_IP option IP_PORTRANGE to change this
* default assignment range.
*
* The value IP_PORTRANGE_DEFAULT causes the default behavior.
*
* The value IP_PORTRANGE_HIGH is the same as IP_PORTRANGE_DEFAULT,
* and exists only for FreeBSD compatibility purposes.
*
* The value IP_PORTRANGE_LOW changes the range to the "low" are
* that is (by convention) restricted to privileged processes.
* This convention is based on "vouchsafe" principles only.
* It is only secure if you trust the remote host to restrict these ports.
* The range is IPPORT_RESERVEDMIN to IPPORT_RESERVEDMAX.
*/
#define IPPORT_RESERVED 1024
#define IPPORT_ANONMIN 49152
#define IPPORT_ANONMAX 65535
#define IPPORT_RESERVEDMIN 600
#define IPPORT_RESERVEDMAX (IPPORT_RESERVED-1)
/*
* Internet address (a structure for historical reasons)
@ -187,6 +212,7 @@ struct ip_opts {
#define IP_MULTICAST_LOOP 11 /* u_char; set/get IP multicast loopback */
#define IP_ADD_MEMBERSHIP 12 /* ip_mreq; add an IP group membership */
#define IP_DROP_MEMBERSHIP 13 /* ip_mreq; drop an IP group membership */
#define IP_PORTRANGE 19 /* int; range to use for ephemeral port */
#define IP_RECVIF 20 /* bool; receive reception if w/dgram */
#define IP_ERRORMTU 21 /* int; get MTU of last xmit = EMSGSIZE */
@ -205,6 +231,14 @@ struct ip_mreq {
struct in_addr imr_interface; /* local IP address of interface */
};
/*
* Argument for IP_PORTRANGE:
* - which range to search when port is unspecified at bind() or connect()
*/
#define IP_PORTRANGE_DEFAULT 0 /* default range */
#define IP_PORTRANGE_HIGH 1 /* same as DEFAULT (FreeBSD compat) */
#define IP_PORTRANGE_LOW 2 /* use privileged range */
/*
* Definitions for inet sysctl operations.
*

View File

@ -1,4 +1,4 @@
/* $NetBSD: in_pcb.c,v 1.44 1998/01/05 10:31:53 thorpej Exp $ */
/* $NetBSD: in_pcb.c,v 1.45 1998/01/07 22:51:23 lukem Exp $ */
/*
* Copyright (c) 1982, 1986, 1991, 1993, 1995
@ -178,15 +178,38 @@ in_pcbbind(v, nam, p)
return (EADDRINUSE);
}
inp->inp_laddr = sin->sin_addr;
noname:
if (lport == 0) {
int cnt;
int cnt
u_int16_t min, max;
u_int16_t *lastport;
lport = table->inpt_lastport + 1;
for (cnt = anonportmax - anonportmin + 1; cnt; cnt--, lport++) {
if (lport < (u_int16_t)anonportmin ||
lport > (u_int16_t)anonportmax)
lport = (u_int16_t)anonportmin;
if (inp->inp_flags & INP_LOWPORT) {
#ifndef IPNOPRIVPORTS
if (p == 0 || (error = suser(p->p_ucred, &p->p_acflag)))
return (EACCES);
#endif
min = IPPORT_RESERVEDMIN;
max = IPPORT_RESERVEDMAX;
lastport = &table->inpt_lastlow;
} else {
min = anonportmin;
max = anonportmax;
lastport = &table->inpt_lastport;
}
if (min > max) { /* sanity check */
u_int16_t swp;
swp = min;
min = max;
max = swp;
}
lport = *lastport + 1;
for (cnt = max - min + 1; cnt; cnt--, lport++) {
if (lport < min || lport > max)
lport = min;
if (!in_pcblookup_port(table, inp->inp_laddr,
htons(lport), wild))
goto found;
@ -195,7 +218,8 @@ noname:
inp->inp_laddr.s_addr = INADDR_ANY;
return (EAGAIN);
found:
table->inpt_lastport = lport;
inp->inp_flags |= INP_ANONPORT;
*lastport = lport;
lport = htons(lport);
}
inp->inp_lport = lport;

View File

@ -1,4 +1,4 @@
/* $NetBSD: in_pcb.h,v 1.22 1997/10/14 00:52:45 matt Exp $ */
/* $NetBSD: in_pcb.h,v 1.23 1998/01/07 22:51:24 lukem Exp $ */
/*
* Copyright (c) 1982, 1986, 1990, 1993
@ -72,7 +72,9 @@ struct inpcbtable {
u_long inpt_bindhash;
u_long inpt_connecthash;
u_int16_t inpt_lastport;
u_int16_t inpt_lastlow;
};
#define inpt_lasthi inpt_lastport
/* states in inp_state: */
#define INP_ATTACHED 0
@ -84,6 +86,9 @@ struct inpcbtable {
#define INP_RECVRETOPTS 0x02 /* receive IP options for reply */
#define INP_RECVDSTADDR 0x04 /* receive IP dst address */
#define INP_HDRINCL 0x08 /* user supplies entire IP header */
#define INP_HIGHPORT 0x10 /* (unused; FreeBSD compat) */
#define INP_LOWPORT 0x20 /* user wants "low" port binding */
#define INP_ANONPORT 0x40 /* port chosen for user */
#define INP_RECVIF 0x80 /* receive incoming interface */
#define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\
INP_RECVIF)

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_output.c,v 1.40 1997/10/14 00:52:59 matt Exp $ */
/* $NetBSD: ip_output.c,v 1.41 1998/01/07 22:51:25 lukem Exp $ */
/*
* Copyright (c) 1982, 1986, 1988, 1990, 1993
@ -598,6 +598,30 @@ ip_ctloutput(op, so, level, optname, mp)
error = ip_setmoptions(optname, &inp->inp_moptions, m);
break;
case IP_PORTRANGE:
if (m == 0 || m->m_len != sizeof(int))
error = EINVAL;
else {
optval = *mtod(m, int *);
switch (optval) {
case IP_PORTRANGE_DEFAULT:
case IP_PORTRANGE_HIGH:
inp->inp_flags &= ~(INP_LOWPORT);
break;
case IP_PORTRANGE_LOW:
inp->inp_flags |= INP_LOWPORT;
break;
default:
error = EINVAL;
break;
}
}
break;
default:
error = ENOPROTOOPT;
break;
@ -671,6 +695,18 @@ ip_ctloutput(op, so, level, optname, mp)
error = ip_getmoptions(optname, inp->inp_moptions, mp);
break;
case IP_PORTRANGE:
*mp = m = m_get(M_WAIT, MT_SOOPTS);
m->m_len = sizeof(int);
if (inp->inp_flags & INP_LOWPORT)
optval = IP_PORTRANGE_LOW;
else
optval = IP_PORTRANGE_DEFAULT;
*mtod(m, int *) = optval;
break;
default:
error = ENOPROTOOPT;
break;