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