1 /*
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    code to query kernel netmask
5 
6    Copyright (C) Andrew Tridgell 1998
7 
8    Copyright (C) 2011-2021
9    Free Software Foundation, Inc.
10 
11    This file is part of the Midnight Commander.
12 
13    The Midnight Commander is free software: you can redistribute it
14    and/or modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation, either version 3 of the License,
16    or (at your option) any later version.
17 
18    The Midnight Commander is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21    GNU General Public License for more details.
22 
23    You should have received a copy of the GNU General Public License
24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 
28 /* working out the netmask for an interface is an incredibly non-portable
29    thing. We have several possible implementations below, and autoconf
30    tries each of them to see what works
31 
32    Note that this file does _not_ include includes.h. That is so this code
33    can be called directly from the autoconf tests. That also means
34    this code cannot use any of the normal Samba debug stuff or defines.
35    This is standalone code.
36 
37  */
38 
39 #ifndef AUTOCONF
40 #include "config.h"
41 #endif
42 
43 #include <stdlib.h>
44 #include <string.h>
45 
46 #ifdef HAVE_NETMASK_IFCONF
47 
48 #include <stdio.h>
49 #include <unistd.h>
50 #include <sys/types.h>
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <netdb.h>
55 #include <sys/ioctl.h>
56 #include <net/if.h>
57 
58 #ifndef SIOCGIFCONF
59 #include <sys/sockio.h>
60 #endif
61 
62 /*
63  * Prototype for gcc in fussy mode.
64  */
65 
66 int get_netmask (struct in_addr *ipaddr, struct in_addr *nmask);
67 
68 /****************************************************************************
69   get the netmask address for a local interface
70 ****************************************************************************/
71 int
get_netmask(struct in_addr * ipaddr,struct in_addr * nmask)72 get_netmask (struct in_addr *ipaddr, struct in_addr *nmask)
73 {
74     struct ifconf ifc;
75     char buff[2048];
76     int fd, i, n;
77     struct ifreq *ifr = NULL;
78 
79     if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
80     {
81 #ifdef DEBUG
82         fprintf (stderr, "socket failed\n");
83 #endif
84         return -1;
85     }
86 
87     ifc.ifc_len = sizeof (buff);
88     ifc.ifc_buf = buff;
89     if (ioctl (fd, SIOCGIFCONF, &ifc) != 0)
90     {
91 #ifdef DEBUG
92         fprintf (stderr, "SIOCGIFCONF failed\n");
93 #endif
94         close (fd);
95         return -1;
96     }
97 
98     ifr = ifc.ifc_req;
99 
100     n = ifc.ifc_len / sizeof (struct ifreq);
101 
102 #ifdef DEBUG
103     fprintf (stderr, "%d interfaces - looking for %s\n", n, inet_ntoa (*ipaddr));
104 #endif
105 
106     /* Loop through interfaces, looking for given IP address */
107     for (i = n - 1; i >= 0; i--)
108     {
109         if (ioctl (fd, SIOCGIFADDR, &ifr[i]) != 0)
110         {
111 #ifdef DEBUG
112             fprintf (stderr, "SIOCGIFADDR failed\n");
113 #endif
114             continue;
115         }
116 
117 #ifdef DEBUG
118         fprintf (stderr, "interface %s\n",
119                  inet_ntoa ((*(struct sockaddr_in *) &ifr[i].ifr_addr).sin_addr));
120 #endif
121         if (ipaddr->s_addr != (*(struct sockaddr_in *) &ifr[i].ifr_addr).sin_addr.s_addr)
122         {
123             continue;
124         }
125 
126         if (ioctl (fd, SIOCGIFNETMASK, &ifr[i]) != 0)
127         {
128 #ifdef DEBUG
129             fprintf (stderr, "SIOCGIFNETMASK failed\n");
130 #endif
131             close (fd);
132             return -1;
133         }
134         close (fd);
135         (*nmask) = ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr;
136 #ifdef DEBUG
137         fprintf (stderr, "netmask %s\n", inet_ntoa (*nmask));
138 #endif
139         return 0;
140     }
141 
142 #ifdef DEBUG
143     fprintf (stderr, "interface not found\n");
144 #endif
145 
146     close (fd);
147     return -1;
148 }
149 
150 #elif defined(HAVE_NETMASK_IFREQ)
151 
152 #include <stdio.h>
153 #include <sys/types.h>
154 #include <sys/socket.h>
155 #include <netinet/in.h>
156 #include <arpa/inet.h>
157 #include <netdb.h>
158 #include <sys/ioctl.h>
159 #include <net/if.h>
160 
161 #ifndef SIOCGIFCONF
162 #include <sys/sockio.h>
163 #endif
164 
165 #ifndef I_STR
166 #include <sys/stropts.h>
167 #endif
168 
169 
170 /****************************************************************************
171 this should cover most of the rest of systems
172 ****************************************************************************/
173 int
get_netmask(struct in_addr * ipaddr,struct in_addr * nmask)174 get_netmask (struct in_addr *ipaddr, struct in_addr *nmask)
175 {
176     struct ifreq ifreq;
177     struct strioctl strioctl;
178     struct ifconf *ifc;
179     char buff[2048];
180     int fd, i, n;
181     struct ifreq *ifr = NULL;
182 
183     if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
184     {
185 #ifdef DEBUG
186         fprintf (stderr, "socket failed\n");
187 #endif
188         return -1;
189     }
190 
191     ifc = (struct ifconf *) buff;
192     ifc->ifc_len = BUFSIZ - sizeof (struct ifconf);
193     strioctl.ic_cmd = SIOCGIFCONF;
194     strioctl.ic_dp = (char *) ifc;
195     strioctl.ic_len = sizeof (buff);
196     if (ioctl (fd, I_STR, &strioctl) < 0)
197     {
198 #ifdef DEBUG
199         fprintf (stderr, "SIOCGIFCONF failed\n");
200 #endif
201         close (fd);
202         return -1;
203     }
204 
205     ifr = (struct ifreq *) ifc->ifc_req;
206 
207     /* Loop through interfaces, looking for given IP address */
208     n = ifc->ifc_len / sizeof (struct ifreq);
209 
210     for (i = 0; i < n; i++, ifr++)
211     {
212 #ifdef DEBUG
213         fprintf (stderr, "interface %s\n",
214                  inet_ntoa ((*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr));
215 #endif
216         if (ipaddr->s_addr == (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr)
217         {
218             break;
219         }
220     }
221 
222 #ifdef DEBUG
223     if (i == n)
224     {
225         fprintf (stderr, "interface not found\n");
226         close (fd);
227         return -1;
228     }
229 #endif
230 
231     ifreq = *ifr;
232 
233     strioctl.ic_cmd = SIOCGIFNETMASK;
234     strioctl.ic_dp = (char *) &ifreq;
235     strioctl.ic_len = sizeof (struct ifreq);
236     if (ioctl (fd, I_STR, &strioctl) != 0)
237     {
238 #ifdef DEBUG
239         fprintf (stderr, "Failed SIOCGIFNETMASK\n");
240 #endif
241         close (fd);
242         return -1;
243     }
244 
245     close (fd);
246     *nmask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr;
247 #ifdef DEBUG
248     fprintf (stderr, "netmask %s\n", inet_ntoa (*nmask));
249 #endif
250     return 0;
251 }
252 
253 #elif defined(HAVE_NETMASK_AIX)
254 
255 #include <stdio.h>
256 #include <unistd.h>             /* close() declaration for gcc in fussy mode */
257 #include <sys/types.h>
258 #include <sys/socket.h>
259 #include <netinet/in.h>
260 #include <arpa/inet.h>
261 #include <netdb.h>
262 #include <sys/ioctl.h>
263 #include <net/if.h>
264 
265 #ifndef SIOCGIFCONF
266 #include <sys/sockio.h>
267 #endif
268 
269 /*
270  * Prototype for gcc in fussy mode.
271  */
272 
273 int get_netmask (struct in_addr *ipaddr, struct in_addr *nmask);
274 
275 /****************************************************************************
276 this one is for AIX
277 ****************************************************************************/
278 
279 int
get_netmask(struct in_addr * ipaddr,struct in_addr * nmask)280 get_netmask (struct in_addr *ipaddr, struct in_addr *nmask)
281 {
282     char buff[2048];
283     int fd, i;
284     struct ifconf ifc;
285     struct ifreq *ifr = NULL;
286 
287     if ((fd = socket (AF_INET, SOCK_DGRAM, 0)) == -1)
288     {
289 #ifdef DEBUG
290         fprintf (stderr, "socket failed\n");
291 #endif
292         return -1;
293     }
294 
295 
296     ifc.ifc_len = sizeof (buff);
297     ifc.ifc_buf = buff;
298 
299     if (ioctl (fd, SIOCGIFCONF, &ifc) != 0)
300     {
301 #ifdef DEBUG
302         fprintf (stderr, "SIOCGIFCONF failed\n");
303 #endif
304         close (fd);
305         return -1;
306     }
307 
308     ifr = ifc.ifc_req;
309     /* Loop through interfaces, looking for given IP address */
310     i = ifc.ifc_len;
311     while (i > 0)
312     {
313 #ifdef DEBUG
314         fprintf (stderr, "interface %s\n",
315                  inet_ntoa ((*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr));
316 #endif
317         if (ipaddr->s_addr == (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr)
318         {
319             break;
320         }
321         i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
322         ifr = (struct ifreq *) ((char *) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
323     }
324 
325 
326 #ifdef DEBUG
327     if (i <= 0)
328     {
329         fprintf (stderr, "interface not found\n");
330         close (fd);
331         return -1;
332     }
333 #endif
334 
335     if (ioctl (fd, SIOCGIFNETMASK, ifr) != 0)
336     {
337 #ifdef DEBUG
338         fprintf (stderr, "SIOCGIFNETMASK failed\n");
339 #endif
340         close (fd);
341         return -1;
342     }
343 
344     close (fd);
345 
346     (*nmask) = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr;
347 #ifdef DEBUG
348     fprintf (stderr, "netmask %s\n", inet_ntoa (*nmask));
349 #endif
350     return 0;
351 }
352 
353 #else /* a dummy version */
354 struct in_addr;                 /* it may not have been declared before */
355 int get_netmask (struct in_addr *ipaddr, struct in_addr *nmask);
356 int
get_netmask(struct in_addr * ipaddr,struct in_addr * nmask)357 get_netmask (struct in_addr *ipaddr, struct in_addr *nmask)
358 {
359     return -1;
360 }
361 #endif
362 
363 
364 #ifdef AUTOCONF
365 /* this is the autoconf driver to test get_netmask() */
366 
main()367 main ()
368 {
369     char buf[1024];
370     struct hostent *hp;
371     struct in_addr ip, nmask;
372 
373     if (gethostname (buf, sizeof (buf) - 1) != 0)
374     {
375         fprintf (stderr, "gethostname failed\n");
376         exit (1);
377     }
378 
379     hp = gethostbyname (buf);
380 
381     if (!hp)
382     {
383         fprintf (stderr, "gethostbyname failed\n");
384         exit (1);
385     }
386 
387     memcpy ((char *) &ip, (char *) hp->h_addr, hp->h_length);
388 
389     if (get_netmask (&ip, &nmask) == 0)
390         exit (0);
391 
392     fprintf (stderr, "get_netmask failed\n");
393     exit (1);
394 }
395 #endif
396