diff options
-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; |