This is it ! The mega-merge of the JRA_NMBD_REWRITE branch
[kai/samba.git] / source3 / lib / interface.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    multiple interface handling
5    Copyright (C) Andrew Tridgell 1992-1997
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern int DEBUGLEVEL;
25
26 struct in_addr ipzero;
27 struct in_addr allones_ip;
28 struct in_addr loopback_ip;
29 static struct in_addr default_ip;
30 static struct in_addr default_bcast;
31 static struct in_addr default_nmask;
32 static BOOL got_ip=False;
33 static BOOL got_bcast=False;
34 static BOOL got_nmask=False;
35
36 static struct interface *local_interfaces  = NULL;
37
38 struct interface *last_iface;
39
40 /****************************************************************************
41 calculate the default netmask for an address
42 ****************************************************************************/
43 static void default_netmask(struct in_addr *inm, struct in_addr *iad)
44 {
45   uint32 ad = ntohl(iad->s_addr);
46   uint32 nm;
47   /*
48   ** Guess a netmask based on the class of the IP address given.
49   */
50   if ( (ad & 0x80000000) == 0 ) {
51     /* class A address */
52     nm = 0xFF000000;
53   } else if ( (ad & 0xC0000000) == 0x80000000 ) {
54     /* class B address */
55     nm = 0xFFFF0000;
56   } else if ( (ad & 0xE0000000) == 0xC0000000 ) {
57     /* class C address */
58     nm = 0xFFFFFF00;
59   }  else {
60     /* class D or E; netmask doesn't make much sense - guess 4 bits */
61     nm =  0xFFFFFFF0;
62   }
63   inm->s_addr = htonl(nm);
64 }
65
66
67 /****************************************************************************
68   get the broadcast address for our address 
69 (troyer@saifr00.ateng.az.honeywell.com)
70 ****************************************************************************/
71 static void get_broadcast(struct in_addr *if_ipaddr,
72                           struct in_addr *if_bcast,
73                           struct in_addr *if_nmask)
74 {  
75   BOOL found = False;
76 #ifndef NO_GET_BROADCAST
77   int sock = -1;               /* AF_INET raw socket desc */
78   char buff[1024];
79   struct ifreq *ifr=NULL;
80   int i;
81
82 #if defined(EVEREST)
83   int n_interfaces;
84   struct ifconf ifc;
85   struct ifreq  *ifreqs;
86 #elif defined(USE_IFREQ)
87   struct ifreq ifreq;
88   struct strioctl strioctl;
89   struct ifconf *ifc;
90 #else
91   struct ifconf ifc;
92 #endif
93 #endif
94
95   /* get a default netmask and broadcast */
96   default_netmask(if_nmask, if_ipaddr);
97
98 #ifndef NO_GET_BROADCAST  
99   /* Create a socket to the INET kernel. */
100 #if USE_SOCKRAW
101   if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0)
102 #else
103     if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0)
104 #endif
105       {
106         DEBUG(0,( "Unable to open socket to get broadcast address\n"));
107         return;
108       }
109   
110   /* Get a list of the configured interfaces */
111 #ifdef EVEREST
112   /* This is part of SCO Openserver 5: The ioctls are no longer part
113      if the lower level STREAMS interface glue. They are now real
114      ioctl calls */
115
116   if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) {
117     DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno)));
118   } else {
119     DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces));
120
121     ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
122     ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
123
124     if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
125       DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
126     else {
127       ifr = ifc.ifc_req;
128
129       for (i = 0; i < n_interfaces; ++i) {
130         if (if_ipaddr->s_addr ==
131             ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) {
132           found = True;
133           break;
134         }
135       }
136     }
137   }
138 #elif defined(USE_IFREQ)
139   ifc = (struct ifconf *)buff;
140   ifc->ifc_len = BUFSIZ - sizeof(struct ifconf);
141   strioctl.ic_cmd = SIOCGIFCONF;
142   strioctl.ic_dp  = (char *)ifc;
143   strioctl.ic_len = sizeof(buff);
144   if (ioctl(sock, I_STR, &strioctl) < 0) {
145     DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno)));
146   } else {
147     ifr = (struct ifreq *)ifc->ifc_req;  
148
149     /* Loop through interfaces, looking for given IP address */
150     for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
151       if (if_ipaddr->s_addr ==
152           (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
153         found = True;
154         break;
155       }
156     }
157   }
158 #elif defined(__FreeBSD__) || defined(NETBSD) || defined(AMIGA) || defined(_AIX41)
159   ifc.ifc_len = sizeof(buff);
160   ifc.ifc_buf = buff;
161   if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
162     DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
163   } else {
164     ifr = ifc.ifc_req;
165     /* Loop through interfaces, looking for given IP address */
166     i = ifc.ifc_len;
167     while (i > 0) {
168       if (if_ipaddr->s_addr ==
169           (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
170         found = True;
171         break;
172       }
173       i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
174       ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
175     }
176   }
177 #else
178   ifc.ifc_len = sizeof(buff);
179   ifc.ifc_buf = buff;
180   if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
181     DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
182   } else {
183     ifr = ifc.ifc_req;
184   
185     /* Loop through interfaces, looking for given IP address */
186     for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
187 #ifdef BSDI
188       if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break;
189 #endif
190       if (if_ipaddr->s_addr ==
191           (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
192         found = True;
193         break;
194       }
195     }
196   }
197 #endif
198   
199   if (!found) {
200     DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr)));
201   } else {
202     /* Get the netmask address from the kernel */
203 #ifdef USE_IFREQ
204     ifreq = *ifr;
205   
206     strioctl.ic_cmd = SIOCGIFNETMASK;
207     strioctl.ic_dp  = (char *)&ifreq;
208     strioctl.ic_len = sizeof(struct ifreq);
209     if (ioctl(sock, I_STR, &strioctl) < 0)
210       DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno)));
211     else
212       *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
213 #else
214     if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0)
215       DEBUG(0,("SIOCGIFNETMASK failed\n"));
216     else
217       *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
218 #endif
219
220     DEBUG(4,("Netmask for %s = %s\n", ifr->ifr_name,
221              inet_ntoa(*if_nmask)));
222   }
223
224   /* Close up shop */
225   (void) close(sock);
226   
227 #endif
228
229   /* sanity check on the netmask */
230   {
231     uint32 nm = ntohl(if_nmask->s_addr);
232     if ((nm >> 24) != 0xFF) {
233       DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask)));
234       default_netmask(if_nmask, if_ipaddr);      
235     }
236   }
237
238   /* derive the broadcast assuming a 1's broadcast, as this is what
239      all MS operating systems do, we have to comply even if the unix
240      box is setup differently */
241   {
242     uint32 ad = ntohl(if_ipaddr->s_addr);
243     uint32 nm = ntohl(if_nmask->s_addr);
244     uint32 bc = (ad & nm) | (0xffffffff & ~nm);
245     if_bcast->s_addr = htonl(bc);
246   }
247   
248   DEBUG(4,("Derived broadcast address %s\n", inet_ntoa(*if_bcast)));
249 }  /* get_broadcast */
250
251
252
253 /****************************************************************************
254 load a list of network interfaces
255 ****************************************************************************/
256 static void interpret_interfaces(char *s, struct interface **interfaces,
257                 char *description)
258 {
259   char *ptr = s;
260   fstring token;
261   struct interface *iface;
262   struct in_addr ip;
263
264   ipzero = *interpret_addr2("0.0.0.0");
265   allones_ip = *interpret_addr2("255.255.255.255");
266   loopback_ip = *interpret_addr2("127.0.0.1");
267
268   while (next_token(&ptr,token,NULL)) {
269     /* parse it into an IP address/netmasklength pair */
270     char *p = strchr(token,'/');
271     if (p) *p = 0;
272
273     ip = *interpret_addr2(token);
274
275     /* maybe we already have it listed */
276     {
277       struct interface *i;
278       for (i=(*interfaces);i;i=i->next)
279         if (ip_equal(ip,i->ip)) break;
280       if (i) continue;
281     }
282
283     iface = (struct interface *)malloc(sizeof(*iface));
284     if (!iface) return;
285
286     iface->ip = ip;
287
288     if (p) {
289       if (strlen(p+1)>2)
290         iface->nmask = *interpret_addr2(p+1);
291       else
292         iface->nmask.s_addr = htonl(~((1<<(32-atoi(p+1)))-1));
293     } else {
294       default_netmask(&iface->nmask,&iface->ip);
295     }
296     iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr;
297     iface->next = NULL;
298
299     if (!(*interfaces)) {
300       (*interfaces) = iface;
301     } else {
302       last_iface->next = iface;
303     }
304     last_iface = iface;
305     DEBUG(2,("Added %s ip=%s ",description,inet_ntoa(iface->ip)));
306     DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
307     DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));         
308   }
309
310   if (*interfaces) return;
311
312   /* setup a default interface */
313   iface = (struct interface *)malloc(sizeof(*iface));
314   if (!iface) return;
315
316   iface->next = NULL;
317
318   if (got_ip) {
319     iface->ip = default_ip;
320   } else {
321     get_myname(NULL,&iface->ip);
322   }
323
324   if (got_bcast) {
325     iface->bcast = default_bcast;
326   } else {
327     get_broadcast(&iface->ip,&iface->bcast,&iface->nmask);
328   }
329
330   if (got_nmask) {
331     iface->nmask = default_nmask;
332     iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr;
333   }
334
335   if (iface->bcast.s_addr != (iface->ip.s_addr | ~iface->nmask.s_addr)) {
336     DEBUG(2,("Warning: inconsistant interface %s\n",inet_ntoa(iface->ip)));
337   }
338
339   iface->next = NULL;
340   (*interfaces) = last_iface = iface;
341
342   DEBUG(2,("Added interface ip=%s ",inet_ntoa(iface->ip)));
343   DEBUG(2,("bcast=%s ",inet_ntoa(iface->bcast)));
344   DEBUG(2,("nmask=%s\n",inet_ntoa(iface->nmask)));           
345 }
346
347
348 /****************************************************************************
349 load the remote and local interfaces
350 ****************************************************************************/
351 void load_interfaces(void)
352 {
353   /* add the machine's interfaces to local interface structure*/
354   interpret_interfaces(lp_interfaces(), &local_interfaces,"interface");
355 }
356
357
358 /****************************************************************************
359   override the defaults
360   **************************************************************************/
361 void iface_set_default(char *ip,char *bcast,char *nmask)
362 {
363   if (ip) {
364     got_ip = True;
365     default_ip = *interpret_addr2(ip);
366   }
367
368   if (bcast) {
369     got_bcast = True;
370     default_bcast = *interpret_addr2(bcast);
371   }
372
373   if (nmask) {
374     got_nmask = True;
375     default_nmask = *interpret_addr2(nmask);
376   }
377 }
378
379
380 /****************************************************************************
381   check if an IP is one of mine
382   **************************************************************************/
383 BOOL ismyip(struct in_addr ip)
384 {
385   struct interface *i;
386   for (i=local_interfaces;i;i=i->next)
387     if (ip_equal(i->ip,ip)) return True;
388   return False;
389 }
390
391 /****************************************************************************
392   check if a bcast is one of mine
393   **************************************************************************/
394 BOOL ismybcast(struct in_addr bcast)
395 {
396   struct interface *i;
397   for (i=local_interfaces;i;i=i->next)
398     if (ip_equal(i->bcast,bcast)) return True;
399   return False;
400 }
401
402 /****************************************************************************
403   check if a packet is from a local (known) net
404   **************************************************************************/
405 BOOL is_local_net(struct in_addr from)
406 {
407   struct interface *i;
408   for (i=local_interfaces;i;i=i->next)
409     if((from.s_addr & i->nmask.s_addr) == (i->ip.s_addr & i->nmask.s_addr))
410       return True;
411   return False;
412 }
413
414 /****************************************************************************
415   how many interfaces do we have
416   **************************************************************************/
417 int iface_count(void)
418 {
419   int ret = 0;
420   struct interface *i;
421
422   for (i=local_interfaces;i;i=i->next)
423     ret++;
424   return ret;
425 }
426
427 /****************************************************************************
428  True if we have two or more interfaces.
429   **************************************************************************/
430 BOOL we_are_multihomed()
431 {
432   static int multi = -1;
433
434   if(multi == -1)
435     multi = (iface_count() > 1 ? True : False);
436
437   return multi;
438 }
439
440 /****************************************************************************
441   return the Nth interface
442   **************************************************************************/
443 struct interface *get_interface(int n)
444
445   struct interface *i;
446   
447   for (i=local_interfaces;i && n;i=i->next)
448     n--;
449
450   if (i) return i;
451   return NULL;
452 }
453
454 /****************************************************************************
455   return IP of the Nth interface
456   **************************************************************************/
457 struct in_addr *iface_n_ip(int n)
458 {
459   struct interface *i;
460   
461   for (i=local_interfaces;i && n;i=i->next)
462     n--;
463
464   if (i) return &i->ip;
465   return NULL;
466 }
467
468 /****************************************************************************
469 Try and find an interface that matches an ip. If we cannot, return NULL
470   **************************************************************************/
471 static struct interface *iface_find(struct in_addr ip)
472 {
473   struct interface *i;
474   if (zero_ip(ip)) return local_interfaces;
475
476   for (i=local_interfaces;i;i=i->next)
477     if (same_net(i->ip,ip,i->nmask)) return i;
478
479   return NULL;
480 }
481
482 /* these 3 functions return the ip/bcast/nmask for the interface
483    most appropriate for the given ip address. If they can't find
484    an appropriate interface they return the requested field of the
485    first known interface. */
486
487 struct in_addr *iface_bcast(struct in_addr ip)
488 {
489   struct interface *i = iface_find(ip);
490   return(i ? &i->bcast : &local_interfaces->bcast);
491 }
492
493 struct in_addr *iface_nmask(struct in_addr ip)
494 {
495   struct interface *i = iface_find(ip);
496   return(i ? &i->nmask : &local_interfaces->nmask);
497 }
498
499 struct in_addr *iface_ip(struct in_addr ip)
500 {
501   struct interface *i = iface_find(ip);
502   return(i ? &i->ip : &local_interfaces->ip);
503 }
504
505
506