From owner-freebsd-questions@FreeBSD.ORG Fri Jul 13 09:46:07 2012 Return-Path: Delivered-To: freebsd-questions@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id E26381065670 for ; Fri, 13 Jul 2012 09:46:07 +0000 (UTC) (envelope-from guru@unixarea.de) Received: from ms16-1.1blu.de (ms16-1.1blu.de [89.202.0.34]) by mx1.freebsd.org (Postfix) with ESMTP id 73FF98FC0C for ; Fri, 13 Jul 2012 09:46:07 +0000 (UTC) Received: from [89.204.130.223] (helo=tiny.Sisis.de) by ms16-1.1blu.de with esmtpsa (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1SpcRq-0007sC-0q for freebsd-questions@freebsd.org; Fri, 13 Jul 2012 11:46:06 +0200 Received: from tiny.Sisis.de (localhost [127.0.0.1]) by tiny.Sisis.de (8.14.5/8.14.3) with ESMTP id q6D9k6UN001306 for ; Fri, 13 Jul 2012 11:46:07 +0200 (CEST) (envelope-from guru@unixarea.de) Received: (from guru@localhost) by tiny.Sisis.de (8.14.5/8.14.3/Submit) id q6D9k6LF001305 for freebsd-questions@freebsd.org; Fri, 13 Jul 2012 11:46:06 +0200 (CEST) (envelope-from guru@unixarea.de) X-Authentication-Warning: tiny.Sisis.de: guru set sender to guru@unixarea.de using -f Date: Fri, 13 Jul 2012 11:46:05 +0200 From: Matthias Apitz To: freebsd-questions@freebsd.org Message-ID: <20120713094604.GA1282@tiny.Sisis.de> References: <80BE761E-42B1-4111-ACEC-0C31E43D105D@lafn.org> <201207130201.q6D21oTp045911@mail.r-bonomi.com> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <201207130201.q6D21oTp045911@mail.r-bonomi.com> X-Operating-System: FreeBSD 10.0-CURRENT r226986 (i386) User-Agent: Mutt/1.5.21 (2010-09-15) X-Con-Id: 51246 X-Con-U: 0-guru X-Originating-IP: 89.204.130.223 Subject: Re: IPv6 && getaddrinfo(3C) X-BeenThere: freebsd-questions@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Matthias Apitz List-Id: User questions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 13 Jul 2012 09:46:08 -0000 El día Thursday, July 12, 2012 a las 09:01:50PM -0500, Robert Bonomi escribió: > > > req.ai_flags = AI_ADDRCONFIG|AI_NUMERICHOST; > > > req.ai_family = AF_INET6; /* Same as AF_INET6. */ > > Isn't the setting of 'req.ai_family', above, going to guarantee that > something that "looks like" an IPv4 address will not be considered valid? > > After all, what *POSSIBLE* _IPv6_info_ is there about an IPv4 address? > > Per the manpage example, try PF_UNSPEC. With PF_UNSPEC it works fine now, thanks for the hint; I'm attaching the code for the client and as well one for a server creating LISTEN on IPv6 and IPv4 at the same time and handling the connections on both ports; HIH matthias /* IPv6 client code using getaddrinfo */ #include #include #include #include #include #include #include main(int argc, char **argv) { struct addrinfo req, *ans; int code, s, n; char buf[1024]; memset(&req, 0, sizeof(req)); req.ai_flags = 0; /* may be restricted to AI_ADDRCONFIG|AI_NUMERICHOST|... */ /* req.ai_family = AF_INET6; /* validates only AF_INET6 */ /* req.ai_family = AF_INET; /* validates only AF_INET, i.e. IPv4 */ req.ai_family = PF_UNSPEC; /* validates IPv4 and IPv6. */ req.ai_socktype = SOCK_STREAM; /* Use protocol TCP */ req.ai_protocol = IPPROTO_TCP; /* 0: any, IPPROTO_UDP: UDP */ printf("host: %s\n", argv[1]); if ((code = getaddrinfo(argv[1], "ssh", &req, &ans)) != 0) { fprintf(stderr, "ssh: getaddrinfo failed code %d: %s\n", code, gai_strerror(code)); exit(1); } /* 'ans' must contain at least one addrinfo, use the first */ s = socket(ans->ai_family, ans->ai_socktype, ans->ai_protocol); if (s < 0) { perror("ssh: socket"); exit(3); } /* Connect does the bind for us */ if (connect(s, ans->ai_addr, ans->ai_addrlen) < 0) { perror("ssh: connect"); exit(5); } /* just for test: read in SSH' good morning message */ n = read(s, buf, 1024); printf ("read: %s", buf); /* Free answers after use */ freeaddrinfo(ans); exit(0); } /* IPv6 server code using getaddrinfo */ #include #include #include #include #include #include #include #include #include #include #include void doit() { printf("child forked end ended\n"); } main(int argc, char **argv) { struct sockaddr_in6 from; struct addrinfo req, *ans, *ans2; int code, sockFd1, sockFd2, len; /* Set ai_flags to AI_PASSIVE to indicate that return addres s is suitable for bind() */ memset(&req, 0, sizeof(req)); req.ai_flags = AI_PASSIVE; req.ai_family = PF_UNSPEC; /* IPv6+IPv4: PF_UNSPEC, IPv4: PF_INET */ req.ai_socktype = SOCK_STREAM; req.ai_protocol = IPPROTO_TCP; #define SLNP "3025" if ((code = getaddrinfo(NULL, SLNP, &req, &ans)) != 0) { fprintf(stderr, "SLNP (%s): getaddrinfo failed code %d: %s\n", SLNP, code, gai_strerror(code)); exit(1); } /* 'ans' must contain at least one addrinfo and we use the first. */ /* it seems(!) that 1st one is the IPv6 when we use PF_UNSPEC */ if( (sockFd1 = socket(ans->ai_family, ans->ai_socktype, ans->ai_protocol)) < 0) { perror("socket"); exit(-1); } if (bind(sockFd1, ans->ai_addr, ans->ai_addrlen) < 0) { perror("bind"); close(sockFd1); exit(-1); } /* create the 1st LISTEN */ printf("1st (IPv6) LISTEN...\n"); listen(sockFd1, 5); /* if there is a 2nd addrinfo provided by getaddrinfo(3C) and we will create 2nd socket... */ ans2 = NULL; if( ans->ai_next != NULL ) ans2 = ans->ai_next; sockFd2 = -1; /* set to -1 to be used as this in poll, see below */ if( ans2 != NULL ) { if( (sockFd2 = socket(ans2->ai_family, ans2->ai_socktype, ans2->ai_protocol)) < 0) { perror("socket"); exit(-1); } if (bind(sockFd2, ans2->ai_addr, ans2->ai_addrlen) < 0) { perror("bind"); close(sockFd2); exit(-1); } printf("2nd (IPv4) LISTEN...\n"); listen(sockFd2, 5); } for (;;) { int newsockFd, len = sizeof(from), readyFd, polled; struct pollfd fds[2]; /* we poll both fds for events and accept the one which is ready */ fds[0].fd = sockFd1; fds[0].events = POLLIN | POLLPRI; fds[0].revents = 0; fds[1].fd = sockFd2; /* will not be poll'ed if -1 */ fds[1].events = POLLIN | POLLPRI; fds[1].revents = 0; polled = poll(fds, 2, INFTIM); printf("poll fds ready: (IPv6) %d (IPv4) %d\n", fds[0].revents, fds[1].revents); /* this is rather dirty, because both fds could be ready and this would always prefer the 2nd fd */ if( fds[0].revents ) readyFd = fds[0].fd; if( fds[1].revents ) readyFd = fds[1].fd; newsockFd = accept(readyFd, (struct sockaddr *)&from, &len); if (newsockFd < 0) { perror("accept"); exit(-1); } if (fork() == 0) { close(readyFd); (void) doit(newsockFd, &from); exit(0); } close(newsockFd); } /* Free answers after use */ freeaddrinfo(ans); exit(0); } -- Matthias Apitz e - w http://www.unixarea.de/ UNIX since V7 on PDP-11, UNIX on mainframe since ESER 1055 (IBM /370) UNIX on x86 since SVR4.2 UnixWare 2.1.2, FreeBSD since 2.2.5