1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-19 10:03:58 +03:00
samba-mirror/source/lib/interface.c

482 lines
14 KiB
C
Raw Normal View History

/*
Unix SMB/Netbios implementation.
Version 1.9.
multiple interface handling
'The mother of all checkins' :-). Jeremy Allison (jallison@whistle.com) Wed May 7 1997: Update for 1.9.17alpha1 release - 'browsefix release' designed to make browsing across subnets work. byteorder.h: Updated copyright to 1997. charcnv.c: Updated copyright to 1997. charset.c Updated copyright to 1997. charset.h Updated copyright to 1997. client.c Updated copyright to 1997. clientutil.c Updated copyright to 1997. dir.c Updated copyright to 1997. fault.c Updated copyright to 1997. includes.h Updated copyright to 1997. interface.c Updated copyright to 1997. ipc.c Updated copyright to 1997. kanji.c Updated copyright to 1997. kanji.h Updated copyright to 1997. loadparm.c Updated copyright to 1997. locking.c Updated copyright to 1997. mangle.c Updated copyright to 1997. message.c Updated copyright to 1997. nameannounce.c Made use of WINS subnet explicit. Added reset_announce_timer() so announcement can be made immediately when we become a master. Expanded code to do sync with dmb. namebrowse.c Removed redundent checks for AM_MASTER in sync code. Made use of WINS subnet explicit. namedbname.c Made use of WINS subnet explicit. namedbresp.c Made use of WINS subnet explicit. namedbserver.c Made use of WINS subnet explicit. namedbsubnet.c Explicitly add workgroup to WINS subnet when we become a dmb. Made use of WINS subnet explicit. namedbwork.c Made use of WINS subnet explicit. Removed redundent check_work_servertype() function. nameelect.c Explicitly add workgroup to WINS subnet when we become a master browser. Made use of WINS subnet explicit. namelogon.c Updated copyright to 1997. namepacket.c Updated copyright to 1997. namequery.c Updated copyright to 1997. nameresp.c Made use of WINS subnet explicit. Made nmbd fail if configured as master browser and one exists already. nameserv.c Made use of WINS subnet explicit. Remove redundent logon server and domain master code. nameserv.h Add emumerate subnet macros. nameservreply.c Made use of WINS subnet explicit. nameservresp.c Updated copyright to 1997. namework.c Made use of WINS subnet explicit. Updated code to add sync browser entries to add subnet parameter. nmbd.c Added sanity check for misconfigured nmbd. nmblib.c Updated copyright to 1997. nmblookup.c Updated copyright to 1997. nmbsync.c Removed redundent AM_ANY_MASTER check. params.c Updated copyright to 1997. password.c Updated copyright to 1997. pipes.c Updated copyright to 1997. predict.c Updated copyright to 1997. printing.c Updated copyright to 1997. proto.h Changed protos for new nmbd code. quotas.c Updated copyright to 1997. replace.c Updated copyright to 1997. reply.c Updated copyright to 1997. server.c Updated copyright to 1997. shmem.c Updated copyright to 1997. smb.h Updated copyright to 1997. smbencrypt.c Updated copyright to 1997. smbpasswd.c Updated copyright to 1997. smbrun.c Updated copyright to 1997. status.c Updated copyright to 1997. system.c Updated copyright to 1997. testparm.c Updated copyright to 1997. testprns.c Updated copyright to 1997. time.c Updated copyright to 1997. trans2.c Updated copyright to 1997. trans2.h Updated copyright to 1997. uid.c Updated copyright to 1997. username.c Updated copyright to 1997. util.c Updated copyright to 1997. version.h Changed to 1.9.17alpha1.
-
Copyright (C) Andrew Tridgell 1992-1997
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 <assert.h> /* added by philipp */
extern int DEBUGLEVEL;
struct in_addr ipzero;
struct in_addr wins_ip;
struct interface *local_interfaces = NULL;
struct interface *present_interfaces = NULL;
struct interface *last_iface;
static void get_interfaces()
{
int sock = -1; /* AF_INET raw socket desc */
char buff[1024];
struct ifreq *ifr=NULL, ifr2;
int i;
struct interface *iface, *last_iface = NULL;
#ifndef ifr_mtu
#define ifr_mtu ifr_metric
#endif
#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
if (present_interfaces) return; /* already initialized */
/* 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) {
ifr2 = ifr[i];
if (ioctl(sock, SIOCGIFFLAGS, &ifr2) < 0)
DEBUG(0,("SIOCGIFFLAGS failed\n"));
if ((ifr2.ifr_flags & (IFF_RUNNING | IFF_LOOPBACK)) != IFF_RUNNING)
continue;
iface = (struct interface *)malloc(sizeof(*iface));
assert(iface != NULL);
iface->next = NULL;
iface->ip = ((struct sockaddr_in *) &ifr[i].ifr_addr)->sin_addr;
iface->name = strdup(ifr[i].ifr_name);
iface->flags = ifr2.ifr_flags;
/* complete with netmask and b'cast address */
ifr2 = *ifr;
if (ioctl(sock, SIOCGIFNETMASK, &ifr2) < 0)
DEBUG(0,("SIOCGIFNETMASK failed\n"));
else
iface->nmask = ((struct sockaddr_in *)&ifr2.ifr_addr)->sin_addr;
if (ioctl(sock, SIOCGIFBRDADDR, &ifr2) < 0)
DEBUG(0,("SIOCGIFBRDADDR failed\n"));
else
iface->bcast = ((struct sockaddr_in *)&ifr2.ifr_addr)->sin_addr;
if (ioctl(sock, SIOCGIFMTU, &ifr2) < 0)
DEBUG(0,("SIOCGIFMTU failed\n"));
else
iface->mtu = ifr2.ifr_mtu;
DEBUG(4,("Netmask for %s = %s\n", iface->name, inet_ntoa(iface->nmask)));
if (!present_interfaces)
present_interfaces = iface;
else
last_iface->next = iface;
last_iface = iface;
}
}
}
#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++) {
ifr2 = *ifr;
if (ioctl(sock, SIOCGIFFLAGS, &ifr2) < 0)
DEBUG(0,("SIOCGIFFLAGS failed\n"));
if ((ifr2.ifr_flags & (IFF_RUNNING | IFF_LOOPBACK)) == IFF_RUNNING) {
iface = (struct interface *)malloc(sizeof(*iface));
assert(iface != NULL);
iface->next = NULL;
iface->ip = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
iface->name = strdup(ifr->ifr_name);
iface->flags = ifr2.ifr_flags;
/* complete with netmask and b'cast address */
ifr2 = *ifr;
strioctl.ic_cmd = SIOCGIFNETMASK;
strioctl.ic_dp = (char *)&ifr2;
strioctl.ic_len = sizeof(struct ifr2);
if (ioctl(sock, I_STR, &strioctl) < 0)
DEBUG(0,("Failed I_STR/SIOCGIFNETMASK: %s\n", strerror(errno)));
else
iface->nmask = ((struct sockaddr_in *)&ifr2.ifr_addr)->sin_addr;
strioctl.ic_cmd = SIOCGIFBRDADDR;
if (ioctl(sock, I_STR, &strioctl) < 0)
DEBUG(0,("SIOCGIFBRDADDR failed\n"));
else
iface->bcast = ((struct sockaddr_in *)&ifr2.ifr_addr)->sin_addr;
strioctl.ic_cmd = SIOCGIFMTU;
if (ioctl(sock, I_STR, &strioctl) < 0)
DEBUG(0,("SIOCGIFMTU failed\n"));
else
iface->mtu = ifr2.ifr_mtu;
DEBUG(4,("Netmask for %s = %s\n", iface->name, inet_ntoa(iface->nmask)));
if (!present_interfaces)
present_interfaces = iface;
else
last_iface->next = iface;
last_iface = iface;
}
}
}
#elif defined(__FreeBSD__) || defined(NETBSD) || defined(AMIGA) || defined(_AIX41)
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) {
ifr2 = *ifr;
if (ioctl(sock, SIOCGIFFLAGS, &ifr2) < 0)
DEBUG(0,("SIOCGIFFLAGS failed\n"));
if ((ifr2.ifr_flags & (IFF_RUNNING | IFF_LOOPBACK)) == IFF_RUNNING) {
iface = (struct interface *)malloc(sizeof(*iface));
assert(iface != NULL);
iface->next = NULL;
iface->ip = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
iface->name = strdup(ifr->ifr_name);
iface->flags = ifr2.ifr_flags;
/* complete with netmask and b'cast address */
ifr2 = *ifr;
if (ioctl(sock, SIOCGIFNETMASK, &ifr2) < 0)
DEBUG(0,("SIOCGIFNETMASK failed\n"));
else
iface->nmask = (*(struct sockaddr_in *)&ifr2.ifr_addr).sin_addr;
if (ioctl(sock, SIOCGIFBRDADDR, &ifr2) < 0)
DEBUG(0,("SIOCGIFBRDADDR failed\n"));
else
iface->bcast = (*(struct sockaddr_in *)&ifr2.ifr_addr).sin_addr;
if (ioctl(sock, SIOCGIFMTU, &ifr2) < 0)
DEBUG(0,("SIOCGIFMTU failed\n"));
else
iface->mtu = ifr2.ifr_mtu;
DEBUG(4,("Netmask for %s = %s\n", iface->name, inet_ntoa(iface->nmask)));
if (!present_interfaces)
present_interfaces = iface;
else
last_iface->next = iface;
last_iface = iface;
}
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++) {
ifr2 = *ifr;
if (ioctl(sock, SIOCGIFFLAGS, &ifr2) < 0)
DEBUG(0,("SIOCGIFFLAGS failed\n"));
if ((ifr2.ifr_flags & (IFF_RUNNING | IFF_LOOPBACK)) == IFF_RUNNING) {
#ifdef BSDI
if (ioctl(sock, SIOCGIFADDR, ifr) < 0) break;
#endif
iface = (struct interface *)malloc(sizeof(*iface));
assert(iface != NULL);
iface->next = NULL;
iface->ip = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
iface->name = strdup(ifr->ifr_name);
iface->flags = ifr2.ifr_flags;
/* complete with netmask and b'cast address */
ifr2 = *ifr;
if (ioctl(sock, SIOCGIFNETMASK, &ifr2) < 0)
DEBUG(0,("SIOCGIFNETMASK failed\n"));
else
iface->nmask = (*(struct sockaddr_in *)&ifr2.ifr_addr).sin_addr;
if (ioctl(sock, SIOCGIFBRDADDR, &ifr2) < 0)
DEBUG(0,("SIOCGIFBRDADDR failed\n"));
else
iface->bcast = (*(struct sockaddr_in *)&ifr2.ifr_addr).sin_addr;
if (ioctl(sock, SIOCGIFMTU, &ifr2) < 0)
DEBUG(0,("SIOCGIFMTU failed\n"));
else
iface->mtu = ifr2.ifr_mtu;
DEBUG(4,("Netmask for %s = %s\n", iface->name, inet_ntoa(iface->nmask)));
if (!present_interfaces)
present_interfaces = iface;
else
last_iface->next = iface;
last_iface = iface;
}
}
}
#endif
/* Close up shop */
(void) close(sock);
} /* get_interfaces */
/****************************************************************************
load a list of network interfaces
****************************************************************************/
static void interpret_interfaces(char *s, struct interface **interfaces,
char *description)
{
char *ptr = s;
fstring token;
struct interface *iface, *i;
BOOL seenALL = False;
ipzero = *interpret_addr2("0.0.0.0");
wins_ip = *interpret_addr2("255.255.255.255");
get_interfaces();
while (next_token(&ptr,token,NULL)) {
if (strcasecmp(token, "ALL")) {
if (*interfaces) {
DEBUG(0, ("Error: interface name \"ALL\" must occur alone\n"));
/* should do something here ... */
}
/* should we copy the list, or just point at it? */
for (i = present_interfaces; i; i = i->next) {
iface = (struct interface *)malloc(sizeof(*iface));
if (!iface) return;
*iface = *i;
iface->next = NULL;
if (!(*interfaces))
(*interfaces) = iface;
else
last_iface->next = iface;
last_iface = iface;
}
seenALL = True;
continue;
} else if (seenALL) {
DEBUG(0, ("Error: can't mix interface \"ALL\" with other interface namess\n"));
continue;
}
/* maybe we already have it listed */
for (i=(*interfaces);i;i=i->next)
if (strcasecmp(token,i->name)) break;
if (i) continue;
iface = (struct interface *)malloc(sizeof(*iface));
if (!iface) return;
/* make sure name is known */
for (i=present_interfaces;i;i=i->next)
if (strcasecmp(token,i->name)) break;
if (!i) {
DEBUG(0, ("Warning: unknown interface \"%s\" specified\n", token));
continue;
}
*iface = *i;
iface->next = NULL;
if (iface->bcast.s_addr != (iface->ip.s_addr | ~iface->nmask.s_addr)) {
DEBUG(0, ("Warning: overriding b'cast address %s on interface %s\n",
inet_ntoa(iface->bcast), iface->name));
iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr;
}
if (!(*interfaces)) {
(*interfaces) = iface;
} else {
last_iface->next = iface;
}
last_iface = iface;
DEBUG(1,("Added %s ip=%s ",description,inet_ntoa(iface->ip)));
DEBUG(1,("bcast=%s ",inet_ntoa(iface->bcast)));
DEBUG(1,("nmask=%s\n",inet_ntoa(iface->nmask)));
}
if (! *interfaces)
DEBUG(0,("Error: no interfaces specified.\n"));
}
/****************************************************************************
load the remote and local interfaces
****************************************************************************/
void load_interfaces(void)
{
/* add the machine's interfaces to local interface structure*/
interpret_interfaces(lp_interfaces(), &local_interfaces,"interface");
}
/****************************************************************************
override the defaults
**************************************************************************/
void iface_set_default(char *ip,char *bcast,char *nmask)
{
DEBUG(0, ("iface_set_default: function deprecated.\n"));
exit(1);
}
/****************************************************************************
check if an IP is one of mine
**************************************************************************/
BOOL ismyip(struct in_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 bcast is one of mine
**************************************************************************/
BOOL ismybcast(struct in_addr bcast)
{
struct interface *i;
for (i=local_interfaces;i;i=i->next)
if (ip_equal(i->bcast,bcast)) 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 in_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;
}
static struct interface *iface_find(struct in_addr ip)
{
struct interface *i;
if (zero_ip(ip)) return local_interfaces;
for (i=local_interfaces;i;i=i->next)
if (same_net(i->ip,ip,i->nmask)) return i;
return local_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);
}