1 /* getifaddrs -- get names and addresses of all network interfaces
2    Copyright (C) 2002-2022 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
__getifaddrs(struct ifaddrs ** ifap)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 }
weak_alias(__getifaddrs,getifaddrs)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)
167