diff options
author | Andrew Tridgell <tridge@samba.org> | 1996-06-06 11:43:09 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 1996-06-06 11:43:09 +0000 |
commit | 7ed71b73ae745da099072eee36fc2700d1d91407 (patch) | |
tree | 9b0b7714443f6d105c7476324d5faa4aec5d90c4 /source/lib/interface.c | |
parent | 8eb701d0d6483d0f5c6de3640b38f98128cd321c (diff) | |
download | samba-7ed71b73ae745da099072eee36fc2700d1d91407.tar.gz samba-7ed71b73ae745da099072eee36fc2700d1d91407.tar.xz samba-7ed71b73ae745da099072eee36fc2700d1d91407.zip |
- added interface.c and removed all the references to myip, bcast_ip
and Netmask, instead replacing them with calls to routines in
interface.c
- got rid of old MAXINT define
- added code to ensure we only return one entry for each name in the ipc
enum routines
- added new_only option to add_netbios_entry() to prevent overwriting
of important names
- minor time handling fixup
Diffstat (limited to 'source/lib/interface.c')
-rw-r--r-- | source/lib/interface.c | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/source/lib/interface.c b/source/lib/interface.c new file mode 100644 index 00000000000..a47ef6e47e7 --- /dev/null +++ b/source/lib/interface.c @@ -0,0 +1,421 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + multiple interface handling + Copyright (C) Andrew Tridgell 1992-1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "loadparm.h" + +extern int DEBUGLEVEL; + +struct in_addr ipzero; +static struct in_addr default_ip; +static struct in_addr default_bcast; +static struct in_addr default_nmask; +static BOOL got_ip=False; +static BOOL got_bcast=False; +static BOOL got_nmask=False; + +static struct interface { + struct interface *next; + struct in_addr ip; + struct in_addr bcast; + struct in_addr nmask; +} *interfaces = NULL; +struct interface *last_iface; + +/**************************************************************************** +calculate the default netmask for an address +****************************************************************************/ +static void default_netmask(struct in_addr *inm, struct in_addr *iad) +{ + unsigned long ad = ntohl(iad->s_addr); + unsigned long nm; + /* + ** Guess a netmask based on the class of the IP address given. + */ + if ( (ad & 0x80000000) == 0 ) { + /* class A address */ + nm = 0xFF000000; + } else if ( (ad & 0xC0000000) == 0x80000000 ) { + /* class B address */ + nm = 0xFFFF0000; + } else if ( (ad & 0xE0000000) == 0xC0000000 ) { + /* class C address */ + nm = 0xFFFFFF00; + } else { + /* class D or E; netmask doesn't make much sense - guess 4 bits */ + nm = 0xFFFFFFF0; + } + inm->s_addr = htonl(nm); +} + + +/**************************************************************************** + get the broadcast address for our address +(troyer@saifr00.ateng.az.honeywell.com) +****************************************************************************/ +static void get_broadcast(struct in_addr *if_ipaddr, + struct in_addr *if_bcast, + struct in_addr *if_nmask) +{ + BOOL found = False; +#ifndef NO_GET_BROADCAST + int sock = -1; /* AF_INET raw socket desc */ + char buff[1024]; + struct ifreq *ifr=NULL; + int i; + +#if defined(EVEREST) + int n_interfaces; + struct ifconf ifc; + struct ifreq *ifreqs; +#elif defined(USE_IFREQ) + struct ifreq ifreq; + struct strioctl strioctl; + struct ifconf *ifc; +#else + struct ifconf ifc; +#endif +#endif + + /* get a default netmask and broadcast */ + default_netmask(if_nmask, if_ipaddr); + +#ifndef NO_GET_BROADCAST + /* Create a socket to the INET kernel. */ +#if USE_SOCKRAW + if ((sock = socket(AF_INET, SOCK_RAW, PF_INET )) < 0) +#else + if ((sock = socket(AF_INET, SOCK_DGRAM, 0 )) < 0) +#endif + { + DEBUG(0,( "Unable to open socket to get broadcast address\n")); + return; + } + + /* Get a list of the configured interfaces */ +#ifdef EVEREST + /* This is part of SCO Openserver 5: The ioctls are no longer part + if the lower level STREAMS interface glue. They are now real + ioctl calls */ + + if (ioctl(sock, SIOCGIFANUM, &n_interfaces) < 0) { + DEBUG(0,( "SIOCGIFANUM: %s\n", strerror(errno))); + } else { + DEBUG(0,( "number of interfaces returned is: %d\n", n_interfaces)); + + ifc.ifc_len = sizeof(struct ifreq) * n_interfaces; + ifc.ifc_buf = (caddr_t) alloca(ifc.ifc_len); + + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) + DEBUG(0, ( "SIOCGIFCONF: %s\n", strerror(errno))); + else { + ifr = ifc.ifc_req; + + for (i = 0; i < n_interfaces; ++i) { + if (if_ipaddr->s_addr == + ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr.s_addr) { + found = True; + break; + } + } + } + } +#elif defined(USE_IFREQ) + ifc = (struct ifconf *)buff; + ifc->ifc_len = BUFSIZ - sizeof(struct ifconf); + strioctl.ic_cmd = SIOCGIFCONF; + strioctl.ic_dp = (char *)ifc; + strioctl.ic_len = sizeof(buff); + if (ioctl(sock, I_STR, &strioctl) < 0) { + DEBUG(0,( "I_STR/SIOCGIFCONF: %s\n", strerror(errno))); + } else { + ifr = (struct ifreq *)ifc->ifc_req; + + /* Loop through interfaces, looking for given IP address */ + for (i = ifc->ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { + if (if_ipaddr->s_addr == + (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { + found = True; + break; + } + } + } +#elif defined(__FreeBSD__) || defined(NETBSD) + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { + DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno))); + } else { + ifr = ifc.ifc_req; + /* Loop through interfaces, looking for given IP address */ + i = ifc.ifc_len; + while (i > 0) { + if (if_ipaddr->s_addr == + (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { + found = True; + break; + } + i -= ifr->ifr_addr.sa_len + IFNAMSIZ; + ifr = (struct ifreq*) ((char*) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ); + } + } +#else + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { + DEBUG(0,("SIOCGIFCONF: %s\n", strerror(errno))); + } else { + ifr = ifc.ifc_req; + + /* Loop through interfaces, looking for given IP address */ + for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { +#ifdef BSDI + if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break; +#endif + if (if_ipaddr->s_addr == + (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr.s_addr) { + found = True; + break; + } + } + } +#endif + + if (!found) { + DEBUG(0,("No interface found for address %s\n", inet_ntoa(*if_ipaddr))); + } else { + /* Get the netmask address from the kernel */ +#ifdef USE_IFREQ + ifreq = *ifr; + + strioctl.ic_cmd = SIOCGIFNETMASK; + strioctl.ic_dp = (char *)&ifreq; + strioctl.ic_len = sizeof(struct ifreq); + if (ioctl(sock, I_STR, &strioctl) < 0) + DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno))); + else + *if_nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr; +#else + if (ioctl(sock, SIOCGIFNETMASK, ifr) < 0) + DEBUG(0,("SIOCGIFNETMASK failed\n")); + else + *if_nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; +#endif + + DEBUG(4,("Netmask for %s = %s\n", ifr->ifr_name, + inet_ntoa(*if_nmask))); + } + + /* Close up shop */ + (void) close(sock); + +#endif + + /* sanity check on the netmask */ + { + unsigned long nm = ntohl(if_nmask->s_addr); + if ((nm >> 24) != 0xFF) { + DEBUG(0,("Impossible netmask %s - using defaults\n",inet_ntoa(*if_nmask))); + default_netmask(if_nmask, if_ipaddr); + } + } + + /* derive the broadcast assuming a 1's broadcast, as this is what + all MS operating systems do, we have to comply even if the unix + box is setup differently */ + { + unsigned long ad = ntohl(if_ipaddr->s_addr); + unsigned long nm = ntohl(if_nmask->s_addr); + unsigned long bc = (ad & nm) | (0xffffffff & ~nm); + if_bcast->s_addr = htonl(bc); + } + + DEBUG(4,("Derived broadcast address %s\n", inet_ntoa(*if_bcast))); +} /* get_broadcast */ + + + + +/**************************************************************************** +load a list of network interfaces +****************************************************************************/ +void load_interfaces(void) +{ + char *s = lp_interfaces(); + char *ptr = s; + fstring token; + struct interface *iface; + struct in_addr ip; + + ipzero = *interpret_addr2("0.0.0.0"); + + while (next_token(&ptr,token,NULL)) { + /* parse it into an IP address/netmasklength pair */ + char *p = strchr(token,'/'); + if (p) *p = 0; + + ip = *interpret_addr2(token); + + /* maybe we already have it listed */ + { + struct interface *i; + for (i=interfaces;i;i=i->next) + if (ip_equal(ip,i->ip)) break; + if (i) continue; + } + + iface = (struct interface *)malloc(sizeof(*iface)); + if (!iface) return; + + iface->ip = ip; + + if (p) { + if (strlen(p+1)>2) + iface->nmask = *interpret_addr2(p+1); + else + iface->nmask.s_addr = htonl(~((1<<(32-atoi(p+1)))-1)); + } else { + default_netmask(&iface->nmask,&iface->ip); + } + iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr; + iface->next = NULL; + + if (!interfaces) { + interfaces = iface; + } else { + last_iface->next = iface; + } + last_iface = iface; + DEBUG(1,("Added interface ip=%s ",inet_ntoa(iface->ip))); + DEBUG(1,("bcast=%s ",inet_ntoa(iface->bcast))); + DEBUG(1,("nmask=%s\n",inet_ntoa(iface->nmask))); + } + + if (interfaces) return; + + /* setup a default interface */ + iface = (struct interface *)malloc(sizeof(*iface)); + if (!iface) return; + + if (got_ip) { + iface->ip = default_ip; + } else { + get_myname(NULL,&iface->ip); + } + + if (got_bcast) { + iface->bcast = default_bcast; + } else { + get_broadcast(&iface->ip,&iface->bcast,&iface->nmask); + } + + if (got_nmask) { + iface->nmask = default_nmask; + iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr; + } + + if (iface->bcast.s_addr != (iface->ip.s_addr | ~iface->nmask.s_addr)) { + DEBUG(2,("Warning: inconsistant interface %s\n",inet_ntoa(iface->ip))); + } + + interfaces = last_iface = iface; + + DEBUG(1,("Added interface ip=%s ",inet_ntoa(iface->ip))); + DEBUG(1,("bcast=%s ",inet_ntoa(iface->bcast))); + DEBUG(1,("nmask=%s\n",inet_ntoa(iface->nmask))); +} + + +/**************************************************************************** + override the defaults + **************************************************************************/ +void iface_set_default(char *ip,char *bcast,char *nmask) +{ + if (ip) { + got_ip = True; + default_ip = *interpret_addr2(ip); + } + + if (bcast) { + got_bcast = True; + default_bcast = *interpret_addr2(bcast); + } + + if (nmask) { + got_nmask = True; + default_nmask = *interpret_addr2(nmask); + } +} + + +/**************************************************************************** + check if an IP is one of mine + **************************************************************************/ +BOOL ismyip(struct in_addr ip) +{ + struct interface *i; + for (i=interfaces;i;i=i->next) + if (ip_equal(i->ip,ip)) return True; + return False; +} + +/**************************************************************************** + check if a bcast is one of mine + **************************************************************************/ +BOOL ismybcast(struct in_addr bcast) +{ + struct interface *i; + for (i=interfaces;i;i=i->next) + if (ip_equal(i->bcast,bcast)) return True; + return False; +} + +static struct interface *iface_find(struct in_addr ip) +{ + struct interface *i; + if (zero_ip(ip)) return interfaces; + + for (i=interfaces;i;i=i->next) + if (same_net(i->ip,ip,i->nmask)) return i; + + return interfaces; +} + + +/* these 3 functions return the ip/bcast/nmask for the interface + most appropriate for the given ip address */ + +struct in_addr *iface_bcast(struct in_addr ip) +{ + return(&iface_find(ip)->bcast); +} + +struct in_addr *iface_nmask(struct in_addr ip) +{ + return(&iface_find(ip)->nmask); +} + +struct in_addr *iface_ip(struct in_addr ip) +{ + return(&iface_find(ip)->ip); +} + + |