summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6/ip6_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet6/ip6_input.c')
-rw-r--r--freebsd/sys/netinet6/ip6_input.c215
1 files changed, 45 insertions, 170 deletions
diff --git a/freebsd/sys/netinet6/ip6_input.c b/freebsd/sys/netinet6/ip6_input.c
index 25ab624c..6800d002 100644
--- a/freebsd/sys/netinet6/ip6_input.c
+++ b/freebsd/sys/netinet6/ip6_input.c
@@ -205,9 +205,6 @@ struct rmlock in6_ifaddr_lock;
RM_SYSINIT(in6_ifaddr_lock, &in6_ifaddr_lock, "in6_ifaddr_lock");
static int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *);
-#ifdef PULLDOWN_TEST
-static struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int);
-#endif
/*
* IP6 initialization: fill in IP6 protocol switch table.
@@ -396,6 +393,7 @@ ip6_destroy(void *unused __unused)
}
IFNET_RUNLOCK();
+ frag6_destroy();
nd6_destroy();
in6_ifattach_destroy();
@@ -406,20 +404,22 @@ VNET_SYSUNINIT(inet6, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ip6_destroy, NULL);
#endif
static int
-ip6_input_hbh(struct mbuf *m, uint32_t *plen, uint32_t *rtalert, int *off,
+ip6_input_hbh(struct mbuf **mp, uint32_t *plen, uint32_t *rtalert, int *off,
int *nxt, int *ours)
{
+ struct mbuf *m;
struct ip6_hdr *ip6;
struct ip6_hbh *hbh;
- if (ip6_hopopts_input(plen, rtalert, &m, off)) {
+ if (ip6_hopopts_input(plen, rtalert, mp, off)) {
#if 0 /*touches NULL pointer*/
- in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard);
+ in6_ifstat_inc((*mp)->m_pkthdr.rcvif, ifs6_in_discard);
#endif
goto out; /* m have already been freed */
}
/* adjust pointer */
+ m = *mp;
ip6 = mtod(m, struct ip6_hdr *);
/*
@@ -441,17 +441,8 @@ ip6_input_hbh(struct mbuf *m, uint32_t *plen, uint32_t *rtalert, int *off,
(caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
goto out;
}
-#ifndef PULLDOWN_TEST
/* ip6_hopopts_input() ensures that mbuf is contiguous */
hbh = (struct ip6_hbh *)(ip6 + 1);
-#else
- IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
- sizeof(struct ip6_hbh));
- if (hbh == NULL) {
- IP6STAT_INC(ip6s_tooshort);
- goto out;
- }
-#endif
*nxt = hbh->ip6h_nxt;
/*
@@ -602,7 +593,6 @@ ip6_input(struct mbuf *m)
in6_ifstat_inc(rcvif, ifs6_in_receive);
IP6STAT_INC(ip6s_total);
-#ifndef PULLDOWN_TEST
/*
* L2 bridge code and some other code can return mbuf chain
* that does not conform to KAME requirement. too bad.
@@ -624,9 +614,6 @@ ip6_input(struct mbuf *m)
m_freem(m);
m = n;
}
- IP6_EXTHDR_CHECK(m, 0, sizeof(struct ip6_hdr), /* nothing */);
-#endif
-
if (m->m_len < sizeof(struct ip6_hdr)) {
if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
IP6STAT_INC(ip6s_toosmall);
@@ -693,11 +680,10 @@ ip6_input(struct mbuf *m)
* and bypass security checks (act as if it was from 127.0.0.1 by using
* IPv6 src ::ffff:127.0.0.1). Be cautious.
*
- * This check chokes if we are in an SIIT cloud. As none of BSDs
- * support IPv4-less kernel compilation, we cannot support SIIT
- * environment at all. So, it makes more sense for us to reject any
- * malicious packets for non-SIIT environment, than try to do a
- * partial support for SIIT environment.
+ * We have supported IPv6-only kernels for a few years and this issue
+ * has not come up. The world seems to move mostly towards not using
+ * v4mapped on the wire, so it makes sense for us to keep rejecting
+ * any such packets.
*/
if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
@@ -859,7 +845,7 @@ passin:
*/
plen = (u_int32_t)ntohs(ip6->ip6_plen);
if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
- if (ip6_input_hbh(m, &plen, &rtalert, &off, &nxt, &ours) != 0)
+ if (ip6_input_hbh(&m, &plen, &rtalert, &off, &nxt, &ours) != 0)
return;
} else
nxt = ip6->ip6_nxt;
@@ -915,24 +901,6 @@ passin:
return;
}
- ip6 = mtod(m, struct ip6_hdr *);
-
- /*
- * Malicious party may be able to use IPv4 mapped addr to confuse
- * tcp/udp stack and bypass security checks (act as if it was from
- * 127.0.0.1 by using IPv6 src ::ffff:127.0.0.1). Be cautious.
- *
- * For SIIT end node behavior, you may want to disable the check.
- * However, you will become vulnerable to attacks using IPv4 mapped
- * source.
- */
- if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
- IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
- IP6STAT_INC(ip6s_badscope);
- in6_ifstat_inc(rcvif, ifs6_in_addrerr);
- goto bad;
- }
-
/*
* Tell launch routine the next header
*/
@@ -987,33 +955,33 @@ ip6_hopopts_input(u_int32_t *plenp, u_int32_t *rtalertp,
struct ip6_hbh *hbh;
/* validation of the length of the header */
-#ifndef PULLDOWN_TEST
- IP6_EXTHDR_CHECK(m, off, sizeof(*hbh), -1);
+ if (m->m_len < off + sizeof(*hbh)) {
+ m = m_pullup(m, off + sizeof(*hbh));
+ if (m == NULL) {
+ IP6STAT_INC(ip6s_exthdrtoolong);
+ *mp = NULL;
+ return (-1);
+ }
+ }
hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
hbhlen = (hbh->ip6h_len + 1) << 3;
- IP6_EXTHDR_CHECK(m, off, hbhlen, -1);
- hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
-#else
- IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
- sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
- if (hbh == NULL) {
- IP6STAT_INC(ip6s_tooshort);
- return -1;
- }
- hbhlen = (hbh->ip6h_len + 1) << 3;
- IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
- hbhlen);
- if (hbh == NULL) {
- IP6STAT_INC(ip6s_tooshort);
- return -1;
+ if (m->m_len < off + hbhlen) {
+ m = m_pullup(m, off + hbhlen);
+ if (m == NULL) {
+ IP6STAT_INC(ip6s_exthdrtoolong);
+ *mp = NULL;
+ return (-1);
+ }
}
-#endif
+ hbh = (struct ip6_hbh *)(mtod(m, caddr_t) + off);
off += hbhlen;
hbhlen -= sizeof(struct ip6_hbh);
if (ip6_process_hopopts(m, (u_int8_t *)hbh + sizeof(struct ip6_hbh),
- hbhlen, rtalertp, plenp) < 0)
+ hbhlen, rtalertp, plenp) < 0) {
+ *mp = NULL;
return (-1);
+ }
*offp = off;
*mp = m;
@@ -1198,10 +1166,9 @@ ip6_unknown_opt(u_int8_t *optp, struct mbuf *m, int off)
* Create the "control" list for this pcb.
* These functions will not modify mbuf chain at all.
*
- * With KAME mbuf chain restriction:
* The routine will be called from upper layer handlers like tcp6_input().
* Thus the routine assumes that the caller (tcp6_input) have already
- * called IP6_EXTHDR_CHECK() and all the extension headers are located in the
+ * called m_pullup() and all the extension headers are located in the
* very first mbuf on the mbuf chain.
*
* ip6_savecontrol_v4 will handle those options that are possible to be
@@ -1409,15 +1376,16 @@ ip6_savecontrol_v4(struct inpcb *inp, struct mbuf *m, struct mbuf **mp,
}
void
-ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
+ip6_savecontrol(struct inpcb *inp, struct mbuf *m, struct mbuf **mp)
{
- struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
+ struct ip6_hdr *ip6;
int v4only = 0;
- mp = ip6_savecontrol_v4(in6p, m, mp, &v4only);
+ mp = ip6_savecontrol_v4(inp, m, mp, &v4only);
if (v4only)
return;
+ ip6 = mtod(m, struct ip6_hdr *);
/*
* IPV6_HOPOPTS socket option. Recall that we required super-user
* privilege for the option (see ip6_ctloutput), but it might be too
@@ -1425,7 +1393,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
* returned to normal user.
* See also RFC 2292 section 6 (or RFC 3542 section 8).
*/
- if ((in6p->inp_flags & IN6P_HOPOPTS) != 0) {
+ if ((inp->inp_flags & IN6P_HOPOPTS) != 0) {
/*
* Check if a hop-by-hop options header is contatined in the
* received packet, and if so, store the options as ancillary
@@ -1435,29 +1403,10 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
*/
if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
struct ip6_hbh *hbh;
- int hbhlen = 0;
-#ifdef PULLDOWN_TEST
- struct mbuf *ext;
-#endif
+ int hbhlen;
-#ifndef PULLDOWN_TEST
hbh = (struct ip6_hbh *)(ip6 + 1);
hbhlen = (hbh->ip6h_len + 1) << 3;
-#else
- ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr),
- ip6->ip6_nxt);
- if (ext == NULL) {
- IP6STAT_INC(ip6s_tooshort);
- return;
- }
- hbh = mtod(ext, struct ip6_hbh *);
- hbhlen = (hbh->ip6h_len + 1) << 3;
- if (hbhlen != ext->m_len) {
- m_freem(ext);
- IP6STAT_INC(ip6s_tooshort);
- return;
- }
-#endif
/*
* XXX: We copy the whole header even if a
@@ -1467,17 +1416,14 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
* Note: this constraint is removed in RFC3542
*/
*mp = sbcreatecontrol((caddr_t)hbh, hbhlen,
- IS2292(in6p, IPV6_2292HOPOPTS, IPV6_HOPOPTS),
+ IS2292(inp, IPV6_2292HOPOPTS, IPV6_HOPOPTS),
IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
-#ifdef PULLDOWN_TEST
- m_freem(ext);
-#endif
}
}
- if ((in6p->inp_flags & (IN6P_RTHDR | IN6P_DSTOPTS)) != 0) {
+ if ((inp->inp_flags & (IN6P_RTHDR | IN6P_DSTOPTS)) != 0) {
int nxt = ip6->ip6_nxt, off = sizeof(struct ip6_hdr);
/*
@@ -1490,9 +1436,6 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
while (1) { /* is explicit loop prevention necessary? */
struct ip6_ext *ip6e = NULL;
int elen;
-#ifdef PULLDOWN_TEST
- struct mbuf *ext = NULL;
-#endif
/*
* if it is not an extension header, don't try to
@@ -1508,7 +1451,6 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
goto loopend;
}
-#ifndef PULLDOWN_TEST
if (off + sizeof(*ip6e) > m->m_len)
goto loopend;
ip6e = (struct ip6_ext *)(mtod(m, caddr_t) + off);
@@ -1518,42 +1460,25 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
elen = (ip6e->ip6e_len + 1) << 3;
if (off + elen > m->m_len)
goto loopend;
-#else
- ext = ip6_pullexthdr(m, off, nxt);
- if (ext == NULL) {
- IP6STAT_INC(ip6s_tooshort);
- return;
- }
- ip6e = mtod(ext, struct ip6_ext *);
- if (nxt == IPPROTO_AH)
- elen = (ip6e->ip6e_len + 2) << 2;
- else
- elen = (ip6e->ip6e_len + 1) << 3;
- if (elen != ext->m_len) {
- m_freem(ext);
- IP6STAT_INC(ip6s_tooshort);
- return;
- }
-#endif
switch (nxt) {
case IPPROTO_DSTOPTS:
- if (!(in6p->inp_flags & IN6P_DSTOPTS))
+ if (!(inp->inp_flags & IN6P_DSTOPTS))
break;
*mp = sbcreatecontrol((caddr_t)ip6e, elen,
- IS2292(in6p,
+ IS2292(inp,
IPV6_2292DSTOPTS, IPV6_DSTOPTS),
IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
break;
case IPPROTO_ROUTING:
- if (!(in6p->inp_flags & IN6P_RTHDR))
+ if (!(inp->inp_flags & IN6P_RTHDR))
break;
*mp = sbcreatecontrol((caddr_t)ip6e, elen,
- IS2292(in6p, IPV6_2292RTHDR, IPV6_RTHDR),
+ IS2292(inp, IPV6_2292RTHDR, IPV6_RTHDR),
IPPROTO_IPV6);
if (*mp)
mp = &(*mp)->m_next;
@@ -1569,9 +1494,6 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
* the code just in case (nxt overwritten or
* other cases).
*/
-#ifdef PULLDOWN_TEST
- m_freem(ext);
-#endif
goto loopend;
}
@@ -1580,16 +1502,12 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
off += elen;
nxt = ip6e->ip6e_nxt;
ip6e = NULL;
-#ifdef PULLDOWN_TEST
- m_freem(ext);
- ext = NULL;
-#endif
}
loopend:
;
}
- if (in6p->inp_flags2 & INP_RECVFLOWID) {
+ if (inp->inp_flags2 & INP_RECVFLOWID) {
uint32_t flowid, flow_type;
flowid = m->m_pkthdr.flowid;
@@ -1610,7 +1528,7 @@ ip6_savecontrol(struct inpcb *in6p, struct mbuf *m, struct mbuf **mp)
}
#ifdef RSS
- if (in6p->inp_flags2 & INP_RECVRSSBUCKETID) {
+ if (inp->inp_flags2 & INP_RECVRSSBUCKETID) {
uint32_t flowid, flow_type;
uint32_t rss_bucketid;
@@ -1669,49 +1587,6 @@ ip6_notify_pmtu(struct inpcb *inp, struct sockaddr_in6 *dst, u_int32_t mtu)
sorwakeup(so);
}
-#ifdef PULLDOWN_TEST
-/*
- * pull single extension header from mbuf chain. returns single mbuf that
- * contains the result, or NULL on error.
- */
-static struct mbuf *
-ip6_pullexthdr(struct mbuf *m, size_t off, int nxt)
-{
- struct ip6_ext ip6e;
- size_t elen;
- struct mbuf *n;
-
-#ifdef DIAGNOSTIC
- switch (nxt) {
- case IPPROTO_DSTOPTS:
- case IPPROTO_ROUTING:
- case IPPROTO_HOPOPTS:
- case IPPROTO_AH: /* is it possible? */
- break;
- default:
- printf("ip6_pullexthdr: invalid nxt=%d\n", nxt);
- }
-#endif
-
- m_copydata(m, off, sizeof(ip6e), (caddr_t)&ip6e);
- if (nxt == IPPROTO_AH)
- elen = (ip6e.ip6e_len + 2) << 2;
- else
- elen = (ip6e.ip6e_len + 1) << 3;
-
- if (elen > MLEN)
- n = m_getcl(M_NOWAIT, MT_DATA, 0);
- else
- n = m_get(M_NOWAIT, MT_DATA);
- if (n == NULL)
- return NULL;
-
- m_copydata(m, off, elen, mtod(n, caddr_t));
- n->m_len = elen;
- return n;
-}
-#endif
-
/*
* Get pointer to the previous header followed by the header
* currently processed.