chiark / gitweb /
sd-dhcp: message_init - only set secs in the client
[elogind.git] / src / libsystemd-dhcp / dhcp-packet.c
index d606d55a05bfadbe8934d10fdbeb1b9199ac4298..1937de4252110106aa7abf1fb2ad7842bed43267 100644 (file)
 #define DHCP_CLIENT_MIN_OPTIONS_SIZE            312
 
 int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
-                      uint8_t type, uint16_t secs, uint8_t **opt,
-                      size_t *optlen) {
+                      uint8_t type, uint8_t **opt, size_t *optlen) {
         int err;
 
+        assert(op == BOOTREQUEST || op == BOOTREPLY);
+
         *opt = (uint8_t *)(message + 1);
 
         if (*optlen < 4)
@@ -52,10 +53,6 @@ int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
         message->hlen = ETHER_ADDR_LEN;
         message->xid = htobe32(xid);
 
-        /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers
-           refuse to issue an DHCP lease if 'secs' is set to zero */
-        message->secs = htobe16(secs);
-
         (*opt)[0] = 0x63;
         (*opt)[1] = 0x82;
         (*opt)[2] = 0x53;
@@ -94,10 +91,7 @@ static uint16_t dhcp_checksum(void *buf, int len) {
         return ~sum;
 }
 
-void dhcp_packet_append_ip_headers(DHCPPacket *packet, uint8_t op,
-                                   uint16_t len) {
-        assert(op == BOOTREQUEST || op == BOOTREPLY);
-
+void dhcp_packet_append_ip_headers(DHCPPacket *packet, uint16_t len) {
         packet->ip.version = IPVERSION;
         packet->ip.ihl = DHCP_IP_SIZE / 4;
         packet->ip.tot_len = htobe16(len);
@@ -106,16 +100,8 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, uint8_t op,
         packet->ip.saddr = INADDR_ANY;
         packet->ip.daddr = INADDR_BROADCAST;
 
-        switch (op) {
-                case BOOTREQUEST:
-                        packet->udp.source = htobe16(DHCP_PORT_CLIENT);
-                        packet->udp.dest = htobe16(DHCP_PORT_SERVER);
-                        break;
-                case BOOTREPLY:
-                        packet->udp.source = htobe16(DHCP_PORT_SERVER);
-                        packet->udp.dest = htobe16(DHCP_PORT_CLIENT);
-                        break;
-        }
+        packet->udp.source = htobe16(DHCP_PORT_CLIENT);
+        packet->udp.dest = htobe16(DHCP_PORT_SERVER);
 
         packet->udp.len = htobe16(len - DHCP_IP_SIZE);
 
@@ -127,44 +113,77 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, uint8_t op,
         packet->ip.check = dhcp_checksum(&packet->ip, DHCP_IP_SIZE);
 }
 
-int dhcp_packet_verify_headers(DHCPPacket *packet, uint8_t op, size_t len) {
+int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len) {
         size_t hdrlen;
 
-        assert(op == BOOTREQUEST || op == BOOTREPLY);
+        assert(packet);
 
-        if (len < (DHCP_IP_UDP_SIZE + DHCP_MESSAGE_SIZE))
+        /* IP */
+
+        if (len < DHCP_IP_SIZE) {
+                log_dhcp_client(client, "ignoring packet: packet (%zu bytes) "
+                                " smaller than IP header (%u bytes)", len,
+                                DHCP_IP_SIZE);
+                return -EINVAL;
+        }
+
+        if (packet->ip.ihl < 5) {
+                log_dhcp_client(client, "ignoring packet: IPv4 IHL (%u words) invalid",
+                                packet->ip.ihl);
                 return -EINVAL;
+        }
 
         hdrlen = packet->ip.ihl * 4;
-        if (hdrlen < 20 || hdrlen > len || dhcp_checksum(&packet->ip, hdrlen))
+        if (hdrlen < 20) {
+                log_dhcp_client(client, "ignoring packet: IPv4 IHL (%zu bytes) "
+                                "smaller than minimum (20 bytes)", hdrlen);
                 return -EINVAL;
+        }
 
-        if (hdrlen + be16toh(packet->udp.len) > len)
+        if (len < hdrlen) {
+                log_dhcp_client(client, "ignoring packet: packet (%zu bytes) "
+                                "smaller than expected (%zu) by IP header", len,
+                                hdrlen);
                 return -EINVAL;
+        }
+
+        if (dhcp_checksum(&packet->ip, hdrlen)) {
+                log_dhcp_client(client, "ignoring packet: invalid IP checksum");
+                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,
+                                DHCP_IP_UDP_SIZE);
+                return -EINVAL;
+        }
+
+        if (len < hdrlen + be16toh(packet->udp.len)) {
+                log_dhcp_client(client, "ignoring packet: packet (%zu bytes) "
+                                "smaller than expected (%zu) by UDP header", len,
+                                hdrlen + be16toh(packet->udp.len));
+                return -EINVAL;
+        }
 
         if (packet->udp.check) {
                 packet->ip.check = packet->udp.len;
                 packet->ip.ttl = 0;
 
                 if (dhcp_checksum(&packet->ip.ttl,
-                                  be16toh(packet->udp.len) + 12))
+                                  be16toh(packet->udp.len) + 12)) {
+                        log_dhcp_client(client, "ignoring packet: invalid UDP checksum");
                         return -EINVAL;
+                }
         }
 
-        if (packet->dhcp.op != op)
+        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;
-
-        switch (op) {
-                case BOOTREQUEST:
-                        if (be16toh(packet->udp.source) != DHCP_PORT_CLIENT ||
-                            be16toh(packet->udp.dest) != DHCP_PORT_SERVER)
-                                return -EINVAL;
-                        break;
-                case BOOTREPLY:
-                        if (be16toh(packet->udp.source) != DHCP_PORT_SERVER ||
-                            be16toh(packet->udp.dest) != DHCP_PORT_CLIENT)
-                                return -EINVAL;
-                        break;
         }
 
         return 0;