diff options
-rw-r--r-- | sys/netinet/ip_ah.c | 9 | ||||
-rw-r--r-- | sys/netinet/ip_ah_new.c | 7 | ||||
-rw-r--r-- | sys/netinet/ip_ah_old.c | 7 | ||||
-rw-r--r-- | sys/netinet/ip_esp.c | 19 | ||||
-rw-r--r-- | sys/netinet/ip_esp_new.c | 516 | ||||
-rw-r--r-- | sys/netinet/ip_esp_old.c | 7 | ||||
-rw-r--r-- | sys/netinet/ip_ether.c | 5 | ||||
-rw-r--r-- | sys/netinet/ip_ip4.c | 151 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.c | 4 | ||||
-rw-r--r-- | sys/netinet/ip_ipsp.h | 31 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 38 |
11 files changed, 457 insertions, 337 deletions
diff --git a/sys/netinet/ip_ah.c b/sys/netinet/ip_ah.c index 2b87e7cae55..1735573970c 100644 --- a/sys/netinet/ip_ah.c +++ b/sys/netinet/ip_ah.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ah.c,v 1.26 1999/11/04 11:23:43 ho Exp $ */ +/* $OpenBSD: ip_ah.c,v 1.27 1999/12/06 07:14:35 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -84,6 +84,10 @@ extern struct enc_softc encif[]; #define DPRINTF(x) #endif +#ifndef offsetof +#define offsetof(s, e) ((int)&((s *)0)->e) +#endif + int ah_enable = 0; /* @@ -190,7 +194,8 @@ ah_input(m, va_alist) ipn = *ipo; ahn = *ahp; - m = (*(tdbp->tdb_xform->xf_input))(m, tdbp); + m = (*(tdbp->tdb_xform->xf_input))(m, tdbp, ipo->ip_hl << 2, + offsetof(struct ip, ip_p)); if (m == NULL) { DPRINTF(("ah_input(): authentication failed for AH packet from %s to %s, spi %08x\n", inet_ntoa4(ipn.ip_src), ipsp_address(sunion), ntohl(ahn.ah_spi))); diff --git a/sys/netinet/ip_ah_new.c b/sys/netinet/ip_ah_new.c index 73b91396791..639dc7dbff4 100644 --- a/sys/netinet/ip_ah_new.c +++ b/sys/netinet/ip_ah_new.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ah_new.c,v 1.28 1999/10/29 02:10:01 angelos Exp $ */ +/* $OpenBSD: ip_ah_new.c,v 1.29 1999/12/06 07:14:35 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -191,7 +191,7 @@ ah_new_zeroize(struct tdb *tdbp) */ struct mbuf * -ah_new_input(struct mbuf *m, struct tdb *tdb) +ah_new_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) { struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform; struct ip *ip, ipo; @@ -432,7 +432,8 @@ ah_new_input(struct mbuf *m, struct tdb *tdb) } int -ah_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) +ah_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip, + int protoff) { struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform; struct ip *ip, ipo; diff --git a/sys/netinet/ip_ah_old.c b/sys/netinet/ip_ah_old.c index c669107f47a..8e2a6f62458 100644 --- a/sys/netinet/ip_ah_old.c +++ b/sys/netinet/ip_ah_old.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ah_old.c,v 1.25 1999/10/29 02:10:01 angelos Exp $ */ +/* $OpenBSD: ip_ah_old.c,v 1.26 1999/12/06 07:14:35 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -173,7 +173,7 @@ ah_old_zeroize(struct tdb *tdbp) */ struct mbuf * -ah_old_input(struct mbuf *m, struct tdb *tdb) +ah_old_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) { struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform; struct ip *ip, ipo; @@ -375,7 +375,8 @@ ah_old_input(struct mbuf *m, struct tdb *tdb) } int -ah_old_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) +ah_old_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip, + int protoff) { struct auth_hash *ahx = (struct auth_hash *) tdb->tdb_authalgxform; struct ip *ip, ipo; diff --git a/sys/netinet/ip_esp.c b/sys/netinet/ip_esp.c index 10c16389760..ab3eae18fea 100644 --- a/sys/netinet/ip_esp.c +++ b/sys/netinet/ip_esp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_esp.c,v 1.26 1999/11/04 11:23:43 ho Exp $ */ +/* $OpenBSD: ip_esp.c,v 1.27 1999/12/06 07:14:35 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -84,6 +84,10 @@ extern struct enc_softc encif[]; #define DPRINTF(x) #endif +#ifndef offsetof +#define offsetof(s, e) ((int)&((s *)0)->e) +#endif + int esp_enable = 0; /* @@ -188,7 +192,8 @@ esp_input(m, va_alist) ipn = *ipo; - m = (*(tdbp->tdb_xform->xf_input))(m, tdbp); + m = (*(tdbp->tdb_xform->xf_input))(m, tdbp, ipo->ip_hl << 2, + offsetof(struct ip, ip_p)); if (m == NULL) { @@ -197,7 +202,17 @@ esp_input(m, va_alist) return; } + if ((m = m_pullup(m, ipn.ip_hl << 2)) == 0) + { + espstat.esps_hdrops++; + return; + } + ipo = mtod(m, struct ip *); + ipo->ip_len = htons(m->m_pkthdr.len); + ipo->ip_sum = 0; + ipo->ip_sum = in_cksum(m, ipo->ip_hl << 2); + if (ipo->ip_p == IPPROTO_IPIP) /* IP-in-IP encapsulation */ { /* ipn will now contain the inner IP header */ diff --git a/sys/netinet/ip_esp_new.c b/sys/netinet/ip_esp_new.c index 0c5c4e5d8ad..a8b46c0bda4 100644 --- a/sys/netinet/ip_esp_new.c +++ b/sys/netinet/ip_esp_new.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_esp_new.c,v 1.48 1999/12/04 23:20:21 angelos Exp $ */ +/* $OpenBSD: ip_esp_new.c,v 1.49 1999/12/06 07:14:35 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -65,6 +65,13 @@ #include <sys/socketvar.h> #include <net/raw_cb.h> +#ifdef INET6 +#include <netinet6/ip6.h> +#include <netinet6/in6_pcb.h> +#include <netinet6/ip6_var.h> +#include <netinet6/icmp6.h> +#endif /* INET6 */ + #include <netinet/ip_icmp.h> #include <netinet/ip_ipsp.h> #include <netinet/ip_esp.h> @@ -76,6 +83,10 @@ #define DPRINTF(x) #endif +#ifndef offsetof +#define offsetof(s, e) ((int)&((s *)0)->e) +#endif + extern struct auth_hash auth_hash_hmac_md5_96; extern struct auth_hash auth_hash_hmac_sha1_96; extern struct auth_hash auth_hash_hmac_ripemd_160_96; @@ -222,7 +233,7 @@ esp_new_zeroize(struct tdb *tdbp) { if (tdbp->tdb_key && tdbp->tdb_encalgxform && tdbp->tdb_encalgxform->zerokey) - tdbp->tdb_encalgxform->zerokey(&tdbp->tdb_key); + tdbp->tdb_encalgxform->zerokey(&tdbp->tdb_key); if (tdbp->tdb_ictx) { @@ -243,27 +254,21 @@ esp_new_zeroize(struct tdb *tdbp) return 0; } +#define MAXBUFSIZ (AH_ALEN_MAX > ESP_MAX_IVS ? AH_ALEN_MAX : ESP_MAX_IVS) struct mbuf * -esp_new_input(struct mbuf *m, struct tdb *tdb) +esp_new_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) { - struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform; struct auth_hash *esph = (struct auth_hash *) tdb->tdb_authalgxform; - u_char iv[ESP_MAX_IVS], niv[ESP_MAX_IVS]; - u_char blk[ESP_MAX_BLKS], *lblk, opts[40]; - int ohlen, oplen, plen, alen, ilen, i, blks, rest; - int count, off, errc; - struct mbuf *mi, *mo; + struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform; + int ohlen, oplen, plen, alen, ilen, i, blks, rest, count, off, roff; + u_char iv[MAXBUFSIZ], niv[MAXBUFSIZ], blk[ESP_MAX_BLKS], *lblk; u_char *idat, *odat, *ivp, *ivn; - struct esp_new *esp; - struct ip *ip, ipo; - u_int32_t btsx; + struct mbuf *mi, *mo, *m1; union authctx ctx; - u_char buf[AH_ALEN_MAX], buf2[AH_ALEN_MAX]; -#if INET6 - struct ipv6 *ipv6, ipv6o; -#endif /* INET6 */ + u_int32_t btsx; + ohlen = skip + ESP_NEW_FLENGTH; blks = espx->blocksize; if (esph) @@ -271,35 +276,56 @@ esp_new_input(struct mbuf *m, struct tdb *tdb) else alen = 0; - if (m->m_len < sizeof(struct ip)) + /* Skip the IP header, IP options, SPI, Replay, IV, and any Auth Data */ + plen = m->m_pkthdr.len - (skip + 2 * sizeof(u_int32_t) + tdb->tdb_ivlen + + alen); + if ((plen & (blks - 1)) || (plen <= 0)) { - if ((m = m_pullup(m, sizeof(struct ip))) == NULL) - { - DPRINTF(("esp_new_input(): (possibly too short) packet dropped\n")); - espstat.esps_hdrops++; - return NULL; - } + DPRINTF(("esp_new_input(): payload not a multiple of %d octets, SA %s/%08x\n", blks, ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_badilen++; + m_freem(m); + return NULL; } - ip = mtod(m, struct ip *); - ohlen = (ip->ip_hl << 2) + ESP_NEW_FLENGTH; + /* Auth covers SPI + SN + IV */ + oplen = plen + 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; - /* Make sure the IP header, any IP options, and the ESP header are here */ - if (m->m_len < ohlen + blks) + /* Replay window checking */ + if (tdb->tdb_wnd > 0) { - if ((m = m_pullup(m, ohlen + blks)) == NULL) + m_copydata(m, skip + offsetof(struct esp_new, esp_rpl), + sizeof(u_int32_t), (unsigned char *) &btsx); + btsx = ntohl(btsx); + + switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl), tdb->tdb_wnd, + &(tdb->tdb_bitmap))) { - DPRINTF(("esp_new_input(): m_pullup() failed\n")); - espstat.esps_hdrops++; - return NULL; - } + case 0: /* All's well */ + break; + + case 1: + DPRINTF(("esp_new_input(): replay counter wrapped for SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_wrap++; + m_freem(m); + return NULL; - ip = mtod(m, struct ip *); + case 2: + case 3: + DPRINTF(("esp_new_input(): duplicate packet received in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_replay++; + m_freem(m); + return NULL; + + default: + DPRINTF(("esp_new_input(): bogus value from checkreplaywindow32() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + return NULL; + } } /* Update the counters */ - tdb->tdb_cur_bytes += ip->ip_len - ohlen - alen; - espstat.esps_ibytes += ip->ip_len - ohlen - alen; + tdb->tdb_cur_bytes += m->m_pkthdr.len - ohlen - alen; + espstat.esps_ibytes += m->m_pkthdr.len - ohlen - alen; /* Hard expiration */ if ((tdb->tdb_flags & TDBF_BYTES) && @@ -319,65 +345,34 @@ esp_new_input(struct mbuf *m, struct tdb *tdb) tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ } - esp = (struct esp_new *) ((u_int8_t *) ip + (ip->ip_hl << 2)); - ipo = *ip; - - /* Replay window checking */ - if (tdb->tdb_wnd > 0) - { - btsx = ntohl(esp->esp_rpl); - if ((errc = checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl), tdb->tdb_wnd, - &(tdb->tdb_bitmap))) != 0) - { - switch(errc) - { - case 1: - DPRINTF(("esp_new_input(): replay counter wrapped for packets from %s to %s, spi %08x\n", inet_ntoa4(ip->ip_src), inet_ntoa4(ip->ip_dst), ntohl(esp->esp_spi))); - espstat.esps_wrap++; - break; - - case 2: - case 3: - DPRINTF(("esp_new_input(): duplicate packet received from %s to %s, spi %08x\n", inet_ntoa4(ip->ip_src), inet_ntoa4(ip->ip_dst), ntohl(esp->esp_spi))); - espstat.esps_replay++; - break; - } - - m_freem(m); - return NULL; - } - } - - /* Skip the IP header, IP options, SPI, SN and IV and minus Auth Data */ - plen = m->m_pkthdr.len - (ip->ip_hl << 2) - 2 * sizeof(u_int32_t) - - tdb->tdb_ivlen - alen; - - if ((plen & (blks - 1)) || (plen <= 0)) - { - DPRINTF(("esp_new_input(): payload not a multiple of %d octets for packet from %s to %s, spi %08x\n", blks, inet_ntoa4(ipo.ip_src), inet_ntoa4(ipo.ip_dst), ntohl(tdb->tdb_spi))); - espstat.esps_badilen++; - m_freem(m); - return NULL; - } - + /* Verify the authenticator */ if (esph) { bcopy(tdb->tdb_ictx, &ctx, esph->ctxsize); - /* Auth covers SPI + SN + IV */ - oplen = plen + 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; - off = (ip->ip_hl << 2); - /* Copy the authentication data */ - m_copydata(m, m->m_pkthdr.len - alen, alen, buf); + m_copydata(m, m->m_pkthdr.len - alen, alen, iv); + + /* + * Skip forward to the begining of the ESP header. If we run out + * of mbufs in the process, the check inside the following while() + * loop will catch it. + */ + for (mo = m, i = 0; mo && i + mo->m_len <= skip; mo = mo->m_next) + i += mo->m_len; - mo = m; + off = skip - i; + + /* Preserve these for later processing */ + roff = off; + m1 = mo; while (oplen > 0) { if (mo == 0) { - DPRINTF(("esp_new_input(): bad mbuf chain for packet from %s to %s, spi %08x\n", inet_ntoa4(ip->ip_src), inet_ntoa4(ip->ip_dst), ntohl(esp->esp_spi))); + DPRINTF(("esp_new_input(): bad mbuf chain, SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); espstat.esps_hdrops++; m_freem(m); return NULL; @@ -390,14 +385,14 @@ esp_new_input(struct mbuf *m, struct tdb *tdb) mo = mo->m_next; } - esph->Final(buf2, &ctx); + esph->Final(niv, &ctx); bcopy(tdb->tdb_octx, &ctx, esph->ctxsize); - esph->Update(&ctx, buf2, esph->hashsize); - esph->Final(buf2, &ctx); + esph->Update(&ctx, niv, esph->hashsize); + esph->Final(niv, &ctx); - if (bcmp(buf2, buf, AH_HMAC_HASHLEN)) + if (bcmp(niv, iv, AH_HMAC_HASHLEN)) { - DPRINTF(("esp_new_input(): authentication failed for packet from %s to %s, spi %08x\n", inet_ntoa4(ip->ip_src), inet_ntoa4(ip->ip_dst), ntohl(esp->esp_spi))); + DPRINTF(("esp_new_input(): authentication failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); espstat.esps_badauth++; m_freem(m); return NULL; @@ -405,14 +400,97 @@ esp_new_input(struct mbuf *m, struct tdb *tdb) } oplen = plen; - ilen = m->m_len - (ip->ip_hl << 2) - 2 * sizeof(u_int32_t); - idat = mtod(m, unsigned char *) + (ip->ip_hl << 2) + 2 * sizeof(u_int32_t); - bcopy(idat, iv, tdb->tdb_ivlen); + /* Find beginning of encrypted data (actually, the IV) */ + mi = m1; + ilen = mi->m_len - roff - 2 * sizeof(u_int32_t); + while (ilen <= 0) + { + mi = mi->m_next; + if (mi == NULL) + { + DPRINTF(("esp_new_input(): bad mbuf chain, SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_hdrops++; + m_freem(m); + return NULL; + } + + ilen += mi->m_len; + } + + idat = mtod(mi, unsigned char *) + (mi->m_len - ilen); + m_copydata(mi, mi->m_len - ilen, tdb->tdb_ivlen, iv); + + /* Now skip over the IV */ ilen -= tdb->tdb_ivlen; - idat += tdb->tdb_ivlen; + while (ilen <= 0) + { + mi = mi->m_next; + if (mi == NULL) + { + DPRINTF(("esp_new_input(): bad mbuf chain, SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_hdrops++; + m_freem(m); + return NULL; + } - mi = m; + ilen += mi->m_len; + } + + /* + * Remove the ESP header and IV from the mbuf. + */ + if (roff == 0) + { + /* The ESP header was conveniently at the begining of the mbuf */ + m_adj(m1, 2 * sizeof(u_int32_t) + tdb->tdb_ivlen); + if (!(m1->m_flags & M_PKTHDR)) + m->m_pkthdr.len -= (2 * sizeof(u_int32_t) + tdb->tdb_ivlen); + } + else + if (roff + 2 * sizeof(u_int32_t) + tdb->tdb_ivlen > m1->m_len) + { + /* + * Part of the ESP header is at the end of this mbuf, so first + * let's remove the remainder of the ESP header from the + * begining of the remainder of the mbuf chain. + */ + m_adj(m1->m_next, roff + 2 * sizeof(u_int32_t) + + tdb->tdb_ivlen - m1->m_len); + m->m_pkthdr.len -= roff + 2 * sizeof(u_int32_t) + tdb->tdb_ivlen - + m1->m_len; + + /* Now, let's unlink the mbuf chain for a second...*/ + mo = m1->m_next; + m1->m_next = NULL; + + /* ...and trim the end of the first part of the chain...sick */ + m_adj(m1, -(m1->m_len - roff)); + if (!(m1->m_flags & M_PKTHDR)) + m->m_pkthdr.len -= (m1->m_len - roff); + + /* Finally, let's relink */ + m1->m_next = mo; + } + else + { + /* + * The ESP header lies in the "middle" of the mbuf...do an + * overlapping copy of the remainder of the mbuf over the ESP + * header. + */ + bcopy(mtod(m1, u_char *) + roff + 2 * sizeof(u_int32_t) + + tdb->tdb_ivlen, + mtod(m1, u_char *) + roff, + m1->m_len - (roff + 2 * sizeof(u_int32_t) + tdb->tdb_ivlen)); + m1->m_len -= (2 * sizeof(u_int32_t) + tdb->tdb_ivlen); + m->m_pkthdr.len -= (2 * sizeof(u_int32_t) + tdb->tdb_ivlen); + } + + /* Point to the encrypted data */ + idat = mtod(mi, unsigned char *) + (mi->m_len - ilen); /* * At this point: @@ -447,7 +525,8 @@ esp_new_input(struct mbuf *m, struct tdb *tdb) mi = (mo = mi)->m_next; if (mi == NULL) { - DPRINTF(("esp_new_input(): bad mbuf chain, SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + DPRINTF(("esp_new_input(): bad mbuf chain, SA %s/%08x\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); espstat.esps_hdrops++; m_freem(m); return NULL; @@ -519,10 +598,7 @@ esp_new_input(struct mbuf *m, struct tdb *tdb) } } - /* Save the options */ - m_copydata(m, sizeof(struct ip), (ipo.ip_hl << 2) - sizeof(struct ip), - (caddr_t) opts); - + /* Save last block (end of padding), if it was in-place decrypted */ if (lblk != blk) bcopy(lblk, blk, blks); @@ -534,9 +610,10 @@ esp_new_input(struct mbuf *m, struct tdb *tdb) * Verify correct decryption by checking the last padding bytes. */ - if (blk[blks - 2] + 2 + alen > m->m_pkthdr.len - (ip->ip_hl << 2) - 2 * sizeof(u_int32_t) - tdb->tdb_ivlen) + if (blk[blks - 2] + 2 + alen > m->m_pkthdr.len - skip - + 2 * sizeof(u_int32_t) - tdb->tdb_ivlen) { - DPRINTF(("esp_new_input(): invalid padding length %d for packet from %s to %s, spi %08x\n", blk[blks - 2], inet_ntoa4(ipo.ip_src), inet_ntoa4(ipo.ip_dst), ntohl(tdb->tdb_spi))); + DPRINTF(("esp_new_input(): invalid padding length %d for packet in SA %s/%08x\n", blk[blks - 2], ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); espstat.esps_badilen++; m_freem(m); return NULL; @@ -544,60 +621,39 @@ esp_new_input(struct mbuf *m, struct tdb *tdb) if ((blk[blks - 2] != blk[blks - 3]) && (blk[blks - 2] != 0)) { - DPRINTF(("esp_new_input(): decryption failed for packet from %s to %s, spi %08x\n", inet_ntoa4(ipo.ip_src), inet_ntoa4(ipo.ip_dst), ntohl(tdb->tdb_spi))); + DPRINTF(("esp_new_input(): decryption failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + espstat.esps_badenc++; m_freem(m); return NULL; } - m_adj(m, - blk[blks - 2] - 2 - alen); /* Old type padding */ - m_adj(m, 2 * sizeof(u_int32_t) + tdb->tdb_ivlen); - - if (m->m_len < (ipo.ip_hl << 2)) - { - m = m_pullup(m, (ipo.ip_hl << 2)); - if (m == NULL) - { - DPRINTF(("esp_new_input(): m_pullup() failed for packet from %s to %s, spi %08x\n", inet_ntoa4(ipo.ip_src), inet_ntoa4(ipo.ip_dst), ntohl(tdb->tdb_spi))); - espstat.esps_hdrops++; - return NULL; - } - } - - ip = mtod(m, struct ip *); - ipo.ip_p = blk[blks - 1]; - ipo.ip_id = htons(ipo.ip_id); - ipo.ip_off = 0; - ipo.ip_len += (ipo.ip_hl << 2) - 2 * sizeof(u_int32_t) - tdb->tdb_ivlen - - blk[blks - 2] - 2 - alen; - - ipo.ip_len = htons(ipo.ip_len); - ipo.ip_sum = 0; - *ip = ipo; - - /* Copy the options back */ - m_copyback(m, sizeof(struct ip), (ipo.ip_hl << 2) - sizeof(struct ip), - (caddr_t) opts); + /* Trim the mbuf chain to remove the trailing authenticator */ + m_adj(m, - blk[blks - 2] - 2 - alen); - ip->ip_sum = in_cksum(m, (ip->ip_hl << 2)); + /* Restore the Next Protocol field */ + m_copyback(m, protoff, 1, &blk[blks - 1]); return m; } int -esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) +esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip, + int protoff) { struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform; struct auth_hash *esph = (struct auth_hash *) tdb->tdb_authalgxform; - struct ip *ip, ipo; - int i, ilen, ohlen, nh, rlen, plen, padding, rest; - struct esp_new espo; + u_char iv[ESP_MAX_IVS], blk[ESP_MAX_BLKS], auth[AH_ALEN_MAX]; + int i, ilen, ohlen, rlen, plen, padding, rest, blks, alen; struct mbuf *mi, *mo = (struct mbuf *) NULL; u_char *pad, *idat, *odat, *ivp; - u_char iv[ESP_MAX_IVS], blk[ESP_MAX_BLKS], auth[AH_ALEN_MAX], opts[40]; + struct esp_new *esp; union authctx ctx; - int iphlen, blks, alen; - + blks = espx->blocksize; + ohlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; + rlen = m->m_pkthdr.len - skip; /* Raw payload length */ + padding = ((blks - ((rlen + 2) % blks)) % blks) + 2; + plen = rlen + padding; /* Padded payload length */ if (esph) alen = AH_HMAC_HASHLEN; @@ -614,7 +670,7 @@ esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) while (mi != NULL && (!(mi->m_flags & M_EXT) || (mi->m_ext.ext_ref == NULL && - mclrefcnt[mtocl(mi->m_ext.ext_buf)] <= 1))) + mclrefcnt[mtocl(mi->m_ext.ext_buf)] <= 1))) { mo = mi; mi = mi->m_next; @@ -640,16 +696,8 @@ esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) m_freem(mi); } - m = m_pullup(m, sizeof (struct ip)); /* Get IP header in one mbuf */ - if (m == NULL) - { - DPRINTF(("esp_new_output(): m_pullup() failed, SA %s/%08x\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - espstat.esps_hdrops++; - return ENOBUFS; - } - - if (tdb->tdb_rpl == 0) + /* Check for replay counter wrap-around in automatic (not manual) keying */ + if ((tdb->tdb_rpl == 0) && (tdb->tdb_wnd > 0)) { DPRINTF(("esp_new_output(): SA %s/%0x8 should have expired\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); @@ -658,17 +706,24 @@ esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) return ENOBUFS; } - espo.esp_spi = tdb->tdb_spi; - espo.esp_rpl = htonl(tdb->tdb_rpl++); +#ifdef INET + /* In IPv4, check for max packet size violations. Not needed in IPv6. */ + if (tdb->tdb_dst.sa.sa_family == AF_INET) + if (skip + ohlen + rlen + padding + alen > IP_MAXPACKET) + { + DPRINTF(("esp_new_output(): packet in SA %s/%0x8 got too big\n", + ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + espstat.esps_toobig++; + return EMSGSIZE; + } +#endif /* INET */ - ip = mtod(m, struct ip *); - iphlen = (ip->ip_hl << 2); - /* Update the counters */ - tdb->tdb_cur_bytes += ntohs(ip->ip_len) - (ip->ip_hl << 2); - espstat.esps_obytes += ntohs(ip->ip_len) - (ip->ip_hl << 2); + tdb->tdb_cur_bytes += m->m_pkthdr.len - skip; + espstat.esps_obytes += m->m_pkthdr.len - skip; - /* Hard expiration */ + /* Hard byte expiration */ if ((tdb->tdb_flags & TDBF_BYTES) && (tdb->tdb_cur_bytes >= tdb->tdb_exp_bytes)) { @@ -678,7 +733,7 @@ esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) return EINVAL; } - /* Notify on expiration */ + /* Soft byte expiration */ if ((tdb->tdb_flags & TDBF_SOFT_BYTES) && (tdb->tdb_cur_bytes >= tdb->tdb_soft_bytes)) { @@ -686,45 +741,30 @@ esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) tdb->tdb_flags &= ~TDBF_SOFT_BYTES; /* Turn off checking */ } - /* - * If options are present, pullup the IP header, the options. - */ - if (iphlen != sizeof(struct ip)) + /* Inject ESP header */ + mo = m_inject(m, skip, ohlen, M_WAITOK); + if (mo == NULL) { - m = m_pullup(m, iphlen + 8); - if (m == NULL) - { - DPRINTF(("esp_new_input(): m_pullup() failed for SA %s/%08x\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - espstat.esps_hdrops++; - return ENOBUFS; - } - - ip = mtod(m, struct ip *); - - /* Keep the options */ - m_copydata(m, sizeof(struct ip), iphlen - sizeof(struct ip), - (caddr_t) opts); + DPRINTF(("esp_new_output(): failed to inject ESP header for SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); + m_freem(m); + espstat.esps_wrap++; + return ENOBUFS; } - ilen = ntohs(ip->ip_len); /* Size of the packet */ - ohlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; - - ipo = *ip; - nh = ipo.ip_p; + /* Initialize ESP header */ + esp = mtod(mo, struct esp_new *); + esp->esp_spi = tdb->tdb_spi; + esp->esp_rpl = htonl(tdb->tdb_rpl++); - /* Raw payload length */ - rlen = ilen - iphlen; - padding = ((blks - ((rlen + 2) % blks)) % blks) + 2; - if (iphlen + ohlen + rlen + padding + alen > IP_MAXPACKET) - { - DPRINTF(("esp_new_output(): packet in SA %s/%0x8 got too big\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - m_freem(m); - espstat.esps_toobig++; - return EMSGSIZE; - } + /* + * We can cheat and use bcopy() instead of m_copyback() for the + * second copy below, because m_inject() is guaranteed to fit the + * ESP header in one mbuf. + */ + bcopy(tdb->tdb_iv, iv, tdb->tdb_ivlen); + bcopy(iv, esp->esp_iv, tdb->tdb_ivlen); + /* Add padding */ pad = (u_char *) m_pad(m, padding + alen, 0); if (pad == NULL) { @@ -733,31 +773,42 @@ esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) return ENOBUFS; } - /* Self describing padding */ - for (i = 0; i < padding - 2; i++) - pad[i] = i + 1; + /* Self-describing padding */ + for (ilen = 0; ilen < padding - 2; ilen++) + pad[ilen] = ilen + 1; + /* Fix padding length and Next Protocol in padding itself */ pad[padding - 2] = padding - 2; - pad[padding - 1] = nh; + m_copydata(m, protoff, 1, &pad[padding - 1]); - mi = m; - plen = rlen + padding; - ilen = m->m_len - iphlen; - idat = mtod(m, u_char *) + iphlen; + /* Fix Next Protocol in IPv4/IPv6 header */ + ilen = IPPROTO_ESP; + m_copyback(m, protoff, 1, (u_char *) &ilen); - bcopy(tdb->tdb_iv, iv, tdb->tdb_ivlen); - bcopy(tdb->tdb_iv, espo.esp_iv, tdb->tdb_ivlen); + mi = mo; + + /* If it's just the ESP header, just skip to the next mbuf */ + if (mi->m_len == ohlen) + { + mi = mi->m_next; + ilen = mi->m_len; + idat = mtod(mi, u_char *); + } + else + { /* There's data at the end of this mbuf, skip over ESP header */ + ilen = mi->m_len - ohlen; + idat = mtod(mi, u_char *) + ohlen; + } - /* Authenticate the esp header */ + /* Authenticate the ESP header */ if (esph) { bcopy(tdb->tdb_ictx, &ctx, esph->ctxsize); - esph->Update(&ctx, (unsigned char *) &espo, - 2 * sizeof(u_int32_t) + tdb->tdb_ivlen); + esph->Update(&ctx, (unsigned char *) esp, + 2 * sizeof(u_int32_t) + tdb->tdb_ivlen); } /* Encrypt the payload */ - ivp = iv; rest = ilen % blks; while (plen > 0) /* while not done */ @@ -768,8 +819,8 @@ esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) { if (ivp == blk) { - bcopy(blk, iv, blks); - ivp = iv; + bcopy(blk, iv, blks); + ivp = iv; } bcopy(idat, blk, rest); @@ -812,12 +863,12 @@ esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) bcopy(idat, blk + rest, blks - rest); for (i = 0; i < blks; i++) - blk[i] ^= ivp[i]; + blk[i] ^= ivp[i]; espx->encrypt(tdb, blk); if (esph) - esph->Update(&ctx, blk, blks); + esph->Update(&ctx, blk, blks); ivp = blk; @@ -835,12 +886,12 @@ esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) while (ilen >= blks && plen > 0) { for (i = 0; i < blks; i++) - idat[i] ^= ivp[i]; + idat[i] ^= ivp[i]; espx->encrypt(tdb, idat); if (esph) - esph->Update(&ctx, idat, blks); + esph->Update(&ctx, idat, blks); ivp = idat; idat += blks; @@ -858,54 +909,17 @@ esp_new_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) esph->Update(&ctx, auth, esph->hashsize); esph->Final(auth, &ctx); - /* Copy the final authenticator */ + /* Copy the final authenticator -- cheat and use bcopy() again */ bcopy(auth, pad + padding, alen); } - - /* - * Done with encryption. Let's wedge in the ESP header - * and send it out. - */ - - M_PREPEND(m, ohlen, M_DONTWAIT); - if (m == NULL) - { - DPRINTF(("esp_new_output(): M_PREPEND failed, SA %s/%08x\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - return ENOBUFS; - } - - m = m_pullup(m, iphlen + ohlen); - if (m == NULL) - { - DPRINTF(("esp_new_output(): m_pullup() failed, SA %s/%08x\n", - ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); - espstat.esps_hdrops++; - return ENOBUFS; - } - - /* Fix the length and the next protocol, copy back and off we go */ - ipo.ip_len = htons(iphlen + ohlen + rlen + padding + alen); - ipo.ip_p = IPPROTO_ESP; - + /* Save the last encrypted block, to be used as the next IV */ bcopy(ivp, tdb->tdb_iv, tdb->tdb_ivlen); - m_copyback(m, 0, sizeof(struct ip), (caddr_t) &ipo); - - /* Copy options, if existing */ - if (iphlen != sizeof(struct ip)) - m_copyback(m, sizeof(struct ip), iphlen - sizeof(struct ip), - (caddr_t) opts); - - /* Copy in the esp header */ - m_copyback(m, iphlen, ohlen, (caddr_t) &espo); - *mp = m; return 0; -} - +} /* * return 0 on success diff --git a/sys/netinet/ip_esp_old.c b/sys/netinet/ip_esp_old.c index dc4ebe2b118..309fddc4118 100644 --- a/sys/netinet/ip_esp_old.c +++ b/sys/netinet/ip_esp_old.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_esp_old.c,v 1.37 1999/10/29 02:10:02 angelos Exp $ */ +/* $OpenBSD: ip_esp_old.c,v 1.38 1999/12/06 07:14:35 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -161,7 +161,7 @@ esp_old_zeroize(struct tdb *tdbp) * esp_old_input() gets called to decrypt an input packet */ struct mbuf * -esp_old_input(struct mbuf *m, struct tdb *tdb) +esp_old_input(struct mbuf *m, struct tdb *tdb, int skip, int protoff) { struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform; struct ip *ip, ipo; @@ -428,7 +428,8 @@ esp_old_input(struct mbuf *m, struct tdb *tdb) } int -esp_old_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) +esp_old_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip, + int protoff) { struct enc_xform *espx = (struct enc_xform *) tdb->tdb_encalgxform; struct ip *ip, ipo; diff --git a/sys/netinet/ip_ether.c b/sys/netinet/ip_ether.c index 8167733e054..88be0cbf530 100644 --- a/sys/netinet/ip_ether.c +++ b/sys/netinet/ip_ether.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ether.c,v 1.3 1999/11/04 05:16:32 jason Exp $ */ +/* $OpenBSD: ip_ether.c,v 1.4 1999/12/06 07:14:35 angelos Exp $ */ /* * The author of this code is Angelos D. Keromytis (kermit@adk.gr) @@ -197,7 +197,8 @@ va_dcl #ifdef IPSEC int -etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) +etherip_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip, + int protoff) { struct ip *ipo; ushort ilen; diff --git a/sys/netinet/ip_ip4.c b/sys/netinet/ip_ip4.c index b715b9c508a..0438ec05400 100644 --- a/sys/netinet/ip_ip4.c +++ b/sys/netinet/ip_ip4.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ip4.c,v 1.33 1999/10/29 02:02:33 angelos Exp $ */ +/* $OpenBSD: ip_ip4.c,v 1.34 1999/12/06 07:14:36 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -69,6 +69,14 @@ #include <netinet/ip_mroute.h> #endif +#ifdef INET6 +#include <netinet6/in6.h> +#include <netinet6/ip6.h> +#include <netinet6/in6_pcb.h> +#include <netinet6/ip6_var.h> +#include <netinet6/icmp6.h> +#endif /* INET6 */ + #include <sys/socketvar.h> #include <net/raw_cb.h> @@ -106,15 +114,19 @@ ip4_input(m, va_alist) va_dcl #endif { + register struct sockaddr_in *sin; register struct ifnet *ifp; register struct ifaddr *ifa; - register struct sockaddr_in *sin; - int iphlen; - struct ip *ipo, *ipi; struct ifqueue *ifq = NULL; - int s; + struct ip *ipo, *ipi; + int s, iphlen; va_list ap; +#ifdef INET6 + register struct sockaddr_in6 *sin6; + struct ip6_hdr *ipv6; +#endif /* INET6 */ + va_start(ap, m); iphlen = va_arg(ap, int); va_end(ap); @@ -171,34 +183,56 @@ ip4_input(m, va_alist) ipo = mtod(m, struct ip *); } - ipi = (struct ip *) ((caddr_t) ipo + iphlen); - /* * RFC 1853 specifies that the inner TTL should not be touched on * decapsulation. There's no reason this comment should be here, but * this is as good as any a position. */ - if (ipi->ip_v != IPVERSION) + if (ipo->ip_p == IPPROTO_IPIP) { - DPRINTF(("ip4_input(): wrong version %d on packet from %s to %s (%s->%s)\n", ipi->ip_v, inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet_ntoa4(ipi->ip_src), inet_ntoa4(ipi->ip_dst))); - ip4stat.ip4s_notip4++; - m_freem(m); - return; - } + ipi = (struct ip *) ((caddr_t) ipo + iphlen); - /* - * If we do not accept IP4 other than part of ESP & AH, we should - * not accept a packet with double ip4 headers neither. - */ + if (ipi->ip_v != IPVERSION) + { + DPRINTF(("ip4_input(): wrong version %d on packet from %s to %s (%s->%s)\n", ipi->ip_v, inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet_ntoa4(ipi->ip_src), inet_ntoa4(ipi->ip_dst))); + ip4stat.ip4s_notip4++; + m_freem(m); + return; + } + + /* + * If we do not accept IP4 other than as part of ESP & AH, we should + * not accept a packet with double ip4 headers neither. + */ - if (!ip4_allow && ipi->ip_p == IPPROTO_IPIP) + if (!ip4_allow && + ((ipi->ip_p == IPPROTO_IPIP) || + (ipi->ip_p == IPPROTO_IPV6))) + { + DPRINTF(("ip4_input(): dropped due to policy\n")); + ip4stat.ip4s_pdrops++; + m_freem(m); + return; + } + } + +#ifdef INET6 + if (ipo->ip_p == IPPROTO_IPIP) { - DPRINTF(("ip4_input(): dropped due to policy\n")); - ip4stat.ip4s_pdrops++; - m_freem(m); - return; + ipv6 = (struct ip6_hdr *) ((caddr_t) ipo + iphlen); + + if (ipv6->ip6_vfc != IPV6_VERSION) + { + DPRINTF(("ip4_input(): wrong version %d on packet from %s to %s (%s->%s)\n", ipi->ip_v, inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet6_ntoa4(ipv6->ip6_src), inet6_ntoa4(ipv6->ip6_dst))); + ip4stat.ip4s_notip4++; + m_freem(m); + return; + } + + /* XXX Do we need to check that we don't have double-headers ? */ } +#endif /* INET6 */ /* * Check remote packets for local address spoofing. @@ -212,23 +246,57 @@ ip4_input(m, va_alist) ifa != 0; ifa = ifa->ifa_list.tqe_next) { - if (ifa->ifa_addr->sa_family != AF_INET) - continue; - - sin = (struct sockaddr_in *) ifa->ifa_addr; - - if (sin->sin_addr.s_addr == ipi->ip_src.s_addr) + switch (ipo->ip_p) { - DPRINTF(("ip_input(): possible local address spoofing detected on packet from %s to %s (%s->%s)\n", inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet_ntoa4(ipi->ip_src), inet_ntoa4(ipi->ip_dst))); - ip4stat.ip4s_spoof++; - m_freem(m); - return; + case IPPROTO_IPIP: + if (ifa->ifa_addr->sa_family != AF_INET) + continue; + + sin = (struct sockaddr_in *) ifa->ifa_addr; + + if (sin->sin_addr.s_addr == ipi->ip_src.s_addr) + { + DPRINTF(("ip_input(): possible local address spoofing detected on packet from %s to %s (%s->%s)\n", inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet_ntoa4(ipi->ip_src), inet_ntoa4(ipi->ip_dst))); + ip4stat.ip4s_spoof++; + m_freem(m); + return; + } + + break; + +#ifdef INET6 + case IPPROTO_IPV6: + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + + sin6 = (struct sockaddr_in6 *) ifa->ifa_addr; + + if (!bcmp(&sin6->sin6_addr, &ipv6->sin6_addr, + sizeof(struct in6_addr))) + { + DPRINTF(("ip_input(): possible local address spoofing detected on packet from %s to %s (%s->%s)\n", inet_ntoa4(ipo->ip_src), inet_ntoa4(ipo->ip_dst), inet6_ntoa4(ipv6->ip6_src), inet6_ntoa4(ipv6->ip6_dst))); + ip4stat.ip4s_spoof++; + m_freem(m); + return; + } + + break; +#endif /* INET6 */ } + } } /* Statistics */ - ip4stat.ip4s_ibytes += ntohs(ipi->ip_len); + ip4stat.ip4s_ibytes += m->m_pkthdr.len - iphlen; + + /* Determine whether we need to queue in IPv4 or IPv6 input queue */ + ifq = &ipintrq; + +#ifdef INET6 + if (ipo->ip_p == IPPROTO_IPV6) + ifq = &ip6intrq; +#endif /* * Interface pointer is already in first mbuf; chop off the @@ -239,7 +307,7 @@ ip4_input(m, va_alist) m->m_pkthdr.len -= iphlen; m->m_data += iphlen; - /* tdbi is only set in esp or ah, if next protocol is udp or tcp */ + /* tdbi is only set in ESP or AH, if the next protocol is UDP or TCP */ if (m->m_flags & (M_CONF|M_AUTH)) m->m_pkthdr.tdbi = NULL; @@ -251,8 +319,6 @@ ip4_input(m, va_alist) * untrusted packets. */ - ifq = &ipintrq; - s = splimp(); /* isn't it already? */ if (IF_QFULL(ifq)) { @@ -266,14 +332,23 @@ ip4_input(m, va_alist) } IF_ENQUEUE(ifq, m); - schednetisr(NETISR_IP); + + if (ifq == &ipintrq) + schednetisr(NETISR_IP); + +#ifdef INET6 + if (ifq == &ip6intrq) + schednetisr(NETISR_IP6); +#endif /* INET6 */ + splx(s); return; } #ifdef IPSEC int -ipe4_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp) +ipe4_output(struct mbuf *m, struct tdb *tdb, struct mbuf **mp, int skip, + int protoff) { struct ip *ipo, *ipi; ushort ilen; diff --git a/sys/netinet/ip_ipsp.c b/sys/netinet/ip_ipsp.c index 4c626c533ba..704203fba1f 100644 --- a/sys/netinet/ip_ipsp.c +++ b/sys/netinet/ip_ipsp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.c,v 1.57 1999/12/05 22:09:18 angelos Exp $ */ +/* $OpenBSD: ip_ipsp.c,v 1.58 1999/12/06 07:14:36 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -133,7 +133,7 @@ u_int8_t hmac_opad_buffer[64] = { struct xformsw xformsw[] = { { XF_IP4, 0, "IPv4 Simple Encapsulation", ipe4_attach, ipe4_init, ipe4_zeroize, - (struct mbuf * (*)(struct mbuf *, struct tdb *))ipe4_input, + (struct mbuf * (*)(struct mbuf *, struct tdb *, int, int))ipe4_input, ipe4_output, }, { XF_OLD_AH, XFT_AUTH, "Keyed Authentication, RFC 1828/1852", ah_old_attach, ah_old_init, ah_old_zeroize, diff --git a/sys/netinet/ip_ipsp.h b/sys/netinet/ip_ipsp.h index b3a06d3d7cc..992169c9560 100644 --- a/sys/netinet/ip_ipsp.h +++ b/sys/netinet/ip_ipsp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_ipsp.h,v 1.47 1999/12/04 23:20:21 angelos Exp $ */ +/* $OpenBSD: ip_ipsp.h,v 1.48 1999/12/06 07:14:36 angelos Exp $ */ /* * The authors of this code are John Ioannidis (ji@tla.org), @@ -385,8 +385,8 @@ struct xformsw int (*xf_attach)(void); /* called at config time */ int (*xf_init)(struct tdb *, struct xformsw *, struct ipsecinit *); int (*xf_zeroize)(struct tdb *); /* termination */ - struct mbuf *(*xf_input)(struct mbuf *, struct tdb *); /* input */ - int (*xf_output)(struct mbuf *, struct tdb *, struct mbuf **); /* output */ + struct mbuf *(*xf_input)(struct mbuf *, struct tdb *, int, int); /* input */ + int (*xf_output)(struct mbuf *, struct tdb *, struct mbuf **, int, int); /* output */ }; /* xform IDs */ @@ -505,41 +505,46 @@ extern struct flow *find_global_flow(union sockaddr_union *, extern int ipe4_attach(void); extern int ipe4_init(struct tdb *, struct xformsw *, struct ipsecinit *); extern int ipe4_zeroize(struct tdb *); -extern int ipe4_output(struct mbuf *, struct tdb *, struct mbuf **); +extern int ipe4_output(struct mbuf *, struct tdb *, struct mbuf **, int, int); extern void ipe4_input __P((struct mbuf *, ...)); extern void ip4_input __P((struct mbuf *, ...)); /* XF_ETHERIP */ -extern int etherip_output(struct mbuf *, struct tdb *, struct mbuf **); +extern int etherip_output(struct mbuf *, struct tdb *, struct mbuf **, + int, int); extern void etherip_input __P((struct mbuf *, ...)); /* XF_OLD_AH */ extern int ah_old_attach(void); extern int ah_old_init(struct tdb *, struct xformsw *, struct ipsecinit *); extern int ah_old_zeroize(struct tdb *); -extern int ah_old_output(struct mbuf *, struct tdb *, struct mbuf **); -extern struct mbuf *ah_old_input(struct mbuf *, struct tdb *); +extern int ah_old_output(struct mbuf *, struct tdb *, struct mbuf **, + int, int); +extern struct mbuf *ah_old_input(struct mbuf *, struct tdb *, int, int); /* XF_NEW_AH */ extern int ah_new_attach(void); extern int ah_new_init(struct tdb *, struct xformsw *, struct ipsecinit *); extern int ah_new_zeroize(struct tdb *); -extern int ah_new_output(struct mbuf *, struct tdb *, struct mbuf **); -extern struct mbuf *ah_new_input(struct mbuf *, struct tdb *); +extern int ah_new_output(struct mbuf *, struct tdb *, struct mbuf **, + int, int); +extern struct mbuf *ah_new_input(struct mbuf *, struct tdb *, int, int); /* XF_OLD_ESP */ extern int esp_old_attach(void); extern int esp_old_init(struct tdb *, struct xformsw *, struct ipsecinit *); extern int esp_old_zeroize(struct tdb *); -extern int esp_old_output(struct mbuf *, struct tdb *, struct mbuf **); -extern struct mbuf *esp_old_input(struct mbuf *, struct tdb *); +extern int esp_old_output(struct mbuf *, struct tdb *, struct mbuf **, + int, int); +extern struct mbuf *esp_old_input(struct mbuf *, struct tdb *, int, int); /* XF_NEW_ESP */ extern int esp_new_attach(void); extern int esp_new_init(struct tdb *, struct xformsw *, struct ipsecinit *); extern int esp_new_zeroize(struct tdb *); -extern int esp_new_output(struct mbuf *, struct tdb *, struct mbuf **); -extern struct mbuf *esp_new_input(struct mbuf *, struct tdb *); +extern int esp_new_output(struct mbuf *, struct tdb *, struct mbuf **, + int, int); +extern struct mbuf *esp_new_input(struct mbuf *, struct tdb *, int, int); /* XF_TCPSIGNATURE */ extern int tcp_signature_tdb_attach __P((void)); diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index ea4b083e0db..186433bef12 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.53 1999/12/04 23:20:21 angelos Exp $ */ +/* $OpenBSD: ip_output.c,v 1.54 1999/12/06 07:14:36 angelos Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -76,6 +76,10 @@ #define DPRINTF(x) #endif +#ifndef offsetof +#define offsetof(s, e) ((int)&((s *)0)->e) +#endif + extern u_int8_t get_sa_require __P((struct inpcb *)); #endif @@ -470,7 +474,7 @@ sendit: sunion.sin.sin_len = sizeof(struct sockaddr_in); sunion.sin.sin_addr = gw->sen_ipsp_dst; } -#if INET6 +#ifdef INET6 else { sunion.sin6.sin6_family = AF_INET6; sunion.sin6.sin6_len = sizeof(struct sockaddr_in6); @@ -541,7 +545,7 @@ sendit: DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto)); #if INET6 else - DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto)); + DPRINTF(("ip_output(): non-existant TDB for SA %s/%08x/%u\n", inet6_ntoa4(gw->sen_ipsp_dst), ntohl(gw->sen_ipsp_spi), gw->sen_ipsp_sproto)); #endif /* INET6 */ if (re->re_rt) @@ -598,12 +602,12 @@ sendit: ip->ip_dst.s_addr)) || ((tdb->tdb_flags & TDBF_TUNNELING) && (tdb->tdb_xform->xf_type != XF_IP4))) { - /* - * Fix checksum here, AH and ESP fix the - * checksum in their output routines. - */ - ip->ip_sum = in_cksum(m, ip->ip_hl << 2); - error = ipe4_output(m, tdb, &mp); + /* Fix length and checksum */ + ip->ip_len = htons(m->m_pkthdr.len); + ip->ip_sum = in_cksum(m, ip->ip_hl << 2); + error = ipe4_output(m, tdb, &mp, + ip->ip_hl << 2, + offsetof(struct ip, ip_p)); if (mp == NULL) error = EFAULT; if (error) { @@ -613,20 +617,16 @@ sendit: return error; } m = mp; + mp = NULL; } if (tdb->tdb_xform->xf_type == XF_IP4) { - /* - * Fix checksum if IP-IP; AH and ESP fix the - * IP header checksum in their - * output routines. - */ ip = mtod(m, struct ip *); + ip->ip_len = htons(m->m_pkthdr.len); ip->ip_sum = in_cksum(m, ip->ip_hl << 2); } - - error = (*(tdb->tdb_xform->xf_output))(m, tdb, &mp); + error = (*(tdb->tdb_xform->xf_output))(m, tdb, &mp, ip->ip_hl << 2, offsetof(struct ip, ip_p)); if (!error && mp == NULL) error = EFAULT; if (error) { @@ -639,14 +639,16 @@ sendit: } m = mp; + mp = NULL; ip = mtod(m, struct ip *); - if (tdb->tdb_xform->xf_type == XF_IP4) - ip->ip_sum = in_cksum(m, ip->ip_hl << 2); + ip->ip_len = htons(m->m_pkthdr.len); tdb = tdb->tdb_onext; } splx(s); + ip->ip_sum = in_cksum(m, ip->ip_hl << 2); + /* * At this point, m is pointing to an mbuf chain with the * processed packet. Call ourselves recursively, but |