diff options
author | Vincent Gross <vgross@cvs.openbsd.org> | 2016-03-21 21:21:36 +0000 |
---|---|---|
committer | Vincent Gross <vgross@cvs.openbsd.org> | 2016-03-21 21:21:36 +0000 |
commit | 3398b845bea90b6e21e6ee578d08773e2f2575d4 (patch) | |
tree | fdbc2d47b07cb5d96c293595b367788ed8ca1320 /sys | |
parent | e7a2cc500fe2a74821ba762fa07a21e438b09509 (diff) |
Extract in6_pcbaddrisavail() from in6_pcbbind(), and use it when
checking for source availability in udp6_output(); This time with
all the files.
Ok jca@ bluhm@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/in_pcb.h | 4 | ||||
-rw-r--r-- | sys/netinet6/in6_pcb.c | 193 | ||||
-rw-r--r-- | sys/netinet6/udp6_output.c | 25 |
3 files changed, 114 insertions, 108 deletions
diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 25d7b9b44ad..a22d85bc15d 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.h,v 1.93 2015/12/03 10:34:24 tedu Exp $ */ +/* $OpenBSD: in_pcb.h,v 1.94 2016/03/21 21:21:35 vgross Exp $ */ /* $NetBSD: in_pcb.h,v 1.14 1996/02/13 23:42:00 christos Exp $ */ /* @@ -262,6 +262,8 @@ struct inpcb * struct in6_addr *, u_int, int, struct mbuf *, u_int); int in6_pcbbind(struct inpcb *, struct mbuf *, struct proc *); +int in6_pcbaddrisavail(struct inpcb *, struct sockaddr_in6 *, int, + struct proc *); int in6_pcbconnect(struct inpcb *, struct mbuf *); int in6_setsockaddr(struct inpcb *, struct mbuf *); int in6_setpeeraddr(struct inpcb *, struct mbuf *); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 2c093a852a4..66a59f8e618 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_pcb.c,v 1.87 2016/03/20 01:26:30 jca Exp $ */ +/* $OpenBSD: in6_pcb.c,v 1.88 2016/03/21 21:21:35 vgross Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -158,10 +158,9 @@ in6_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p) { struct socket *so = inp->inp_socket; - struct inpcbtable *head = inp->inp_table; struct sockaddr_in6 *sin6; u_short lport = 0; - int wild = INPLOOKUP_IPV6, reuseport = (so->so_options & SO_REUSEPORT); + int wild = INPLOOKUP_IPV6; int error; /* @@ -194,95 +193,10 @@ in6_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p) if (sin6->sin6_family != AF_INET6) return EAFNOSUPPORT; - /* KAME hack: embed scopeid */ - if (in6_embedscope(&sin6->sin6_addr, sin6, inp) != 0) - return EINVAL; - /* this must be cleared for ifa_ifwithaddr() */ - sin6->sin6_scope_id = 0; - - lport = sin6->sin6_port; - - /* reject IPv4 mapped address, we have no support for it */ - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) - return EADDRNOTAVAIL; - - if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { - /* - * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; - * allow complete duplication of binding if - * SO_REUSEPORT is set, or if SO_REUSEADDR is set - * and a multicast address is bound on both - * new and duplicated sockets. - */ - if (so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) - reuseport = SO_REUSEADDR | SO_REUSEPORT; - } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { - struct ifaddr *ifa = NULL; - - sin6->sin6_port = 0; /* - * Yechhhh, because of upcoming - * call to ifa_ifwithaddr(), which - * does bcmp's over the PORTS as - * well. (What about flow?) - */ - sin6->sin6_flowinfo = 0; - if (!(so->so_options & SO_BINDANY) && - (ifa = ifa_ifwithaddr(sin6tosa(sin6), - inp->inp_rtableid)) == NULL) - return EADDRNOTAVAIL; - - /* - * bind to an anycast address might accidentally - * cause sending a packet with an anycast source - * address, so we forbid it. - * - * We should allow to bind to a deprecated address, - * since the application dare to use it. - * But, can we assume that they are careful enough - * to check if the address is deprecated or not? - * Maybe, as a safeguard, we should have a setsockopt - * flag to control the bind(2) behavior against - * deprecated addresses (default: forbid bind(2)). - */ - if (ifa && - ifatoia6(ifa)->ia6_flags & - (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) - return (EADDRNOTAVAIL); - } - if (lport) { - struct inpcb *t; - - /* - * Question: Do we wish to continue the Berkeley - * tradition of ports < IPPORT_RESERVED be only for - * root? - * Answer: For now yes, but IMHO, it should be REMOVED! - * OUCH: One other thing, is there no better way of - * finding a process for a socket instead of using - * curproc? (Marked with BSD's {in,}famous XXX ? - */ - if (ntohs(lport) < IPPORT_RESERVED && - (error = suser(p, 0))) - return error; - if (so->so_euid) { - t = in_pcblookup(head, - (struct in_addr *)&zeroin6_addr, 0, - (struct in_addr *)&sin6->sin6_addr, lport, - INPLOOKUP_WILDCARD | INPLOOKUP_IPV6, - inp->inp_rtableid); - if (t && - (so->so_euid != t->inp_socket->so_euid)) - return EADDRINUSE; - } - t = in_pcblookup(head, - (struct in_addr *)&zeroin6_addr, 0, - (struct in_addr *)&sin6->sin6_addr, lport, - wild, inp->inp_rtableid); - - if (t && (reuseport & t->inp_socket->so_options) == 0) - return EADDRINUSE; - } + if ((error = in6_pcbaddrisavail(inp, sin6, wild, p))) + return (error); inp->inp_laddr6 = sin6->sin6_addr; + lport = sin6->sin6_port; } if (lport == 0) @@ -293,6 +207,103 @@ in6_pcbbind(struct inpcb *inp, struct mbuf *nam, struct proc *p) return 0; } +int +in6_pcbaddrisavail(struct inpcb *inp, struct sockaddr_in6 *sin6, int wild, + struct proc *p) +{ + struct socket *so = inp->inp_socket; + struct inpcbtable *table = inp->inp_table; + u_short lport = sin6->sin6_port; + int reuseport = (so->so_options & SO_REUSEPORT); + int error; + + wild |= INPLOOKUP_IPV6; + /* KAME hack: embed scopeid */ + if (in6_embedscope(&sin6->sin6_addr, sin6, inp) != 0) + return (EINVAL); + /* this must be cleared for ifa_ifwithaddr() */ + sin6->sin6_scope_id = 0; + /* reject IPv4 mapped address, we have no support for it */ + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + return (EADDRNOTAVAIL); + + if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { + /* + * Treat SO_REUSEADDR as SO_REUSEPORT for multicast; + * allow complete duplication of binding if + * SO_REUSEPORT is set, or if SO_REUSEADDR is set + * and a multicast address is bound on both + * new and duplicated sockets. + */ + if (so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) + reuseport = SO_REUSEADDR | SO_REUSEPORT; + } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + struct ifaddr *ifa = NULL; + + sin6->sin6_port = 0; /* + * Yechhhh, because of upcoming + * call to ifa_ifwithaddr(), which + * does bcmp's over the PORTS as + * well. (What about flow?) + */ + sin6->sin6_flowinfo = 0; + if (!(so->so_options & SO_BINDANY) && + (ifa = ifa_ifwithaddr(sin6tosa(sin6), + inp->inp_rtableid)) == NULL) + return (EADDRNOTAVAIL); + sin6->sin6_port = lport; + + /* + * bind to an anycast address might accidentally + * cause sending a packet with an anycast source + * address, so we forbid it. + * + * We should allow to bind to a deprecated address, + * since the application dare to use it. + * But, can we assume that they are careful enough + * to check if the address is deprecated or not? + * Maybe, as a safeguard, we should have a setsockopt + * flag to control the bind(2) behavior against + * deprecated addresses (default: forbid bind(2)). + */ + if (ifa && + ifatoia6(ifa)->ia6_flags & + (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) + return (EADDRNOTAVAIL); + } + if (lport) { + struct inpcb *t; + + /* + * Question: Do we wish to continue the Berkeley + * tradition of ports < IPPORT_RESERVED be only for + * root? + * Answer: For now yes, but IMHO, it should be REMOVED! + * OUCH: One other thing, is there no better way of + * finding a process for a socket instead of using + * curproc? (Marked with BSD's {in,}famous XXX ? + */ + if (ntohs(lport) < IPPORT_RESERVED && (error = suser(p, 0))) + return error; + if (so->so_euid) { + t = in_pcblookup(table, + (struct in_addr *)&zeroin6_addr, 0, + (struct in_addr *)&sin6->sin6_addr, lport, + INPLOOKUP_WILDCARD | INPLOOKUP_IPV6, + inp->inp_rtableid); + if (t && (so->so_euid != t->inp_socket->so_euid)) + return (EADDRINUSE); + } + t = in_pcblookup(table, + (struct in_addr *)&zeroin6_addr, 0, + (struct in_addr *)&sin6->sin6_addr, lport, + wild, inp->inp_rtableid); + if (t && (reuseport & t->inp_socket->so_options) == 0) + return (EADDRINUSE); + } + return (0); +} + /* * Connect from a socket to a specified address. * Both address and port must be specified in argument sin6. diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c index 7717b056aab..a56bdd9a5a1 100644 --- a/sys/netinet6/udp6_output.c +++ b/sys/netinet6/udp6_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udp6_output.c,v 1.44 2016/03/20 01:26:30 jca Exp $ */ +/* $OpenBSD: udp6_output.c,v 1.45 2016/03/21 21:21:35 vgross Exp $ */ /* $KAME: udp6_output.c,v 1.21 2001/02/07 11:51:54 itojun Exp $ */ /* @@ -102,7 +102,7 @@ udp6_output(struct inpcb *in6p, struct mbuf *m, struct mbuf *addr6, struct udphdr *udp6; struct in6_addr *laddr, *faddr; struct ip6_pktopts *optp, opt; - struct sockaddr_in6 tmp; + struct sockaddr_in6 tmp, valid; struct proc *p = curproc; /* XXX */ u_short fport; @@ -168,21 +168,14 @@ udp6_output(struct inpcb *in6p, struct mbuf *m, struct mbuf *addr6, goto release; } - if (!IN6_ARE_ADDR_EQUAL(&in6p->inp_laddr6, laddr) && - (in6p->inp_socket->so_euid != 0)) { - struct inpcb *t; - - t = in_pcblookup(in6p->inp_table, - (struct in_addr *)&zeroin6_addr, 0, - (struct in_addr *)laddr, in6p->inp_lport, - (INPLOOKUP_WILDCARD | INPLOOKUP_IPV6), - in6p->inp_rtableid); - if (t && - (t->inp_socket->so_euid != - in6p->inp_socket->so_euid)) { - error = EADDRINUSE; + if (!IN6_ARE_ADDR_EQUAL(&in6p->inp_laddr6, laddr)) { + valid.sin6_addr = *laddr; + valid.sin6_port = in6p->inp_lport; + valid.sin6_family = AF_INET6; + valid.sin6_len = sizeof(valid); + error = in6_pcbaddrisavail(in6p, &valid, 0, p); + if (error) goto release; - } } } else { if (IN6_IS_ADDR_UNSPECIFIED(&in6p->inp_faddr6)) { |