diff options
author | Jason Downs <downsj@cvs.openbsd.org> | 1996-07-29 02:34:32 +0000 |
---|---|---|
committer | Jason Downs <downsj@cvs.openbsd.org> | 1996-07-29 02:34:32 +0000 |
commit | bf3a4122548d5c8a98859e6351f4ffd44452e504 (patch) | |
tree | 970b81341e0fd628b9c31f123fbbd4034e9df6dc /sys/netinet | |
parent | 0e8e403d85399cff180aa8e63fe4030057acfa77 (diff) |
From FreeBSD (with slightly different sysctl names):
"... Allow the user to nominate one of three ranges of port numbers as
candidates for selecting a local address to replace a zero port number.
The ranges are selected via a setsockopt(s, IPPROTO_IP, IP_PORTRANGE, &arg)
call. The three ranges are: default, high (to bypass firewalls) and
low (to get a port below 1024).
The default and high port ranges are sysctl settable under sysctl
net.inet.ip.portrange.* [net.inet.ip.portfirst, net.inet.ip.portlast,
net.inet.ip.porthifirst, and net.inet.ip.porthilast currently in OpenBSD.]
This code also fixes a potential deadlock if the system accidently ran out
of local port addresses. It'd drop into an infinite while loop.
The secure port selection (for root) should reduce overheads and increase
reliability of rlogin/rlogind/rsh/rshd if they are modified to take
advantage of it."
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/in.h | 63 | ||||
-rw-r--r-- | sys/netinet/in_pcb.c | 76 | ||||
-rw-r--r-- | sys/netinet/in_pcb.h | 4 | ||||
-rw-r--r-- | sys/netinet/ip_input.c | 20 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 47 |
5 files changed, 196 insertions, 14 deletions
diff --git a/sys/netinet/in.h b/sys/netinet/in.h index 9bfe6041ec2..7e9c0fa0dc4 100644 --- a/sys/netinet/in.h +++ b/sys/netinet/in.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in.h,v 1.5 1996/03/03 22:30:29 niklas Exp $ */ +/* $OpenBSD: in.h,v 1.6 1996/07/29 02:34:29 downsj Exp $ */ /* $NetBSD: in.h,v 1.20 1996/02/13 23:41:47 christos Exp $ */ /* @@ -66,7 +66,42 @@ /* + * From FreeBSD: + * * Local port number conventions: + * + * 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_RESERVED through + * IPPORT_USERRESERVED, although that is settable by sysctl. + * + * 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 changes the range of candidate port numbers + * into the "high" range. These are reserved for client outbound connections + * which do not want to be filtered by any firewalls. + * + * 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 default range of ports and the high range can be changed by + * sysctl(3). (net.inet.ip.port{hi}{first,last}) + * + * Changing those values has bad security implications if you are + * using a a stateless firewall that is allowing packets outside of that + * range in order to allow transparent outgoing connections. + * + * Such a firewall configuration will generally depend on the use of these + * default values. If you change them, you may find your Security + * Administrator looking for you with a heavy object. + */ + +/* * Ports < IPPORT_RESERVED are reserved for * privileged processes (e.g. root). * Ports > IPPORT_USERRESERVED are reserved @@ -76,6 +111,12 @@ #define IPPORT_USERRESERVED 5000 /* + * Default local port range to use by setting IP_PORTRANGE_HIGH + */ +#define IPPORT_HIFIRSTAUTO 40000 +#define IPPORT_HILASTAUTO 44999 + +/* * Internet address (a structure for historical reasons) */ struct in_addr { @@ -186,6 +227,8 @@ 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 */ + /* 14-17 left empty for future compatibility with FreeBSD */ +#define IP_PORTRANGE 19 /* int; range to choose for unspec port */ /* * Defaults and limits for options @@ -203,6 +246,14 @@ struct ip_mreq { }; /* + * 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 /* "high" - request firewall bypass */ +#define IP_PORTRANGE_LOW 2 /* "low" - vouchsafe security */ + +/* * Definitions for inet sysctl operations. * * Third level is protocol number. @@ -247,7 +298,11 @@ struct ip_mreq { #endif #define IPCTL_SOURCEROUTE 5 /* may perform source routes */ #define IPCTL_DIRECTEDBCAST 6 /* default broadcast behavior */ -#define IPCTL_MAXID 7 +#define IPCTL_IPPORT_FIRSTAUTO 7 +#define IPCTL_IPPORT_LASTAUTO 8 +#define IPCTL_IPPORT_HIFIRSTAUTO 9 +#define IPCTL_IPPORT_HILASTAUTO 10 +#define IPCTL_MAXID 11 #define IPCTL_NAMES { \ { 0, 0 }, \ @@ -257,6 +312,10 @@ struct ip_mreq { { "mtu", CTLTYPE_INT }, \ { "sourceroute", CTLTYPE_INT }, \ { "directed-broadcast", CTLTYPE_INT }, \ + { "portfirst", CTLTYPE_INT }, \ + { "portlast", CTLTYPE_INT }, \ + { "porthifirst", CTLTYPE_INT }, \ + { "porthilast", CTLTYPE_INT }, \ } diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 90a6392fba7..a2b195ee83a 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.4 1996/05/14 19:37:34 deraadt Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.5 1996/07/29 02:34:29 downsj Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -60,6 +60,15 @@ struct in_addr zeroin_addr; +/* + * These configure the range of local port addresses assigned to + * "unspecified" outgoing connections/packets/whatever. + */ +int ipport_firstauto = IPPORT_RESERVED; /* 1024 */ +int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */ +int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 40000 */ +int ipport_hilastauto = IPPORT_HILASTAUTO; /* 44999 */ + #define INPCBHASH(table, faddr, fport, laddr, lport) \ &(table)->inpt_hashtbl[(ntohl((faddr)->s_addr) + ntohs((fport)) + ntohs((lport))) & (table->inpt_hash)] @@ -106,6 +115,7 @@ in_pcbbind(v, nam) register struct inpcb *inp = v; register struct socket *so = inp->inp_socket; register struct inpcbtable *table = inp->inp_table; + u_int16_t *lastport = &inp->inp_table->inpt_lastport; register struct sockaddr_in *sin; struct proc *p = curproc; /* XXX */ u_int16_t lport = 0; @@ -170,14 +180,62 @@ in_pcbbind(v, nam) } inp->inp_laddr = sin->sin_addr; } - if (lport == 0) - do { - if (table->inpt_lastport++ < IPPORT_RESERVED || - table->inpt_lastport > IPPORT_USERRESERVED) - table->inpt_lastport = IPPORT_RESERVED; - lport = htons(table->inpt_lastport); - } while (in_pcblookup(table, - zeroin_addr, 0, inp->inp_laddr, lport, wild)); + if (lport == 0) { + 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 + * a deadlock here. + * + * We split the two cases (up and down) so that the direction + * is not being tested on each round of the loop. + */ + if (first > last) { + /* + * counting down + */ + count = first - last; + + do { + if (count-- <= 0) /* completely used? */ + return (EADDRNOTAVAIL); + --*lastport; + if (*lastport > first || *lastport < last) + *lastport = first; + lport = htons(*lastport); + } while (in_pcblookup(table, + zeroin_addr, 0, inp->inp_laddr, lport, wild)); + } else { + /* + * counting up + */ + count = last - first; + + do { + if (count-- <= 0) /* completely used? */ + return (EADDRNOTAVAIL); + ++*lastport; + if (*lastport < first || *lastport > last) + *lastport = first; + lport = htons(*lastport); + } while (in_pcblookup(table, + zeroin_addr, 0, inp->inp_laddr, lport, wild)); + } + } inp->inp_lport = lport; in_pcbrehash(inp); return (0); diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 6a533ca4703..32f8116678d 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.h,v 1.2 1996/03/03 22:30:32 niklas Exp $ */ +/* $OpenBSD: in_pcb.h,v 1.3 1996/07/29 02:34:30 downsj Exp $ */ /* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */ /* @@ -75,6 +75,8 @@ struct inpcbtable { #define INP_RECVDSTADDR 0x04 /* receive IP dst address */ #define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR) #define INP_HDRINCL 0x08 /* user supplies entire IP header */ +#define INP_HIGHPORT 0x10 /* user wants "high" port binding */ +#define INP_LOWPORT 0x20 /* user wants "low" port binding */ #define INPLOOKUP_WILDCARD 1 #define INPLOOKUP_SETLOCAL 2 diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 5b8b0ba031f..1c9149297ce 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_input.c,v 1.13 1996/07/18 05:01:04 dm Exp $ */ +/* $OpenBSD: ip_input.c,v 1.14 1996/07/29 02:34:30 downsj Exp $ */ /* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */ /* @@ -93,6 +93,12 @@ int ip_directedbcast = IPDIRECTEDBCAST; int ipprintfs = 0; #endif +/* from in_pcb.c */ +extern int ipport_firstauto; +extern int ipport_lastauto; +extern int ipport_hifirstauto; +extern int ipport_hilastauto; + extern struct domain inetdomain; extern struct protosw inetsw[]; u_char ip_protox[IPPROTO_MAX]; @@ -1221,6 +1227,18 @@ ip_sysctl(name, namelen, oldp, oldlenp, newp, newlen) case IPCTL_DIRECTEDBCAST: return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_directedbcast)); + case IPCTL_IPPORT_FIRSTAUTO: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &ipport_firstauto)); + case IPCTL_IPPORT_LASTAUTO: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &ipport_lastauto)); + case IPCTL_IPPORT_HIFIRSTAUTO: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &ipport_hifirstauto)); + case IPCTL_IPPORT_HILASTAUTO: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &ipport_hilastauto)); default: return (EOPNOTSUPP); } diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 4cf3e2f7fce..2b31d8dd9f2 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.5 1996/03/04 10:34:33 mickey Exp $ */ +/* $OpenBSD: ip_output.c,v 1.6 1996/07/29 02:34:31 downsj Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -583,6 +583,37 @@ 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: + inp->inp_flags &= ~(INP_LOWPORT); + inp->inp_flags &= ~(INP_HIGHPORT); + break; + + case IP_PORTRANGE_HIGH: + inp->inp_flags &= ~(INP_LOWPORT); + inp->inp_flags |= INP_HIGHPORT; + break; + + case IP_PORTRANGE_LOW: + inp->inp_flags &= ~(INP_HIGHPORT); + inp->inp_flags |= INP_LOWPORT; + break; + + default: + + error = EINVAL; + break; + } + } + break; + default: error = ENOPROTOOPT; break; @@ -646,6 +677,20 @@ 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_HIGHPORT) + optval = IP_PORTRANGE_HIGH; + else if (inp->inp_flags & INP_LOWPORT) + optval = IP_PORTRANGE_LOW; + else + optval = 0; + + *mtod(m, int *) = optval; + break; + default: error = ENOPROTOOPT; break; |