r11555: - change socket_wrapper to support multiple IP's
authorStefan Metzmacher <metze@samba.org>
Mon, 7 Nov 2005 15:36:51 +0000 (15:36 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:45:53 +0000 (13:45 -0500)
- SOCKET_WRAPPER_DEFAULT_IFACE=X specifies the default interface
  for 127.0.0.X
- we now use multiple interfaces for smbtorture in make test
  127.0.0.26-127.0.0.31
- and 127.0.0.1 only for smbd

the are more work needed for better support for broacast messages...
but this is enough for the winsrepl tests

metze
(This used to be commit dbd01110d1a3e0f5914ae8d156723d6d6edf160c)

source4/lib/socket_wrapper/socket_wrapper.c
source4/script/tests/selftest.sh
source4/script/tests/test_nbt.sh

index d95806783d3187be394990db0e38d877796a9807..d9f61f7e3c64111b9da043b48994a09b81a076c1 100644 (file)
@@ -63,7 +63,9 @@
    
    with this format we have 8 chars left for the directory name
 */
-#define SOCKET_FORMAT "%u_%05u"
+#define SOCKET_FORMAT "%c%02X%04X"
+#define SOCKET_TYPE_CHAR_TCP           'T'
+#define SOCKET_TYPE_CHAR_UDP           'U'
 
 static struct sockaddr *sockaddr_dup(const void *data, socklen_t len)
 {
@@ -80,6 +82,7 @@ struct socket_info
        int type;
        int protocol;
        int bound;
+       int bcast;
 
        char *path;
        char *tmp_path;
@@ -108,45 +111,199 @@ static const char *socket_wrapper_dir(void)
        return s;
 }
 
+static unsigned int socket_wrapper_default_iface(void)
+{
+       const char *s = getenv("SOCKET_WRAPPER_DEFAULT_IFACE");
+       if (s) {
+               unsigned int iface;
+               if (sscanf(s, "%u", &iface) == 1) {
+                       if (iface >= 1 && iface <= 0xFF) {
+                               return iface;
+                       }
+               }
+       }
+
+       return 1;/* 127.0.0.1 */
+}
+
 static int convert_un_in(const struct sockaddr_un *un, struct sockaddr_in *in, socklen_t *len)
 {
+       unsigned int iface;
        unsigned int prt;
        const char *p;
-       int type;
+       char type;
 
        if ((*len) < sizeof(struct sockaddr_in)) {
                return 0;
        }
 
-       in->sin_family = AF_INET;
-       in->sin_port = htons(1025); /* Default to 1025 */
        p = strrchr(un->sun_path, '/');
        if (p) p++; else p = un->sun_path;
 
-       if (sscanf(p, SOCKET_FORMAT, &type, &prt) == 2) {
-               in->sin_port = htons(prt);
+       if (sscanf(p, SOCKET_FORMAT, &type, &iface, &prt) != 3) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (type != SOCKET_TYPE_CHAR_TCP && type != SOCKET_TYPE_CHAR_UDP) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (iface == 0 || iface > 0xFF) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (prt > 0xFFFF) {
+               errno = EINVAL;
+               return -1;
        }
-       in->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+       in->sin_addr.s_addr = htonl((127<<24) | iface);
+       in->sin_port = htons(prt);
+
        *len = sizeof(struct sockaddr_in);
        return 0;
 }
 
-static int convert_in_un(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un)
+static int convert_in_un_remote(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un,
+                               int *bcast)
 {
-       int type = si->type;
-       uint16_t prt = ntohs(in->sin_port);
+       char u_type = '\0';
+       char b_type = '\0';
+       char a_type = '\0';
+       char type = '\0';
+       unsigned int addr= ntohl(in->sin_addr.s_addr);
+       unsigned int prt = ntohs(in->sin_port);
+       unsigned int iface;
+       int is_bcast = 0;
+
+       if (bcast) *bcast = 0;
+
+       if (prt == 0) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       switch (si->type) {
+       case SOCK_STREAM:
+               u_type = SOCKET_TYPE_CHAR_TCP;
+               break;
+       case SOCK_DGRAM:
+               u_type = SOCKET_TYPE_CHAR_UDP;
+               a_type = SOCKET_TYPE_CHAR_UDP;
+               b_type = SOCKET_TYPE_CHAR_UDP;
+               break;
+       }
+
+       if (a_type && addr == 0xFFFFFFFF) {
+               /* 255.255.255.255 only udp */
+               is_bcast = 2;
+               type = a_type;
+               iface = socket_wrapper_default_iface();
+       } else if (b_type && addr == 0x7FFFFFFF) {
+               /* 127.255.255.255 only udp */
+               is_bcast = 1;
+               type = b_type;
+               iface = socket_wrapper_default_iface();
+       } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
+               /* 127.0.0.X */
+               is_bcast = 0;
+               type = u_type;
+               iface = (addr & 0x000000FF);
+       } else {
+               errno = ENETUNREACH;
+               return -1;
+       }
+
+       if (bcast) *bcast = is_bcast;
+
+       if (is_bcast) {
+               snprintf(un->sun_path, sizeof(un->sun_path), "%s/EINVAL", 
+                        socket_wrapper_dir());
+               /* the caller need to do more processing */
+               return 0;
+       }
+
+       snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
+                socket_wrapper_dir(), type, iface, prt);
+
+       return 0;
+}
+
+static int convert_in_un_alloc(struct socket_info *si, const struct sockaddr_in *in, struct sockaddr_un *un,
+                              int *bcast)
+{
+       char u_type = '\0';
+       char d_type = '\0';
+       char b_type = '\0';
+       char a_type = '\0';
+       char type = '\0';
+       unsigned int addr= ntohl(in->sin_addr.s_addr);
+       unsigned int prt = ntohs(in->sin_port);
+       unsigned int iface;
+       struct stat st;
+       int is_bcast = 0;
+
+       if (bcast) *bcast = 0;
+
+       switch (si->type) {
+       case SOCK_STREAM:
+               u_type = SOCKET_TYPE_CHAR_TCP;
+               d_type = SOCKET_TYPE_CHAR_TCP;
+               break;
+       case SOCK_DGRAM:
+               u_type = SOCKET_TYPE_CHAR_UDP;
+               d_type = SOCKET_TYPE_CHAR_UDP;
+               a_type = SOCKET_TYPE_CHAR_UDP;
+               b_type = SOCKET_TYPE_CHAR_UDP;
+               break;
+       }
+
+       if (addr == 0) {
+               /* 0.0.0.0 */
+               is_bcast = 0;
+               type = d_type;
+               iface = socket_wrapper_default_iface();
+       } else if (a_type && addr == 0xFFFFFFFF) {
+               /* 255.255.255.255 only udp */
+               is_bcast = 2;
+               type = a_type;
+               iface = socket_wrapper_default_iface();
+       } else if (b_type && addr == 0x7FFFFFFF) {
+               /* 127.255.255.255 only udp */
+               is_bcast = 1;
+               type = b_type;
+               iface = socket_wrapper_default_iface();
+       } else if ((addr & 0xFFFFFF00) == 0x7F000000) {
+               /* 127.0.0.X */
+               is_bcast = 0;
+               type = u_type;
+               iface = (addr & 0x000000FF);
+       } else {
+               errno = EADDRNOTAVAIL;
+               return -1;
+       }
+
+       if (bcast) *bcast = is_bcast;
+
        if (prt == 0) {
-               struct stat st;
                /* handle auto-allocation of ephemeral ports */
-               prt = 5000;
-               do {
+               for (prt = 5001; prt < 10000; prt++) {
                        snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
-                                socket_wrapper_dir(), type, ++prt);
-               } while (stat(un->sun_path, &st) == 0 && prt < 10000);
-               ((struct sockaddr_in *)si->myname)->sin_port = htons(prt);
-       } 
+                                socket_wrapper_dir(), type, iface, prt);
+                       if (stat(un->sun_path, &st) == 0) continue;
+
+                       ((struct sockaddr_in *)si->myname)->sin_port = htons(prt);
+                       return 0;
+               }
+               errno = ENFILE;
+               return -1;
+       }
+
        snprintf(un->sun_path, sizeof(un->sun_path), "%s/"SOCKET_FORMAT, 
-                socket_wrapper_dir(), type, prt);
+                socket_wrapper_dir(), type, iface, prt);
        return 0;
 }
 
@@ -162,7 +319,7 @@ static struct socket_info *find_socket_info(int fd)
 }
 
 static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr *in_addr, socklen_t in_len, 
-                                        struct sockaddr_un *out_addr)
+                                 struct sockaddr_un *out_addr, int alloc_sock, int *bcast)
 {
        if (!out_addr)
                return 0;
@@ -171,7 +328,19 @@ static int sockaddr_convert_to_un(struct socket_info *si, const struct sockaddr
 
        switch (in_addr->sa_family) {
        case AF_INET:
-               return convert_in_un(si, (const struct sockaddr_in *)in_addr, out_addr);
+               switch (si->type) {
+               case SOCK_STREAM:
+               case SOCK_DGRAM:
+                       break;
+               default:
+                       errno = ESOCKTNOSUPPORT;
+                       return -1;
+               }
+               if (alloc_sock) {
+                       return convert_in_un_alloc(si, (const struct sockaddr_in *)in_addr, out_addr, bcast);
+               } else {
+                       return convert_in_un_remote(si, (const struct sockaddr_in *)in_addr, out_addr, bcast);
+               }
        case AF_UNIX:
                memcpy(out_addr, in_addr, sizeof(*out_addr));
                return 0;
@@ -200,6 +369,14 @@ static int sockaddr_convert_from_un(const struct socket_info *si,
 
        switch (family) {
        case AF_INET:
+               switch (si->type) {
+               case SOCK_STREAM:
+               case SOCK_DGRAM:
+                       break;
+               default:
+                       errno = ESOCKTNOSUPPORT;
+                       return -1;
+               }
                return convert_un_in(in_addr, (struct sockaddr_in *)out_addr, out_len);
        case AF_UNIX:
                memcpy(out_addr, in_addr, sizeof(*in_addr));
@@ -288,28 +465,46 @@ static int swrap_auto_bind(struct socket_info *si)
        struct sockaddr_un un_addr;
        struct sockaddr_in in;
        int i;
+       char type;
+       int ret;
+       struct stat st;
        
        un_addr.sun_family = AF_UNIX;
+
+       switch (si->type) {
+       case SOCK_STREAM:
+               type = SOCKET_TYPE_CHAR_TCP;
+               break;
+       case SOCK_DGRAM:
+               type = SOCKET_TYPE_CHAR_UDP;
+               break;
+       default:
+               errno = ESOCKTNOSUPPORT;
+               return -1;
+       }
        
        for (i=0;i<1000;i++) {
                snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), 
                         "%s/"SOCKET_FORMAT, socket_wrapper_dir(),
-                        SOCK_DGRAM, i + 10000);
-               if (bind(si->fd, (struct sockaddr *)&un_addr, 
-                        sizeof(un_addr)) == 0) {
-                       si->tmp_path = strdup(un_addr.sun_path);
-                       si->bound = 1;
-                       break;
-               }
+                        type, socket_wrapper_default_iface(), i + 10000);
+               if (stat(un_addr.sun_path, &st) == 0) continue;
+               
+               ret = real_bind(si->fd, (struct sockaddr *)&un_addr, sizeof(un_addr));
+               if (ret == -1) return ret;
+
+               si->tmp_path = strdup(un_addr.sun_path);
+               si->bound = 1;
+               break;
        }
        if (i == 1000) {
+               errno = ENFILE;
                return -1;
        }
        
        memset(&in, 0, sizeof(in));
        in.sin_family = AF_INET;
        in.sin_port   = htons(i);
-       in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       in.sin_addr.s_addr = htonl(127<<24 | socket_wrapper_default_iface());
        
        si->myname_len = sizeof(in);
        si->myname = sockaddr_dup(&in, si->myname_len);
@@ -328,25 +523,24 @@ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen)
                return real_connect(s, serv_addr, addrlen);
        }
 
-       /* only allow pseudo loopback connections */
-       if (serv_addr->sa_family == AF_INET &&
-               ((const struct sockaddr_in *)serv_addr)->sin_addr.s_addr != 
-           htonl(INADDR_LOOPBACK)) {
-               errno = ENETUNREACH;
-               return -1;
-       }
-
        if (si->bound == 0 && si->domain != AF_UNIX) {
                ret = swrap_auto_bind(si);
                if (ret == -1) return -1;
        }
 
-       ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr);
+       ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr, 0, NULL);
        if (ret == -1) return -1;
 
        ret = real_connect(s, (struct sockaddr *)&un_addr, 
                           sizeof(struct sockaddr_un));
 
+       /* to give better errors */
+       if (serv_addr->sa_family == AF_INET) {
+               if (ret == -1 && errno == ENOENT) {
+                       errno = EHOSTUNREACH;
+               }
+       }
+
        if (ret == 0) {
                si->peername_len = addrlen;
                si->peername = sockaddr_dup(serv_addr, addrlen);
@@ -368,12 +562,7 @@ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen)
        si->myname_len = addrlen;
        si->myname = sockaddr_dup(myaddr, addrlen);
 
-       if (myaddr->sa_family == AF_INET &&
-           ((const struct sockaddr_in *)myaddr)->sin_addr.s_addr == 0) {
-               ((struct sockaddr_in *)si->myname)->sin_addr.s_addr = 
-                       htonl(INADDR_LOOPBACK);
-       }
-       ret = sockaddr_convert_to_un(si, (const struct sockaddr *)myaddr, addrlen, &un_addr);
+       ret = sockaddr_convert_to_un(si, (const struct sockaddr *)myaddr, addrlen, &un_addr, 1, &si->bcast);
        if (ret == -1) return -1;
 
        unlink(un_addr.sun_path);
@@ -501,6 +690,7 @@ ssize_t swrap_sendto(int  s,  const  void *buf, size_t len, int flags, const str
        struct sockaddr_un un_addr;
        int ret;
        struct socket_info *si = find_socket_info(s);
+       int bcast = 0;
 
        if (!si) {
                return real_sendto(s, buf, len, flags, to, tolen);
@@ -511,11 +701,37 @@ ssize_t swrap_sendto(int  s,  const  void *buf, size_t len, int flags, const str
                if (ret == -1) return -1;
        }
 
-       ret = sockaddr_convert_to_un(si, to, tolen, &un_addr);
+       ret = sockaddr_convert_to_un(si, to, tolen, &un_addr, 0, &bcast);
        if (ret == -1) return -1;
 
+       if (bcast) {
+               struct stat st;
+               unsigned int iface;
+               unsigned int prt = ntohs(((const struct sockaddr_in *)to)->sin_port);
+               char type;
+
+               type = SOCKET_TYPE_CHAR_UDP;
+
+               for(iface=0; iface <= 0xFF; iface++) {
+                       snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT, 
+                                socket_wrapper_dir(), type, iface, prt);
+                       if (stat(un_addr.sun_path, &st) != 0) continue;
+
+                       /* ignore the any errors in broadcast sends */
+                       real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
+               }
+               return len;
+       }
+
        ret = real_sendto(s, buf, len, flags, (struct sockaddr *)&un_addr, sizeof(un_addr));
 
+       /* to give better errors */
+       if (to->sa_family == AF_INET) {
+               if (ret == -1 && errno == ENOENT) {
+                       errno = EHOSTUNREACH;
+               }
+       }
+
        return ret;
 }
 
index a3bc6efdb9453399b190415109e994740330060f..2648e40b03d17a5d151e3d5e832e287fdd856a64 100755 (executable)
@@ -82,18 +82,15 @@ rm -rf $PREFIX/*
 mkdir -p $PRIVATEDIR $LIBDIR $PIDDIR $NCALRPCDIR $LOCKDIR $TMPDIR $TLSDIR
 
 cat >$PRIVATEDIR/wins.ldif<<EOF
-dn: name=127.0.0.1,CN=PARTNERS
+dn: name=TORTURE_26,CN=PARTNERS
 objectClass: wreplPartner
-name: 127.0.0.1
-address: 127.0.0.1
-pullRetryInterval: 100
-pullInterval: 200
-type: 0x2
+name: TORTURE_26
+address: 127.0.0.26
+pullInterval: 0
+pushChangeCount: 0
+type: 0x3
 EOF
 
-WREPL_TORTURE_OPTIONS=
-export WREPL_TORTURE_OPTIONS
-
 cat >$CONFFILE<<EOF
 [global]
        netbios name = $SERVER
@@ -106,7 +103,7 @@ cat >$CONFFILE<<EOF
        setup directory = $SRCDIR/setup
        js include = $SRCDIR/scripting/libjs
        name resolve order = bcast
-       interfaces = lo*
+       interfaces = 127.0.0.1/8
        tls enabled = $TLS_ENABLED
        panic action = $SRCDIR/script/gdb_backtrace %PID% %PROG%
        wins support = yes
@@ -163,13 +160,17 @@ if [ x"$RUN_FROM_BUILD_FARM" = x"yes" ];then
        CONFIGURATION="$CONFIGURATION --option=\"torture:progress=no\""
 fi
 
+SOCKET_WRAPPER_DEFAULT_IFACE=1
+export SOCKET_WRAPPER_DEFAULT_IFACE
 smbd_check_or_start
 
 # ensure any one smbtorture call doesn't run too long
-TORTURE_OPTIONS="--maximum-runtime=300 $CONFIGURATION"
+SOCKET_WRAPPER_DEFAULT_IFACE=26
+export SOCKET_WRAPPER_DEFAULT_IFACE
+TORTURE_INTERFACES='127.0.0.26/8,127.0.0.27/8,127.0.0.28/8,127.0.0.29/8,127.0.0.30/8,127.0.0.31/8'
+TORTURE_OPTIONS="--maximum-runtime=300 --option=interfaces=$TORTURE_INTERFACES $CONFIGURATION"
 export TORTURE_OPTIONS
 
-
 START=`date`
 (
  # give time for nbt server to register its names
index 1537617241ea6f3d80cfc25ed3f5015604adc405..4ed510e081bda12262d760fb61d06dbaf3df5a13 100755 (executable)
@@ -18,12 +18,11 @@ SCRIPTDIR=../testprogs/ejs
 PATH=bin:$PATH
 export PATH
 
-for f in NBT-REGISTER NBT-WINS; do
-    testit "$f" bin/smbtorture $TORTURE_OPTIONS //$SERVER/_none_ $f || failed=`expr $failed + 1`
-done
+testit "nmblookup -U $SERVER $SERVER" bin/nmblookup $TORTURE_OPTIONS -U $SERVER $SERVER || failed=`expr $failed + 1`
+testit "nmblookup $SERVER" bin/nmblookup $TORTURE_OPTIONS $SERVER || failed=`expr $failed + 1`
 
-for f in NBT-WINSREPLICATION-QUICK; do
-    testit "$f" bin/smbtorture $TORTURE_OPTIONS $WREPL_TORTURE_OPTIONS //$SERVER/_none_ $f || failed=`expr $failed + 1`
+for f in NBT-REGISTER NBT-WINS NBT-WINSREPLICATION-QUICK; do
+    testit "$f" bin/smbtorture $TORTURE_OPTIONS //$SERVER/_none_ $f || failed=`expr $failed + 1`
 done
 
 testok $0 $failed