1  /* getifaddrs -- get names and addresses of all network interfaces
       2     Copyright (C) 2002-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <ifaddrs.h>
      20  #include <net/if.h>
      21  #include <sys/socket.h>
      22  #include <sys/ioctl.h>
      23  #include <unistd.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <errno.h>
      27  #include <netinet/in.h>
      28  
      29  #include "ifreq.h"
      30  
      31  /* Create a linked list of `struct ifaddrs' structures, one for each
      32     network interface on the host machine.  If successful, store the
      33     list in *IFAP and return 0.  On errors, return -1 and set `errno'.  */
      34  int
      35  __getifaddrs (struct ifaddrs **ifap)
      36  {
      37    /* This implementation handles only IPv4 interfaces.
      38       The various ioctls below will only work on an AF_INET socket.
      39       Some different mechanism entirely must be used for IPv6.  */
      40    int fd = __socket (AF_INET, SOCK_DGRAM, 0);
      41    struct ifreq *ifreqs;
      42    int nifs;
      43  
      44    if (fd < 0)
      45      return -1;
      46  
      47    __ifreq (&ifreqs, &nifs, fd);
      48    if (ifreqs == NULL)		/* XXX doesn't distinguish error vs none */
      49      {
      50        __close (fd);
      51        return -1;
      52      }
      53  
      54    /* Now we have the list of interfaces and each one's address.
      55       Put it into the expected format and fill in the remaining details.  */
      56    if (nifs == 0)
      57      *ifap = NULL;
      58    else
      59      {
      60        struct
      61        {
      62  	struct ifaddrs ia;
      63  	struct sockaddr addr, netmask, broadaddr;
      64  	char name[IF_NAMESIZE];
      65        } *storage;
      66        struct ifreq *ifr;
      67        int i;
      68  
      69        storage = malloc (nifs * sizeof storage[0]);
      70        if (storage == NULL)
      71  	{
      72  	  __close (fd);
      73  	  __if_freereq (ifreqs, nifs);
      74  	  return -1;
      75  	}
      76  
      77        i = 0;
      78        ifr = ifreqs;
      79        do
      80  	{
      81  	  /* Fill in pointers to the storage we've already allocated.  */
      82  	  storage[i].ia.ifa_next = &storage[i + 1].ia;
      83  	  storage[i].ia.ifa_addr = &storage[i].addr;
      84  
      85  	  /* Now copy the information we already have from SIOCGIFCONF.  */
      86  	  storage[i].ia.ifa_name = strncpy (storage[i].name, ifr->ifr_name,
      87  					    sizeof storage[i].name);
      88  	  storage[i].addr = ifr->ifr_addr;
      89  
      90  	  /* The SIOCGIFCONF call filled in only the name and address.
      91  	     Now we must also ask for the other information we need.  */
      92  
      93  	  if (__ioctl (fd, SIOCGIFFLAGS, ifr) < 0)
      94  	    break;
      95  	  storage[i].ia.ifa_flags = ifr->ifr_flags;
      96  
      97  	  ifr->ifr_addr = storage[i].addr;
      98  
      99  	  if (__ioctl (fd, SIOCGIFNETMASK, ifr) < 0)
     100  	    storage[i].ia.ifa_netmask = NULL;
     101  	  else
     102  	    {
     103  	      storage[i].ia.ifa_netmask = &storage[i].netmask;
     104  	      storage[i].netmask = ifr->ifr_netmask;
     105  	    }
     106  
     107  	  if (ifr->ifr_flags & IFF_BROADCAST)
     108  	    {
     109  	      ifr->ifr_addr = storage[i].addr;
     110  	      if (__ioctl (fd, SIOCGIFBRDADDR, ifr) < 0)
     111  		storage[i].ia.ifa_broadaddr = NULL;
     112  	      {
     113  		storage[i].ia.ifa_broadaddr = &storage[i].broadaddr;
     114  		storage[i].broadaddr = ifr->ifr_broadaddr;
     115  	      }
     116  	    }
     117  	  else if (ifr->ifr_flags & IFF_POINTOPOINT)
     118  	    {
     119  	      ifr->ifr_addr = storage[i].addr;
     120  	      if (__ioctl (fd, SIOCGIFDSTADDR, ifr) < 0)
     121  		storage[i].ia.ifa_broadaddr = NULL;
     122  	      else
     123  		{
     124  		  storage[i].ia.ifa_broadaddr = &storage[i].broadaddr;
     125  		  storage[i].broadaddr = ifr->ifr_dstaddr;
     126  		}
     127  	    }
     128  	  else
     129  	    storage[i].ia.ifa_broadaddr = NULL;
     130  
     131  	  storage[i].ia.ifa_data = NULL; /* Nothing here for now.  */
     132  
     133  	  ifr = __if_nextreq (ifr);
     134  	} while (++i < nifs);
     135        if (i < nifs)		/* Broke out early on error.  */
     136  	{
     137  	  __close (fd);
     138  	  free (storage);
     139  	  __if_freereq (ifreqs, nifs);
     140  	  return -1;
     141  	}
     142  
     143        storage[i - 1].ia.ifa_next = NULL;
     144  
     145        *ifap = &storage[0].ia;
     146  
     147        __close (fd);
     148        __if_freereq (ifreqs, nifs);
     149      }
     150  
     151    return 0;
     152  }
     153  weak_alias (__getifaddrs, getifaddrs)
     154  libc_hidden_def (__getifaddrs)
     155  #ifndef getifaddrs
     156  libc_hidden_weak (getifaddrs)
     157  #endif
     158  
     159  void
     160  __freeifaddrs (struct ifaddrs *ifa)
     161  {
     162    free (ifa);
     163  }
     164  weak_alias (__freeifaddrs, freeifaddrs)
     165  libc_hidden_def (__freeifaddrs)
     166  libc_hidden_weak (freeifaddrs)