busybox/networking/udhcp/d6_socket.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Copyright (C) 2011 Denys Vlasenko.
   4 *
   5 * Licensed under GPLv2, see file LICENSE in this source tree.
   6 */
   7#include "common.h"
   8#include "d6_common.h"
   9#include <net/if.h>
  10#include <ifaddrs.h>
  11#include <netpacket/packet.h>
  12
  13int FAST_FUNC d6_read_interface(
  14                const char *interface,
  15                int *ifindex,
  16                struct in6_addr *nip6,
  17                uint8_t *mac)
  18{
  19        int retval = 3;
  20        struct ifaddrs *ifap, *ifa;
  21
  22        getifaddrs(&ifap);
  23        for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
  24                struct sockaddr_in6 *sip6;
  25
  26                if (!ifa->ifa_addr || (strcmp(ifa->ifa_name, interface) != 0))
  27                        continue;
  28
  29                if (ifa->ifa_addr->sa_family == AF_PACKET) {
  30                        struct sockaddr_ll *sll = (void*)(ifa->ifa_addr);
  31                        memcpy(mac, sll->sll_addr, 6);
  32                        log2("MAC %02x:%02x:%02x:%02x:%02x:%02x",
  33                                mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
  34                        );
  35                        *ifindex = sll->sll_ifindex;
  36                        log2("ifindex %d", *ifindex);
  37                        retval &= (3 - (1<<0));
  38                }
  39#if 0
  40                if (ifa->ifa_addr->sa_family == AF_INET) {
  41                        *nip = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
  42                        log1("IP %s", inet_ntoa(((struct sockaddr_in *)ifa->ifa_addr)->sin_addr));
  43                }
  44#endif
  45/* RFC 3315
  46 * 16. Client Source Address and Interface Selection
  47 *
  48 * "When a client sends a DHCP message to the
  49 * All_DHCP_Relay_Agents_and_Servers address, ... ... The client
  50 * MUST use a link-local address assigned to the interface for which it
  51 * is requesting configuration information as the source address in the
  52 * header of the IP datagram."
  53 */
  54                sip6 = (void*)(ifa->ifa_addr);
  55
  56                if (ifa->ifa_addr->sa_family == AF_INET6
  57                 && IN6_IS_ADDR_LINKLOCAL(&sip6->sin6_addr)
  58                ) {
  59                        *nip6 = sip6->sin6_addr; /* struct copy */
  60                        log1(
  61                                "IPv6 %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
  62                                nip6->s6_addr[0], nip6->s6_addr[1],
  63                                nip6->s6_addr[2], nip6->s6_addr[3],
  64                                nip6->s6_addr[4], nip6->s6_addr[5],
  65                                nip6->s6_addr[6], nip6->s6_addr[7],
  66                                nip6->s6_addr[8], nip6->s6_addr[9],
  67                                nip6->s6_addr[10], nip6->s6_addr[11],
  68                                nip6->s6_addr[12], nip6->s6_addr[13],
  69                                nip6->s6_addr[14], nip6->s6_addr[15]
  70                        );
  71                        retval &= (3 - (1<<1));
  72                }
  73        }
  74        freeifaddrs(ifap);
  75
  76        if (retval & (1<<0)) {
  77                /* This iface has no MAC (e.g. ppp), generate a random one */
  78                struct ifreq ifr;
  79                int fd;
  80
  81                /*memset(&ifr, 0, sizeof(ifr)); - SIOCGIFINDEX does not need to clear all */
  82                strncpy_IFNAMSIZ(ifr.ifr_name, interface);
  83                fd = xsocket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
  84                if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) {
  85                        *ifindex = ifr.ifr_ifindex;
  86                        log2("ifindex %d", *ifindex);
  87                        if (((uint32_t*)mac)[0] == 0) {
  88                                /* invent a fictitious MAC (once) */
  89                                ((uint32_t*)mac)[0] = rand();
  90                                ((uint16_t*)mac)[2] = rand();
  91                                mac[0] &= 0xfc; /* make sure it's not bcast */
  92                        }
  93                        retval &= (3 - (1<<0));
  94                }
  95                close(fd);
  96        }
  97
  98        if (retval & (1<<0))
  99                bb_error_msg("can't get %s", "MAC");
 100        if (retval & (1<<1))
 101                bb_error_msg("can't get %s", "link-local IPv6 address");
 102        return retval;
 103}
 104
 105int FAST_FUNC d6_listen_socket(int port, const char *inf)
 106{
 107        int fd;
 108        struct sockaddr_in6 addr;
 109        char *colon;
 110
 111        log2("opening listen socket on *:%d %s", port, inf);
 112        fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
 113
 114        setsockopt_reuseaddr(fd);
 115        if (setsockopt_broadcast(fd) == -1)
 116                bb_simple_perror_msg_and_die("SO_BROADCAST");
 117
 118        /* SO_BINDTODEVICE doesn't work on ethernet aliases (ethN:M) */
 119        colon = strrchr(inf, ':');
 120        if (colon)
 121                *colon = '\0';
 122
 123        if (setsockopt_bindtodevice(fd, inf))
 124                xfunc_die(); /* warning is already printed */
 125
 126        if (colon)
 127                *colon = ':';
 128
 129        memset(&addr, 0, sizeof(addr));
 130        addr.sin6_family = AF_INET6;
 131        addr.sin6_port = htons(port);
 132        /* addr.sin6_addr is all-zeros */
 133        xbind(fd, (struct sockaddr *)&addr, sizeof(addr));
 134
 135        return fd;
 136}
 137