LCOV - code coverage report
Current view: top level - libsystemd-network - dhcp-packet.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 60 75 80.0 %
Date: 2019-08-23 13:36:53 Functions: 4 4 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 26 64 40.6 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : /***
       3                 :            :   Copyright © 2013 Intel Corporation. All rights reserved.
       4                 :            : ***/
       5                 :            : 
       6                 :            : #include <errno.h>
       7                 :            : #include <net/ethernet.h>
       8                 :            : #include <net/if_arp.h>
       9                 :            : #include <string.h>
      10                 :            : 
      11                 :            : #include "dhcp-internal.h"
      12                 :            : #include "dhcp-protocol.h"
      13                 :            : 
      14                 :            : #define DHCP_CLIENT_MIN_OPTIONS_SIZE            312
      15                 :            : 
      16                 :         12 : int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
      17                 :            :                       uint8_t type, uint16_t arp_type, size_t optlen,
      18                 :            :                       size_t *optoffset) {
      19                 :         12 :         size_t offset = 0;
      20                 :            :         int r;
      21                 :            : 
      22   [ +  -  -  + ]:         12 :         assert(IN_SET(op, BOOTREQUEST, BOOTREPLY));
      23   [ +  -  -  + ]:         12 :         assert(IN_SET(arp_type, ARPHRD_ETHER, ARPHRD_INFINIBAND));
      24                 :            : 
      25                 :         12 :         message->op = op;
      26                 :         12 :         message->htype = arp_type;
      27         [ +  - ]:         12 :         message->hlen = (arp_type == ARPHRD_ETHER) ? ETHER_ADDR_LEN : 0;
      28                 :         12 :         message->xid = htobe32(xid);
      29                 :         12 :         message->magic = htobe32(DHCP_MAGIC_COOKIE);
      30                 :            : 
      31                 :         12 :         r = dhcp_option_append(message, optlen, &offset, 0,
      32                 :            :                                SD_DHCP_OPTION_MESSAGE_TYPE, 1, &type);
      33         [ -  + ]:         12 :         if (r < 0)
      34                 :          0 :                 return r;
      35                 :            : 
      36                 :         12 :         *optoffset = offset;
      37                 :            : 
      38                 :         12 :         return 0;
      39                 :            : }
      40                 :            : 
      41                 :         40 : uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
      42                 :         40 :         uint64_t *buf_64 = (uint64_t*)buf;
      43                 :         40 :         uint64_t *end_64 = buf_64 + (len / sizeof(uint64_t));
      44                 :         40 :         uint64_t sum = 0;
      45                 :            : 
      46                 :            :         /* See RFC1071 */
      47                 :            : 
      48         [ +  + ]:        680 :         while (buf_64 < end_64) {
      49                 :        640 :                 sum += *buf_64;
      50         [ +  + ]:        640 :                 if (sum < *buf_64)
      51                 :            :                         /* wrap around in one's complement */
      52                 :         24 :                         sum++;
      53                 :            : 
      54                 :        640 :                 buf_64++;
      55                 :            :         }
      56                 :            : 
      57         [ +  + ]:         40 :         if (len % sizeof(uint64_t)) {
      58                 :            :                 /* If the buffer is not aligned to 64-bit, we need
      59                 :            :                    to zero-pad the last few bytes and add them in */
      60                 :         32 :                 uint64_t buf_tail = 0;
      61                 :            : 
      62                 :         32 :                 memcpy(&buf_tail, buf_64, len % sizeof(uint64_t));
      63                 :            : 
      64                 :         32 :                 sum += buf_tail;
      65         [ -  + ]:         32 :                 if (sum < buf_tail)
      66                 :            :                         /* wrap around */
      67                 :          0 :                         sum++;
      68                 :            :         }
      69                 :            : 
      70         [ +  + ]:        145 :         while (sum >> 16)
      71                 :        105 :                 sum = (sum & 0xffff) + (sum >> 16);
      72                 :            : 
      73                 :         40 :         return ~sum;
      74                 :            : }
      75                 :            : 
      76                 :          8 : void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr,
      77                 :            :                                    uint16_t source_port, be32_t destination_addr,
      78                 :            :                                    uint16_t destination_port, uint16_t len) {
      79                 :          8 :         packet->ip.version = IPVERSION;
      80                 :          8 :         packet->ip.ihl = DHCP_IP_SIZE / 4;
      81                 :          8 :         packet->ip.tot_len = htobe16(len);
      82                 :            : 
      83                 :          8 :         packet->ip.tos = IPTOS_CLASS_CS6;
      84                 :            : 
      85                 :          8 :         packet->ip.protocol = IPPROTO_UDP;
      86                 :          8 :         packet->ip.saddr = source_addr;
      87                 :          8 :         packet->ip.daddr = destination_addr;
      88                 :            : 
      89                 :          8 :         packet->udp.source = htobe16(source_port);
      90                 :          8 :         packet->udp.dest = htobe16(destination_port);
      91                 :            : 
      92                 :          8 :         packet->udp.len = htobe16(len - DHCP_IP_SIZE);
      93                 :            : 
      94                 :          8 :         packet->ip.check = packet->udp.len;
      95                 :          8 :         packet->udp.check = dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, len - 8);
      96                 :            : 
      97                 :          8 :         packet->ip.ttl = IPDEFTTL;
      98                 :          8 :         packet->ip.check = 0;
      99                 :          8 :         packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE);
     100                 :          8 : }
     101                 :            : 
     102                 :          4 : int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port) {
     103                 :            :         size_t hdrlen;
     104                 :            : 
     105         [ -  + ]:          4 :         assert(packet);
     106                 :            : 
     107                 :            :         /* IP */
     108                 :            : 
     109         [ -  + ]:          4 :         if (packet->ip.version != IPVERSION)
     110         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     111                 :            :                                        "ignoring packet: not IPv4");
     112                 :            : 
     113         [ -  + ]:          4 :         if (packet->ip.ihl < 5)
     114         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     115                 :            :                                        "ignoring packet: IPv4 IHL (%u words) invalid",
     116                 :            :                                        packet->ip.ihl);
     117                 :            : 
     118                 :          4 :         hdrlen = packet->ip.ihl * 4;
     119         [ -  + ]:          4 :         if (hdrlen < 20)
     120         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     121                 :            :                                        "ignoring packet: IPv4 IHL (%zu bytes) "
     122                 :            :                                        "smaller than minimum (20 bytes)",
     123                 :            :                                        hdrlen);
     124                 :            : 
     125         [ -  + ]:          4 :         if (len < hdrlen)
     126         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     127                 :            :                                        "ignoring packet: packet (%zu bytes) "
     128                 :            :                                        "smaller than expected (%zu) by IP header",
     129                 :            :                                        len, hdrlen);
     130                 :            : 
     131                 :            :         /* UDP */
     132                 :            : 
     133         [ -  + ]:          4 :         if (packet->ip.protocol != IPPROTO_UDP)
     134         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     135                 :            :                                        "ignoring packet: not UDP");
     136                 :            : 
     137         [ -  + ]:          4 :         if (len < hdrlen + be16toh(packet->udp.len))
     138         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     139                 :            :                                        "ignoring packet: packet (%zu bytes) "
     140                 :            :                                        "smaller than expected (%zu) by UDP header",
     141                 :            :                                        len, hdrlen + be16toh(packet->udp.len));
     142                 :            : 
     143         [ -  + ]:          4 :         if (be16toh(packet->udp.dest) != port)
     144         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     145                 :            :                                        "ignoring packet: to port %u, which "
     146                 :            :                                        "is not the DHCP client port (%u)",
     147                 :            :                                        be16toh(packet->udp.dest), port);
     148                 :            : 
     149                 :            :         /* checksums - computing these is relatively expensive, so only do it
     150                 :            :            if all the other checks have passed
     151                 :            :          */
     152                 :            : 
     153         [ -  + ]:          4 :         if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen))
     154         [ #  # ]:          0 :                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     155                 :            :                                        "ignoring packet: invalid IP checksum");
     156                 :            : 
     157   [ +  -  -  + ]:          4 :         if (checksum && packet->udp.check) {
     158                 :          0 :                 packet->ip.check = packet->udp.len;
     159                 :          0 :                 packet->ip.ttl = 0;
     160                 :            : 
     161         [ #  # ]:          0 :                 if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl,
     162                 :          0 :                                   be16toh(packet->udp.len) + 12))
     163         [ #  # ]:          0 :                         return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
     164                 :            :                                                "ignoring packet: invalid UDP checksum");
     165                 :            :         }
     166                 :            : 
     167                 :          4 :         return 0;
     168                 :            : }

Generated by: LCOV version 1.14