1 | /* getifaddrs -- get names and addresses of all network interfaces |
2 | Copyright (C) 2002-2024 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: &ifreqs, num_ifs: &nifs, sockfd: 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 (size: nifs * sizeof storage[0]); |
70 | if (storage == NULL) |
71 | { |
72 | __close (fd); |
73 | __if_freereq (ifreqs, num_ifs: 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 (ptr: storage); |
139 | __if_freereq (ifreqs, num_ifs: 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, num_ifs: 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 (ptr: ifa); |
163 | } |
164 | weak_alias (__freeifaddrs, freeifaddrs) |
165 | libc_hidden_def (__freeifaddrs) |
166 | libc_hidden_weak (freeifaddrs) |
167 | |