"Fossies" - the Fresh Open Source Software Archive

Member "minidlna-1.3.0/getifaddr.c" (24 Nov 2020, 10321 Bytes) of package /linux/privat/minidlna-1.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "getifaddr.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.1_vs_1.3.0.

    1 /* MiniUPnP project
    2  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
    3  *
    4  * Copyright (c) 2006, Thomas Bernard
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions are met:
    9  *     * Redistributions of source code must retain the above copyright
   10  *       notice, this list of conditions and the following disclaimer.
   11  *     * Redistributions in binary form must reproduce the above copyright
   12  *       notice, this list of conditions and the following disclaimer in the
   13  *       documentation and/or other materials provided with the distribution.
   14  *     * The name of the author may not be used to endorse or promote products
   15  *       derived from this software without specific prior written permission.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   27  * POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 #include <stdio.h>
   30 #include <stdlib.h>
   31 #include <string.h>
   32 #include <unistd.h>
   33 #include <sys/ioctl.h>
   34 #include <sys/types.h>
   35 #include <sys/socket.h>
   36 #include <net/if.h>
   37 #include <arpa/inet.h>
   38 #include <netinet/in.h>
   39 #include <netdb.h>
   40 #include <errno.h>
   41 #if defined(sun)
   42 #include <sys/sockio.h>
   43 #endif
   44 
   45 #include "config.h"
   46 #include "event.h"
   47 #if HAVE_GETIFADDRS
   48 # include <ifaddrs.h>
   49 # ifdef __linux__
   50 #  ifndef AF_LINK
   51 #   define AF_LINK AF_INET
   52 #  endif
   53 # else
   54 #  include <net/if_dl.h>
   55 # endif
   56 # ifndef IFF_SLAVE
   57 #  define IFF_SLAVE 0
   58 # endif
   59 #endif
   60 #ifdef HAVE_NETLINK
   61 # include <linux/rtnetlink.h>
   62 # include <linux/netlink.h>
   63 #endif
   64 #include "upnpglobalvars.h"
   65 #include "getifaddr.h"
   66 #include "minissdp.h"
   67 #include "utils.h"
   68 #include "log.h"
   69 
   70 static int
   71 getifaddr(const char *ifname)
   72 {
   73 #if HAVE_GETIFADDRS
   74     struct ifaddrs *ifap, *p;
   75     struct sockaddr_in *addr_in;
   76 
   77     if (getifaddrs(&ifap) != 0)
   78     {
   79         DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno));
   80         return -1;
   81     }
   82 
   83     for (p = ifap; p != NULL; p = p->ifa_next)
   84     {
   85         if (!p->ifa_addr || p->ifa_addr->sa_family != AF_INET)
   86             continue;
   87         if (ifname && strcmp(p->ifa_name, ifname) != 0)
   88             continue;
   89         addr_in = (struct sockaddr_in *)p->ifa_addr;
   90         if (!ifname && (p->ifa_flags & (IFF_LOOPBACK | IFF_SLAVE)))
   91             continue;
   92         memcpy(&lan_addr[n_lan_addr].addr, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].addr));
   93         if (!inet_ntop(AF_INET, &addr_in->sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)) )
   94         {
   95             DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
   96             continue;
   97         }
   98         addr_in = (struct sockaddr_in *)p->ifa_netmask;
   99         memcpy(&lan_addr[n_lan_addr].mask, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].mask));
  100         lan_addr[n_lan_addr].ifindex = if_nametoindex(p->ifa_name);
  101         lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(&lan_addr[n_lan_addr]);
  102         if (lan_addr[n_lan_addr].snotify >= 0)
  103             n_lan_addr++;
  104         if (ifname || n_lan_addr >= MAX_LAN_ADDR)
  105             break;
  106     }
  107     freeifaddrs(ifap);
  108     if (ifname && !p)
  109     {
  110         DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname);
  111         return -1;
  112     }
  113 #else
  114     int s = socket(PF_INET, SOCK_STREAM, 0);
  115     struct sockaddr_in addr;
  116     struct ifconf ifc;
  117     struct ifreq *ifr;
  118     char buf[8192];
  119     int i, n;
  120 
  121     memset(&ifc, '\0', sizeof(ifc));
  122     ifc.ifc_buf = buf;
  123     ifc.ifc_len = sizeof(buf);
  124 
  125     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
  126     {
  127         DPRINTF(E_ERROR, L_GENERAL, "SIOCGIFCONF: %s\n", strerror(errno));
  128         close(s);
  129         return -1;
  130     }
  131 
  132     n = ifc.ifc_len / sizeof(struct ifreq);
  133     for (i = 0; i < n; i++)
  134     {
  135         ifr = &ifc.ifc_req[i];
  136         if (ifname && strcmp(ifr->ifr_name, ifname) != 0)
  137             continue;
  138         if (!ifname &&
  139             (ioctl(s, SIOCGIFFLAGS, ifr) < 0 || ifr->ifr_ifru.ifru_flags & IFF_LOOPBACK))
  140             continue;
  141         if (ioctl(s, SIOCGIFADDR, ifr) < 0)
  142             continue;
  143         memcpy(&addr, &(ifr->ifr_addr), sizeof(addr));
  144         memcpy(&lan_addr[n_lan_addr].addr, &addr.sin_addr, sizeof(lan_addr[n_lan_addr].addr));
  145         if (!inet_ntop(AF_INET, &addr.sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)))
  146         {
  147             DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
  148             close(s);
  149             continue;
  150         }
  151         if (ioctl(s, SIOCGIFNETMASK, ifr) < 0)
  152             continue;
  153         memcpy(&addr, &(ifr->ifr_addr), sizeof(addr));
  154         memcpy(&lan_addr[n_lan_addr].mask, &addr.sin_addr, sizeof(addr));
  155         lan_addr[n_lan_addr].ifindex = if_nametoindex(ifr->ifr_name);
  156         lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(&lan_addr[n_lan_addr]);
  157         if (lan_addr[n_lan_addr].snotify >= 0)
  158             n_lan_addr++;
  159         if (ifname || n_lan_addr >= MAX_LAN_ADDR)
  160             break;
  161     }
  162     close(s);
  163     if (ifname && i == n)
  164     {
  165         DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname);
  166         return -1;
  167     }
  168 #endif
  169     return n_lan_addr;
  170 }
  171 
  172 int
  173 getsyshwaddr(char *buf, int len)
  174 {
  175     unsigned char mac[6];
  176     int ret = -1;
  177 #if defined(HAVE_GETIFADDRS) && !defined (__linux__) && !defined (__sun__)
  178     struct ifaddrs *ifap, *p;
  179     struct sockaddr_in *addr_in;
  180     uint8_t a;
  181 
  182     if (getifaddrs(&ifap) != 0)
  183     {
  184         DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno));
  185         return -1;
  186     }
  187     for (p = ifap; p != NULL; p = p->ifa_next)
  188     {
  189         if (p->ifa_addr && p->ifa_addr->sa_family == AF_LINK)
  190         {
  191             addr_in = (struct sockaddr_in *)p->ifa_addr;
  192             a = (htonl(addr_in->sin_addr.s_addr) >> 0x18) & 0xFF;
  193             if (a == 127)
  194                 continue;
  195 #if defined(__linux__)
  196             struct ifreq ifr;
  197             int fd;
  198             fd = socket(AF_INET, SOCK_DGRAM, 0);
  199             if (fd < 0)
  200                 continue;
  201             strncpy(ifr.ifr_name, p->ifa_name, IFNAMSIZ);
  202             ret = ioctl(fd, SIOCGIFHWADDR, &ifr);
  203             close(fd);
  204             if (ret < 0)
  205                 continue;
  206             memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
  207 #else
  208             if (p->ifa_addr->sa_family != AF_LINK)
  209                 continue;
  210             struct sockaddr_dl *sdl;
  211             sdl = (struct sockaddr_dl*)p->ifa_addr;
  212             if (sdl->sdl_alen != 6)
  213                 continue;
  214             memcpy(mac, LLADDR(sdl), 6);
  215 #endif
  216             if (MACADDR_IS_ZERO(mac))
  217                 continue;
  218             ret = 0;
  219             break;
  220         }
  221     }
  222     freeifaddrs(ifap);
  223 #else
  224     struct if_nameindex *ifaces, *if_idx;
  225     struct ifreq ifr;
  226     int fd;
  227 
  228     memset(&mac, '\0', sizeof(mac));
  229     /* Get the spatially unique node identifier */
  230     fd = socket(AF_INET, SOCK_DGRAM, 0);
  231     if (fd < 0)
  232         return ret;
  233 
  234     ifaces = if_nameindex();
  235     if (!ifaces)
  236     {
  237         close(fd);
  238         return ret;
  239     }
  240 
  241     for (if_idx = ifaces; if_idx->if_index; if_idx++)
  242     {
  243         strncpyt(ifr.ifr_name, if_idx->if_name, IFNAMSIZ);
  244         if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
  245             continue;
  246         if (ifr.ifr_ifru.ifru_flags & IFF_LOOPBACK)
  247             continue;
  248         if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
  249             continue;
  250 #ifdef __sun__
  251         if (MACADDR_IS_ZERO(ifr.ifr_addr.sa_data))
  252             continue;
  253         memcpy(mac, ifr.ifr_addr.sa_data, 6);
  254 #else
  255         if (MACADDR_IS_ZERO(ifr.ifr_hwaddr.sa_data))
  256             continue;
  257         memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
  258 #endif
  259         ret = 0;
  260         break;
  261     }
  262     if_freenameindex(ifaces);
  263     close(fd);
  264 #endif
  265     if (ret == 0)
  266     {
  267         if (len > 12)
  268             sprintf(buf, "%02x%02x%02x%02x%02x%02x",
  269                     mac[0]&0xFF, mac[1]&0xFF, mac[2]&0xFF,
  270                     mac[3]&0xFF, mac[4]&0xFF, mac[5]&0xFF);
  271         else if (len == 6)
  272             memmove(buf, mac, 6);
  273     }
  274     return ret;
  275 }
  276 
  277 int
  278 get_remote_mac(struct in_addr ip_addr, unsigned char *mac)
  279 {
  280     struct in_addr arp_ent;
  281     FILE * arp;
  282     char remote_ip[16];
  283     int matches, hwtype, flags;
  284     memset(mac, 0xFF, 6);
  285 
  286     arp = fopen("/proc/net/arp", "r");
  287     if (!arp)
  288         return 1;
  289     while (!feof(arp))
  290     {
  291         matches = fscanf(arp, "%15s 0x%8X 0x%8X %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
  292                               remote_ip, &hwtype, &flags,
  293                               &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
  294         if (matches != 9)
  295             continue;
  296         inet_pton(AF_INET, remote_ip, &arp_ent);
  297         if (ip_addr.s_addr == arp_ent.s_addr)
  298             break;
  299         mac[0] = 0xFF;
  300     }
  301     fclose(arp);
  302 
  303     if (mac[0] == 0xFF)
  304     {
  305         memset(mac, 0xFF, 6);
  306         return 1;
  307     }
  308 
  309     return 0;
  310 }
  311 
  312 void
  313 reload_ifaces(int force_notify)
  314 {
  315     struct in_addr old_addr[MAX_LAN_ADDR];
  316     int i, j;
  317 
  318     memset(&old_addr, 0xFF, sizeof(old_addr));
  319     for (i = 0; i < n_lan_addr; i++)
  320     {
  321         memcpy(&old_addr[i], &lan_addr[i].addr, sizeof(struct in_addr));
  322         close(lan_addr[i].snotify);
  323     }
  324     n_lan_addr = 0;
  325 
  326     i = 0;
  327     do {
  328         getifaddr(runtime_vars.ifaces[i]);
  329         i++;
  330     } while (i < MAX_LAN_ADDR && runtime_vars.ifaces[i]);
  331 
  332     for (i = 0; i < n_lan_addr; i++)
  333     {
  334         for (j = 0; j < MAX_LAN_ADDR; j++)
  335         {
  336             if (memcmp(&lan_addr[i].addr, &old_addr[j], sizeof(struct in_addr)) == 0)
  337                 break;
  338         }
  339         /* Send out startup notifies if it's a new interface, or on SIGHUP */
  340         if (force_notify || j == MAX_LAN_ADDR)
  341         {
  342             DPRINTF(E_INFO, L_GENERAL, "Enabling interface %s/%s\n",
  343                 lan_addr[i].str, inet_ntoa(lan_addr[i].mask));
  344             SendSSDPGoodbyes(lan_addr[i].snotify);
  345             SendSSDPNotifies(lan_addr[i].snotify, lan_addr[i].str,
  346                     runtime_vars.port, runtime_vars.notify_interval);
  347         }
  348     }
  349 }
  350 
  351 int
  352 OpenAndConfMonitorSocket(void)
  353 {
  354 #ifdef HAVE_NETLINK
  355     struct sockaddr_nl addr;
  356     int s;
  357     int ret;
  358 
  359     s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  360     if (s < 0)
  361     {
  362         perror("couldn't open NETLINK_ROUTE socket");
  363         return -1;
  364     }
  365 
  366     memset(&addr, 0, sizeof(addr));
  367     addr.nl_family = AF_NETLINK;
  368     addr.nl_groups = RTMGRP_IPV4_IFADDR;
  369 
  370     ret = bind(s, (struct sockaddr*)&addr, sizeof(addr));
  371     if (ret < 0)
  372     {
  373         perror("couldn't bind");
  374         close(s);
  375         return -1;
  376     }
  377 
  378     return s;
  379 #else
  380     return -1;
  381 #endif
  382 }
  383 
  384 void
  385 ProcessMonitorEvent(struct event *ev)
  386 {
  387 #ifdef HAVE_NETLINK
  388     int s = ev->fd;
  389     int len;
  390     char buf[4096];
  391     struct nlmsghdr *nlh;
  392     int changed = 0;
  393 
  394     nlh = (struct nlmsghdr*)buf;
  395 
  396     len = recv(s, nlh, sizeof(buf), 0);
  397     if (len <= 0)
  398         return;
  399     while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE))
  400     {
  401         if (nlh->nlmsg_type == RTM_NEWADDR ||
  402             nlh->nlmsg_type == RTM_DELADDR)
  403         {
  404             changed = 1;
  405         }
  406         nlh = NLMSG_NEXT(nlh, len);
  407     }
  408     if (changed)
  409         reload_ifaces(0);
  410 #endif
  411 }