interface.c: Fix for AIX4.x finding interfaces.
[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 wins_ip;
28 static struct in_addr default_ip;
29 static struct in_addr default_bcast;
30 static struct in_addr default_nmask;
31 static BOOL got_ip=False;
32 static BOOL got_bcast=False;
33 static BOOL got_nmask=False;
34
35 struct interface *local_interfaces  = NULL;
36
37 struct interface *last_iface;
38
39 /****************************************************************************
40 calculate the default netmask for an address
41 ****************************************************************************/
42 static void default_netmask(struct in_addr *inm, struct in_addr *iad)
43 {
44   uint32 ad = ntohl(iad->s_addr);
45   uint32 nm;
46   /*
47   ** Guess a netmask based on the class of the IP address given.
48   */
49   if ( (ad & 0x80000000) == 0 ) {
50     /* class A address */
51     nm = 0xFF000000;
52   } else if ( (ad & 0xC0000000) == 0x80000000 ) {
53     /* class B address */
54     nm = 0xFFFF0000;
55   } else if ( (ad & 0xE0000000) == 0xC0000000 ) {
56     /* class C address */
57     nm = 0xFFFFFF00;
58   }  else {
59     /* class D or E; netmask doesn't make much sense - guess 4 bits */
60     nm =  0xFFFFFFF0;
61   }
62   inm->s_addr = htonl(nm);
63 }
64
65
66 /****************************************************************************
67   get the broadcast address for our address 
68 (troyer@saifr00.ateng.az.honeywell.com)
69 ****************************************************************************/
70 static void get_broadcast(struct in_addr *if_ipaddr,
71                           struct in_addr *if_bcast,
72                           struct in_addr *if_nmask)
73 {  
74   BOOL found = False;
75 #ifndef NO_GET_BROADCAST
76   int sock = -1;               /* AF_INET raw socket desc */
77   char buff[1024];
78   struct ifreq *ifr=NULL;
79   int i;
80
81 #if defined(EVEREST)
82   int n_interfaces;
83   struct ifconf ifc;
84   struct ifreq  *ifreqs;
85 #elif defined(USE_IFREQ)
86   struct ifreq ifreq;
87   struct strioctl strioctl;
88   struct ifconf *ifc;
89 #else
90   struct ifconf ifc;
91 #endif
92 #endif
93
94   /* get a default netmask and broadcast */
95   default_netmask(if_nmask, if_ipaddr);
96
97 #ifndef NO_GET_BROADCAST  
98   /* Create a socket to the INET kernel. */
99 #if USE_SOCKRAW
100   if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0)
101 #else
102     if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0)
103 #endif
104       {
105         DEBUG(0,( "Unable to open socket to get broadcast address\n"));
106         return;
107       }
108   
109   /* Get a list of the configured interfaces */
110 #ifdef EVEREST
111   /* This is part of SCO Openserver 5: The ioctls are no longer part
112      if the lower level STREAMS interface glue. They are now real
113      ioctl calls */
114
115   if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) {
116     DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno)));
117   } else {
118     DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces));
119
120     ifc.ifc_len = sizeof(struct ifreq) * n_interfaces;
121     ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len);
122
123     if (ioctl(sock, SIOCGIFCONF, &ifc) < 0)
124       DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno)));
125     else {
126       ifr = ifc.ifc_req;
127
128       for (i = 0; i < n_interfaces; ++i) {
129         if (if_ipaddr->s_addr ==
130             ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) {
131           found = True;
132           break;
133         }
134       }
135     }
136   }
137 #elif defined(USE_IFREQ)
138   ifc = (struct ifconf *)buff;
139   ifc->ifc_len = BUFSIZ - sizeof(struct ifconf);
140   strioctl.ic_cmd = SIOCGIFCONF;
141   strioctl.ic_dp  = (char *)ifc;
142   strioctl.ic_len = sizeof(buff);
143   if (ioctl(sock, I_STR, &strioctl) < 0) {
144     DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno)));
145   } else {
146     ifr = (struct ifreq *)ifc->ifc_req;  
147
148     /* Loop through interfaces, looking for given IP address */
149     for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
150       if (if_ipaddr->s_addr ==
151           (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
152         found = True;
153         break;
154       }
155     }
156   }
157 #elif defined(__FreeBSD__) || defined(NETBSD) || defined(AMIGA) || defined(_AIX41)
158   ifc.ifc_len = sizeof(buff);
159   ifc.ifc_buf = buff;
160   if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
161     DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
162   } else {
163     ifr = ifc.ifc_req;
164     /* Loop through interfaces, looking for given IP address */
165     i = ifc.ifc_len;
166     while (i > 0) {
167       if (if_ipaddr->s_addr ==
168           (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
169         found = True;
170         break;
171       }
172       i -= ifr->ifr_addr.sa_len + IFNAMSIZ;
173       ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ);
174     }
175   }
176 #else
177   ifc.ifc_len = sizeof(buff);
178   ifc.ifc_buf = buff;
179   if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
180     DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno)));
181   } else {
182     ifr = ifc.ifc_req;
183   
184     /* Loop through interfaces, looking for given IP address */
185     for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
186 #ifdef BSDI
187       if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break;
188 #endif
189       if (if_ipaddr->s_addr ==
190           (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) {
191         found = True;
192         break;
193       }
194     }
195   }
196 #endif
197   
198   if (!found) {
199     DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr)));
200   } else {
201     /* Get the netmask address from the kernel */
202 #ifdef USE_IFREQ
203     ifreq = *ifr;
204   
205     strioctl.ic_cmd = SIOCGIFNETMASK;
206     strioctl.ic_dp  = (char *)&ifreq;
207     strioctl.ic_len = sizeof(struct ifreq);
208     if (ioctl(sock, I_STR, &strioctl) < 0)
209       DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno)));
210     else
211       *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
212 #else
213     if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0)
214       DEBUG(0,("SIOCGIFNETMASK failed\n"));
215     else
216       *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
217 #endif
218
219     DEBUG(4,("Netmask for %s = %s\n", ifr->ifr_name,
220              inet_ntoa(*if_nmask)));
221   }
222
223   /* Close up shop */
224   (void) close(sock);
225   
226 #endif
227
228   /* sanity check on the netmask */
229   {
230     uint32 nm = ntohl(if_nmask->s_addr);
231     if ((nm >> 24) != 0xFF) {
232       DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask)));
233       default_netmask(if_nmask, if_ipaddr);      
234     }
235   }
236
237   /* derive the broadcast assuming a 1's broadcast, as this is what
238      all MS operating systems do, we have to comply even if the unix
239      box is setup differently */
240   {
241     uint32 ad = ntohl(if_ipaddr->s_addr);
242     uint32 nm = ntohl(if_nmask->s_addr);
243     uint32 bc = (ad & nm) | (0xffffffff & ~nm);
244     if_bcast->s_addr = htonl(bc);
245   }
246   
247   DEBUG(4,("Derived broadcast address %s\n", inet_ntoa(*if_bcast)));
248 }  /* get_broadcast */
249
250
251
252 /****************************************************************************
253 load a list of network interfaces
254 ****************************************************************************/
255 static void interpret_interfaces(char *s, struct interface **interfaces,
256                 char *description)
257 {
258   char *ptr = s;
259   fstring token;
260   struct interface *iface;
261   struct in_addr ip;
262
263   ipzero = *interpret_addr2("0.0.0.0");
264   wins_ip = *interpret_addr2("255.255.255.255");
265
266   while (next_token(&ptr,token,NULL)) {
267     /* parse it into an IP address/netmasklength pair */
268     char *p = strchr(token,'/');
269     if (p) *p = 0;
270
271     ip = *interpret_addr2(token);
272
273     /* maybe we already have it listed */
274     {
275       struct interface *i;
276       for (i=(*interfaces);i;i=i->next)
277         if (ip_equal(ip,i->ip)) break;
278       if (i) continue;
279     }
280
281     iface = (struct interface *)malloc(sizeof(*iface));
282     if (!iface) return;
283
284     iface->ip = ip;
285
286     if (p) {
287       if (strlen(p+1)>2)
288         iface->nmask = *interpret_addr2(p+1);
289       else
290         iface->nmask.s_addr = htonl(~((1<<(32-atoi(p+1)))-1));
291     } else {
292       default_netmask(&iface->nmask,&iface->ip);
293     }
294     iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr;
295     iface->next = NULL;
296
297     if (!(*interfaces)) {
298       (*interfaces) = iface;
299     } else {
300       last_iface->next = iface;
301     }
302     last_iface = iface;
303     DEBUG(1,("Added %s ip=%s ",description,inet_ntoa(iface->ip)));
304     DEBUG(1,("bcast=%s ",inet_ntoa(iface->bcast)));
305     DEBUG(1,("nmask=%s\n",inet_ntoa(iface->nmask)));         
306   }
307
308   if (*interfaces) return;
309
310   /* setup a default interface */
311   iface = (struct interface *)malloc(sizeof(*iface));
312   if (!iface) return;
313
314   iface->next = NULL;
315
316   if (got_ip) {
317     iface->ip = default_ip;
318   } else {
319     get_myname(NULL,&iface->ip);
320   }
321
322   if (got_bcast) {
323     iface->bcast = default_bcast;
324   } else {
325     get_broadcast(&iface->ip,&iface->bcast,&iface->nmask);
326   }
327
328   if (got_nmask) {
329     iface->nmask = default_nmask;
330     iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr;
331   }
332
333   if (iface->bcast.s_addr != (iface->ip.s_addr | ~iface->nmask.s_addr)) {
334     DEBUG(2,("Warning: inconsistant interface %s\n",inet_ntoa(iface->ip)));
335   }
336
337   iface->next = NULL;
338   (*interfaces) = last_iface = iface;
339
340   DEBUG(1,("Added interface ip=%s ",inet_ntoa(iface->ip)));
341   DEBUG(1,("bcast=%s ",inet_ntoa(iface->bcast)));
342   DEBUG(1,("nmask=%s\n",inet_ntoa(iface->nmask)));           
343 }
344
345
346 /****************************************************************************
347 load the remote and local interfaces
348 ****************************************************************************/
349 void load_interfaces(void)
350 {
351   /* add the machine's interfaces to local interface structure*/
352   interpret_interfaces(lp_interfaces(), &local_interfaces,"interface");
353 }
354
355
356 /****************************************************************************
357   override the defaults
358   **************************************************************************/
359 void iface_set_default(char *ip,char *bcast,char *nmask)
360 {
361   if (ip) {
362     got_ip = True;
363     default_ip = *interpret_addr2(ip);
364   }
365
366   if (bcast) {
367     got_bcast = True;
368     default_bcast = *interpret_addr2(bcast);
369   }
370
371   if (nmask) {
372     got_nmask = True;
373     default_nmask = *interpret_addr2(nmask);
374   }
375 }
376
377
378 /****************************************************************************
379   check if an IP is one of mine
380   **************************************************************************/
381 BOOL ismyip(struct in_addr ip)
382 {
383   struct interface *i;
384   for (i=local_interfaces;i;i=i->next)
385     if (ip_equal(i->ip,ip)) return True;
386   return False;
387 }
388
389 /****************************************************************************
390   check if a bcast is one of mine
391   **************************************************************************/
392 BOOL ismybcast(struct in_addr bcast)
393 {
394   struct interface *i;
395   for (i=local_interfaces;i;i=i->next)
396     if (ip_equal(i->bcast,bcast)) return True;
397   return False;
398 }
399
400 /****************************************************************************
401   how many interfaces do we have
402   **************************************************************************/
403 int iface_count(void)
404 {
405   int ret = 0;
406   struct interface *i;
407
408   for (i=local_interfaces;i;i=i->next)
409     ret++;
410   return ret;
411 }
412
413 /****************************************************************************
414   return IP of the Nth interface
415   **************************************************************************/
416 struct in_addr *iface_n_ip(int n)
417 {
418   struct interface *i;
419   
420   for (i=local_interfaces;i && n;i=i->next)
421     n--;
422
423   if (i) return &i->ip;
424   return NULL;
425 }
426
427 static struct interface *iface_find(struct in_addr ip)
428 {
429   struct interface *i;
430   if (zero_ip(ip)) return local_interfaces;
431
432   for (i=local_interfaces;i;i=i->next)
433     if (same_net(i->ip,ip,i->nmask)) return i;
434
435   return local_interfaces;
436 }
437
438 /* these 3 functions return the ip/bcast/nmask for the interface
439    most appropriate for the given ip address */
440
441 struct in_addr *iface_bcast(struct in_addr ip)
442 {
443   return(&iface_find(ip)->bcast);
444 }
445
446 struct in_addr *iface_nmask(struct in_addr ip)
447 {
448   return(&iface_find(ip)->nmask);
449 }
450
451 struct in_addr *iface_ip(struct in_addr ip)
452 {
453   return(&iface_find(ip)->ip);
454 }
455
456
457