ip-util: introduce ip_checksum()
It is equivalent to dhcp_packet_checksum(). It is generic and not specific to DHCP. Hence, renamed to ip_checksum().
This commit is contained in:
@@ -4,10 +4,10 @@
|
||||
***/
|
||||
|
||||
#include <net/if_arp.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dhcp-option.h"
|
||||
#include "dhcp-packet.h"
|
||||
#include "ip-util.h"
|
||||
#include "log.h"
|
||||
#include "memory-util.h"
|
||||
|
||||
@@ -79,41 +79,6 @@ int dhcp_message_init(
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
|
||||
uint64_t *buf_64 = (uint64_t*)buf;
|
||||
uint64_t *end_64 = buf_64 + (len / sizeof(uint64_t));
|
||||
uint64_t sum = 0;
|
||||
|
||||
/* See RFC1071 */
|
||||
|
||||
while (buf_64 < end_64) {
|
||||
sum += *buf_64;
|
||||
if (sum < *buf_64)
|
||||
/* wrap around in one's complement */
|
||||
sum++;
|
||||
|
||||
buf_64++;
|
||||
}
|
||||
|
||||
if (len % sizeof(uint64_t)) {
|
||||
/* If the buffer is not aligned to 64-bit, we need
|
||||
to zero-pad the last few bytes and add them in */
|
||||
uint64_t buf_tail = 0;
|
||||
|
||||
memcpy(&buf_tail, buf_64, len % sizeof(uint64_t));
|
||||
|
||||
sum += buf_tail;
|
||||
if (sum < buf_tail)
|
||||
/* wrap around */
|
||||
sum++;
|
||||
}
|
||||
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
return ~sum;
|
||||
}
|
||||
|
||||
void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
|
||||
uint16_t source_port, be32_t destination_addr,
|
||||
uint16_t destination_port, uint16_t len, int ip_service_type) {
|
||||
@@ -136,11 +101,11 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
|
||||
packet->udp.len = htobe16(len - DHCP_IP_SIZE);
|
||||
|
||||
packet->ip.check = packet->udp.len;
|
||||
packet->udp.check = dhcp_packet_checksum(&packet->ip.ttl, len - 8);
|
||||
packet->udp.check = ip_checksum(&packet->ip.ttl, len - 8);
|
||||
|
||||
packet->ip.ttl = IPDEFTTL;
|
||||
packet->ip.check = 0;
|
||||
packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE);
|
||||
packet->ip.check = ip_checksum(&packet->ip, DHCP_IP_SIZE);
|
||||
}
|
||||
|
||||
int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port) {
|
||||
@@ -193,7 +158,7 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, ui
|
||||
if all the other checks have passed
|
||||
*/
|
||||
|
||||
if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen))
|
||||
if (ip_checksum(&packet->ip, hdrlen))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: invalid IP checksum");
|
||||
|
||||
@@ -201,8 +166,7 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, ui
|
||||
packet->ip.check = packet->udp.len;
|
||||
packet->ip.ttl = 0;
|
||||
|
||||
if (dhcp_packet_checksum(&packet->ip.ttl,
|
||||
be16toh(packet->udp.len) + 12))
|
||||
if (ip_checksum(&packet->ip.ttl, be16toh(packet->udp.len) + 12))
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"ignoring packet: invalid UDP checksum");
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ int dhcp_message_init(
|
||||
size_t optlen,
|
||||
size_t *ret_optoffset);
|
||||
|
||||
uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len);
|
||||
|
||||
void dhcp_packet_append_ip_headers(
|
||||
DHCPPacket *packet,
|
||||
be32_t source_addr,
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "iovec-util.h"
|
||||
#include "ip-util.h"
|
||||
|
||||
static uint64_t complement_sum(uint64_t a, uint64_t b) {
|
||||
/* This performs one's complement addition (end-around carry). See RFC1071. */
|
||||
if (a <= UINT64_MAX - b)
|
||||
return a + b;
|
||||
|
||||
return a - (UINT64_MAX - b);
|
||||
}
|
||||
|
||||
static uint64_t checksum_iov(uint64_t sum, const struct iovec *iov) {
|
||||
assert(iov);
|
||||
|
||||
for (struct iovec i = *iov; iovec_is_set(&i); iovec_inc(&i, sizeof(uint64_t))) {
|
||||
uint64_t t = 0;
|
||||
memcpy(&t, i.iov_base, MIN(i.iov_len, sizeof(uint64_t)));
|
||||
sum = complement_sum(sum, t);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
static uint16_t checksum_finalize(uint64_t sum) {
|
||||
while ((sum >> 16) != 0)
|
||||
sum = (sum & 0xffffu) + (sum >> 16);
|
||||
|
||||
return ~sum;
|
||||
}
|
||||
|
||||
uint16_t ip_checksum(const void *buf, size_t len) {
|
||||
/* See RFC1071 */
|
||||
return checksum_finalize(checksum_iov(0, &IOVEC_MAKE(buf, len)));
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-forward.h"
|
||||
|
||||
uint16_t ip_checksum(const void *buf, size_t len);
|
||||
@@ -12,6 +12,7 @@ libsystemd_network_sources = files(
|
||||
'dhcp6-protocol.c',
|
||||
'icmp6-packet.c',
|
||||
'icmp6-util.c',
|
||||
'ip-util.c',
|
||||
'lldp-neighbor.c',
|
||||
'lldp-network.c',
|
||||
'ndisc-option.c',
|
||||
@@ -84,6 +85,9 @@ executables += [
|
||||
network_test_template + {
|
||||
'sources' : files('test-dhcp6-client.c'),
|
||||
},
|
||||
network_test_template + {
|
||||
'sources' : files('test-ip-util.c'),
|
||||
},
|
||||
network_test_template + {
|
||||
'sources' : files('test-ipv4ll-manual.c'),
|
||||
'type' : 'manual',
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "dhcp-network.h"
|
||||
#include "dhcp-option.h"
|
||||
#include "dhcp-packet.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "ip-util.h"
|
||||
#include "log.h"
|
||||
#include "tests.h"
|
||||
|
||||
@@ -107,16 +107,6 @@ TEST(dhcp_client_anonymize) {
|
||||
ASSERT_OK_ZERO(sd_dhcp_client_set_request_option(client, 101));
|
||||
}
|
||||
|
||||
TEST(dhcp_packet_checksum) {
|
||||
uint8_t buf[20] = {
|
||||
0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
ASSERT_EQ(dhcp_packet_checksum(buf, 20), be16toh(0x78ae));
|
||||
}
|
||||
|
||||
TEST(dhcp_identifier_set_iaid) {
|
||||
uint32_t iaid_legacy;
|
||||
be32_t iaid;
|
||||
@@ -181,13 +171,13 @@ int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const
|
||||
discover->ip.ttl = 0;
|
||||
discover->ip.check = discover->udp.len;
|
||||
|
||||
udp_check = ~dhcp_packet_checksum(&discover->ip.ttl, len - 8);
|
||||
udp_check = ~ip_checksum(&discover->ip.ttl, len - 8);
|
||||
ASSERT_EQ(udp_check, 0xffff);
|
||||
|
||||
discover->ip.ttl = IPDEFTTL;
|
||||
discover->ip.check = ip_check;
|
||||
|
||||
ip_check = ~dhcp_packet_checksum((uint8_t*) &discover->ip, sizeof(discover->ip));
|
||||
ip_check = ~ip_checksum((uint8_t*) &discover->ip, sizeof(discover->ip));
|
||||
ASSERT_EQ(ip_check, 0xffff);
|
||||
|
||||
ASSERT_NE(discover->dhcp.xid, 0u);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "ip-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
TEST(ip_checksum) {
|
||||
uint8_t buf[20] = {
|
||||
0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
ASSERT_EQ(ip_checksum(buf, 20), be16toh(0x78ae));
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
Reference in New Issue
Block a user