From a89f0f10de9b70c0bcc0ab31552a12e1a8b83921 Mon Sep 17 00:00:00 2001 From: Alexander Koeppe Date: Mon, 19 Aug 2013 21:24:23 +0200 Subject: Fix #34 correct checksum caculation when IPv6 extension headers being used --- libnet/src/common.h | 3 +++ libnet/src/libnet_checksum.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/libnet/src/common.h b/libnet/src/common.h index c0747e8..7b9f8fb 100644 --- a/libnet/src/common.h +++ b/libnet/src/common.h @@ -43,6 +43,9 @@ * included. */ #include +#ifndef IPPROTO_MH +#define IPPROTO_MH 135 /* IPv6 mobility header */ +#endif /* TODO - should ../include/gnuc.h be included here? */ diff --git a/libnet/src/libnet_checksum.c b/libnet/src/libnet_checksum.c index 69ccfea..a5009f8 100644 --- a/libnet/src/libnet_checksum.c +++ b/libnet/src/libnet_checksum.c @@ -201,12 +201,40 @@ libnet_inet_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len, const ip6h_p = (struct libnet_ipv6_hdr *)iph_p; iph_p = NULL; ip_hl = 40; + uint8_t ip_nh = ip6h_p->ip_nh; + if((uint8_t*)(ip6h_p+1) > end) { snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): ipv6 hdr not inside packet", __func__); return -1; } + + while (ip_nh != protocol && (uint8_t*)ip6h_p + ip_hl + 1 < end) + { /* next header is not the upper layer protocol */ + switch (ip_nh) + { + case IPPROTO_DSTOPTS: + case IPPROTO_HOPOPTS: + case IPPROTO_ROUTING: + case IPPROTO_FRAGMENT: + case IPPROTO_AH: + case IPPROTO_ESP: + case IPPROTO_MH: + /* + * count option headers to the header length for + * checksum processing + */ + ip_nh = *((uint8_t*)ip6h_p+ip_hl); /* next next header */ + ip_hl += (*((uint8_t*)ip6h_p+ip_hl+1)+1)*8; /* ext header length */ + break; + default: + snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, + "%s(): unsupported extension header (%d)", __func__, ip_nh); + return -1; + } + + } } else { -- cgit v1.2.1 From a4693ae62c6eaced9fcc849d87f5fd3b98eb8998 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Tue, 20 Aug 2013 20:33:18 -0700 Subject: Insource comments and whitespace cleanups --- libnet/src/common.h | 2 +- libnet/src/libnet_checksum.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/libnet/src/common.h b/libnet/src/common.h index 7b9f8fb..de31704 100644 --- a/libnet/src/common.h +++ b/libnet/src/common.h @@ -43,7 +43,7 @@ * included. */ #include -#ifndef IPPROTO_MH +#ifndef IPPROTO_MH #define IPPROTO_MH 135 /* IPv6 mobility header */ #endif diff --git a/libnet/src/libnet_checksum.c b/libnet/src/libnet_checksum.c index a5009f8..faf6d44 100644 --- a/libnet/src/libnet_checksum.c +++ b/libnet/src/libnet_checksum.c @@ -210,8 +210,13 @@ libnet_inet_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len, const return -1; } + /* FIXME this entire fragile exercise would be avoided if we just passed + * in the pointer to the protocol block 'q' we are checksumming, which + * we know. + */ while (ip_nh != protocol && (uint8_t*)ip6h_p + ip_hl + 1 < end) - { /* next header is not the upper layer protocol */ + { + /* next header is not the upper layer protocol */ switch (ip_nh) { case IPPROTO_DSTOPTS: @@ -222,9 +227,15 @@ libnet_inet_checksum(libnet_t *l, uint8_t *iphdr, int protocol, int h_len, const case IPPROTO_ESP: case IPPROTO_MH: /* - * count option headers to the header length for + * count option headers to the header length for * checksum processing */ + /* Common structure of ipv6 ext headers is: + * uint8: next header protocol + * uint8: length of this header, in multiples of 8, not + * including first eight octets + * The pointer arithmetic below follows from above. + */ ip_nh = *((uint8_t*)ip6h_p+ip_hl); /* next next header */ ip_hl += (*((uint8_t*)ip6h_p+ip_hl+1)+1)*8; /* ext header length */ break; -- cgit v1.2.1