summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2018-10-23 08:22:44 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2018-10-25 08:38:45 +0200
commitb3169c2a6a01cc0555181f61b5254dd2c1f1c310 (patch)
treef84d67c9d17b2625481513fa6dc85929fdb08442 /freebsd/sys/netinet6
parentUpdate rtems_waf (diff)
downloadrtems-libbsd-b3169c2a6a01cc0555181f61b5254dd2c1f1c310.tar.bz2
Update to FreeBSD head 2018-10-23
Git mirror commit 59f44d20be3f99d181ca742e636d45fc39ec982b. This commit updates OpenSSL to version 1.1.1. This required an update of racoon which uses some internal stuff from OpenSSL and seems to be mostly unmaintained, e.g. there is update in the FreeBSD ports to cope with OpenSSL 1.1.1. Update #3472.
Diffstat (limited to 'freebsd/sys/netinet6')
-rw-r--r--freebsd/sys/netinet6/icmp6.c4
-rw-r--r--freebsd/sys/netinet6/in6.c8
-rw-r--r--freebsd/sys/netinet6/in6_gif.c60
-rw-r--r--freebsd/sys/netinet6/in6_pcb.c38
-rw-r--r--freebsd/sys/netinet6/udp6_usrreq.c66
5 files changed, 135 insertions, 41 deletions
diff --git a/freebsd/sys/netinet6/icmp6.c b/freebsd/sys/netinet6/icmp6.c
index 2b080169..6dd25e98 100644
--- a/freebsd/sys/netinet6/icmp6.c
+++ b/freebsd/sys/netinet6/icmp6.c
@@ -1950,6 +1950,10 @@ icmp6_rip6_input(struct mbuf **mp, int off)
!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src))
continue;
INP_RLOCK(in6p);
+ if (__predict_false(in6p->inp_flags2 & INP_FREED)) {
+ INP_RUNLOCK(in6p);
+ continue;
+ }
if (ICMP6_FILTER_WILLBLOCK(icmp6->icmp6_type,
in6p->in6p_icmp6filt)) {
INP_RUNLOCK(in6p);
diff --git a/freebsd/sys/netinet6/in6.c b/freebsd/sys/netinet6/in6.c
index c415cf78..ef59203e 100644
--- a/freebsd/sys/netinet6/in6.c
+++ b/freebsd/sys/netinet6/in6.c
@@ -716,7 +716,8 @@ aifaddr_out:
ND6_WUNLOCK();
nd6_prefix_del(pr);
}
- EVENTHANDLER_INVOKE(ifaddr_event, ifp);
+ EVENTHANDLER_INVOKE(ifaddr_event_ext, ifp, &ia->ia_ifa,
+ IFADDR_EVENT_DEL);
break;
}
@@ -1460,7 +1461,10 @@ done:
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
"Invoking IPv6 network device address event may sleep");
- EVENTHANDLER_INVOKE(ifaddr_event, ifp);
+ ifa_ref(&ia->ia_ifa);
+ EVENTHANDLER_INVOKE(ifaddr_event_ext, ifp, &ia->ia_ifa,
+ IFADDR_EVENT_ADD);
+ ifa_free(&ia->ia_ifa);
return (error);
}
diff --git a/freebsd/sys/netinet6/in6_gif.c b/freebsd/sys/netinet6/in6_gif.c
index 66b4c63a..66c2cfb4 100644
--- a/freebsd/sys/netinet6/in6_gif.c
+++ b/freebsd/sys/netinet6/in6_gif.c
@@ -89,12 +89,16 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim,
* Interfaces with GIF_IGNORE_SOURCE flag are linked into plain list.
*/
VNET_DEFINE_STATIC(struct gif_list *, ipv6_hashtbl) = NULL;
+VNET_DEFINE_STATIC(struct gif_list *, ipv6_srchashtbl) = NULL;
VNET_DEFINE_STATIC(struct gif_list, ipv6_list) = CK_LIST_HEAD_INITIALIZER();
#define V_ipv6_hashtbl VNET(ipv6_hashtbl)
+#define V_ipv6_srchashtbl VNET(ipv6_srchashtbl)
#define V_ipv6_list VNET(ipv6_list)
#define GIF_HASH(src, dst) (V_ipv6_hashtbl[\
in6_gif_hashval((src), (dst)) & (GIF_HASH_SIZE - 1)])
+#define GIF_SRCHASH(src) (V_ipv6_srchashtbl[\
+ fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (GIF_HASH_SIZE - 1)])
#define GIF_HASH_SC(sc) GIF_HASH(&(sc)->gif_ip6hdr->ip6_src,\
&(sc)->gif_ip6hdr->ip6_dst)
static uint32_t
@@ -127,6 +131,43 @@ in6_gif_checkdup(const struct gif_softc *sc, const struct in6_addr *src,
return (0);
}
+/*
+ * Check that ingress address belongs to local host.
+ */
+static void
+in6_gif_set_running(struct gif_softc *sc)
+{
+
+ if (in6_localip(&sc->gif_ip6hdr->ip6_src))
+ GIF2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING;
+ else
+ GIF2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
+}
+
+/*
+ * ifaddr_event handler.
+ * Clear IFF_DRV_RUNNING flag when ingress address disappears to prevent
+ * source address spoofing.
+ */
+static void
+in6_gif_srcaddr(void *arg __unused, const struct sockaddr *sa, int event)
+{
+ const struct sockaddr_in6 *sin;
+ struct gif_softc *sc;
+
+ if (V_ipv6_srchashtbl == NULL)
+ return;
+
+ MPASS(in_epoch(net_epoch_preempt));
+ sin = (const struct sockaddr_in6 *)sa;
+ CK_LIST_FOREACH(sc, &GIF_SRCHASH(&sin->sin6_addr), srchash) {
+ if (IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_src,
+ &sin->sin6_addr) == 0)
+ continue;
+ in6_gif_set_running(sc);
+ }
+}
+
static void
in6_gif_attach(struct gif_softc *sc)
{
@@ -135,6 +176,9 @@ in6_gif_attach(struct gif_softc *sc)
CK_LIST_INSERT_HEAD(&V_ipv6_list, sc, chain);
else
CK_LIST_INSERT_HEAD(&GIF_HASH_SC(sc), sc, chain);
+
+ CK_LIST_INSERT_HEAD(&GIF_SRCHASH(&sc->gif_ip6hdr->ip6_src),
+ sc, srchash);
}
int
@@ -147,6 +191,7 @@ in6_gif_setopts(struct gif_softc *sc, u_int options)
if ((options & GIF_IGNORE_SOURCE) !=
(sc->gif_options & GIF_IGNORE_SOURCE)) {
+ CK_LIST_REMOVE(sc, srchash);
CK_LIST_REMOVE(sc, chain);
sc->gif_options = options;
in6_gif_attach(sc);
@@ -189,8 +234,10 @@ in6_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
(error = sa6_embedscope(dst, 0)) != 0)
break;
- if (V_ipv6_hashtbl == NULL)
+ if (V_ipv6_hashtbl == NULL) {
V_ipv6_hashtbl = gif_hashinit();
+ V_ipv6_srchashtbl = gif_hashinit();
+ }
error = in6_gif_checkdup(sc, &src->sin6_addr,
&dst->sin6_addr);
if (error == EADDRNOTAVAIL)
@@ -206,6 +253,7 @@ in6_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
ip6->ip6_vfc = IPV6_VERSION;
if (sc->gif_family != 0) {
/* Detach existing tunnel first */
+ CK_LIST_REMOVE(sc, srchash);
CK_LIST_REMOVE(sc, chain);
GIF_WAIT();
free(sc->gif_hdr, M_GIF);
@@ -214,6 +262,7 @@ in6_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
sc->gif_family = AF_INET6;
sc->gif_ip6hdr = ip6;
in6_gif_attach(sc);
+ in6_gif_set_running(sc);
break;
case SIOCGIFPSRCADDR_IN6:
case SIOCGIFPDSTADDR_IN6:
@@ -367,6 +416,7 @@ done:
return (ret);
}
+static const struct srcaddrtab *ipv6_srcaddrtab;
static struct {
const struct encap_config encap;
const struct encaptab *cookie;
@@ -412,6 +462,9 @@ in6_gif_init(void)
if (!IS_DEFAULT_VNET(curvnet))
return;
+
+ ipv6_srcaddrtab = ip6_encap_register_srcaddr(in6_gif_srcaddr,
+ NULL, M_WAITOK);
for (i = 0; i < nitems(ipv6_encap_cfg); i++)
ipv6_encap_cfg[i].cookie = ip6_encap_attach(
&ipv6_encap_cfg[i].encap, NULL, M_WAITOK);
@@ -425,7 +478,10 @@ in6_gif_uninit(void)
if (IS_DEFAULT_VNET(curvnet)) {
for (i = 0; i < nitems(ipv6_encap_cfg); i++)
ip6_encap_detach(ipv6_encap_cfg[i].cookie);
+ ip6_encap_unregister_srcaddr(ipv6_srcaddrtab);
}
- if (V_ipv6_hashtbl != NULL)
+ if (V_ipv6_hashtbl != NULL) {
gif_hashdestroy(V_ipv6_hashtbl);
+ gif_hashdestroy(V_ipv6_srchashtbl);
+ }
}
diff --git a/freebsd/sys/netinet6/in6_pcb.c b/freebsd/sys/netinet6/in6_pcb.c
index a30cb98b..53102764 100644
--- a/freebsd/sys/netinet6/in6_pcb.c
+++ b/freebsd/sys/netinet6/in6_pcb.c
@@ -823,6 +823,10 @@ in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp)
INP_INFO_WLOCK(pcbinfo);
CK_LIST_FOREACH(in6p, pcbinfo->ipi_listhead, inp_list) {
INP_WLOCK(in6p);
+ if (__predict_false(in6p->inp_flags2 & INP_FREED)) {
+ INP_WUNLOCK(in6p);
+ continue;
+ }
im6o = in6p->in6p_moptions;
if ((in6p->inp_vflag & INP_IPV6) && im6o != NULL) {
/*
@@ -883,10 +887,9 @@ in6_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo,
const struct in6_addr *laddr, uint16_t lport, const struct in6_addr *faddr,
uint16_t fport, int lookupflags)
{
- struct inpcb *local_wild = NULL;
+ struct inpcb *local_wild;
const struct inpcblbgrouphead *hdr;
struct inpcblbgroup *grp;
- struct inpcblbgroup *grp_local_wild;
uint32_t idx;
INP_HASH_LOCK_ASSERT(pcbinfo);
@@ -903,33 +906,24 @@ in6_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo,
* - Load balanced group does not contain jailed sockets.
* - Load balanced does not contain IPv4 mapped INET6 wild sockets.
*/
+ local_wild = NULL;
CK_LIST_FOREACH(grp, hdr, il_list) {
#ifdef INET
if (!(grp->il_vflag & INP_IPV6))
continue;
#endif
- if (grp->il_lport == lport) {
- idx = 0;
- int pkt_hash = INP_PCBLBGROUP_PKTHASH(
- INP6_PCBHASHKEY(faddr), lport, fport);
-
- idx = pkt_hash % grp->il_inpcnt;
+ if (grp->il_lport != lport)
+ continue;
- if (IN6_ARE_ADDR_EQUAL(&grp->il6_laddr, laddr)) {
- return (grp->il_inp[idx]);
- } else {
- if (IN6_IS_ADDR_UNSPECIFIED(&grp->il6_laddr) &&
- (lookupflags & INPLOOKUP_WILDCARD)) {
- local_wild = grp->il_inp[idx];
- grp_local_wild = grp;
- }
- }
- }
+ idx = INP_PCBLBGROUP_PKTHASH(INP6_PCBHASHKEY(faddr), lport,
+ fport) % grp->il_inpcnt;
+ if (IN6_ARE_ADDR_EQUAL(&grp->il6_laddr, laddr))
+ return (grp->il_inp[idx]);
+ if (IN6_IS_ADDR_UNSPECIFIED(&grp->il6_laddr) &&
+ (lookupflags & INPLOOKUP_WILDCARD) != 0)
+ local_wild = grp->il_inp[idx];
}
- if (local_wild != NULL) {
- return (local_wild);
- }
- return (NULL);
+ return (local_wild);
}
#ifdef PCBGROUP
diff --git a/freebsd/sys/netinet6/udp6_usrreq.c b/freebsd/sys/netinet6/udp6_usrreq.c
index 67ed0e35..e0fcd06d 100644
--- a/freebsd/sys/netinet6/udp6_usrreq.c
+++ b/freebsd/sys/netinet6/udp6_usrreq.c
@@ -436,8 +436,8 @@ udp6_input(struct mbuf **mp, int *offp, int proto)
INP_RUNLOCK(last);
} else
INP_RUNLOCK(last);
- INP_INFO_RUNLOCK_ET(pcbinfo, et);
inp_lost:
+ INP_INFO_RUNLOCK_ET(pcbinfo, et);
return (IPPROTO_DONE);
}
/*
@@ -700,7 +700,7 @@ udp6_output(struct socket *so, int flags_arg, struct mbuf *m,
u_int32_t ulen, plen;
uint16_t cscov;
u_short fport;
- uint8_t nxt, unlock_udbinfo;
+ uint8_t nxt, unlock_inp, unlock_udbinfo;
/* addr6 has been validated in udp6_send(). */
sin6 = (struct sockaddr_in6 *)addr6;
@@ -736,7 +736,22 @@ udp6_output(struct socket *so, int flags_arg, struct mbuf *m,
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("%s: inp == NULL", __func__));
- INP_RLOCK(inp);
+ /*
+ * In the following cases we want a write lock on the inp for either
+ * local operations or for possible route cache updates in the IPv6
+ * output path:
+ * - on connected sockets (sin6 is NULL) for route cache updates,
+ * - when we are not bound to an address and source port (it is
+ * in6_pcbsetport() which will require the write lock).
+ */
+ if (sin6 == NULL || (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) &&
+ inp->inp_lport == 0)) {
+ INP_WLOCK(inp);
+ unlock_inp = UH_WLOCKED;
+ } else {
+ INP_RLOCK(inp);
+ unlock_inp = UH_RLOCKED;
+ }
nxt = (inp->inp_socket->so_proto->pr_protocol == IPPROTO_UDP) ?
IPPROTO_UDP : IPPROTO_UDPLITE;
@@ -760,7 +775,10 @@ udp6_output(struct socket *so, int flags_arg, struct mbuf *m,
* potential race in which the factors causing us to
* select the UDPv4 output routine are invalidated?
*/
- INP_RUNLOCK(inp);
+ if (unlock_inp == UH_WLOCKED)
+ INP_WUNLOCK(inp);
+ else
+ INP_RUNLOCK(inp);
if (sin6)
in6_sin6_2_sin_in_sock((struct sockaddr *)sin6);
pru = inetsw[ip_protox[nxt]].pr_usrreqs;
@@ -768,13 +786,28 @@ udp6_output(struct socket *so, int flags_arg, struct mbuf *m,
return ((*pru->pru_send)(so, flags_arg, m,
(struct sockaddr *)sin6, control, td));
}
- }
+ } else
#endif
+ if (sin6 && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
+ /*
+ * Given this is either an IPv6-only socket or no INET is
+ * supported we will fail the send if the given destination
+ * address is a v4mapped address.
+ */
+ if (unlock_inp == UH_WLOCKED)
+ INP_WUNLOCK(inp);
+ else
+ INP_RUNLOCK(inp);
+ return (EINVAL);
+ }
if (control) {
if ((error = ip6_setpktopts(control, &opt,
inp->in6p_outputopts, td->td_ucred, nxt)) != 0) {
- INP_RUNLOCK(inp);
+ if (unlock_inp == UH_WLOCKED)
+ INP_WUNLOCK(inp);
+ else
+ INP_RUNLOCK(inp);
ip6_clearpktopts(&opt, -1);
if (control)
m_freem(control);
@@ -788,12 +821,6 @@ udp6_output(struct socket *so, int flags_arg, struct mbuf *m,
pcbinfo = udp_get_inpcbinfo(so->so_proto->pr_protocol);
if (sin6 != NULL &&
IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) && inp->inp_lport == 0) {
- INP_RUNLOCK(inp);
- /*
- * XXX there is a short window here which could lead to a race;
- * should we re-check that what got us here is still valid?
- */
- INP_WLOCK(inp);
INP_HASH_WLOCK(pcbinfo);
unlock_udbinfo = UH_WLOCKED;
} else if (sin6 != NULL &&
@@ -974,9 +1001,10 @@ udp6_output(struct socket *so, int flags_arg, struct mbuf *m,
UDPLITE_PROBE(send, NULL, inp, ip6, inp, udp6);
else
UDP_PROBE(send, NULL, inp, ip6, inp, udp6);
- error = ip6_output(m, optp, &inp->inp_route6, flags,
+ error = ip6_output(m, optp,
+ (unlock_inp == UH_WLOCKED) ? &inp->inp_route6 : NULL, flags,
inp->in6p_moptions, NULL, inp);
- if (unlock_udbinfo == UH_WLOCKED)
+ if (unlock_inp == UH_WLOCKED)
INP_WUNLOCK(inp);
else
INP_RUNLOCK(inp);
@@ -989,12 +1017,20 @@ udp6_output(struct socket *so, int flags_arg, struct mbuf *m,
release:
if (unlock_udbinfo == UH_WLOCKED) {
+ KASSERT(unlock_inp == UH_WLOCKED, ("%s: excl udbinfo lock, "
+ "non-excl inp lock: pcbinfo %p %#x inp %p %#x",
+ __func__, pcbinfo, unlock_udbinfo, inp, unlock_inp));
INP_HASH_WUNLOCK(pcbinfo);
INP_WUNLOCK(inp);
} else if (unlock_udbinfo == UH_RLOCKED) {
+ KASSERT(unlock_inp == UH_RLOCKED, ("%s: non-excl udbinfo lock, "
+ "excl inp lock: pcbinfo %p %#x inp %p %#x",
+ __func__, pcbinfo, unlock_udbinfo, inp, unlock_inp));
INP_HASH_RUNLOCK_ET(pcbinfo, et);
INP_RUNLOCK(inp);
- } else
+ } else if (unlock_inp == UH_WLOCKED)
+ INP_WUNLOCK(inp);
+ else
INP_RUNLOCK(inp);
if (control) {
ip6_clearpktopts(&opt, -1);