LCOV - code coverage report
Current view: top level - libsystemd-network - dhcp-network.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 88 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 5 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 72 0.0 %

           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.h>
       9                 :            : #include <net/if_arp.h>
      10                 :            : #include <stdio.h>
      11                 :            : #include <string.h>
      12                 :            : #include <sys/socket.h>
      13                 :            : #include <linux/filter.h>
      14                 :            : #include <linux/if_infiniband.h>
      15                 :            : #include <linux/if_packet.h>
      16                 :            : 
      17                 :            : #include "dhcp-internal.h"
      18                 :            : #include "fd-util.h"
      19                 :            : #include "socket-util.h"
      20                 :            : #include "unaligned.h"
      21                 :            : 
      22                 :          0 : static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
      23                 :            :                             uint32_t xid, const uint8_t *mac_addr,
      24                 :            :                             size_t mac_addr_len,
      25                 :            :                             const uint8_t *bcast_addr,
      26                 :            :                             const struct ether_addr *eth_mac,
      27                 :            :                             uint16_t arp_type, uint8_t dhcp_hlen,
      28                 :            :                             uint16_t port) {
      29                 :          0 :         struct sock_filter filter[] = {
      30                 :            :                 BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0),                                 /* A <- packet length */
      31                 :            :                 BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0),         /* packet >= DHCPPacket ? */
      32                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
      33                 :            :                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.protocol)), /* A <- IP protocol */
      34                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0),                /* IP protocol == UDP ? */
      35                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
      36                 :            :                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags */
      37                 :            :                 BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x20),                             /* A <- A & 0x20 (More Fragments bit) */
      38                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                          /* A == 0 ? */
      39                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
      40                 :            :                 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags + Fragment offset */
      41                 :            :                 BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x1fff),                           /* A <- A & 0x1fff (Fragment offset) */
      42                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                          /* A == 0 ? */
      43                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
      44                 :            :                 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)),    /* A <- UDP destination port */
      45                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, port, 1, 0),                       /* UDP destination port == DHCP client port ? */
      46                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
      47                 :            :                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)),     /* A <- DHCP op */
      48                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0),                  /* op == BOOTREPLY ? */
      49                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
      50                 :            :                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)),  /* A <- DHCP header type */
      51                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0),                   /* header type == arp_type ? */
      52                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
      53                 :            :                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)),    /* A <- client identifier */
      54                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0),                        /* client identifier == xid ? */
      55                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
      56                 :            :                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)),   /* A <- MAC address length */
      57                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0),                  /* address length == dhcp_hlen ? */
      58                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
      59                 :            : 
      60                 :            :                 /* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally
      61                 :            :                  * compare chaddr for ETH_ALEN bytes. */
      62                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 12),                                  /* A (the MAC address length) == ETH_ALEN ? */
      63                 :          0 :                 BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(&eth_mac->ether_addr_octet[0])),        /* A <- 4 bytes of client's MAC */
      64                 :            :                 BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                       /* X <- A */
      65                 :            :                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)),                 /* A <- 4 bytes of MAC from dhcp.chaddr */
      66                 :            :                 BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0),                                                /* A xor X */
      67                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                                          /* A == 0 ? */
      68                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                                          /* ignore */
      69                 :          0 :                 BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be16(&eth_mac->ether_addr_octet[4])),        /* A <- remainder of client's MAC */
      70                 :            :                 BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                       /* X <- A */
      71                 :            :                 BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4),             /* A <- remainder of MAC from dhcp.chaddr */
      72                 :            :                 BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0),                                                /* A xor X */
      73                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                                          /* A == 0 ? */
      74                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                                          /* ignore */
      75                 :            : 
      76                 :            :                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)),  /* A <- DHCP magic cookie */
      77                 :            :                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0),          /* cookie == DHCP magic cookie ? */
      78                 :            :                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
      79                 :            :                 BPF_STMT(BPF_RET + BPF_K, 65535),                                      /* return all */
      80                 :            :         };
      81                 :          0 :         struct sock_fprog fprog = {
      82                 :            :                 .len = ELEMENTSOF(filter),
      83                 :            :                 .filter = filter
      84                 :            :         };
      85                 :          0 :         _cleanup_close_ int s = -1;
      86                 :            :         int r;
      87                 :            : 
      88         [ #  # ]:          0 :         assert(ifindex > 0);
      89         [ #  # ]:          0 :         assert(link);
      90                 :            : 
      91                 :          0 :         s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
      92         [ #  # ]:          0 :         if (s < 0)
      93                 :          0 :                 return -errno;
      94                 :            : 
      95                 :          0 :         r = setsockopt_int(s, SOL_PACKET, PACKET_AUXDATA, true);
      96         [ #  # ]:          0 :         if (r < 0)
      97                 :          0 :                 return r;
      98                 :            : 
      99                 :          0 :         r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
     100         [ #  # ]:          0 :         if (r < 0)
     101                 :          0 :                 return -errno;
     102                 :            : 
     103                 :          0 :         link->ll = (struct sockaddr_ll) {
     104                 :            :                 .sll_family = AF_PACKET,
     105                 :          0 :                 .sll_protocol = htobe16(ETH_P_IP),
     106                 :            :                 .sll_ifindex = ifindex,
     107                 :          0 :                 .sll_hatype = htobe16(arp_type),
     108                 :            :                 .sll_halen = mac_addr_len,
     109                 :            :         };
     110                 :          0 :         memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len);
     111                 :            : 
     112   [ #  #  #  #  :          0 :         r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll));
                   #  # ]
     113         [ #  # ]:          0 :         if (r < 0)
     114                 :          0 :                 return -errno;
     115                 :            : 
     116                 :          0 :         return TAKE_FD(s);
     117                 :            : }
     118                 :            : 
     119                 :          0 : int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
     120                 :            :                                  uint32_t xid, const uint8_t *mac_addr,
     121                 :            :                                  size_t mac_addr_len, uint16_t arp_type,
     122                 :            :                                  uint16_t port) {
     123                 :            :         static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
     124                 :            :         /* Default broadcast address for IPoIB */
     125                 :            :         static const uint8_t ib_bcast[] = {
     126                 :            :                 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b,
     127                 :            :                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     128                 :            :                 0xff, 0xff, 0xff, 0xff
     129                 :            :           };
     130                 :          0 :         struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } };
     131                 :          0 :         const uint8_t *bcast_addr = NULL;
     132                 :          0 :         uint8_t dhcp_hlen = 0;
     133                 :            : 
     134         [ #  # ]:          0 :         if (arp_type == ARPHRD_ETHER) {
     135   [ #  #  #  # ]:          0 :                 assert_return(mac_addr_len == ETH_ALEN, -EINVAL);
     136                 :          0 :                 memcpy(&eth_mac, mac_addr, ETH_ALEN);
     137                 :          0 :                 bcast_addr = eth_bcast;
     138                 :          0 :                 dhcp_hlen = ETH_ALEN;
     139         [ #  # ]:          0 :         } else if (arp_type == ARPHRD_INFINIBAND) {
     140   [ #  #  #  # ]:          0 :                 assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL);
     141                 :          0 :                 bcast_addr = ib_bcast;
     142                 :            :         } else
     143                 :          0 :                 return -EINVAL;
     144                 :            : 
     145                 :          0 :         return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len,
     146                 :            :                                 bcast_addr, &eth_mac, arp_type, dhcp_hlen, port);
     147                 :            : }
     148                 :            : 
     149                 :          0 : int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
     150                 :          0 :         union sockaddr_union src = {
     151                 :            :                 .in.sin_family = AF_INET,
     152                 :          0 :                 .in.sin_port = htobe16(port),
     153                 :            :                 .in.sin_addr.s_addr = address,
     154                 :            :         };
     155                 :          0 :         _cleanup_close_ int s = -1;
     156                 :            :         int r;
     157                 :            : 
     158                 :          0 :         s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
     159         [ #  # ]:          0 :         if (s < 0)
     160                 :          0 :                 return -errno;
     161                 :            : 
     162                 :          0 :         r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6);
     163         [ #  # ]:          0 :         if (r < 0)
     164                 :          0 :                 return r;
     165                 :            : 
     166                 :          0 :         r = setsockopt_int(s, SOL_SOCKET, SO_REUSEADDR, true);
     167         [ #  # ]:          0 :         if (r < 0)
     168                 :          0 :                 return r;
     169                 :            : 
     170         [ #  # ]:          0 :         if (ifindex > 0) {
     171                 :          0 :                 r = socket_bind_to_ifindex(s, ifindex);
     172         [ #  # ]:          0 :                 if (r < 0)
     173                 :          0 :                         return r;
     174                 :            :         }
     175                 :            : 
     176         [ #  # ]:          0 :         if (address == INADDR_ANY) {
     177                 :          0 :                 r = setsockopt_int(s, IPPROTO_IP, IP_PKTINFO, true);
     178         [ #  # ]:          0 :                 if (r < 0)
     179                 :          0 :                         return r;
     180                 :            : 
     181                 :          0 :                 r = setsockopt_int(s, SOL_SOCKET, SO_BROADCAST, true);
     182         [ #  # ]:          0 :                 if (r < 0)
     183                 :          0 :                         return r;
     184                 :            : 
     185                 :            :         } else {
     186                 :          0 :                 r = setsockopt_int(s, IPPROTO_IP, IP_FREEBIND, true);
     187         [ #  # ]:          0 :                 if (r < 0)
     188                 :          0 :                         return r;
     189                 :            :         }
     190                 :            : 
     191                 :          0 :         r = bind(s, &src.sa, sizeof(src.in));
     192         [ #  # ]:          0 :         if (r < 0)
     193                 :          0 :                 return -errno;
     194                 :            : 
     195                 :          0 :         return TAKE_FD(s);
     196                 :            : }
     197                 :            : 
     198                 :          0 : int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
     199                 :            :                                  const void *packet, size_t len) {
     200                 :            :         int r;
     201                 :            : 
     202         [ #  # ]:          0 :         assert(link);
     203         [ #  # ]:          0 :         assert(packet);
     204         [ #  # ]:          0 :         assert(len);
     205                 :            : 
     206   [ #  #  #  #  :          0 :         r = sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll));
                   #  # ]
     207         [ #  # ]:          0 :         if (r < 0)
     208                 :          0 :                 return -errno;
     209                 :            : 
     210                 :          0 :         return 0;
     211                 :            : }
     212                 :            : 
     213                 :          0 : int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
     214                 :            :                                  const void *packet, size_t len) {
     215                 :          0 :         union sockaddr_union dest = {
     216                 :            :                 .in.sin_family = AF_INET,
     217                 :          0 :                 .in.sin_port = htobe16(port),
     218                 :            :                 .in.sin_addr.s_addr = address,
     219                 :            :         };
     220                 :            :         int r;
     221                 :            : 
     222         [ #  # ]:          0 :         assert(s >= 0);
     223         [ #  # ]:          0 :         assert(packet);
     224         [ #  # ]:          0 :         assert(len);
     225                 :            : 
     226                 :          0 :         r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in));
     227         [ #  # ]:          0 :         if (r < 0)
     228                 :          0 :                 return -errno;
     229                 :            : 
     230                 :          0 :         return 0;
     231                 :            : }

Generated by: LCOV version 1.14