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