1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 multiple interface handling
5
6 Copyright (C) Andrew Tridgell 1992-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 #include "includes.h"
28
29 extern int DEBUGLEVEL;
30
31 struct in_addr ipzero;
32 struct in_addr allones_ip;
33 struct in_addr loopback_ip;
34 static struct in_addr default_ip;
35 static struct in_addr default_bcast;
36 static struct in_addr default_nmask;
37 static BOOL got_ip = False;
38 static BOOL got_bcast = False;
39 static BOOL got_nmask = False;
40
41 static struct interface *local_interfaces = NULL;
42
43 struct interface *last_iface;
44
45 #define ALLONES ((uint32)0xFFFFFFFF)
46 #define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES))
47 /****************************************************************************
48 calculate the default netmask for an address
49 ****************************************************************************/
50 static void
default_netmask(struct in_addr * inm,struct in_addr * iad)51 default_netmask (struct in_addr *inm, struct in_addr *iad)
52 {
53 /*
54 ** Guess a netmask based on the class of the IP address given.
55 */
56 switch ((ntohl (iad->s_addr) & 0xE0000000))
57 {
58 case 0x00000000: /* Class A addr */
59 case 0x20000000:
60 case 0x40000000:
61 case 0x60000000:
62 inm->s_addr = htonl (0xFF000000);
63 break;
64
65 case 0x80000000: /* Class B addr */
66 case 0xA0000000:
67 inm->s_addr = htonl (0xFFFF0000);
68 break;
69
70 case 0xC0000000: /* Class C addr */
71 inm->s_addr = htonl (0xFFFFFF00);
72 break;
73
74 default: /* ??? */
75 inm->s_addr = htonl (0xFFFFFFF0);
76 }
77 }
78
79
80 /****************************************************************************
81 get the broadcast address for our address
82 (troyer@saifr00.ateng.az.honeywell.com)
83 ****************************************************************************/
84 static void
get_broadcast(struct in_addr * if_ipaddr,struct in_addr * if_bcast,struct in_addr * if_nmask)85 get_broadcast (struct in_addr *if_ipaddr, struct in_addr *if_bcast, struct in_addr *if_nmask)
86 {
87 uint32 nm;
88 short onbc;
89 short offbc;
90
91 /* get a default netmask and broadcast */
92 default_netmask (if_nmask, if_ipaddr);
93
94 get_netmask (if_ipaddr, if_nmask);
95
96 /* sanity check on the netmask */
97 nm = ntohl (if_nmask->s_addr);
98 onbc = 0;
99 offbc = 0;
100 while ((onbc + offbc) < 32)
101 {
102 if (nm & 0x80000000)
103 {
104 onbc++;
105 if (offbc)
106 {
107 /* already found an off bit, so mask
108 is wrong */
109 onbc = 34;
110 }
111 }
112 else
113 {
114 offbc++;
115 }
116 nm <<= 1;
117 }
118 if ((onbc < 8) || (onbc == 34))
119 {
120 DEBUG (0, ("Impossible netmask %s - using defaults\n", inet_ntoa (*if_nmask)));
121 default_netmask (if_nmask, if_ipaddr);
122 }
123
124 /* derive the broadcast assuming a 1's broadcast, as this is what
125 all MS operating systems do, we have to comply even if the unix
126 box is setup differently */
127 if_bcast->s_addr = MKBCADDR (if_ipaddr->s_addr, if_nmask->s_addr);
128
129 DEBUG (4, ("Derived broadcast address %s\n", inet_ntoa (*if_bcast)));
130 }
131
132
133
134 /****************************************************************************
135 load a list of network interfaces
136 ****************************************************************************/
137 static void
interpret_interfaces(char * s,struct interface ** interfaces,const char * description)138 interpret_interfaces (char *s, struct interface **interfaces, const char *description)
139 {
140 char *ptr;
141 fstring token;
142 struct interface *iface;
143 struct in_addr ip;
144
145 ptr = s;
146 ipzero = *interpret_addr2 ("0.0.0.0");
147 allones_ip = *interpret_addr2 ("255.255.255.255");
148 loopback_ip = *interpret_addr2 ("127.0.0.1");
149
150 while (next_token (&ptr, token, NULL, sizeof (token)))
151 {
152 /* parse it into an IP address/netmasklength pair */
153 char *p = strchr (token, '/');
154 if (p)
155 *p++ = 0;
156
157 ip = *interpret_addr2 (token);
158
159 /* maybe we already have it listed */
160 {
161 struct interface *i;
162 for (i = (*interfaces); i; i = i->next)
163 if (ip_equal (ip, i->ip))
164 break;
165 if (i)
166 continue;
167 }
168
169 iface = (struct interface *) malloc (sizeof (*iface));
170 if (!iface)
171 return;
172
173 iface->ip = ip;
174
175 if (p)
176 {
177 if (strlen (p) > 2)
178 iface->nmask = *interpret_addr2 (p);
179 else
180 iface->nmask.s_addr = htonl (((ALLONES >> atoi (p)) ^ ALLONES));
181 }
182 else
183 {
184 default_netmask (&iface->nmask, &iface->ip);
185 }
186 iface->bcast.s_addr = MKBCADDR (iface->ip.s_addr, iface->nmask.s_addr);
187 iface->next = NULL;
188
189 if (!(*interfaces))
190 {
191 (*interfaces) = iface;
192 }
193 else
194 {
195 last_iface->next = iface;
196 }
197 last_iface = iface;
198 DEBUG (2, ("Added %s ip=%s ", description, inet_ntoa (iface->ip)));
199 DEBUG (2, ("bcast=%s ", inet_ntoa (iface->bcast)));
200 DEBUG (2, ("nmask=%s\n", inet_ntoa (iface->nmask)));
201 }
202
203 if (*interfaces)
204 return;
205
206 /* setup a default interface */
207 iface = (struct interface *) malloc (sizeof (*iface));
208 if (!iface)
209 return;
210
211 iface->next = NULL;
212
213 if (got_ip)
214 {
215 iface->ip = default_ip;
216 }
217 else
218 {
219 get_myname (NULL, &iface->ip);
220 }
221
222 if (got_bcast)
223 {
224 iface->bcast = default_bcast;
225 }
226 else
227 {
228 get_broadcast (&iface->ip, &iface->bcast, &iface->nmask);
229 }
230
231 if (got_nmask)
232 {
233 iface->nmask = default_nmask;
234 iface->bcast.s_addr = MKBCADDR (iface->ip.s_addr, iface->nmask.s_addr);
235 }
236
237 if (iface->bcast.s_addr != MKBCADDR (iface->ip.s_addr, iface->nmask.s_addr))
238 {
239 DEBUG (2, ("Warning: inconsistent interface %s\n", inet_ntoa (iface->ip)));
240 }
241
242 iface->next = NULL;
243 (*interfaces) = last_iface = iface;
244
245 DEBUG (2, ("Added interface ip=%s ", inet_ntoa (iface->ip)));
246 DEBUG (2, ("bcast=%s ", inet_ntoa (iface->bcast)));
247 DEBUG (2, ("nmask=%s\n", inet_ntoa (iface->nmask)));
248 }
249
250
251 /****************************************************************************
252 load the remote and local interfaces
253 ****************************************************************************/
254 void
load_interfaces(void)255 load_interfaces (void)
256 {
257 /* add the machine's interfaces to local interface structure */
258 interpret_interfaces (lp_interfaces (), &local_interfaces, "interface");
259 }
260
261 #if 0
262 /****************************************************************************
263 override the defaults
264 **************************************************************************/
265 void
266 iface_set_default (char *ip, char *bcast, char *nmask)
267 {
268 if (ip)
269 {
270 got_ip = True;
271 default_ip = *interpret_addr2 (ip);
272 }
273
274 if (bcast)
275 {
276 got_bcast = True;
277 default_bcast = *interpret_addr2 (bcast);
278 }
279
280 if (nmask)
281 {
282 got_nmask = True;
283 default_nmask = *interpret_addr2 (nmask);
284 }
285 }
286 #endif /* 0 */
287
288 /****************************************************************************
289 check if an IP is one of mine
290 **************************************************************************/
291 BOOL
ismyip(struct in_addr ip)292 ismyip (struct in_addr ip)
293 {
294 struct interface *i;
295 for (i = local_interfaces; i; i = i->next)
296 if (ip_equal (i->ip, ip))
297 return True;
298 return False;
299 }
300
301 #if 0
302 /****************************************************************************
303 check if a packet is from a local (known) net
304 **************************************************************************/
305 BOOL
306 is_local_net (struct in_addr from)
307 {
308 struct interface *i;
309 for (i = local_interfaces; i; i = i->next)
310 if ((from.s_addr & i->nmask.s_addr) == (i->ip.s_addr & i->nmask.s_addr))
311 return True;
312 return False;
313 }
314 #endif /* 0 */
315
316 /****************************************************************************
317 how many interfaces do we have
318 **************************************************************************/
319 int
iface_count(void)320 iface_count (void)
321 {
322 int ret = 0;
323 struct interface *i;
324
325 for (i = local_interfaces; i; i = i->next)
326 ret++;
327 return ret;
328 }
329
330 #if 0
331 /****************************************************************************
332 True if we have two or more interfaces.
333 **************************************************************************/
334 BOOL
335 we_are_multihomed (void)
336 {
337 static int multi = -1;
338
339 if (multi == -1)
340 multi = (iface_count () > 1 ? True : False);
341
342 return multi;
343 }
344
345 /****************************************************************************
346 return the Nth interface
347 **************************************************************************/
348 struct interface *
349 get_interface (int n)
350 {
351 struct interface *i;
352
353 for (i = local_interfaces; i && n; i = i->next)
354 n--;
355
356 if (i)
357 return i;
358 return NULL;
359 }
360 #endif /* 0 */
361 /****************************************************************************
362 return IP of the Nth interface
363 **************************************************************************/
364 struct in_addr *
iface_n_ip(int n)365 iface_n_ip (int n)
366 {
367 struct interface *i;
368
369 for (i = local_interfaces; i && n; i = i->next)
370 n--;
371
372 if (i)
373 return &i->ip;
374 return NULL;
375 }
376
377 /****************************************************************************
378 Try and find an interface that matches an ip. If we cannot, return NULL
379 **************************************************************************/
380 static struct interface *
iface_find(struct in_addr ip)381 iface_find (struct in_addr ip)
382 {
383 struct interface *i;
384 if (zero_ip (ip))
385 return local_interfaces;
386
387 for (i = local_interfaces; i; i = i->next)
388 if (same_net (i->ip, ip, i->nmask))
389 return i;
390
391 return NULL;
392 }
393
394 #if 0
395 /****************************************************************************
396 this function provides a simple hash of the configured interfaces. It is
397 used to detect a change in interfaces to tell us whether to discard
398 the current wins.dat file.
399 Note that the result is independent of the order of the interfaces
400 **************************************************************************/
401 unsigned
402 iface_hash (void)
403 {
404 unsigned ret = 0;
405 struct interface *i;
406
407 for (i = local_interfaces; i; i = i->next)
408 {
409 unsigned x1 = (unsigned) str_checksum (inet_ntoa (i->ip));
410 unsigned x2 = (unsigned) str_checksum (inet_ntoa (i->nmask));
411 ret ^= (x1 ^ x2);
412 }
413
414 return ret;
415 }
416 #endif /* 0 */
417
418 /* these 3 functions return the ip/bcast/nmask for the interface
419 most appropriate for the given ip address. If they can't find
420 an appropriate interface they return the requested field of the
421 first known interface. */
422
423 struct in_addr *
iface_bcast(struct in_addr ip)424 iface_bcast (struct in_addr ip)
425 {
426 struct interface *i = iface_find (ip);
427 return (i ? &i->bcast : &local_interfaces->bcast);
428 }
429
430 struct in_addr *
iface_ip(struct in_addr ip)431 iface_ip (struct in_addr ip)
432 {
433 struct interface *i = iface_find (ip);
434 return (i ? &i->ip : &local_interfaces->ip);
435 }
436