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