LCOV - code coverage report
Current view: top level - libsystemd-network - dhcp-network.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 0 88 0.0 %
Date: 2019-08-22 15:41:25 Functions: 0 5 0.0 %

          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