diff options
author | 2019-01-18 02:10:40 +0000 | |
---|---|---|
committer | 2019-01-18 02:10:40 +0000 | |
commit | 96ffc0c66ee4e58e63529b22377b95dfa55c3ea0 (patch) | |
tree | 9f421fb03d798915b5579d041dd90d57073cd3bd | |
parent | Yet another long line broke cover. (diff) | |
download | wireguard-openbsd-96ffc0c66ee4e58e63529b22377b95dfa55c3ea0.tar.xz wireguard-openbsd-96ffc0c66ee4e58e63529b22377b95dfa55c3ea0.zip |
Revert Rev 1.351, the change is not quite right yet.
-rw-r--r-- | sys/netinet/ip_output.c | 85 |
1 files changed, 36 insertions, 49 deletions
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index e9c64fd2c75..747e1e72b77 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.351 2019/01/06 11:05:09 claudio Exp $ */ +/* $OpenBSD: ip_output.c,v 1.352 2019/01/18 02:10:40 claudio Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -1234,15 +1234,13 @@ ip_ctloutput(int op, struct socket *so, int level, int optname, int ip_pcbopts(struct mbuf **pcbopt, struct mbuf *m) { - struct mbuf *n; - struct ipoption *p; - int cnt, off, optlen; + int cnt, optlen; u_char *cp; u_char opt; /* turn off any old options */ m_free(*pcbopt); - *pcbopt = NULL; + *pcbopt = 0; if (m == NULL || m->m_len == 0) { /* * Only turning off any previous options. @@ -1250,36 +1248,38 @@ ip_pcbopts(struct mbuf **pcbopt, struct mbuf *m) return (0); } - if (m->m_len % sizeof(int32_t) || - m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) + if (m->m_len % sizeof(int32_t)) return (EINVAL); - /* Don't sleep because NET_LOCK() is hold. */ - if ((n = m_get(M_NOWAIT, MT_SOOPTS)) == NULL) - return (ENOBUFS); - p = mtod(n, struct ipoption *); - p->ipopt_dst.s_addr = 0; - n->m_len = sizeof(struct in_addr); - - off = 0; + /* + * IP first-hop destination address will be stored before + * actual options; move other options back + * and clear it when none present. + */ + if (m_trailingspace(m) < sizeof(struct in_addr)) + return (EINVAL); cnt = m->m_len; + m->m_len += sizeof(struct in_addr); cp = mtod(m, u_char *) + sizeof(struct in_addr); + memmove((caddr_t)cp, mtod(m, caddr_t), (unsigned)cnt); + memset(mtod(m, caddr_t), 0, sizeof(struct in_addr)); - while (cnt > 0) { + for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[IPOPT_OPTVAL]; - - if (opt == IPOPT_NOP || opt == IPOPT_EOL) + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) optlen = 1; else { if (cnt < IPOPT_OLEN + sizeof(*cp)) - goto bad; + return (EINVAL); optlen = cp[IPOPT_OLEN]; if (optlen < IPOPT_OLEN + sizeof(*cp) || optlen > cnt) - goto bad; + return (EINVAL); } switch (opt) { + default: - memcpy(p->ipopt_list + off, cp, optlen); break; case IPOPT_LSRR: @@ -1293,46 +1293,33 @@ ip_pcbopts(struct mbuf **pcbopt, struct mbuf *m) * actual IP option, but is stored before the options. */ if (optlen < IPOPT_MINOFF - 1 + sizeof(struct in_addr)) - goto bad; - - /* - * Optlen is smaller because first address is popped. - * Cnt and cp will be adjusted a bit later to reflect - * this. - */ + return (EINVAL); + m->m_len -= sizeof(struct in_addr); + cnt -= sizeof(struct in_addr); optlen -= sizeof(struct in_addr); - p->ipopt_list[off + IPOPT_OPTVAL] = opt; - p->ipopt_list[off + IPOPT_OLEN] = optlen; - + cp[IPOPT_OLEN] = optlen; /* * Move first hop before start of options. */ - memcpy(&p->ipopt_dst, cp + IPOPT_OFFSET, + memcpy(mtod(m, caddr_t), &cp[IPOPT_OFFSET+1], sizeof(struct in_addr)); - cp += sizeof(struct in_addr); - cnt -= sizeof(struct in_addr); /* - * Then copy rest of options + * Then copy rest of options back + * to close up the deleted entry. */ - memcpy(p->ipopt_list + off + IPOPT_OFFSET, - cp + IPOPT_OFFSET, optlen - IPOPT_OFFSET); + memmove((caddr_t)&cp[IPOPT_OFFSET+1], + (caddr_t)(&cp[IPOPT_OFFSET+1] + + sizeof(struct in_addr)), + (unsigned)cnt - (IPOPT_OFFSET+1)); break; } - off += optlen; - cp += optlen; - cnt -= optlen; - - if (opt == IPOPT_EOL) - break; } - n->m_len += off; - if (n->m_len > sizeof(*p)) { - bad: - m_freem(n); + if (m->m_len > MAX_IPOPTLEN + sizeof(struct in_addr)) return (EINVAL); - } + *pcbopt = m_copym(m, 0, M_COPYALL, M_NOWAIT); + if (*pcbopt == NULL) + return (ENOBUFS); - *pcbopt = n; return (0); } |