]>
Commit | Line | Data |
---|---|---|
7f1deee6 | 1 | /* getifaddrs -- get names and addresses of all network interfaces |
b168057a | 2 | Copyright (C) 2002-2015 Free Software Foundation, Inc. |
7f1deee6 RM |
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 | |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
7f1deee6 RM |
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 | |
7f994279 | 35 | __getifaddrs (struct ifaddrs **ifap) |
7f1deee6 RM |
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; | |
9db6ee8d | 42 | int nifs; |
7f1deee6 RM |
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; | |
9db6ee8d RM |
66 | struct ifreq *ifr; |
67 | int i; | |
7f1deee6 RM |
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; | |
9db6ee8d | 78 | ifr = ifreqs; |
7f1deee6 RM |
79 | do |
80 | { | |
6938e63f | 81 | /* Fill in pointers to the storage we've already allocated. */ |
7f1deee6 RM |
82 | storage[i].ia.ifa_next = &storage[i + 1].ia; |
83 | storage[i].ia.ifa_addr = &storage[i].addr; | |
7f1deee6 RM |
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; | |
9db6ee8d | 98 | |
7f1deee6 | 99 | if (__ioctl (fd, SIOCGIFNETMASK, ifr) < 0) |
6938e63f RM |
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 | } | |
7f1deee6 RM |
106 | |
107 | if (ifr->ifr_flags & IFF_BROADCAST) | |
108 | { | |
109 | ifr->ifr_addr = storage[i].addr; | |
110 | if (__ioctl (fd, SIOCGIFBRDADDR, ifr) < 0) | |
6938e63f RM |
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 | } | |
7f1deee6 RM |
116 | } |
117 | else if (ifr->ifr_flags & IFF_POINTOPOINT) | |
118 | { | |
119 | ifr->ifr_addr = storage[i].addr; | |
120 | if (__ioctl (fd, SIOCGIFDSTADDR, ifr) < 0) | |
6938e63f RM |
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 | } | |
7f1deee6 RM |
127 | } |
128 | else | |
6938e63f | 129 | storage[i].ia.ifa_broadaddr = NULL; |
7f1deee6 RM |
130 | |
131 | storage[i].ia.ifa_data = NULL; /* Nothing here for now. */ | |
132 | ||
9db6ee8d | 133 | ifr = __if_nextreq (ifr); |
7f1deee6 RM |
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 | } | |
9db6ee8d | 142 | |
7f1deee6 RM |
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 | } | |
7f994279 | 153 | weak_alias (__getifaddrs, getifaddrs) |
925c3c5c | 154 | #ifndef getifaddrs |
7f994279 | 155 | libc_hidden_weak (getifaddrs) |
925c3c5c | 156 | #endif |
7f1deee6 RM |
157 | |
158 | void | |
7f994279 | 159 | __freeifaddrs (struct ifaddrs *ifa) |
7f1deee6 RM |
160 | { |
161 | free (ifa); | |
162 | } | |
7f994279 JM |
163 | weak_alias (__freeifaddrs, freeifaddrs) |
164 | libc_hidden_weak (freeifaddrs) |