1 /*
2 * Network interface functions for CUPS.
3 *
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 1997-2006 by Easy Software Products, all rights reserved.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
9 */
10
11 /*
12 * Include necessary headers.
13 */
14
15 #include "getifaddrs-internal.h"
16
17
18 #ifndef HAVE_GETIFADDRS
19 /*
20 * '_cups_getifaddrs()' - Get a list of network interfaces on the system.
21 */
22
23 int /* O - 0 on success, -1 on error */
_cups_getifaddrs(struct ifaddrs ** addrs)24 _cups_getifaddrs(struct ifaddrs **addrs)/* O - List of interfaces */
25 {
26 int sock; /* Socket */
27 char buffer[65536], /* Buffer for address info */
28 *bufptr, /* Pointer into buffer */
29 *bufend; /* End of buffer */
30 struct ifconf conf; /* Interface configurations */
31 struct sockaddr addr; /* Address data */
32 struct ifreq *ifp; /* Interface data */
33 int ifpsize; /* Size of interface data */
34 struct ifaddrs *temp; /* Pointer to current interface */
35 struct ifreq request; /* Interface request */
36
37
38 /*
39 * Start with an empty list...
40 */
41
42 if (addrs == NULL)
43 return (-1);
44
45 *addrs = NULL;
46
47 /*
48 * Create a UDP socket to get the interface data...
49 */
50
51 memset (&addr, 0, sizeof(addr));
52 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
53 return (-1);
54
55 /*
56 * Try to get the list of interfaces...
57 */
58
59 conf.ifc_len = sizeof(buffer);
60 conf.ifc_buf = buffer;
61
62 if (ioctl(sock, SIOCGIFCONF, &conf) < 0)
63 {
64 /*
65 * Couldn't get the list of interfaces...
66 */
67
68 close(sock);
69 return (-1);
70 }
71
72 /*
73 * OK, got the list of interfaces, now lets step through the
74 * buffer to pull them out...
75 */
76
77 # ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
78 # define sockaddr_len(a) ((a)->sa_len)
79 # else
80 # define sockaddr_len(a) (sizeof(struct sockaddr))
81 # endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
82
83 for (bufptr = buffer, bufend = buffer + conf.ifc_len;
84 bufptr < bufend;
85 bufptr += ifpsize)
86 {
87 /*
88 * Get the current interface information...
89 */
90
91 ifp = (struct ifreq *)bufptr;
92 ifpsize = sizeof(ifp->ifr_name) + sockaddr_len(&(ifp->ifr_addr));
93
94 if (ifpsize < sizeof(struct ifreq))
95 ifpsize = sizeof(struct ifreq);
96
97 memset(&request, 0, sizeof(request));
98 memcpy(request.ifr_name, ifp->ifr_name, sizeof(ifp->ifr_name));
99
100 /*
101 * Check the status of the interface...
102 */
103
104 if (ioctl(sock, SIOCGIFFLAGS, &request) < 0)
105 continue;
106
107 /*
108 * Allocate memory for a single interface record...
109 */
110
111 if ((temp = calloc(1, sizeof(struct ifaddrs))) == NULL)
112 {
113 /*
114 * Unable to allocate memory...
115 */
116
117 close(sock);
118 return (-1);
119 }
120
121 /*
122 * Add this record to the front of the list and copy the name, flags,
123 * and network address...
124 */
125
126 temp->ifa_next = *addrs;
127 *addrs = temp;
128 temp->ifa_name = strdup(ifp->ifr_name);
129 temp->ifa_flags = request.ifr_flags;
130 if ((temp->ifa_addr = calloc(1, sockaddr_len(&(ifp->ifr_addr)))) != NULL)
131 memcpy(temp->ifa_addr, &(ifp->ifr_addr), sockaddr_len(&(ifp->ifr_addr)));
132
133 /*
134 * Try to get the netmask for the interface...
135 */
136
137 if (!ioctl(sock, SIOCGIFNETMASK, &request))
138 {
139 /*
140 * Got it, make a copy...
141 */
142
143 if ((temp->ifa_netmask = calloc(1, sizeof(request.ifr_netmask))) != NULL)
144 memcpy(temp->ifa_netmask, &(request.ifr_netmask),
145 sizeof(request.ifr_netmask));
146 }
147
148 /*
149 * Then get the broadcast or point-to-point (destination) address,
150 * if applicable...
151 */
152
153 if (temp->ifa_flags & IFF_BROADCAST)
154 {
155 /*
156 * Have a broadcast address, so get it!
157 */
158
159 if (!ioctl(sock, SIOCGIFBRDADDR, &request))
160 {
161 /*
162 * Got it, make a copy...
163 */
164
165 if ((temp->ifa_broadaddr =
166 calloc(1, sizeof(request.ifr_broadaddr))) != NULL)
167 memcpy(temp->ifa_broadaddr, &(request.ifr_broadaddr),
168 sizeof(request.ifr_broadaddr));
169 }
170 }
171 else if (temp->ifa_flags & IFF_POINTOPOINT)
172 {
173 /*
174 * Point-to-point interface; grab the remote address...
175 */
176
177 if (!ioctl(sock, SIOCGIFDSTADDR, &request))
178 {
179 temp->ifa_dstaddr = malloc(sizeof(request.ifr_dstaddr));
180 memcpy(temp->ifa_dstaddr, &(request.ifr_dstaddr),
181 sizeof(request.ifr_dstaddr));
182 }
183 }
184 }
185
186 /*
187 * OK, we're done with the socket, close it and return 0...
188 */
189
190 close(sock);
191
192 return (0);
193 }
194
195
196 /*
197 * '_cups_freeifaddrs()' - Free an interface list...
198 */
199
200 void
_cups_freeifaddrs(struct ifaddrs * addrs)201 _cups_freeifaddrs(struct ifaddrs *addrs)/* I - Interface list to free */
202 {
203 struct ifaddrs *next; /* Next interface in list */
204
205
206 while (addrs != NULL)
207 {
208 /*
209 * Make a copy of the next interface pointer...
210 */
211
212 next = addrs->ifa_next;
213
214 /*
215 * Free data values as needed...
216 */
217
218 if (addrs->ifa_name)
219 {
220 free(addrs->ifa_name);
221 addrs->ifa_name = NULL;
222 }
223
224 if (addrs->ifa_addr)
225 {
226 free(addrs->ifa_addr);
227 addrs->ifa_addr = NULL;
228 }
229
230 if (addrs->ifa_netmask)
231 {
232 free(addrs->ifa_netmask);
233 addrs->ifa_netmask = NULL;
234 }
235
236 if (addrs->ifa_dstaddr)
237 {
238 free(addrs->ifa_dstaddr);
239 addrs->ifa_dstaddr = NULL;
240 }
241
242 /*
243 * Free this node and continue to the next...
244 */
245
246 free(addrs);
247
248 addrs = next;
249 }
250 }
251 #endif /* !HAVE_GETIFADDRS */
252