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