summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/in_pcb.h4
-rw-r--r--sys/netinet6/in6_pcb.c193
-rw-r--r--sys/netinet6/udp6_output.c25
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)) {