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