summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Koeppe <format_c@online.de>2013-08-19 21:24:23 +0200
committerAlexander Koeppe <format_c@online.de>2013-08-19 22:06:01 +0200
commita89f0f10de9b70c0bcc0ab31552a12e1a8b83921 (patch)
treecd83fb885ada95e7d88a3cf8f1aafc890859cd90
parentd5d7b1f92659094172f5e2f9dec3996db5720b6d (diff)
downloadlibnet-a89f0f10de9b70c0bcc0ab31552a12e1a8b83921.tar.gz
Fix #34 correct checksum caculation when IPv6 extension headers being used
-rw-r--r--libnet/src/common.h3
-rw-r--r--libnet/src/libnet_checksum.c28
2 files changed, 31 insertions, 0 deletions
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 <netinet/in.h>
+#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
{