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