static int ipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir) { struct ip *ip; int rv, hlen; #if __NetBSD_Version__ >= 200080000 /* * ensure that mbufs are writable beforehand * as it's assumed by ipf code. * XXX inefficient */ int error = m_makewritable(mp, 0, M_COPYALL, M_DONTWAIT); if (error) { m_freem(*mp); *mp = NULL; return error; } #endif ip = mtod(*mp, struct ip *); hlen = ip->ip_hl << 2; #ifdef INET #if defined(M_CSUM_TCPv4) /* * If the packet is out-bound, we can't delay checksums * here. For in-bound, the checksum has already been * validated. */ if (dir == PFIL_OUT) { if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) { in_delayed_cksum(*mp); (*mp)->m_pkthdr.csum_flags &= ~(M_CSUM_TCPv4|M_CSUM_UDPv4); } } #endif /* M_CSUM_TCPv4 */ #endif /* INET */ /* * Note, we don't need to update the checksum, because * it has already been verified. */ rv = ipf_check(&ipfmain, ip, hlen, ifp, (dir == PFIL_OUT), mp); return (rv); }
bool nbuf_cksum_barrier(nbuf_t *nbuf, int di) { #ifdef _KERNEL struct mbuf *m; if (di != PFIL_OUT) { return false; } m = nbuf->nb_mbuf0; KASSERT(m_flags_p(m, M_PKTHDR)); if (m->m_pkthdr.csum_flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) { in_delayed_cksum(m); m->m_pkthdr.csum_flags &= ~(M_CSUM_TCPv4 | M_CSUM_UDPv4); return true; } #else (void)nbuf; (void)di; #endif return false; }
/* * * Called from ip_output(). * 1 = drop packet, 0 = continue processing packet, * -1 = packet was reinjected and stop processing packet */ int ip_ipsec_output(struct mbuf **m, struct inpcb *inp, int *flags, int *error) { #ifdef IPSEC struct secpolicy *sp = NULL; struct ip *ip = mtod(*m, struct ip *); struct tdb_ident *tdbi; struct m_tag *mtag; int s; /* * Check the security policy (SP) for the packet and, if * required, do IPsec-related processing. There are two * cases here; the first time a packet is sent through * it will be untagged and handled by ipsec4_checkpolicy. * If the packet is resubmitted to ip_output (e.g. after * AH, ESP, etc. processing), there will be a tag to bypass * the lookup and related policy checking. */ mtag = m_tag_find(*m, PACKET_TAG_IPSEC_PENDING_TDB, NULL); s = splnet(); if (mtag != NULL) { tdbi = (struct tdb_ident *)(mtag + 1); sp = ipsec_getpolicy(tdbi, IPSEC_DIR_OUTBOUND); if (sp == NULL) *error = -EINVAL; /* force silent drop */ m_tag_delete(*m, mtag); } else { sp = ipsec4_checkpolicy(*m, IPSEC_DIR_OUTBOUND, *flags, error, inp); } /* * There are four return cases: * sp != NULL apply IPsec policy * sp == NULL, error == 0 no IPsec handling needed * sp == NULL, error == -EINVAL discard packet w/o error * sp == NULL, error != 0 discard packet, report error */ if (sp != NULL) { /* Loop detection, check if ipsec processing already done */ KASSERT(sp->req != NULL, ("ip_output: no ipsec request")); for (mtag = m_tag_first(*m); mtag != NULL; mtag = m_tag_next(*m, mtag)) { if (mtag->m_tag_cookie != MTAG_ABI_COMPAT) continue; if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE && mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED) continue; /* * Check if policy has an SA associated with it. * This can happen when an SP has yet to acquire * an SA; e.g. on first reference. If it occurs, * then we let ipsec4_process_packet do its thing. */ if (sp->req->sav == NULL) break; tdbi = (struct tdb_ident *)(mtag + 1); if (tdbi->spi == sp->req->sav->spi && tdbi->proto == sp->req->sav->sah->saidx.proto && bcmp(&tdbi->dst, &sp->req->sav->sah->saidx.dst, sizeof (union sockaddr_union)) == 0) { /* * No IPsec processing is needed, free * reference to SP. * * NB: null pointer to avoid free at * done: below. */ KEY_FREESP(&sp), sp = NULL; splx(s); goto done; } } /* * Do delayed checksums now because we send before * this is done in the normal processing path. */ if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { in_delayed_cksum(*m); (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } #ifdef SCTP if ((*m)->m_pkthdr.csum_flags & CSUM_SCTP) { sctp_delayed_cksum(*m, (uint32_t)(ip->ip_hl << 2)); (*m)->m_pkthdr.csum_flags &= ~CSUM_SCTP; } #endif ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); /* NB: callee frees mbuf */ *error = ipsec4_process_packet(*m, sp->req, *flags, 0); if (*error == EJUSTRETURN) { /* * We had a SP with a level of 'use' and no SA. We * will just continue to process the packet without * IPsec processing and return without error. */ *error = 0; ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); goto done; } /* * Preserve KAME behaviour: ENOENT can be returned * when an SA acquire is in progress. Don't propagate * this to user-level; it confuses applications. * * XXX this will go away when the SADB is redone. */ if (*error == ENOENT) *error = 0; splx(s); goto reinjected; } else { /* sp == NULL */ splx(s); if (*error != 0) { /* * Hack: -EINVAL is used to signal that a packet * should be silently discarded. This is typically * because we asked key management for an SA and * it was delayed (e.g. kicked up to IKE). */ if (*error == -EINVAL) *error = 0; goto bad; } else { /* No IPsec processing for this packet. */ } } done: if (sp != NULL) KEY_FREESP(&sp); return 0; reinjected: if (sp != NULL) KEY_FREESP(&sp); return -1; bad: if (sp != NULL) KEY_FREESP(&sp); return 1; #endif /* IPSEC */ return 0; }
/* * * Called from ip_output(). * 1 = drop packet, 0 = continue processing packet, * -1 = packet was reinjected and stop processing packet */ int ip_ipsec_output(struct mbuf **m, struct inpcb *inp, int *error) { struct secpolicy *sp; if (!key_havesp(IPSEC_DIR_OUTBOUND)) return 0; /* * Check the security policy (SP) for the packet and, if * required, do IPsec-related processing. There are two * cases here; the first time a packet is sent through * it will be untagged and handled by ipsec4_checkpolicy. * If the packet is resubmitted to ip_output (e.g. after * AH, ESP, etc. processing), there will be a tag to bypass * the lookup and related policy checking. */ if (m_tag_find(*m, PACKET_TAG_IPSEC_OUT_DONE, NULL) != NULL) { *error = 0; return (0); } sp = ipsec4_checkpolicy(*m, IPSEC_DIR_OUTBOUND, error, inp); /* * There are four return cases: * sp != NULL apply IPsec policy * sp == NULL, error == 0 no IPsec handling needed * sp == NULL, error == -EINVAL discard packet w/o error * sp == NULL, error != 0 discard packet, report error */ if (sp != NULL) { /* * Do delayed checksums now because we send before * this is done in the normal processing path. */ if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { in_delayed_cksum(*m); (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } #ifdef SCTP if ((*m)->m_pkthdr.csum_flags & CSUM_SCTP) { struct ip *ip = mtod(*m, struct ip *); sctp_delayed_cksum(*m, (uint32_t)(ip->ip_hl << 2)); (*m)->m_pkthdr.csum_flags &= ~CSUM_SCTP; } #endif /* NB: callee frees mbuf */ *error = ipsec4_process_packet(*m, sp->req); KEY_FREESP(&sp); if (*error == EJUSTRETURN) { /* * We had a SP with a level of 'use' and no SA. We * will just continue to process the packet without * IPsec processing and return without error. */ *error = 0; goto done; } /* * Preserve KAME behaviour: ENOENT can be returned * when an SA acquire is in progress. Don't propagate * this to user-level; it confuses applications. * * XXX this will go away when the SADB is redone. */ if (*error == ENOENT) *error = 0; goto reinjected; } else { /* sp == NULL */ if (*error != 0) {
int ip6_ipsec_output(struct mbuf **m, struct inpcb *inp, int *error) { #ifdef IPSEC struct secpolicy *sp; /* * Check the security policy (SP) for the packet and, if * required, do IPsec-related processing. There are two * cases here; the first time a packet is sent through * it will be untagged and handled by ipsec4_checkpolicy. * If the packet is resubmitted to ip6_output (e.g. after * AH, ESP, etc. processing), there will be a tag to bypass * the lookup and related policy checking. */ if (m_tag_find(*m, PACKET_TAG_IPSEC_OUT_DONE, NULL) != NULL) { *error = 0; return (0); } sp = ipsec4_checkpolicy(*m, IPSEC_DIR_OUTBOUND, error, inp); /* * There are four return cases: * sp != NULL apply IPsec policy * sp == NULL, error == 0 no IPsec handling needed * sp == NULL, error == -EINVAL discard packet w/o error * sp == NULL, error != 0 discard packet, report error */ if (sp != NULL) { /* * Do delayed checksums now because we send before * this is done in the normal processing path. */ #ifdef INET if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { in_delayed_cksum(*m); (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } #endif if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA_IPV6) { in6_delayed_cksum(*m, (*m)->m_pkthdr.len - sizeof(struct ip6_hdr), sizeof(struct ip6_hdr)); (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA_IPV6; } #ifdef SCTP if ((*m)->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) { sctp_delayed_cksum(*m, sizeof(struct ip6_hdr)); (*m)->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; } #endif /* NB: callee frees mbuf */ *error = ipsec6_process_packet(*m, sp->req); if (*error == EJUSTRETURN) { /* * We had a SP with a level of 'use' and no SA. We * will just continue to process the packet without * IPsec processing. */ *error = 0; goto done; } /* * Preserve KAME behaviour: ENOENT can be returned * when an SA acquire is in progress. Don't propagate * this to user-level; it confuses applications. * * XXX this will go away when the SADB is redone. */ if (*error == ENOENT) *error = 0; goto reinjected; } else { /* sp == NULL */ if (*error != 0) { /* * Hack: -EINVAL is used to signal that a packet * should be silently discarded. This is typically * because we asked key management for an SA and * it was delayed (e.g. kicked up to IKE). */ if (*error == -EINVAL) *error = 0; goto bad; } /* No IPsec processing for this packet. */ } done: if (sp != NULL) KEY_FREESP(&sp); return 0; reinjected: if (sp != NULL) KEY_FREESP(&sp); return -1; bad: if (sp != NULL) KEY_FREESP(&sp); return 1; #endif /* IPSEC */ return 0; }
int ip6_ipsec_output(struct mbuf **m, struct inpcb *inp, int *flags, int *error, struct ifnet **ifp, struct secpolicy **sp) { #ifdef IPSEC struct tdb_ident *tdbi; struct m_tag *mtag; /* XXX int s; */ if (sp == NULL) return 1; mtag = m_tag_find(*m, PACKET_TAG_IPSEC_PENDING_TDB, NULL); if (mtag != NULL) { tdbi = (struct tdb_ident *)(mtag + 1); *sp = ipsec_getpolicy(tdbi, IPSEC_DIR_OUTBOUND); if (*sp == NULL) *error = -EINVAL; /* force silent drop */ m_tag_delete(*m, mtag); } else { *sp = ipsec4_checkpolicy(*m, IPSEC_DIR_OUTBOUND, *flags, error, inp); } /* * There are four return cases: * sp != NULL apply IPsec policy * sp == NULL, error == 0 no IPsec handling needed * sp == NULL, error == -EINVAL discard packet w/o error * sp == NULL, error != 0 discard packet, report error */ if (*sp != NULL) { /* Loop detection, check if ipsec processing already done */ KASSERT((*sp)->req != NULL, ("ip_output: no ipsec request")); for (mtag = m_tag_first(*m); mtag != NULL; mtag = m_tag_next(*m, mtag)) { if (mtag->m_tag_cookie != MTAG_ABI_COMPAT) continue; if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE && mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED) continue; /* * Check if policy has an SA associated with it. * This can happen when an SP has yet to acquire * an SA; e.g. on first reference. If it occurs, * then we let ipsec4_process_packet do its thing. */ if ((*sp)->req->sav == NULL) break; tdbi = (struct tdb_ident *)(mtag + 1); if (tdbi->spi == (*sp)->req->sav->spi && tdbi->proto == (*sp)->req->sav->sah->saidx.proto && bcmp(&tdbi->dst, &(*sp)->req->sav->sah->saidx.dst, sizeof (union sockaddr_union)) == 0) { /* * No IPsec processing is needed, free * reference to SP. * * NB: null pointer to avoid free at * done: below. */ KEY_FREESP(sp), *sp = NULL; /* XXX splx(s); */ goto done; } } /* * Do delayed checksums now because we send before * this is done in the normal processing path. */ if ((*m)->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { ipseclog((LOG_DEBUG, "%s: we do not support IPv4 over IPv6", __func__)); #ifdef INET in_delayed_cksum(*m); #endif (*m)->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; } /* * Preserve KAME behaviour: ENOENT can be returned * when an SA acquire is in progress. Don't propagate * this to user-level; it confuses applications. * * XXX this will go away when the SADB is redone. */ if (*error == ENOENT) *error = 0; goto do_ipsec; } else { /* sp == NULL */ if (*error != 0) { /* * Hack: -EINVAL is used to signal that a packet * should be silently discarded. This is typically * because we asked key management for an SA and * it was delayed (e.g. kicked up to IKE). */ if (*error == -EINVAL) *error = 0; goto bad; } else { /* No IPsec processing for this packet. */ } } done: return 0; do_ipsec: return -1; bad: return 1; #endif /* IPSEC */ return 0; }