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