X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-network%2Fdhcp-packet.c;h=4f90c283a21485a686b18704dbf1227b2a058d46;hp=95c4277f8c45cf425c125f6a304d3a77c2c9e784;hb=2ad7561f9f658f8dee168a76654c7d918e2260c7;hpb=fe8db0c5ee3365a2fc80ee7ebffa238f9a0a2ae2;ds=sidebyside diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c index 95c4277f8..4f90c283a 100644 --- a/src/libsystemd-network/dhcp-packet.c +++ b/src/libsystemd-network/dhcp-packet.c @@ -69,7 +69,7 @@ int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, return 0; } -static uint16_t dhcp_checksum(void *buf, int len) { +uint16_t dhcp_packet_checksum(void *buf, int len) { uint32_t sum; uint16_t *check; int i; @@ -92,26 +92,28 @@ static uint16_t dhcp_checksum(void *buf, int len) { return ~sum; } -void dhcp_packet_append_ip_headers(DHCPPacket *packet, uint16_t len) { +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) { packet->ip.version = IPVERSION; packet->ip.ihl = DHCP_IP_SIZE / 4; packet->ip.tot_len = htobe16(len); packet->ip.protocol = IPPROTO_UDP; - packet->ip.saddr = INADDR_ANY; - packet->ip.daddr = INADDR_BROADCAST; + packet->ip.saddr = source_addr; + packet->ip.daddr = destination_addr; - packet->udp.source = htobe16(DHCP_PORT_CLIENT); - packet->udp.dest = htobe16(DHCP_PORT_SERVER); + packet->udp.source = htobe16(source_port); + packet->udp.dest = htobe16(destination_port); packet->udp.len = htobe16(len - DHCP_IP_SIZE); packet->ip.check = packet->udp.len; - packet->udp.check = dhcp_checksum(&packet->ip.ttl, len - 8); + packet->udp.check = dhcp_packet_checksum(&packet->ip.ttl, len - 8); packet->ip.ttl = IPDEFTTL; packet->ip.check = 0; - packet->ip.check = dhcp_checksum(&packet->ip, DHCP_IP_SIZE); + packet->ip.check = dhcp_packet_checksum(&packet->ip, DHCP_IP_SIZE); } int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { @@ -128,6 +130,11 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { return -EINVAL; } + if (packet->ip.version != IPVERSION) { + log_dhcp_client(client, "ignoring packet: not IPv4"); + return -EINVAL; + } + if (packet->ip.ihl < 5) { log_dhcp_client(client, "ignoring packet: IPv4 IHL (%u words) invalid", packet->ip.ihl); @@ -148,13 +155,13 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { return -EINVAL; } - if (dhcp_checksum(&packet->ip, hdrlen)) { - log_dhcp_client(client, "ignoring packet: invalid IP checksum"); + /* UDP */ + + if (packet->ip.protocol != IPPROTO_UDP) { + log_dhcp_client(client, "ignoring packet: not UDP"); return -EINVAL; } - /* UDP */ - if (len < DHCP_IP_UDP_SIZE) { log_dhcp_client(client, "ignoring packet: packet (%zu bytes) " " smaller than IP+UDP header (%u bytes)", len, @@ -169,23 +176,32 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { return -EINVAL; } + if (be16toh(packet->udp.dest) != DHCP_PORT_CLIENT) { + log_dhcp_client(client, "ignoring packet: to port %u, which " + "is not the DHCP client port (%u)", + be16toh(packet->udp.dest), DHCP_PORT_CLIENT); + return -EINVAL; + } + + /* checksums - computing these is relatively expensive, so only do it + if all the other checks have passed + */ + + if (dhcp_packet_checksum(&packet->ip, hdrlen)) { + log_dhcp_client(client, "ignoring packet: invalid IP checksum"); + return -EINVAL; + } + if (checksum && packet->udp.check) { packet->ip.check = packet->udp.len; packet->ip.ttl = 0; - if (dhcp_checksum(&packet->ip.ttl, + if (dhcp_packet_checksum(&packet->ip.ttl, be16toh(packet->udp.len) + 12)) { log_dhcp_client(client, "ignoring packet: invalid UDP checksum"); return -EINVAL; } } - if (be16toh(packet->udp.dest) != DHCP_PORT_CLIENT) { - log_dhcp_client(client, "ignoring packet: to port %u, which " - "is not the DHCP client port (%u)", - be16toh(packet->udp.dest), DHCP_PORT_CLIENT); - return -EINVAL; - } - return 0; }