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