summaryrefslogtreecommitdiff
path: root/src/libipsec
diff options
context:
space:
mode:
Diffstat (limited to 'src/libipsec')
-rw-r--r--src/libipsec/Makefile.in2
-rw-r--r--src/libipsec/ip_packet.c70
-rw-r--r--src/libipsec/ipsec_sa_mgr.c11
-rw-r--r--src/libipsec/tests/Makefile.in2
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@