diff options
Diffstat (limited to 'src/libipsec')
-rw-r--r-- | src/libipsec/Makefile.in | 2 | ||||
-rw-r--r-- | src/libipsec/ip_packet.c | 70 | ||||
-rw-r--r-- | src/libipsec/ipsec_sa_mgr.c | 11 | ||||
-rw-r--r-- | src/libipsec/tests/Makefile.in | 2 |
4 files changed, 76 insertions, 9 deletions
diff --git a/src/libipsec/Makefile.in b/src/libipsec/Makefile.in index e4f0c4411..834be0eeb 100644 --- a/src/libipsec/Makefile.in +++ b/src/libipsec/Makefile.in @@ -287,9 +287,11 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +FUZZING_LDFLAGS = @FUZZING_LDFLAGS@ GEM = @GEM@ GENHTML = @GENHTML@ GPERF = @GPERF@ +GPERF_LEN_TYPE = @GPERF_LEN_TYPE@ GPRBUILD = @GPRBUILD@ GREP = @GREP@ INSTALL = @INSTALL@ diff --git a/src/libipsec/ip_packet.c b/src/libipsec/ip_packet.c index 78b4c407a..904f118fd 100644 --- a/src/libipsec/ip_packet.c +++ b/src/libipsec/ip_packet.c @@ -52,7 +52,15 @@ struct ip6_hdr { uint8_t ip6_hlim; struct in6_addr ip6_src, ip6_dst; } __attribute__((packed)); -#define HAVE_NETINET_IP6_H /* not really, but we only need the struct above */ +struct ip6_ext { + uint8_t ip6e_nxt; + uint8_t ip6e_len; +} __attribute__((packed)); +#define HAVE_NETINET_IP6_H /* not really, but we only need the structs above */ +#endif + +#ifndef IP_OFFMASK +#define IP_OFFMASK 0x1fff #endif /** @@ -219,6 +227,56 @@ static bool parse_transport_header(chunk_t packet, uint8_t proto, return TRUE; } +#ifdef HAVE_NETINET_IP6_H +/** + * Skip to the actual payload and parse the transport header. + */ +static bool parse_transport_header_v6(struct ip6_hdr *ip, chunk_t packet, + chunk_t *payload, uint8_t *proto, + uint16_t *sport, uint16_t *dport) +{ + struct ip6_ext *ext; + bool fragment = FALSE; + + *proto = ip->ip6_nxt; + *payload = chunk_skip(packet, 40); + while (payload->len >= sizeof(struct ip6_ext)) + { + switch (*proto) + { + case 44: /* Fragment Header */ + fragment = TRUE; + /* skip the header */ + case 0: /* Hop-by-Hop Options Header */ + case 43: /* Routing Header */ + case 60: /* Destination Options Header */ + case 135: /* Mobility Header */ + case 139: /* HIP */ + case 140: /* Shim6 */ + /* simply skip over these headers for now */ + ext = (struct ip6_ext*)payload->ptr; + *proto = ext->ip6e_nxt; + *payload = chunk_skip(*payload, 8 * (ext->ip6e_len + 1)); + continue; + default: + /* assume anything else is an upper layer protocol but only + * attempt to parse the transport header for non-fragmented + * packets as there is no guarantee that initial fragments + * contain the transport header, depending on the number and + * type of extension headers */ + if (!fragment && + !parse_transport_header(*payload, *proto, sport, dport)) + { + return FALSE; + } + break; + } + break; + } + return TRUE; +} +#endif /* HAVE_NETINET_IP6_H */ + /** * Described in header. */ @@ -253,7 +311,8 @@ ip_packet_t *ip_packet_create(chunk_t packet) /* remove any RFC 4303 TFC extra padding */ packet.len = min(packet.len, untoh16(&ip->ip_len)); payload = chunk_skip(packet, ip->ip_hl * 4); - if (!parse_transport_header(payload, ip->ip_p, &sport, &dport)) + if ((ip->ip_off & htons(IP_OFFMASK)) == 0 && + !parse_transport_header(payload, ip->ip_p, &sport, &dport)) { goto failed; } @@ -277,10 +336,8 @@ ip_packet_t *ip_packet_create(chunk_t packet) ip = (struct ip6_hdr*)packet.ptr; /* remove any RFC 4303 TFC extra padding */ packet.len = min(packet.len, 40 + untoh16(&ip->ip6_plen)); - /* we only handle packets without extension headers, just skip the - * basic IPv6 header */ - payload = chunk_skip(packet, 40); - if (!parse_transport_header(payload, ip->ip6_nxt, &sport, &dport)) + if (!parse_transport_header_v6(ip, packet, &payload, &next_header, + &sport, &dport)) { goto failed; } @@ -288,7 +345,6 @@ ip_packet_t *ip_packet_create(chunk_t packet) chunk_from_thing(ip->ip6_src), sport); dst = host_create_from_chunk(AF_INET6, chunk_from_thing(ip->ip6_dst), dport); - next_header = ip->ip6_nxt; break; } #endif /* HAVE_NETINET_IP6_H */ diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c index 957d930f2..44d35244a 100644 --- a/src/libipsec/ipsec_sa_mgr.c +++ b/src/libipsec/ipsec_sa_mgr.c @@ -107,6 +107,11 @@ typedef struct { ipsec_sa_entry_t *entry; /** + * SPI of the expired entry + */ + uint32_t spi; + + /** * 0 if this is a hard expire, otherwise the offset in s (soft->hard) */ uint32_t hard_offset; @@ -314,8 +319,9 @@ static job_requeue_t sa_expired(ipsec_sa_expired_t *expired) private_ipsec_sa_mgr_t *this = expired->manager; this->mutex->lock(this->mutex); - if (this->sas->find_first(this->sas, NULL, (void**)&expired->entry)) - { + if (this->sas->find_first(this->sas, NULL, (void**)&expired->entry) && + expired->spi == expired->entry->sa->get_spi(expired->entry->sa)) + { /* only if we find the right SA at this pointer location */ uint32_t hard_offset; hard_offset = expired->hard_offset; @@ -355,6 +361,7 @@ static void schedule_expiration(private_ipsec_sa_mgr_t *this, INIT(expired, .manager = this, .entry = entry, + .spi = entry->sa->get_spi(entry->sa), ); /* schedule a rekey first, a hard timeout will be scheduled then, if any */ diff --git a/src/libipsec/tests/Makefile.in b/src/libipsec/tests/Makefile.in index 5b6c53075..ab5af4634 100644 --- a/src/libipsec/tests/Makefile.in +++ b/src/libipsec/tests/Makefile.in @@ -240,9 +240,11 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +FUZZING_LDFLAGS = @FUZZING_LDFLAGS@ GEM = @GEM@ GENHTML = @GENHTML@ GPERF = @GPERF@ +GPERF_LEN_TYPE = @GPERF_LEN_TYPE@ GPRBUILD = @GPRBUILD@ GREP = @GREP@ INSTALL = @INSTALL@ |