From 284349482f5293a9a23d0f72d7c2aab46b55843b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 1 Nov 2004 22:48:25 +0000 Subject: r3443: the next stage in the include files re-organisation. I have created the include/system/ directory, which will contain the wrappers for the system includes for logical subsystems. So far I have created include/system/kerberos.h and include/system/network.h, which contain all the system includes for kerberos code and networking code. These are the included in subsystems that need kerberos or networking respectively. Note that this method avoids the mess of #ifdef HAVE_XXX_H in every C file, instead each C module includes the include/system/XXX.h file for the logical system support it needs, and the details are kept isolated in include/system/ This patch also creates a "struct ipv4_addr" which replaces "struct in_addr" in our code. That avoids every C file needing to import all the system networking headers. (This used to be commit 2e25c71853f8996f73755277e448e7d670810349) --- source4/lib/netif/interface.c | 355 +++++++++++++++++++++++++++++++++++++ source4/lib/netif/netif.c | 400 ++++++++++++++++++++++++++++++++++++++++++ source4/lib/netif/netif.h | 34 ++++ 3 files changed, 789 insertions(+) create mode 100644 source4/lib/netif/interface.c create mode 100644 source4/lib/netif/netif.c create mode 100644 source4/lib/netif/netif.h (limited to 'source4/lib/netif') diff --git a/source4/lib/netif/interface.c b/source4/lib/netif/interface.c new file mode 100644 index 0000000000..75fdf8c976 --- /dev/null +++ b/source4/lib/netif/interface.c @@ -0,0 +1,355 @@ +/* + Unix SMB/CIFS implementation. + multiple interface handling + Copyright (C) Andrew Tridgell 1992-1998 + + 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 "system/network.h" +#include "lib/netif/netif.h" + +static struct iface_struct *probed_ifaces; +static int total_probed; + +static struct ipv4_addr allones_ip; +struct ipv4_addr loopback_ip; + +/* used for network interfaces */ +struct interface { + struct interface *next, *prev; + struct ipv4_addr ip; + struct ipv4_addr bcast; + struct ipv4_addr nmask; +}; + +static struct interface *local_interfaces; + +#define ALLONES ((uint32_t)0xFFFFFFFF) +#define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES)) +#define MKNETADDR(_IP, _NM) (_IP & _NM) + +static struct ipv4_addr tov4(struct in_addr in) +{ + struct ipv4_addr in2; + in2.s_addr = in.s_addr; + return in2; +} + +/**************************************************************************** +Try and find an interface that matches an ip. If we cannot, return NULL + **************************************************************************/ +static struct interface *iface_find(struct in_addr ip, BOOL CheckMask) +{ + struct interface *i; + if (is_zero_ip(tov4(ip))) return local_interfaces; + + for (i=local_interfaces;i;i=i->next) + if (CheckMask) { + if (same_net(i->ip,tov4(ip),i->nmask)) return i; + } else if ((i->ip).s_addr == ip.s_addr) return i; + + return NULL; +} + + +/**************************************************************************** +add an interface to the linked list of interfaces +****************************************************************************/ +static void add_interface(struct in_addr ip, struct in_addr nmask) +{ + struct interface *iface; + if (iface_find(ip, False)) { + DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip))); + return; + } + + if (ip_equal(nmask, allones_ip)) { + DEBUG(3,("not adding non-broadcast interface %s\n",inet_ntoa(ip))); + return; + } + + iface = (struct interface *)malloc(sizeof(*iface)); + if (!iface) return; + + ZERO_STRUCTPN(iface); + + iface->ip = tov4(ip); + iface->nmask = tov4(nmask); + iface->bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr); + + DLIST_ADD(local_interfaces, iface); + + DEBUG(2,("added interface ip=%s ",sys_inet_ntoa(iface->ip))); + DEBUG(2,("bcast=%s ",sys_inet_ntoa(iface->bcast))); + DEBUG(2,("nmask=%s\n",sys_inet_ntoa(iface->nmask))); +} + + + +/**************************************************************************** +interpret a single element from a interfaces= config line + +This handles the following different forms: + +1) wildcard interface name +2) DNS name +3) IP/masklen +4) ip/mask +5) bcast/mask +****************************************************************************/ +static void interpret_interface(TALLOC_CTX *mem_ctx, const char *token) +{ + struct in_addr ip, nmask; + char *p; + int i, added=0; + + ip.s_addr = 0; + nmask.s_addr = 0; + + /* first check if it is an interface name */ + for (i=0;i 2) { + nmask.s_addr = interpret_addr2(p).s_addr; + } else { + nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES)); + } + + /* maybe the first component was a broadcast address */ + if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) || + ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) { + for (i=0;i 0) { + probed_ifaces = memdup(ifaces, sizeof(ifaces[0])*total_probed); + } + + /* if we don't have a interfaces line then use all broadcast capable + interfaces except loopback */ + if (!ptr || !*ptr || !**ptr) { + if (total_probed <= 0) { + DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n")); + exit(1); + } + for (i=0;i 0 )&& (n != total_probed || + memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) { + return True; + } + + return False; +} + + +/**************************************************************************** + check if an IP is one of mine + **************************************************************************/ +BOOL ismyip(struct ipv4_addr ip) +{ + struct interface *i; + for (i=local_interfaces;i;i=i->next) + if (ip_equal(i->ip,ip)) return True; + return False; +} + +/**************************************************************************** + check if a packet is from a local (known) net + **************************************************************************/ +BOOL is_local_net(struct ipv4_addr from) +{ + struct interface *i; + for (i=local_interfaces;i;i=i->next) { + if((from.s_addr & i->nmask.s_addr) == + (i->ip.s_addr & i->nmask.s_addr)) + return True; + } + return False; +} + +/**************************************************************************** + how many interfaces do we have + **************************************************************************/ +int iface_count(void) +{ + int ret = 0; + struct interface *i; + + for (i=local_interfaces;i;i=i->next) + ret++; + return ret; +} + +/**************************************************************************** + return IP of the Nth interface + **************************************************************************/ +struct ipv4_addr *iface_n_ip(int n) +{ + struct interface *i; + + for (i=local_interfaces;i && n;i=i->next) + n--; + + if (i) return &i->ip; + return NULL; +} + +/**************************************************************************** + return bcast of the Nth interface + **************************************************************************/ +struct ipv4_addr *iface_n_bcast(int n) +{ + struct interface *i; + + for (i=local_interfaces;i && n;i=i->next) + n--; + + if (i) return &i->bcast; + return NULL; +} + + +/* these 3 functions return the ip/bcast/nmask for the interface + most appropriate for the given ip address. If they can't find + an appropriate interface they return the requested field of the + first known interface. */ + +struct ipv4_addr *iface_ip(struct ipv4_addr ip) +{ + struct in_addr in; + struct interface *i; + in.s_addr = ip.s_addr; + i = iface_find(in, True); + return(i ? &i->ip : &local_interfaces->ip); +} + +/* + return True if a IP is directly reachable on one of our interfaces +*/ +BOOL iface_local(struct ipv4_addr ip) +{ + struct in_addr in; + in.s_addr = ip.s_addr; + return iface_find(in, True) ? True : False; +} diff --git a/source4/lib/netif/netif.c b/source4/lib/netif/netif.c new file mode 100644 index 0000000000..729aeedbe3 --- /dev/null +++ b/source4/lib/netif/netif.c @@ -0,0 +1,400 @@ +/* + Unix SMB/CIFS implementation. + return a list of network interfaces + Copyright (C) Andrew Tridgell 1998 + + 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. +*/ + + +/* working out the interfaces for a OS is an incredibly non-portable + thing. We have several possible implementations below, and autoconf + tries each of them to see what works + + Note that this file does _not_ include includes.h. That is so this code + can be called directly from the autoconf tests. That also means + this code cannot use any of the normal Samba debug stuff or defines. + This is standalone code. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef AUTOCONF_TEST +#include "lib/netif/netif.h" +#include "config.h" +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifndef SIOCGIFCONF +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_STRINGS_H +#include +#endif + +#ifdef __COMPAR_FN_T +#define QSORT_CAST (__compar_fn_t) +#endif + +#ifndef QSORT_CAST +#define QSORT_CAST (int (*)(const void *, const void *)) +#endif + +#if HAVE_IFACE_IFCONF + +/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1 + V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2. + + It probably also works on any BSD style system. */ + +/**************************************************************************** + get the netmask address for a local interface +****************************************************************************/ +static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) +{ + struct ifconf ifc; + char buff[8192]; + int fd, i, n; + struct ifreq *ifr=NULL; + int total = 0; + struct in_addr ipaddr; + struct in_addr nmask; + char *iname; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + return -1; + } + + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + + if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { + close(fd); + return -1; + } + + ifr = ifc.ifc_req; + + n = ifc.ifc_len / sizeof(struct ifreq); + + /* Loop through interfaces, looking for given IP address */ + for (i=n-1;i>=0 && total < max_interfaces;i--) { + if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) { + continue; + } + + iname = ifr[i].ifr_name; + ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr; + + if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) { + continue; + } + + if (!(ifr[i].ifr_flags & IFF_UP)) { + continue; + } + + if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) { + continue; + } + + nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr; + + strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1); + ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; + ifaces[total].ip = ipaddr; + ifaces[total].netmask = nmask; + total++; + } + + close(fd); + + return total; +} + +#elif HAVE_IFACE_IFREQ + +#ifndef I_STR +#include +#endif + +/**************************************************************************** +this should cover most of the streams based systems +Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code +****************************************************************************/ +static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) +{ + struct ifreq ifreq; + struct strioctl strioctl; + char buff[8192]; + int fd, i, n; + struct ifreq *ifr=NULL; + int total = 0; + struct in_addr ipaddr; + struct in_addr nmask; + char *iname; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + return -1; + } + + strioctl.ic_cmd = SIOCGIFCONF; + strioctl.ic_dp = buff; + strioctl.ic_len = sizeof(buff); + if (ioctl(fd, I_STR, &strioctl) < 0) { + close(fd); + return -1; + } + + /* we can ignore the possible sizeof(int) here as the resulting + number of interface structures won't change */ + n = strioctl.ic_len / sizeof(struct ifreq); + + /* we will assume that the kernel returns the length as an int + at the start of the buffer if the offered size is a + multiple of the structure size plus an int */ + if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) { + ifr = (struct ifreq *)(buff + sizeof(int)); + } else { + ifr = (struct ifreq *)buff; + } + + /* Loop through interfaces */ + + for (i = 0; isin_addr; + + strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1); + ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; + ifaces[total].ip = ipaddr; + ifaces[total].netmask = nmask; + + total++; + } + + close(fd); + + return total; +} + +#elif HAVE_IFACE_AIX + +/**************************************************************************** +this one is for AIX (tested on 4.2) +****************************************************************************/ +static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) +{ + char buff[8192]; + int fd, i; + struct ifconf ifc; + struct ifreq *ifr=NULL; + struct in_addr ipaddr; + struct in_addr nmask; + char *iname; + int total = 0; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + return -1; + } + + + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + + if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { + close(fd); + return -1; + } + + ifr = ifc.ifc_req; + + /* Loop through interfaces */ + i = ifc.ifc_len; + + while (i > 0 && total < max_interfaces) { + uint_t inc; + + inc = ifr->ifr_addr.sa_len; + + if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { + goto next; + } + + ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr; + iname = ifr->ifr_name; + + if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { + goto next; + } + + if (!(ifr->ifr_flags & IFF_UP)) { + goto next; + } + + if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { + goto next; + } + + nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; + + strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1); + ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; + ifaces[total].ip = ipaddr; + ifaces[total].netmask = nmask; + + total++; + + next: + /* + * Patch from Archie Cobbs (archie@whistle.com). The + * addresses in the SIOCGIFCONF interface list have a + * minimum size. Usually this doesn't matter, but if + * your machine has tunnel interfaces, etc. that have + * a zero length "link address", this does matter. */ + + if (inc < sizeof(ifr->ifr_addr)) + inc = sizeof(ifr->ifr_addr); + inc += IFNAMSIZ; + + ifr = (struct ifreq*) (((char*) ifr) + inc); + i -= inc; + } + + + close(fd); + return total; +} + +#else /* a dummy version */ +static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) +{ + return -1; +} +#endif + + +static int iface_comp(struct iface_struct *i1, struct iface_struct *i2) +{ + int r; + r = strcmp(i1->name, i2->name); + if (r) return r; + r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr); + if (r) return r; + r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr); + return r; +} + +/* this wrapper is used to remove duplicates from the interface list generated + above */ +int get_interfaces(struct iface_struct *ifaces, int max_interfaces) +{ + int total, i, j; + + total = _get_interfaces(ifaces, max_interfaces); + if (total <= 0) return total; + + /* now we need to remove duplicates */ + qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp); + + for (i=1;i +#include +#include + +struct iface_struct { + char name[16]; + struct in_addr ip; + struct in_addr netmask; +}; + +#define MAX_INTERFACES 128 + -- cgit