diff --git a/include/tins/ip.h b/include/tins/ip.h index c147357..72b25ff 100644 --- a/include/tins/ip.h +++ b/include/tins/ip.h @@ -48,6 +48,13 @@ namespace Tins { * By default, IP PDUs are initialized, setting TTL to IP::DEFAULT_TTL, * id field to 1 and version to 4. Taking this into account, users * should set destination and source port and would be enough to send one. + * + * When IP is the lowest layer on a packet, and the packet is serialized + * this willc heck if the source address is different than 0.0.0.0. If it is, + * the address of the interface in which the packet is going to be sent + * is retrieved (by using the routing table and the destination address) + * and set as the source address. If you don't want this behaviour, simply + * set the source address to 0.0.0.0. */ class IP : public PDU { public: diff --git a/src/ip.cpp b/src/ip.cpp index 1cbb360..2aa8cdd 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -426,13 +426,11 @@ void IP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU* pare } memset(buffer + sizeof(_ip) + _options_size, 0, _padded_options_size - _options_size); - if(parent) { - uint32_t check = Utils::do_checksum(buffer, buffer + sizeof(_ip) + _padded_options_size); - while (check >> 16) - check = (check & 0xffff) + (check >> 16); - checksum(~check); - ((iphdr*)buffer)->check = _ip.check; - } + uint32_t check = Utils::do_checksum(buffer, buffer + sizeof(_ip) + _padded_options_size); + while (check >> 16) + check = (check & 0xffff) + (check >> 16); + checksum(~check); + ((iphdr*)buffer)->check = _ip.check; } bool IP::matches_response(const uint8_t *ptr, uint32_t total_sz) const { diff --git a/tests/src/ip.cpp b/tests/src/ip.cpp index f41e7ee..2f82b4f 100644 --- a/tests/src/ip.cpp +++ b/tests/src/ip.cpp @@ -26,6 +26,7 @@ public: fragmented_ether_ip_packet[], tot_len_zero_packet[]; void test_equals(const IP &ip1, const IP &ip2); + void test_overwrite_source_address(IP& ip); }; const uint8_t IPTest::expected_packet[] = { @@ -718,3 +719,42 @@ TEST_F(IPTest, RemoveOption) { PDU::serialization_type new_buffer = ip.serialize(); EXPECT_EQ(old_buffer, new_buffer); } + +void IPTest::test_overwrite_source_address(IP& ip) { + const uint8_t expected_output[] = { + 69,0,0,40,0,1,0,0,128,6,38,186,1,2,3,4,8,8,8,8,0,32,0,12,0, + 0,0,0,0,0,0,0,80,0,127,166,27,253,0,0 + }; + // Add TCP so we can check if the timestamp is correctly calculated + ip /= TCP(12, 32); + + PDU::serialization_type buffer = ip.serialize(); + EXPECT_EQ(IPv4Address("1.2.3.4"), ip.src_addr()); + EXPECT_EQ(0x26ba, ip.checksum()); + + vector output_buffer(expected_output, + expected_output + sizeof(expected_output)); + EXPECT_EQ(output_buffer, buffer); +} + +TEST_F(IPTest, OverwriteSourceAddress) { + IP ip("8.8.8.8"); + ip.src_addr("1.2.3.4"); + test_overwrite_source_address(ip); +} + +TEST_F(IPTest, OverwriteSourceAddressUsingConstructor) { + IP ip("8.8.8.8", "1.2.3.4"); + test_overwrite_source_address(ip); +} + +TEST_F(IPTest, OverwriteSourceAddressConstructingFromBuffer) { + // Only the expected packet's IP layer + const uint8_t expected_output[] = { + 69,0,0,20,0,1,0,0,128,0,0,0,1,2,3,4,8,8,8,8 + }; + IP ip(expected_output, sizeof(expected_output)); + test_overwrite_source_address(ip); +} + +