Changeset View
Standalone View
sys/netipsec/ipsec_output.c
Show First 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | if ((proto) == IPPROTO_ESP) \ | ||||
ESPSTAT_INC(esps_##name); \ | ESPSTAT_INC(esps_##name); \ | ||||
else if ((proto) == IPPROTO_AH)\ | else if ((proto) == IPPROTO_AH)\ | ||||
AHSTAT_INC(ahs_##name); \ | AHSTAT_INC(ahs_##name); \ | ||||
else \ | else \ | ||||
IPCOMPSTAT_INC(ipcomps_##name); \ | IPCOMPSTAT_INC(ipcomps_##name); \ | ||||
} while (0) | } while (0) | ||||
static int ipsec_encap(struct mbuf **mp, struct secasindex *saidx); | static int ipsec_encap(struct mbuf **mp, struct secasindex *saidx); | ||||
static size_t ipsec_get_pmtu(struct secasvar *sav); | |||||
#ifdef INET | #ifdef INET | ||||
static struct secasvar * | static struct secasvar * | ||||
ipsec4_allocsa(struct mbuf *m, struct secpolicy *sp, u_int *pidx, int *error) | ipsec4_allocsa(struct mbuf *m, struct secpolicy *sp, u_int *pidx, int *error) | ||||
{ | { | ||||
struct secasindex *saidx, tmpsaidx; | struct secasindex *saidx, tmpsaidx; | ||||
struct ipsecrequest *isr; | struct ipsecrequest *isr; | ||||
struct sockaddr_in *sin; | struct sockaddr_in *sin; | ||||
▲ Show 20 Lines • Show All 175 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
return (ipsec4_perform_request(m, sp, inp, 0)); | return (ipsec4_perform_request(m, sp, inp, 0)); | ||||
} | } | ||||
int | int | ||||
ipsec4_check_pmtu(struct mbuf *m, struct secpolicy *sp, int forwarding) | ipsec4_check_pmtu(struct mbuf *m, struct secpolicy *sp, int forwarding) | ||||
{ | { | ||||
union sockaddr_union *dst; | |||||
struct in_conninfo inc; | |||||
struct secasvar *sav; | struct secasvar *sav; | ||||
struct ip *ip; | struct ip *ip; | ||||
size_t hlen, pmtu; | size_t hlen, pmtu; | ||||
uint32_t idx; | uint32_t idx; | ||||
int error; | int error; | ||||
/* Don't check PMTU if the frame won't have DF bit set. */ | /* Don't check PMTU if the frame won't have DF bit set. */ | ||||
if (!V_ip4_ipsec_dfbit) | if (!V_ip4_ipsec_dfbit) | ||||
Show All 18 Lines | if (sav == NULL) { | ||||
if (error == 0) | if (error == 0) | ||||
error = EINPROGRESS; | error = EINPROGRESS; | ||||
if (error != EJUSTRETURN) | if (error != EJUSTRETURN) | ||||
m_freem(m); | m_freem(m); | ||||
return (error); | return (error); | ||||
} | } | ||||
dst = &sav->sah->saidx.dst; | pmtu = ipsec_get_pmtu(sav); | ||||
memset(&inc, 0, sizeof(inc)); | if (pmtu == 0) { | ||||
switch (dst->sa.sa_family) { | |||||
case AF_INET: | |||||
inc.inc_faddr = satosin(&dst->sa)->sin_addr; | |||||
break; | |||||
#ifdef INET6 | |||||
case AF_INET6: | |||||
inc.inc6_faddr = satosin6(&dst->sa)->sin6_addr; | |||||
inc.inc_flags |= INC_ISIPV6; | |||||
break; | |||||
#endif | |||||
default: | |||||
key_freesav(&sav); | key_freesav(&sav); | ||||
return (0); | return (0); | ||||
} | } | ||||
hlen = ipsec_hdrsiz_internal(sp); | |||||
key_freesav(&sav); | key_freesav(&sav); | ||||
pmtu = tcp_hc_getmtu(&inc); | |||||
/* No entry in hostcache. Use link MTU instead. */ | |||||
if (pmtu == 0) { | |||||
switch (dst->sa.sa_family) { | |||||
case AF_INET: | |||||
pmtu = tcp_maxmtu(&inc, NULL); | |||||
break; | |||||
#ifdef INET6 | |||||
case AF_INET6: | |||||
pmtu = tcp_maxmtu6(&inc, NULL); | |||||
break; | |||||
#endif | |||||
} | |||||
if (pmtu == 0) | |||||
return (0); | |||||
tcp_hc_updatemtu(&inc, pmtu); | |||||
} | |||||
hlen = ipsec_hdrsiz_internal(sp); | |||||
if (m_length(m, NULL) + hlen > pmtu) { | if (m_length(m, NULL) + hlen > pmtu) { | ||||
/* | /* | ||||
* If we're forwarding generate ICMP message here, | * If we're forwarding generate ICMP message here, | ||||
* so that it contains pmtu substraced by header size. | * so that it contains pmtu substraced by header size. | ||||
* Set error to EINPROGRESS, in order for the frame | * Set error to EINPROGRESS, in order for the frame | ||||
* to be dropped silently. | * to be dropped silently. | ||||
*/ | */ | ||||
if (forwarding) { | if (forwarding) { | ||||
▲ Show 20 Lines • Show All 333 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
ipsec6_process_packet(struct mbuf *m, struct secpolicy *sp, | ipsec6_process_packet(struct mbuf *m, struct secpolicy *sp, | ||||
struct inpcb *inp) | struct inpcb *inp) | ||||
{ | { | ||||
return (ipsec6_perform_request(m, sp, inp, 0)); | return (ipsec6_perform_request(m, sp, inp, 0)); | ||||
} | } | ||||
/* | |||||
* IPv6 implementation is based on IPv4 implementation. | |||||
*/ | |||||
int | |||||
ipsec6_check_pmtu(struct mbuf *m, struct secpolicy *sp, int forwarding) | |||||
{ | |||||
struct secasvar *sav; | |||||
size_t hlen, pmtu; | |||||
uint32_t idx; | |||||
int error; | |||||
/* | |||||
* According to RFC8200 L3 fragmentation is supposed to be done only on | |||||
* locally generated packets. During L3 forwarding packets that are too | |||||
* big are always supposed to be dropped, with an ICMPv6 packet being | |||||
* sent back. | |||||
*/ | |||||
if (!forwarding) | |||||
return (0); | |||||
idx = sp->tcount - 1; | |||||
sav = ipsec6_allocsa(m, sp, &idx, &error); | |||||
if (sav == NULL) { | |||||
key_freesp(&sp); | |||||
/* | |||||
* No matching SA was found and SADB_ACQUIRE message was generated. | |||||
* Since we have matched a SP to this packet drop it silently. | |||||
*/ | |||||
if (error == 0) | |||||
error = EINPROGRESS; | |||||
if (error != EJUSTRETURN) | |||||
m_freem(m); | |||||
return (error); | |||||
} | |||||
pmtu = ipsec_get_pmtu(sav); | |||||
if (pmtu == 0) { | |||||
key_freesav(&sav); | |||||
return (0); | |||||
} | |||||
hlen = ipsec_hdrsiz_internal(sp); | |||||
key_freesav(&sav); | |||||
if (m_length(m, NULL) + hlen > pmtu) { | |||||
/* | |||||
* If we're forwarding generate ICMPv6 message here, | |||||
* so that it contains pmtu substracted by header size. | |||||
* Set error to EINPROGRESS, in order for the frame | |||||
* to be dropped silently. | |||||
*/ | |||||
if (forwarding) { | |||||
if (pmtu > hlen) | |||||
icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, pmtu - hlen); | |||||
bz: I may not have read the full logic and by description cannot fully follow either which exact… | |||||
Done Inline ActionsThis isn’t the case here. When a tunnel gateway receives ICMPv6 PTB (which contains encrypted data), a new PMTU is recorded in the host cache and that’s it, the packet is discarded. We do try not forward this ICMPv6 message to the original sender. bag_semihalf.com: This isn’t the case here. When a tunnel gateway receives ICMPv6 PTB (which contains encrypted… | |||||
else | |||||
m_freem(m); | |||||
key_freesp(&sp); | |||||
return (EINPROGRESS); /* Pretend that we consumed it. */ | |||||
} | |||||
} | |||||
return (0); | |||||
} | |||||
static int | static int | ||||
ipsec6_common_output(struct mbuf *m, struct inpcb *inp, int forwarding) | ipsec6_common_output(struct mbuf *m, struct inpcb *inp, int forwarding) | ||||
{ | { | ||||
struct secpolicy *sp; | struct secpolicy *sp; | ||||
int error; | int error; | ||||
/* Lookup for the corresponding outbound security policy */ | /* Lookup for the corresponding outbound security policy */ | ||||
sp = ipsec6_checkpolicy(m, inp, &error, !forwarding); | sp = ipsec6_checkpolicy(m, inp, &error, !forwarding); | ||||
Show All 30 Lines | if (m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) { | ||||
key_freesp(&sp); | key_freesp(&sp); | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
sctp_delayed_cksum(m, sizeof(struct ip6_hdr)); | sctp_delayed_cksum(m, sizeof(struct ip6_hdr)); | ||||
m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; | m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6; | ||||
} | } | ||||
#endif | #endif | ||||
} | } | ||||
error = ipsec6_check_pmtu(m, sp, forwarding); | |||||
if (error != 0) { | |||||
if (error == EJUSTRETURN) | |||||
return (0); | |||||
return (error); | |||||
} | |||||
/* NB: callee frees mbuf and releases reference to SP */ | /* NB: callee frees mbuf and releases reference to SP */ | ||||
error = ipsec6_process_packet(m, sp, inp); | error = ipsec6_process_packet(m, sp, inp); | ||||
if (error == EJUSTRETURN) { | if (error == EJUSTRETURN) { | ||||
/* | /* | ||||
* We had a SP with a level of 'use' and no SA. We | * We had a SP with a level of 'use' and no SA. We | ||||
* will just continue to process the packet without | * will just continue to process the packet without | ||||
* IPsec processing and return without error. | * IPsec processing and return without error. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 217 Lines • ▼ Show 20 Lines | ipsec_prepend(struct mbuf *m, int len, int how) | ||||
} | } | ||||
m_move_pkthdr(n, m); | m_move_pkthdr(n, m); | ||||
n->m_next = m; | n->m_next = m; | ||||
if (len + IPSEC_TRAILINGSPACE < M_SIZE(n)) | if (len + IPSEC_TRAILINGSPACE < M_SIZE(n)) | ||||
m_align(n, len + IPSEC_TRAILINGSPACE); | m_align(n, len + IPSEC_TRAILINGSPACE); | ||||
n->m_len = len; | n->m_len = len; | ||||
n->m_pkthdr.len += len; | n->m_pkthdr.len += len; | ||||
return (n); | return (n); | ||||
} | |||||
static size_t | |||||
ipsec_get_pmtu(struct secasvar *sav) | |||||
{ | |||||
union sockaddr_union *dst; | |||||
struct in_conninfo inc; | |||||
size_t pmtu; | |||||
dst = &sav->sah->saidx.dst; | |||||
memset(&inc, 0, sizeof(inc)); | |||||
switch (dst->sa.sa_family) { | |||||
#ifdef INET | |||||
case AF_INET: | |||||
inc.inc_faddr = satosin(&dst->sa)->sin_addr; | |||||
break; | |||||
#endif | |||||
#ifdef INET6 | |||||
case AF_INET6: | |||||
inc.inc6_faddr = satosin6(&dst->sa)->sin6_addr; | |||||
inc.inc_flags |= INC_ISIPV6; | |||||
break; | |||||
#endif | |||||
default: | |||||
return (0); | |||||
} | |||||
pmtu = tcp_hc_getmtu(&inc); | |||||
if (pmtu != 0) | |||||
return (pmtu); | |||||
/* No entry in hostcache. Assume that PMTU is equal to link's MTU */ | |||||
switch (dst->sa.sa_family) { | |||||
#ifdef INET | |||||
case AF_INET: | |||||
pmtu = tcp_maxmtu(&inc, NULL); | |||||
break; | |||||
#endif | |||||
#ifdef INET6 | |||||
case AF_INET6: | |||||
pmtu = tcp_maxmtu6(&inc, NULL); | |||||
break; | |||||
#endif | |||||
default: | |||||
return (0); | |||||
} | |||||
if (pmtu == 0) | |||||
return (0); | |||||
tcp_hc_updatemtu(&inc, pmtu); | |||||
return (pmtu); | |||||
} | } | ||||
static int | static int | ||||
ipsec_encap(struct mbuf **mp, struct secasindex *saidx) | ipsec_encap(struct mbuf **mp, struct secasindex *saidx) | ||||
{ | { | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 96 Lines • Show Last 20 Lines |
I may not have read the full logic and by description cannot fully follow either which exact case we handle here these days.
Can we possibly in any case send an ICMP6 PTB here out unencrypted anywhere with data which previously came from an encrypted session?
For a long time this has been a serious concern when sending PTB related to IPsec to leak any previously encrypted data back as that opens up to possible attack vectors.