summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Roberts <vieuxtech@gmail.com>2009-04-30 15:10:03 -0700
committerSam Roberts <vieuxtech@gmail.com>2009-04-30 15:10:03 -0700
commit62579afb26283ac176ef7fb5b34f36d00f732663 (patch)
tree154cc0cf3c3f552c9bf3dd453fffbc710284071e
parentefe6c65e698863d4c694ffd035c2971b6c32fb69 (diff)
downloadlibnet-62579afb26283ac176ef7fb5b34f36d00f732663.tar.gz
Fixed various errors, including memory corruption, when IPv4 options are modified.
- pblock chain's ip_offset corrected - ipv4 pblock's ip total length and ip header length corrected - removed redundant, dead, and misleading code - clarified documentation on meaning of ip_len in build_ipv4 - corrected documentation on order in which options and ipv4 header should be built - ipv4 options unit test added to samples/
-rw-r--r--.gitignore1
-rw-r--r--libnet/include/libnet/libnet-functions.h29
-rw-r--r--libnet/sample/Makefile.am3
-rw-r--r--libnet/sample/test_ipv4_options.c257
-rw-r--r--libnet/src/libnet_build_ip.c117
5 files changed, 299 insertions, 108 deletions
diff --git a/.gitignore b/.gitignore
index dc82c71..850e94e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -68,6 +68,7 @@ libnet/sample/synflood
libnet/sample/synflood6
libnet/sample/synflood6_frag
libnet/sample/test_ipv4
+libnet/sample/test_ipv4_options
libnet/sample/test_ipv6_icmpv4
libnet/sample/tcp1
libnet/sample/tcp2
diff --git a/libnet/include/libnet/libnet-functions.h b/libnet/include/libnet/libnet-functions.h
index 4f1eb27..a9e18bb 100644
--- a/libnet/include/libnet/libnet-functions.h
+++ b/libnet/include/libnet/libnet-functions.h
@@ -795,8 +795,9 @@ u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag);
/**
* Builds a version 4 RFC 791 Internet Protocol (IP) header.
- * @param len total length of the IP packet including all subsequent data
- * FIXME There is no reason this can't be calculated if zero is passed.
+ *
+ * @param ip_len total length of the IP packet including all subsequent data (subsequent
+ * data includes any IP options and IP options padding)
* @param tos type of service bits
* @param id IP identification number
* @param frag fragmentation bits and offset
@@ -812,22 +813,23 @@ u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag);
* @return protocol tag value on success, -1 on error
*/
libnet_ptag_t
-libnet_build_ipv4(u_int16_t len, u_int8_t tos, u_int16_t id, u_int16_t frag,
+libnet_build_ipv4(u_int16_t ip_len, u_int8_t tos, u_int16_t id, u_int16_t frag,
u_int8_t ttl, u_int8_t prot, u_int16_t sum, u_int32_t src, u_int32_t dst,
u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag);
/**
* Builds an version 4 Internet Protocol (IP) options header. The function
* expects options to be a valid IP options string of size options_s, no larger
- * than 40 bytes (the maximum size of an options string). The function checks
- * to make sure that the preceding header is an IPv4 header and that the
- * options string would not result in a packet larger than 65,535 bytes
- * (IPMAXPACKET). The function counts up the number of 32-bit words in the
- * options string and adjusts the IP header length value as necessary.
+ * than 40 bytes (the maximum size of an options string).
+ *
+ * When building a chain, the options must be built, then the IPv4 header.
*
- * WRONG - if no ptag, it must be built BEFORE the IPv4 header is.
+ * When updating a chain, if the block following the options is an IPv4 header,
+ * it's total length and header length will be updated if the options block
+ * size changes.
*
- * @param options byte string of IP options
+ * @param options byte string of IP options (it will be padded up to be an integral
+ * multiple of 32-bit words).
* @param options_s length of options string
* @param l pointer to a libnet context
* @param ptag protocol tag to modify an existing header, 0 to build a new one
@@ -838,7 +840,8 @@ libnet_build_ipv4_options(u_int8_t *options, u_int32_t options_s, libnet_t *l,
libnet_ptag_t ptag);
/**
- * Autobuilds a version 4 Internet Protocol (IP) header. The function is useful * to build an IP header quickly when you do not need a granular level of
+ * Autobuilds a version 4 Internet Protocol (IP) header. The function is useful
+ * to build an IP header quickly when you do not need a granular level of
* control. The function takes the same len, prot, and dst arguments as
* libnet_build_ipv4(). The function does not accept a ptag argument, but it
* does return a ptag. In other words, you can use it to build a new IP header
@@ -2049,7 +2052,9 @@ libnet_diag_dump_pblock_type(u_int8_t type);
* packet.
* @param packet the packet to print
* @param len length of the packet in bytes
- * @param swap 1 to swap byte order, 0 to not
+ * @param swap 1 to swap byte order, 0 to not.
+ * Counter-intuitively, it is necessary to swap in order to see the byte
+ * order as it is on the wire (this may be a bug).
* @param stream a stream pointer to print to
*/
void
diff --git a/libnet/sample/Makefile.am b/libnet/sample/Makefile.am
index 21b072b..aa7a8b6 100644
--- a/libnet/sample/Makefile.am
+++ b/libnet/sample/Makefile.am
@@ -15,7 +15,7 @@ noinst_PROGRAMS = arp cdp dhcp_discover get_addr icmp_timestamp icmp_unreach \
fddi_tcp1 fddi_tcp2 tring_tcp1 tring_tcp2 icmp_redirect \
bgp4_hdr bgp4_open bgp4_update bgp4_notification gre \
synflood6_frag tftp ip_link ip_raw sebek hsrp \
- test_ipv4 test_ipv6_icmpv4
+ test_ipv4 test_ipv6_icmpv4 test_ipv4_options
arp_SOURCES = arp.c
cdp_SOURCES = cdp.c
@@ -62,6 +62,7 @@ ip_link_SOURCES = ip_link.c
sebek_SOURCES = sebek.c
hsrp_SOURCES = hsrp.c
test_ipv4_SOURCES = test_ipv4.c
+test_ipv4_options_SOURCES = test_ipv4_options.c
test_ipv6_icmpv4_SOURCES = test_ipv6_icmpv4.c
EXTRA_DIST = libnet_test.h
diff --git a/libnet/sample/test_ipv4_options.c b/libnet/sample/test_ipv4_options.c
new file mode 100644
index 0000000..29c16e2
--- /dev/null
+++ b/libnet/sample/test_ipv4_options.c
@@ -0,0 +1,257 @@
+/*
+ * Regression test for bugs in ipv4 ip_offset and h_len handling, such as
+ * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=418975
+ *
+ * Copyright (c) 2009 Sam Roberts <sroberts@wurldtech.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#if (HAVE_CONFIG_H)
+#include "../include/config.h"
+#endif
+#include "./libnet_test.h"
+
+#include <assert.h>
+
+static void assert_eq_(long have, long want, const char* file, int line) {
+ if(have != want) {
+ printf("%s:%d: fail - have %ld want %ld\n", file, line, have, want);
+ abort();
+ }
+}
+#define assert_eq(have, want) assert_eq_(have, want, __FILE__, __LINE__)
+
+
+static void print_pblocks(libnet_t* l)
+{
+ libnet_pblock_t* p = l->protocol_blocks;
+
+ while(p) {
+ printf(" tag %2d flags %d type %20s/%#x buf %p b_len %2u h_len %2u ip_offset %2u, copied %2u\n",
+ p->ptag, p->flags,
+ libnet_diag_dump_pblock_type(p->type), p->type,
+ p->buf, p->b_len, p->h_len, p->ip_offset, p->copied);
+ p = p->next;
+ }
+ printf(" link_offset %d aligner %d total_size %u nblocks %d\n",
+ l->link_offset, l->aligner, l->total_size, l->n_pblocks);
+
+}
+
+static void ptag_error(libnet_t* l, int ptag)
+{
+ if(ptag <= 0) {
+ printf("error: %s\n", libnet_geterror(l));
+ }
+ assert(ptag > 0);
+}
+
+static int build_ipo(libnet_t* l, libnet_ptag_t ptag, int payload_s)
+{
+ u_int8_t* payload = malloc(payload_s);
+ assert(payload);
+ memset(payload, '\x88', payload_s);
+
+ ptag = libnet_build_ipv4_options(payload, payload_s, l, ptag);
+
+ ptag_error(l, ptag);
+
+ free(payload);
+
+ return ptag;
+}
+
+static int build_ipv4(libnet_t* l, libnet_ptag_t ptag, int payload_s, int ip_len)
+{
+ u_long src_ip = 0xf101f1f1;
+ u_long dst_ip = 0xf102f1f1;
+ u_int8_t* payload = malloc(payload_s);
+ assert(payload);
+ memset(payload, '\x99', payload_s);
+
+ if(!ip_len) {
+ ip_len = LIBNET_IPV4_H + payload_s;
+ }
+
+ ptag = libnet_build_ipv4(
+ ip_len, /* length */
+ 0, /* TOS */
+ 0xbbbb, /* IP ID */
+ 0, /* IP Frag */
+ 0xcc, /* TTL */
+ IPPROTO_UDP, /* protocol */
+ 0, /* checksum */
+ src_ip, /* source IP */
+ dst_ip, /* destination IP */
+ payload_s ? payload : NULL, /* payload */
+ payload_s, /* payload size */
+ l, /* libnet handle */
+ ptag); /* libnet id */
+
+ ptag_error(l, ptag);
+
+ free(payload);
+
+ return ptag;
+}
+
+static int build_ethernet(libnet_t* l, libnet_ptag_t ptag)
+{
+ u_int8_t enet_src[6] = {0x11, 0x11, 0x11, 0x11, 0x11, 0x11};
+ u_int8_t enet_dst[6] = {0x22, 0x22, 0x22, 0x22, 0x22, 0x22};
+
+ ptag = libnet_build_ethernet(
+ enet_dst, /* ethernet destination */
+ enet_src, /* ethernet source */
+ ETHERTYPE_IP, /* protocol type */
+ NULL, /* payload */
+ 0, /* payload size */
+ l, /* libnet handle */
+ ptag); /* libnet id */
+
+ ptag_error(l, ptag);
+
+ return ptag;
+}
+
+static
+void assert_lengths(libnet_t* l, int ip_len, int ip_ihl, int payload_s)
+{
+ int pkt1_payload = 10;
+ u_int8_t* pkt1 = NULL;
+ u_int32_t pkt1_sz = 0;
+ struct libnet_ipv4_hdr* h1;
+ int pkt2_payload = 2;
+ u_int8_t* pkt2 = NULL;
+ u_int32_t pkt2_sz = 0;
+ struct libnet_ipv4_hdr* h2;
+
+
+ int r = libnet_pblock_coalesce(l, &pkt1, &pkt1_sz);
+ assert(r >= 0);
+
+ print_pblocks(l);
+
+ libnet_diag_dump_hex(pkt1, 14, 1, stdout);
+ libnet_diag_dump_hex(pkt1+14, pkt1_sz-14, 1, stdout);
+
+ // check ip IHL value, total ip pkt length, and options value
+ h1 = (struct libnet_ipv4_hdr*) (pkt1+14);
+ assert_eq(h1->ip_hl, ip_ihl);
+ assert_eq(ntohs(h1->ip_len), ip_len);
+
+ uint8_t* payload = ((u_int8_t*) h1) + ip_ihl * 4;
+ if(payload_s > 0) {
+ assert(payload[0] == (u_int8_t)'\x99');
+ assert(payload[payload_s-1] == (u_int8_t)'\x99');
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ libnet_t *l;
+ int r;
+ char *device = "eth0";
+ char errbuf[LIBNET_ERRBUF_SIZE];
+ libnet_ptag_t ipo_ptag = 0;
+ libnet_ptag_t ip_ptag = 0;
+ libnet_ptag_t eth_ptag = 0;
+ int ip_len = 0;
+
+ l = libnet_init( LIBNET_LINK, device, errbuf);
+
+ assert(l);
+
+ printf("Packet: options=4, payload=0\n");
+
+ ip_len = 20 + 4 + 0; /* ip + options + payload */
+ ipo_ptag = build_ipo(l, ipo_ptag, 4);
+ ip_ptag = build_ipv4(l, ip_ptag, 0, 24);
+ eth_ptag = build_ethernet(l, eth_ptag);
+
+ assert_lengths(l, 24, 6, 0);
+
+ ipo_ptag = ip_ptag = eth_ptag = 0;
+
+ libnet_clear_packet(l);
+
+ printf("Packet: options=3, payload=1\n");
+
+ ip_len = 20 + 4 + 1; /* ip + options + payload */
+ ipo_ptag = build_ipo(l, ipo_ptag, 3);
+ ip_ptag = build_ipv4(l, ip_ptag, 1, 25);
+ eth_ptag = build_ethernet(l, eth_ptag);
+
+ assert_lengths(l, 25, 6, 1);
+
+ ipo_ptag = ip_ptag = eth_ptag = 0;
+
+ libnet_clear_packet(l);
+
+ printf("Packet: options=3, payload=1\n");
+
+ ip_len = 20 + 4 + 1; /* ip + options + payload */
+ ipo_ptag = build_ipo(l, ipo_ptag, 3);
+ ip_ptag = build_ipv4(l, ip_ptag, 1, ip_len);
+ eth_ptag = build_ethernet(l, eth_ptag);
+
+ assert_lengths(l, 25, 6, 1);
+
+ printf("... modify -> options=40\n");
+
+ ip_len = 20 + 40 + 1; /* ip + options + payload */
+ ipo_ptag = build_ipo(l, ipo_ptag, 40);
+
+ assert_lengths(l, ip_len, 15, 1);
+
+ printf("... modify -> options=0\n");
+
+ ip_len = 20 + 0 + 1; /* ip + options + payload */
+ ipo_ptag = build_ipo(l, ipo_ptag, 0);
+
+ assert_lengths(l, ip_len, 5, 1);
+
+ printf("... modify -> options=5\n");
+
+ ip_len = 20 + 8 + 1; /* ip + options + payload */
+ ipo_ptag = build_ipo(l, ipo_ptag, 5);
+
+ assert_lengths(l, ip_len, 7, 1);
+
+ printf("... modify -> ip_payload=5\n");
+
+ ip_len = 20 + 8 + 5; /* ip + options + payload */
+ ip_ptag = build_ipv4(l, ip_ptag, 5, ip_len);
+
+ assert_lengths(l, ip_len, 7, 1);
+
+ ipo_ptag = ip_ptag = eth_ptag = 0;
+
+ libnet_clear_packet(l);
+
+
+ return (EXIT_SUCCESS);
+}
+
diff --git a/libnet/src/libnet_build_ip.c b/libnet/src/libnet_build_ip.c
index f08ec3e..9c20c57 100644
--- a/libnet/src/libnet_build_ip.c
+++ b/libnet/src/libnet_build_ip.c
@@ -40,35 +40,23 @@
#endif
+/* TODO len - should be calculated if zero */
libnet_ptag_t
-libnet_build_ipv4(u_int16_t len, u_int8_t tos, u_int16_t id, u_int16_t frag,
+libnet_build_ipv4(u_int16_t ip_len, u_int8_t tos, u_int16_t id, u_int16_t frag,
u_int8_t ttl, u_int8_t prot, u_int16_t sum, u_int32_t src, u_int32_t dst,
u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
{
- u_int32_t h, n, i, j;
+ u_int32_t n = LIBNET_IPV4_H; /* size of memory block */
libnet_pblock_t *p, *p_data, *p_temp;
struct libnet_ipv4_hdr ip_hdr;
- libnet_ptag_t ptag_data, ptag_hold;
+ libnet_ptag_t ptag_data = 0; /* used if there is ipv4 payload */
+ libnet_ptag_t ptag_hold;
if (l == NULL)
{
return (-1);
}
- n = LIBNET_IPV4_H; /* size of memory block */
- h = len; /* header length */
- // WRONG - this is total len of ip packet, and is put into the IP header
- ptag_data = 0; /* used if options are present */
- // WRONG - is used if there is ipv4 payload
-
- if (h + payload_s > IP_MAXPACKET)
- // WRONG - h is the total length, it already includes payload_s
- {
- snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
- "%s(): IP packet too large\n", __func__);
- return (-1);
- }
-
/*
* Find the existing protocol block if a ptag is specified, or create
* a new one.
@@ -79,24 +67,20 @@ u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
return (-1);
}
- memset(&ip_hdr, 0, sizeof(ip_hdr));
- ip_hdr.ip_v = 4; /* version 4 */
- ip_hdr.ip_hl = 5; /* 20 byte header */
+ memset(&ip_hdr, 0, sizeof(ip_hdr));
+ ip_hdr.ip_v = 4; /* version 4 */
+ ip_hdr.ip_hl = 5; /* 20 byte header, measured in 32-bit words */
/* check to see if there are IP options to include */
if (p->prev)
{
if (p->prev->type == LIBNET_PBLOCK_IPO_H)
{
- /*
- * Count up number of 32-bit words in options list, padding if
- * neccessary.
+ /* IPO block's length must be multiple of 4, or it's incorrectly
+ * padded, in which case there is no "correct" IP header length,
+ * it will too short or too long, we choose too short.
*/
- for (i = 0, j = 0; i < p->prev->b_len; i++)
- {
- (i % 4) ? j : j++;
- }
- ip_hdr.ip_hl += j;
+ ip_hdr.ip_hl += p->prev->b_len / 4;
}
}
// Note that p->h_len is not adjusted. This seems a bug, but it is because
@@ -104,7 +88,7 @@ u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
// but for IPPROTO_IP it is ignored in favor of the ip_hl.
ip_hdr.ip_tos = tos; /* IP tos */
- ip_hdr.ip_len = htons(h); /* total length */
+ ip_hdr.ip_len = htons(ip_len); /* total length */
ip_hdr.ip_id = htons(id); /* IP ID */
ip_hdr.ip_off = htons(frag); /* fragmentation flags */
ip_hdr.ip_ttl = ttl; /* time to live */
@@ -148,9 +132,6 @@ u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
ptag_data = p_temp->ptag;
offset -= p_temp->b_len;
- //p->h_len += offset;
- // WRONG h_len is unused for checksum for IPv4, and even if it was used,
- // the h_len doesn't depend on the payload size.
}
else
{
@@ -210,11 +191,7 @@ u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
/* update without setting this as the final pblock */
p_data->type = LIBNET_PBLOCK_IPDATA;
p_data->ptag = ++(l->ptag_state);
- p_data->h_len = payload_s;
-
- /* Adjust h_len for checksum. */
- p->h_len += payload_s;
- // WRONG - IPV4 checksum doesn't include the payload_s.
+ p_data->h_len = payload_s; /* TODO dead code, data blocks don't have headers */
/* data was added after the initial construction */
for (p_temp = l->protocol_blocks;
@@ -262,19 +239,6 @@ u_int8_t *payload, u_int32_t payload_s, libnet_t *l, libnet_ptag_t ptag)
libnet_pblock_setflags(p, LIBNET_PBLOCK_DO_CHECKSUM);
}
- /*
- * FREDRAYNAL: as we insert a new IP header, all checksums for headers
- * placed after this one will refer to here.
- */
- // WRONG - the total_size when updating the pblock will include the link layer
- // WRONG - it isn't called after adding options, so will be wrong by the amount of ip options
- // WRONG - it updates the wrong protocol blocks:
- // - the first time it runs we set the ip offsets for p (ipv4), and
- // ipdata to the total size of just the ip portion
- // - the next time, it starts at end, which is the ethernet block, and
- // updates everything up to but not including the ipv4 block to the total size, which means it
- // changes just the ethernet block, and the offset it sets is the total size including the ethernet
- // header.... WTF?
libnet_pblock_record_ip_offset(l, p);
return (ptag);
@@ -372,8 +336,8 @@ libnet_ptag_t
libnet_build_ipv4_options(u_int8_t *options, u_int32_t options_s, libnet_t *l,
libnet_ptag_t ptag)
{
- int offset, underflow;
- u_int32_t i, j, n, adj_size;
+ int options_size_increase = 0; /* increase will be negative if it's a decrease */
+ u_int32_t n, adj_size;
libnet_pblock_t *p, *p_temp;
struct libnet_ipv4_hdr *ip_hdr;
@@ -382,9 +346,6 @@ libnet_ptag_t ptag)
return (-1);
}
- underflow = 0;
- offset = 0;
-
/* check options list size */
if (options_s > LIBNET_MAXOPTION_SIZE)
{
@@ -406,15 +367,7 @@ libnet_ptag_t ptag)
p_temp = libnet_pblock_find(l, ptag);
if (p_temp)
{
- if (adj_size >= p_temp->b_len)
- {
- offset = adj_size - p_temp->b_len;
- }
- else
- {
- offset = p_temp->b_len - adj_size;
- underflow = 1;
- }
+ options_size_increase = adj_size - p_temp->b_len;
}
else
{
@@ -453,47 +406,21 @@ libnet_ptag_t ptag)
if (ptag && p->next)
{
p_temp = p->next;
- while ((p_temp->next) && (p_temp->type != LIBNET_PBLOCK_IPV4_H))
- {
- p_temp = p_temp->next;
- }
- /* fix the IP header size */
+ /* fix the IP header sizes */
if (p_temp->type == LIBNET_PBLOCK_IPV4_H)
{
- /*
- * Count up number of 32-bit words in options list, padding if
- * neccessary.
- */
- for (i = 0, j = 0; i < p->b_len; i++)
- {
- (i % 4) ? j : j++;
- }
ip_hdr = (struct libnet_ipv4_hdr *) p_temp->buf;
- ip_hdr->ip_hl = j + 5;
+ ip_hdr->ip_hl = 5 + adj_size / 4; /* 4 bits wide, so no byte order concerns */
+ ip_hdr->ip_len = htons(ntohs(ip_hdr->ip_len) + options_size_increase);
- // WRONG - must also fix the ip_len field!
-
- if (!underflow)
- {
- p_temp->h_len += offset;
- }
- else
- {
- p_temp->h_len -= offset;
- }
+ p_temp->h_len = ip_hdr->ip_hl * 4; /* Dead code, h_len isn't used for IPv4 block */
- // WRONG - must also correct the ip_offsets of the rest of the chain, or
- // the checksums will be wrong.
- //
- // Probably this will fix this, but need unit tests:
+ /* Correct the ip_offsets of the rest of the chain. */
libnet_pblock_record_ip_offset(l, p_temp);
}
}
- /* WRONG - this won't work if an ipv4 block is being replaced, it makes the
- * l->pblock_end point to the options, when it should be the link header.
- */
return (ptag ? ptag : libnet_pblock_update(l, p, adj_size,
LIBNET_PBLOCK_IPO_H));
bad: