LCOV - code coverage report
Current view: top level - lib/socket - interfaces.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 157 201 78.1 %
Date: 2021-09-23 10:06:22 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    return a list of network interfaces
       4             :    Copyright (C) Andrew Tridgell 1998
       5             :    Copyright (C) Jeremy Allison 2007
       6             :    Copyright (C) Jelmer Vernooij 2007
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : 
      23             : #include "includes.h"
      24             : #include "system/network.h"
      25             : #include "interfaces.h"
      26             : #include "lib/util/tsort.h"
      27             : #include "librpc/gen_ndr/ioctl.h"
      28             : 
      29             : #ifdef HAVE_ETHTOOL
      30             : #include "linux/sockios.h"
      31             : #include "linux/ethtool.h"
      32             : #endif
      33             : 
      34             : /****************************************************************************
      35             :  Create a struct sockaddr_storage with the netmask bits set to 1.
      36             : ****************************************************************************/
      37             : 
      38      679094 : bool make_netmask(struct sockaddr_storage *pss_out,
      39             :                         const struct sockaddr_storage *pss_in,
      40             :                         unsigned long masklen)
      41             : {
      42      679094 :         *pss_out = *pss_in;
      43             :         /* Now apply masklen bits of mask. */
      44             : #if defined(HAVE_IPV6)
      45      679094 :         if (pss_in->ss_family == AF_INET6) {
      46      136432 :                 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
      47             :                 unsigned int i;
      48             : 
      49      136432 :                 if (masklen > 128) {
      50           0 :                         return false;
      51             :                 }
      52     1225646 :                 for (i = 0; masklen >= 8; masklen -= 8, i++) {
      53     1091456 :                         *p++ = 0xff;
      54             :                 }
      55             :                 /* Deal with the partial byte. */
      56      136432 :                 *p++ &= (0xff & ~(0xff>>masklen));
      57      136432 :                 i++;
      58     1091456 :                 for (;i < sizeof(struct in6_addr); i++) {
      59      955024 :                         *p++ = '\0';
      60             :                 }
      61      134190 :                 return true;
      62             :         }
      63             : #endif
      64      542662 :         if (pss_in->ss_family == AF_INET) {
      65      542662 :                 if (masklen > 32) {
      66           0 :                         return false;
      67             :                 }
      68      542662 :                 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
      69      555414 :                         htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
      70      542662 :                 return true;
      71             :         }
      72           0 :         return false;
      73             : }
      74             : 
      75             : /****************************************************************************
      76             :  Create a struct sockaddr_storage set to the broadcast or network adress from
      77             :  an incoming sockaddr_storage.
      78             : ****************************************************************************/
      79             : 
      80     1633218 : static void make_bcast_or_net(struct sockaddr_storage *pss_out,
      81             :                         const struct sockaddr_storage *pss_in,
      82             :                         const struct sockaddr_storage *nmask,
      83             :                         bool make_bcast_p)
      84             : {
      85     1633218 :         unsigned int i = 0, len = 0;
      86     1633218 :         const char *pmask = NULL;
      87     1633218 :         char *p = NULL;
      88     1633218 :         *pss_out = *pss_in;
      89             : 
      90             :         /* Set all zero netmask bits to 1. */
      91             : #if defined(HAVE_IPV6)
      92     1633218 :         if (pss_in->ss_family == AF_INET6) {
      93      272864 :                 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
      94      272864 :                 pmask = (const char *)&((const struct sockaddr_in6 *)nmask)->sin6_addr;
      95      272864 :                 len = 16;
      96             :         }
      97             : #endif
      98     1633218 :         if (pss_in->ss_family == AF_INET) {
      99     1360354 :                 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
     100     1360354 :                 pmask = (const char *)&((const struct sockaddr_in *)nmask)->sin_addr;
     101     1360354 :                 len = 4;
     102             :         }
     103             : 
     104    11440458 :         for (i = 0; i < len; i++, p++, pmask++) {
     105     9807240 :                 if (make_bcast_p) {
     106     5453680 :                         *p = (*p & *pmask) | (*pmask ^ 0xff);
     107             :                 } else {
     108             :                         /* make_net */
     109     4353560 :                         *p = (*p & *pmask);
     110             :                 }
     111             :         }
     112     1633218 : }
     113             : 
     114      954124 : void make_bcast(struct sockaddr_storage *pss_out,
     115             :                         const struct sockaddr_storage *pss_in,
     116             :                         const struct sockaddr_storage *nmask)
     117             : {
     118      954124 :         make_bcast_or_net(pss_out, pss_in, nmask, true);
     119      954124 : }
     120             : 
     121      679094 : void make_net(struct sockaddr_storage *pss_out,
     122             :                         const struct sockaddr_storage *pss_in,
     123             :                         const struct sockaddr_storage *nmask)
     124             : {
     125      679094 :         make_bcast_or_net(pss_out, pss_in, nmask, false);
     126      679094 : }
     127             : 
     128             : #ifdef HAVE_ETHTOOL
     129      460564 : static void query_iface_speed_from_name(const char *name, uint64_t *speed)
     130             : {
     131      460564 :         int ret = 0;
     132             :         struct ethtool_cmd ecmd;
     133             :         struct ethtool_value edata;
     134             :         struct ifreq ifr;
     135             :         int fd;
     136             : 
     137      460564 :         fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
     138      460564 :         if (fd == -1) {
     139           0 :                 DBG_ERR("Failed to open socket.");
     140           0 :                 return;
     141             :         }
     142             : 
     143      460564 :         if (strlen(name) >= IF_NAMESIZE) {
     144           0 :                 DBG_ERR("Interface name too long.");
     145           0 :                 goto done;
     146             :         }
     147             : 
     148      460564 :         ZERO_STRUCT(ifr);
     149      460564 :         strlcpy(ifr.ifr_name, name, IF_NAMESIZE);
     150             : 
     151      460564 :         ifr.ifr_data = (void *)&edata;
     152      460564 :         ZERO_STRUCT(edata);
     153      460564 :         edata.cmd = ETHTOOL_GLINK;
     154      460564 :         ret = ioctl(fd, SIOCETHTOOL, &ifr);
     155      460564 :         if (ret == -1) {
     156           0 :                 goto done;
     157             :         }
     158      460564 :         if (edata.data == 0) {
     159             :                 /* no link detected */
     160           0 :                 *speed = 0;
     161           0 :                 goto done;
     162             :         }
     163             : 
     164      460564 :         ifr.ifr_data = (void *)&ecmd;
     165      460564 :         ZERO_STRUCT(ecmd);
     166      460564 :         ecmd.cmd = ETHTOOL_GSET;
     167      460564 :         ret = ioctl(fd, SIOCETHTOOL, &ifr);
     168      460564 :         if (ret == -1) {
     169      225788 :                 goto done;
     170             :         }
     171      234776 :         *speed = ((uint64_t)ethtool_cmd_speed(&ecmd)) * 1000 * 1000;
     172             : 
     173      465058 : done:
     174      460564 :         (void)close(fd);
     175             : }
     176             : 
     177      460564 : static void query_iface_rx_queues_from_name(const char *name,
     178             :                                             uint64_t *rx_queues)
     179             : {
     180      460564 :         int ret = 0;
     181             :         struct ethtool_rxnfc rxcmd;
     182             :         struct ifreq ifr;
     183             :         int fd;
     184             : 
     185      460564 :         fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
     186      460564 :         if (fd == -1) {
     187           0 :                 DBG_ERR("Failed to open socket.");
     188           0 :                 return;
     189             :         }
     190             : 
     191      460564 :         if (strlen(name) >= IF_NAMESIZE) {
     192           0 :                 DBG_ERR("Interface name too long.");
     193           0 :                 goto done;
     194             :         }
     195             : 
     196      460564 :         ZERO_STRUCT(ifr);
     197      460564 :         strlcpy(ifr.ifr_name, name, IF_NAMESIZE);
     198             : 
     199      460564 :         ifr.ifr_data = (void *)&rxcmd;
     200      460564 :         ZERO_STRUCT(rxcmd);
     201      460564 :         rxcmd.cmd = ETHTOOL_GRXRINGS;
     202      460564 :         ret = ioctl(fd, SIOCETHTOOL, &ifr);
     203      460564 :         if (ret == -1) {
     204      451576 :                 goto done;
     205             :         }
     206             : 
     207           0 :         *rx_queues = rxcmd.data;
     208             : 
     209      469552 : done:
     210      460564 :         (void)close(fd);
     211             : }
     212             : #endif
     213             : 
     214             : /****************************************************************************
     215             :  Try the "standard" getifaddrs/freeifaddrs interfaces.
     216             :  Also gets IPv6 interfaces.
     217             : ****************************************************************************/
     218             : 
     219             : /****************************************************************************
     220             :  Get the netmask address for a local interface.
     221             : ****************************************************************************/
     222             : 
     223      137515 : static int _get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
     224             : {
     225             :         struct iface_struct *ifaces;
     226      137515 :         struct ifaddrs *iflist = NULL;
     227      137515 :         struct ifaddrs *ifptr = NULL;
     228             :         int count;
     229      137515 :         int total = 0;
     230             :         size_t copy_size;
     231             : 
     232      137515 :         if (getifaddrs(&iflist) < 0) {
     233           0 :                 return -1;
     234             :         }
     235             : 
     236      137515 :         count = 0;
     237      965876 :         for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
     238      828361 :                 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
     239      275030 :                         continue;
     240             :                 }
     241      553331 :                 if (!(ifptr->ifa_flags & IFF_UP)) {
     242           0 :                         continue;
     243             :                 }
     244      553331 :                 count += 1;
     245             :         }
     246             : 
     247      137515 :         ifaces = talloc_array(mem_ctx, struct iface_struct, count);
     248      137515 :         if (ifaces == NULL) {
     249           0 :                 errno = ENOMEM;
     250           0 :                 return -1;
     251             :         }
     252             : 
     253             :         /* Loop through interfaces, looking for given IP address */
     254      965876 :         for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
     255      828361 :                 uint64_t if_speed = 1000 * 1000 * 1000; /* 1Gbps */
     256      828361 :                 uint64_t rx_queues = 1;
     257             : 
     258      828361 :                 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
     259      596691 :                         continue;
     260             :                 }
     261             : 
     262             :                 /* Check the interface is up. */
     263      553331 :                 if (!(ifptr->ifa_flags & IFF_UP)) {
     264           0 :                         continue;
     265             :                 }
     266             : 
     267      564566 :                 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
     268             : 
     269      553331 :                 copy_size = sizeof(struct sockaddr_in);
     270             : 
     271      553331 :                 ifaces[total].flags = ifptr->ifa_flags;
     272             : 
     273             : #if defined(HAVE_IPV6)
     274      553331 :                 if (ifptr->ifa_addr->sa_family == AF_INET6) {
     275      278301 :                         copy_size = sizeof(struct sockaddr_in6);
     276             :                 }
     277             : #endif
     278             : 
     279      564566 :                 memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
     280      564566 :                 memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
     281             : 
     282             :                 /* calculate broadcast address */
     283             : #if defined(HAVE_IPV6)
     284      553331 :                 if (ifptr->ifa_addr->sa_family == AF_INET6) {
     285      278301 :                         struct sockaddr_in6 *sin6 =
     286             :                                 (struct sockaddr_in6 *)ifptr->ifa_addr;
     287      278301 :                         struct in6_addr *in6 =
     288             :                                 (struct in6_addr *)&sin6->sin6_addr;
     289             : 
     290      280548 :                         if (IN6_IS_ADDR_LINKLOCAL(in6) || IN6_IS_ADDR_V4COMPAT(in6)) {
     291       92767 :                                 continue;
     292             :                         }
     293             :                         /* IPv6 does not have broadcast it uses multicast. */
     294      185534 :                         memset(&ifaces[total].bcast, '\0', copy_size);
     295             :                 } else
     296             : #endif
     297      275030 :                 if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
     298      275030 :                         make_bcast(&ifaces[total].bcast,
     299      270536 :                                 &ifaces[total].ip,
     300      270536 :                                 &ifaces[total].netmask);
     301           0 :                 } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
     302           0 :                                ifptr->ifa_dstaddr ) {
     303           0 :                         memcpy(&ifaces[total].bcast,
     304           0 :                                 ifptr->ifa_dstaddr,
     305             :                                 copy_size);
     306             :                 } else {
     307           0 :                         continue;
     308             :                 }
     309             : 
     310      460564 :                 ifaces[total].if_index = if_nametoindex(ifptr->ifa_name);
     311      460564 :                 if (ifaces[total].if_index == 0) {
     312           0 :                         DBG_ERR("Failed to retrieve interface index for '%s': "
     313             :                                 "%s\n", ifptr->ifa_name, strerror(errno));
     314             :                 }
     315             : 
     316             : #ifdef HAVE_ETHTOOL
     317      460564 :                 query_iface_speed_from_name(ifptr->ifa_name, &if_speed);
     318      460564 :                 query_iface_rx_queues_from_name(ifptr->ifa_name, &rx_queues);
     319             : #endif
     320      460564 :                 ifaces[total].linkspeed = if_speed;
     321      460564 :                 ifaces[total].capability = FSCTL_NET_IFACE_NONE_CAPABLE;
     322      460564 :                 if (rx_queues > 1) {
     323           0 :                         ifaces[total].capability |= FSCTL_NET_IFACE_RSS_CAPABLE;
     324             :                 }
     325             : 
     326      460564 :                 if (strlcpy(ifaces[total].name, ifptr->ifa_name,
     327             :                         sizeof(ifaces[total].name)) >=
     328             :                                 sizeof(ifaces[total].name)) {
     329             :                         /* Truncation ! Ignore. */
     330           0 :                         continue;
     331             :                 }
     332      460564 :                 total++;
     333             :         }
     334             : 
     335      137515 :         freeifaddrs(iflist);
     336             : 
     337      137515 :         *pifaces = ifaces;
     338      137515 :         return total;
     339             : }
     340             : 
     341      876380 : static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
     342             : {
     343             :         int r;
     344             : 
     345             : #if defined(HAVE_IPV6)
     346             :         /*
     347             :          * If we have IPv6 - sort these interfaces lower
     348             :          * than any IPv4 ones.
     349             :          */
     350     1187980 :         if (i1->ip.ss_family == AF_INET6 &&
     351      371068 :                         i2->ip.ss_family == AF_INET) {
     352       90520 :                 return -1;
     353     1204854 :         } else if (i1->ip.ss_family == AF_INET &&
     354      505312 :                         i2->ip.ss_family == AF_INET6) {
     355      181040 :                 return 1;
     356             :         }
     357             : 
     358      598079 :         if (i1->ip.ss_family == AF_INET6) {
     359      278301 :                 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
     360      278301 :                 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
     361             : 
     362      278301 :                 r = memcmp(&s1->sin6_addr,
     363      278301 :                                 &s2->sin6_addr,
     364             :                                 sizeof(struct in6_addr));
     365      278301 :                 if (r) {
     366      271560 :                         return r;
     367             :                 }
     368             : 
     369           0 :                 s1 = (struct sockaddr_in6 *)&i1->netmask;
     370           0 :                 s2 = (struct sockaddr_in6 *)&i2->netmask;
     371             : 
     372           0 :                 r = memcmp(&s1->sin6_addr,
     373           0 :                                 &s2->sin6_addr,
     374             :                                 sizeof(struct in6_addr));
     375           0 :                 if (r) {
     376           0 :                         return r;
     377             :                 }
     378             :         }
     379             : #endif
     380             : 
     381             :         /* AIX uses __ss_family instead of ss_family inside of
     382             :            sockaddr_storage. Instead of trying to figure out which field to
     383             :            use, we can just cast it to a sockaddr.
     384             :          */
     385             : 
     386      319778 :         if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
     387      319778 :                 struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
     388      319778 :                 struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
     389             : 
     390      589713 :                 r = ntohl(s1->sin_addr.s_addr) -
     391      324272 :                         ntohl(s2->sin_addr.s_addr);
     392      319778 :                 if (r) {
     393      315284 :                         return r;
     394             :                 }
     395             : 
     396           0 :                 s1 = (struct sockaddr_in *)&i1->netmask;
     397           0 :                 s2 = (struct sockaddr_in *)&i2->netmask;
     398             : 
     399           0 :                 return ntohl(s1->sin_addr.s_addr) -
     400           0 :                         ntohl(s2->sin_addr.s_addr);
     401             :         }
     402           0 :         return 0;
     403             : }
     404             : 
     405             : /* this wrapper is used to remove duplicates from the interface list generated
     406             :    above */
     407      137515 : int get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
     408             : {
     409      137515 :         struct iface_struct *ifaces = NULL;
     410             :         int total, i, j;
     411             : 
     412      137515 :         total = _get_interfaces(mem_ctx, &ifaces);
     413             :         /* If we have an error, no interface or just one we can leave */
     414      137515 :         if (total <= 1) {
     415           0 :                 *pifaces = ifaces;
     416           0 :                 return total;
     417             :         }
     418             : 
     419             :         /* now we need to remove duplicates */
     420      137515 :         TYPESAFE_QSORT(ifaces, total, iface_comp);
     421             : 
     422      572764 :         for (i=1;i<total;) {
     423      323049 :                 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
     424           0 :                         for (j=i-1;j<total-1;j++) {
     425           0 :                                 ifaces[j] = ifaces[j+1];
     426             :                         }
     427           0 :                         total--;
     428             :                 } else {
     429      323049 :                         i++;
     430             :                 }
     431             :         }
     432             : 
     433      137515 :         *pifaces = ifaces;
     434      137515 :         return total;
     435             : }

Generated by: LCOV version 1.13