as you know, RFC2553 does not specify any ordering constraint on
        bind(2).  this has been source of confusion, as Dave@microsoft
        talked at IETF48 meeting.  BIND9 doc/misc/ipv6 talks about this issue
        in detail.

        implementers, please run the attached program, and send the result to
        me, or to the list, with clear indication of
        - platform (like "NetBSD")
        - version (like "1.5_ALPHA")
        - comments, and some background info/reasoning for your behavior
        sample result is attached.

        i will compile the results got from you guys, and present that to
        the list.  i'm not sure if we can reach consensus about this,
        but i think we should at least document existing behavior,
        to help people like BIND9 implementers.

itojun

NetBSD starfruit.itojun.org 1.5C NetBSD 1.5C (STARFRUIT) #83: Wed Aug  2 21:02:32 JST 
2000     
[EMAIL PROTECTED]:/usr/home/itojun/NetBSD/src/sys/arch/i386/compile/STARFRUIT
 i386

- IPv4 mapped address on AF_INET6 is, in most cases, prohibited.
  this is to avoid possible security issues with it.
- there is no ordering constraint between AF_INET wildcard bind(2) and AF_INET6
  wildcard bind(2).
  this is because we consider AF_INET wildcard as "more specific address"
  than AF_INET6 wildcard, and we usually permit "more specific address" bind(2).

---
starting tests, socktype = SOCK_DGRAM
wild4 then wild4
        bind socket for 0.0.0.0/9999
        bind socket for 0.0.0.0/9999
        failed bind for 0.0.0.0/9999, Address already in use
wild4 then wild6
        bind socket for 0.0.0.0/9999
        bind socket for ::/9999
wild4 then loop4
        bind socket for 0.0.0.0/9999
        bind socket for 127.0.0.1/9999
        failed bind for 127.0.0.1/9999, Address already in use
wild4 then loop6
        bind socket for 0.0.0.0/9999
        bind socket for ::1/9999
wild4 then one4
        bind socket for 0.0.0.0/9999
        bind socket for 0.0.0.1/9999
        failed bind for 0.0.0.1/9999, Can't assign requested address
wild4 then map4
        bind socket for 0.0.0.0/9999
        bind socket for ::ffff:127.0.0.1/9999
        failed bind for ::ffff:127.0.0.1/9999, Can't assign requested address
wild6 then wild4
        bind socket for ::/9999
        bind socket for 0.0.0.0/9999
wild6 then wild6
        bind socket for ::/9999
        bind socket for ::/9999
        failed bind for ::/9999, Address already in use
wild6 then loop4
        bind socket for ::/9999
        bind socket for 127.0.0.1/9999
wild6 then loop6
        bind socket for ::/9999
        bind socket for ::1/9999
        failed bind for ::1/9999, Address already in use
wild6 then one4
        bind socket for ::/9999
        bind socket for 0.0.0.1/9999
        failed bind for 0.0.0.1/9999, Can't assign requested address
wild6 then map4
        bind socket for ::/9999
        bind socket for ::ffff:127.0.0.1/9999
        failed bind for ::ffff:127.0.0.1/9999, Can't assign requested address
loop4 then wild4
        bind socket for 127.0.0.1/9999
        bind socket for 0.0.0.0/9999
        failed bind for 0.0.0.0/9999, Address already in use
loop4 then wild6
        bind socket for 127.0.0.1/9999
        bind socket for ::/9999
loop4 then loop4
        bind socket for 127.0.0.1/9999
        bind socket for 127.0.0.1/9999
        failed bind for 127.0.0.1/9999, Address already in use
loop4 then loop6
        bind socket for 127.0.0.1/9999
        bind socket for ::1/9999
loop4 then one4
        bind socket for 127.0.0.1/9999
        bind socket for 0.0.0.1/9999
        failed bind for 0.0.0.1/9999, Can't assign requested address
loop4 then map4
        bind socket for 127.0.0.1/9999
        bind socket for ::ffff:127.0.0.1/9999
        failed bind for ::ffff:127.0.0.1/9999, Can't assign requested address
loop6 then wild4
        bind socket for ::1/9999
        bind socket for 0.0.0.0/9999
loop6 then wild6
        bind socket for ::1/9999
        bind socket for ::/9999
        failed bind for ::/9999, Address already in use
loop6 then loop4
        bind socket for ::1/9999
        bind socket for 127.0.0.1/9999
loop6 then loop6
        bind socket for ::1/9999
        bind socket for ::1/9999
        failed bind for ::1/9999, Address already in use
loop6 then one4
        bind socket for ::1/9999
        bind socket for 0.0.0.1/9999
        failed bind for 0.0.0.1/9999, Can't assign requested address
loop6 then map4
        bind socket for ::1/9999
        bind socket for ::ffff:127.0.0.1/9999
        failed bind for ::ffff:127.0.0.1/9999, Can't assign requested address
one4 then wild4
        bind socket for 0.0.0.1/9999
        failed bind for 0.0.0.1/9999, Can't assign requested address
one4 then wild6
        bind socket for 0.0.0.1/9999
        failed bind for 0.0.0.1/9999, Can't assign requested address
one4 then loop4
        bind socket for 0.0.0.1/9999
        failed bind for 0.0.0.1/9999, Can't assign requested address
one4 then loop6
        bind socket for 0.0.0.1/9999
        failed bind for 0.0.0.1/9999, Can't assign requested address
one4 then one4
        bind socket for 0.0.0.1/9999
        failed bind for 0.0.0.1/9999, Can't assign requested address
one4 then map4
        bind socket for 0.0.0.1/9999
        failed bind for 0.0.0.1/9999, Can't assign requested address
map4 then wild4
        bind socket for ::ffff:127.0.0.1/9999
        failed bind for ::ffff:127.0.0.1/9999, Can't assign requested address
map4 then wild6
        bind socket for ::ffff:127.0.0.1/9999
        failed bind for ::ffff:127.0.0.1/9999, Can't assign requested address
map4 then loop4
        bind socket for ::ffff:127.0.0.1/9999
        failed bind for ::ffff:127.0.0.1/9999, Can't assign requested address
map4 then loop6
        bind socket for ::ffff:127.0.0.1/9999
        failed bind for ::ffff:127.0.0.1/9999, Can't assign requested address
map4 then one4
        bind socket for ::ffff:127.0.0.1/9999
        failed bind for ::ffff:127.0.0.1/9999, Can't assign requested address
map4 then map4
        bind socket for ::ffff:127.0.0.1/9999
        failed bind for ::ffff:127.0.0.1/9999, Can't assign requested address
/*
 * Copyright (C) 1999 WIDE Project.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without loop prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
/*
 * $Id: bindtest.c,v 1.8 1999/10/06 08:10:05 itojun Exp $
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <errno.h>
#include <err.h>

#include <netinet/in.h>

int main __P((int, char **));
static void usage __P((void));
static struct addrinfo *getres __P((int, const char *, const char *));
static const char *printres __P((struct addrinfo *));
static int test __P((const char *, struct addrinfo *, struct addrinfo *));

static struct addrinfo *wild4, *wild6;
static struct addrinfo *loop4, *loop6;
static struct addrinfo *one4, *map4;
static char *port = NULL;
static int socktype = SOCK_DGRAM;

int
main(argc, argv)
        int argc;
        char **argv;
{
        int ch;
        extern int optind;
        extern char *optarg;

        while ((ch = getopt(argc, argv, "p:t")) != EOF) {
                switch (ch) {
                case 'p':
                        port = strdup(optarg);
                        break;
                case 't':
                        socktype = SOCK_STREAM;
                        break;
                default:
                        usage();
                        exit(1);
                }
        }

#if 0
        if (port == NULL)
                port = allocport();
#endif

        if (port == NULL) {
                errx(1, "no port specified");
                /*NOTREACHED*/
        }

        wild4 = getres(AF_INET, NULL, port);
        wild6 = getres(AF_INET6, NULL, port);
        loop4 = getres(AF_INET, "127.0.0.1", port);
        loop6 = getres(AF_INET6, "::1", port);
        one4 = getres(AF_INET, "0.0.0.1", port);
        map4 = getres(AF_INET6, "::ffff:127.0.0.1", port);

        printf("starting tests, socktype = %s\n",
                socktype == SOCK_DGRAM ? "SOCK_DGRAM" : "SOCK_STREAM");
#define TESTIT(x, y)    test(#x " then " #y, (x), (y))
#define TESTALL(x) \
do { \
        TESTIT(x, wild4); \
        TESTIT(x, wild6); \
        TESTIT(x, loop4); \
        TESTIT(x, loop6); \
        TESTIT(x, one4); \
        TESTIT(x, map4); \
} while (0)

        TESTALL(wild4);
        TESTALL(wild6);
        TESTALL(loop4);
        TESTALL(loop6);
        TESTALL(one4);
        TESTALL(map4);

        exit(0);
}

static void
usage()
{
        fprintf(stderr, "usage: bindtest [-t] -p port\n");
}

static struct addrinfo *
getres(af, host, port)
        int af;
        const char *host;
        const char *port;
{
        struct addrinfo hints, *res;
        int error;

        memset(&hints, 0, sizeof(hints));
        hints.ai_family = af;
        hints.ai_socktype = socktype;
        hints.ai_flags = AI_PASSIVE;
        error = getaddrinfo(host, port, &hints, &res);
        return res;
}

static const char *
printres(res)
        struct addrinfo *res;
{
        char hbuf[MAXHOSTNAMELEN], pbuf[10];
        static char buf[sizeof(hbuf) + sizeof(pbuf)];

        getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
                pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV);
        snprintf(buf, sizeof(buf), "%s/%s", hbuf, pbuf);
        return buf;
}

static int
test(title, a, b)
        const char *title;
        struct addrinfo *a;
        struct addrinfo *b;
{
        int sa = -1, sb = -1;

        printf("%s\n", title);

#if 0
        printf("\tallocating socket for %s\n", printres(a));
#endif
        sa = socket(a->ai_family, a->ai_socktype, a->ai_protocol);
        if (sa < 0) {
                printf("\tfailed socket for %s, %s\n",
                        printres(a), strerror(errno));
                goto fail;
        }
#if 0
        printf("\tallocating socket for %s\n", printres(b));
#endif
        sb = socket(b->ai_family, b->ai_socktype, b->ai_protocol);
        if (sb < 0) {
                printf("\tfailed socket for %s, %s\n",
                        printres(b), strerror(errno));
                goto fail;
        }

        printf("\tbind socket for %s\n", printres(a));
        if (bind(sa, a->ai_addr, a->ai_addrlen) < 0) {
                printf("\tfailed bind for %s, %s\n",
                        printres(a), strerror(errno));
                goto fail;
        }

        printf("\tbind socket for %s\n", printres(b));
        if (bind(sb, b->ai_addr, b->ai_addrlen) < 0) {
                printf("\tfailed bind for %s, %s\n",
                        printres(b), strerror(errno));
                goto fail;
        }

        if (sa >= 0)
                close(sa);
        if (sb >= 0)
                close(sb);
        return 0;

fail:
        if (sa >= 0)
                close(sa);
        if (sb >= 0)
                close(sb);
        return -1;
}
.\" Copyright (C) 1999 WIDE Project.
.\" All rights reserved.
.\" 
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\"    notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\"    notice, this list of conditions and the following disclaimer in the
.\"    documentation and/or other materials provided with the distribution.
.\" 3. Neither the name of the project nor the names of its contributors
.\"    may be used to endorse or promote products derived from this software
.\"    without specific prior written permission.
.\" 
.\" THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\"     $Id: bindtest.1,v 1.4 2000/01/19 06:24:51 itojun Exp $
.\"
.Dd October 6, 1999
.Dt BINDTEST 1
.Os KAME
.\"
.Sh NAME
.Nm bindtest
.Nd test bind(2) behavior on IPv6 implementation
.\"
.Sh SYNOPSIS
.Nm
.Op Fl t
.Fl p Ar port
.\"
.Sh DESCRIPTION
.Nm
tests interaction between IPv4/IPv6 socket interface, implemented into
the kernel it has underneath.
.Pp
RFC2553 defines socket API for IPv6, and relationship between
IPv6 wildcard
.Xr bind 2
socket
.Pq Li ::.port
and IPv4 wildcard
.Xr bind 2
socket
.Pq Li 0.0.0.0.port .
However, the document does not define ordering constraints between them,
relationship with specific
.Xr bind 2 ,
nor relationship with speficfic
.Xr bind 2
using IPv4 mapped IPv6 address
.Pq Li ::ffff:127.0.0.1 .
.Pp
.Nm
tries to reveal the behavior implemented in the kernel,
and shows some report to standard output.
As RFC2553 does not define the expected behavior,
we have no idea what the result should be.
.Pp
By default
.Nm
will use
.Dv SOCK_DGRAM
socket for testing.
With
.Fl t ,
.Nm
will use
.Dv SOCK_STREAM
socket instead.
TCP/UDP port number must be specified with
.Fl p Ar port .
The
.Ar port
needs to be vacant.
.\"
.Sh RETURN VALUES
.Nm
exits with 0 on success, and non-zero on errors.
.\"
.Sh SEE ALSO
.Rs
.%A R. Gilligan
.%A S. Thomson
.%A J. Bound
.%A W. Stevens
.%T Basic Socket Interface Extensions for IPv6
.%D March 1999
.%N RFC2553
.Re
.Pp
.Xr bind 2 ,
.Xr tcpdump 8
.\"
.Sh HISTORY
The
.Nm
command first appeared in WIDE/KAME IPv6 protocol stack kit.

Reply via email to