From owner-svn-ports-all@freebsd.org Tue May 24 16:59:55 2016 Return-Path: Delivered-To: svn-ports-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id EDD65B48842; Tue, 24 May 2016 16:59:55 +0000 (UTC) (envelope-from swills@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id B7A831755; Tue, 24 May 2016 16:59:55 +0000 (UTC) (envelope-from swills@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u4OGxtTT057191; Tue, 24 May 2016 16:59:55 GMT (envelope-from swills@FreeBSD.org) Received: (from swills@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u4OGxsC4057181; Tue, 24 May 2016 16:59:54 GMT (envelope-from swills@FreeBSD.org) Message-Id: <201605241659.u4OGxsC4057181@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: swills set sender to swills@FreeBSD.org using -f From: Steve Wills Date: Tue, 24 May 2016 16:59:54 +0000 (UTC) To: ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org Subject: svn commit: r415801 - in head/net: . sock sock/files X-SVN-Group: ports-head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-ports-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: SVN commit messages for the ports tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 24 May 2016 16:59:56 -0000 Author: swills Date: Tue May 24 16:59:54 2016 New Revision: 415801 URL: https://svnweb.freebsd.org/changeset/ports/415801 Log: net/sock: create port This is a standalone version of W. Richard Stevens' "sock" program, based on the code available for the UNIX Network Programming book. Adapted and reworked code for W. Richard Stevens' "sock" utility by Christian Kreibich. From the author: In TCP/IP Illustrated Vol. 1, Richard Stevens used a program called "sock" to demonstrate the many properties of TCP/IP. Unfortunately, the book only speaks about how to use the program but does not point to a site for downloading its sources. While sock is contained in the code package accompanying UNIX Network Programming, this code is also getting dated. The program can be used to generate TCP or UDP packets for testing various network features. It runs as either client or server. WWW: http://www.icir.org/christian/sock.html PR: 206345 Submitted by: Steve Jacobson (with slight modification) Added: head/net/sock/ head/net/sock/Makefile (contents, props changed) head/net/sock/distinfo (contents, props changed) head/net/sock/files/ head/net/sock/files/patch-src__cliopen.c (contents, props changed) head/net/sock/files/patch-src__loopudp.c (contents, props changed) head/net/sock/files/patch-src__main.c (contents, props changed) head/net/sock/files/patch-src__multicast.c (contents, props changed) head/net/sock/files/patch-src__servopen.c (contents, props changed) head/net/sock/files/patch-src__sock.h (contents, props changed) head/net/sock/files/patch-src__sockopts.c (contents, props changed) head/net/sock/files/patch-src__sourceroute.c (contents, props changed) head/net/sock/files/patch-src__sourceudp.c (contents, props changed) head/net/sock/pkg-descr (contents, props changed) Modified: head/net/Makefile Modified: head/net/Makefile ============================================================================== --- head/net/Makefile Tue May 24 16:15:40 2016 (r415800) +++ head/net/Makefile Tue May 24 16:59:54 2016 (r415801) @@ -1226,6 +1226,7 @@ SUBDIR += sntop SUBDIR += sobby SUBDIR += socat + SUBDIR += sock SUBDIR += socketbind SUBDIR += socketpipe SUBDIR += socketw Added: head/net/sock/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/net/sock/Makefile Tue May 24 16:59:54 2016 (r415801) @@ -0,0 +1,16 @@ +# Created by: Steve Jacobson +# $FreeBSD$ + +PORTNAME= sock +PORTVERSION= 0.3.2 +CATEGORIES= net +MASTER_SITES= http://www.icir.org/christian/downloads/ + +MAINTAINER= sjac@cs.stanford.edu +COMMENT= W. Richard Stevens' sock program + +HAS_CONFIGURE= yes + +PLIST_FILES= bin/sock + +.include Added: head/net/sock/distinfo ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/net/sock/distinfo Tue May 24 16:59:54 2016 (r415801) @@ -0,0 +1,2 @@ +SHA256 (sock-0.3.2.tar.gz) = 4ddc33767900e7cd0a4cc0f4d808638d7cfcb746c23e12274c8eba0622eee2eb +SIZE (sock-0.3.2.tar.gz) = 113640 Added: head/net/sock/files/patch-src__cliopen.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/net/sock/files/patch-src__cliopen.c Tue May 24 16:59:54 2016 (r415801) @@ -0,0 +1,264 @@ +--- src/cliopen.c.orig 2010-05-28 00:03:25 UTC ++++ src/cliopen.c +@@ -10,42 +10,107 @@ + + #include "sock.h" + ++/* ++ * Try to convert the host name as an IPv4 dotted-decimal number ++ * or an IPv6 address. ++ */ ++int convert_host_address(char *host) ++{ ++ struct in_addr inaddr; ++ char inaddr_buf[INET6_ADDRSTRLEN]; ++ ++ if (AF_INET == af_46) { ++ if (inet_pton(AF_INET, host, &inaddr) == 1) { ++ /* IPv4 dotted-decimal */ ++ servaddr4.sin_addr = inaddr; ++ ++ return (1); ++ } ++ } else { ++ if (inet_pton(AF_INET6, host, inaddr_buf) == 1) { ++ /* IPv6 address */ ++ memcpy(&servaddr6.sin6_addr, inaddr_buf, ++ sizeof(struct in6_addr)); ++ ++ return (1); ++ } ++ } ++ ++ return (0); ++} ++ ++/* ++ * Try to convert the host name as a host name string. ++ */ ++int convert_host_name(char *host) ++{ ++ struct hostent *hp; ++ ++ if (AF_INET == af_46) { ++ if ( (hp = gethostbyname2(host, AF_INET)) != NULL) { ++ /* IPv4 address */ ++ memcpy(&servaddr4.sin_addr, hp->h_addr, hp->h_length); ++ ++ return (1); ++ } ++ } else { ++ /* ++ * Fixme: This doesn't work on FreeBSD 8.4. ++ * Only an IPv4 address is returned. ++ * getaddrinfo() doesn't work either. ++ */ ++ if ( (hp = gethostbyname2(host, AF_INET6)) != NULL) { ++ /* IPv6 address */ ++ memcpy(&servaddr6.sin6_addr, hp->h_addr, hp->h_length); ++ ++ return (1); ++ } ++ } ++ ++ return (0); ++} ++ + int cliopen(char *host, char *port) + { + int fd, i, on; + char *protocol; +- struct in_addr inaddr; ++ char inaddr_buf[INET6_ADDRSTRLEN]; + struct servent *sp; +- struct hostent *hp; ++ socklen_t socklen; + + protocol = udp ? "udp" : "tcp"; + + /* initialize socket address structure */ +- bzero(&servaddr, sizeof(servaddr)); +- servaddr.sin_family = AF_INET; ++ bzero(&servaddr4, sizeof(servaddr4)); ++ servaddr4.sin_family = AF_INET; ++ ++ bzero(&servaddr6, sizeof(servaddr6)); ++ servaddr6.sin6_family = AF_INET6; + + /* see if "port" is a service name or number */ + if ( (i = atoi(port)) == 0) { + if ( (sp = getservbyname(port, protocol)) == NULL) +- err_quit("getservbyname() error for: %s/%s", port, protocol); +- +- servaddr.sin_port = sp->s_port; +- } else +- servaddr.sin_port = htons(i); ++ err_quit("getservbyname() error for: %s/%s", ++ port, protocol); ++ servaddr4.sin_port = sp->s_port; ++ servaddr6.sin6_port = sp->s_port; ++ } else { ++ servaddr4.sin_port = htons(i); ++ servaddr6.sin6_port = htons(i); ++ } + + /* +- * First try to convert the host name as a dotted-decimal number. +- * Only if that fails do we call gethostbyname(). ++ * First try to convert the host name as an IPv4 dotted-decimal number ++ * or an IPv6 address. Only if that fails do we try to convert the ++ * host name as a host name string. + */ +- +- if (inet_aton(host, &inaddr) == 1) +- servaddr.sin_addr = inaddr; /* it's dotted-decimal */ +- else if ( (hp = gethostbyname(host)) != NULL) +- bcopy(hp->h_addr, &servaddr.sin_addr, hp->h_length); +- else +- err_quit("invalid hostname: %s", host); ++ if (convert_host_address(host) != 1) { ++ if (convert_host_name(host) != 1) { ++ err_quit("invalid hostname: %s", host); ++ } ++ } + +- if ( (fd = socket(AF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0) ++ if ( (fd = socket(af_46, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0) + err_sys("socket() error"); + + if (reuseaddr) { +@@ -71,21 +136,46 @@ int cliopen(char *host, char *port) + * (and port) using -l option. Allow localip[] to be set but bindport + * to be 0. + */ +- + if (bindport != 0 || localip[0] != 0 || udp) { +- bzero(&cliaddr, sizeof(cliaddr)); +- cliaddr.sin_family = AF_INET; +- cliaddr.sin_port = htons(bindport); /* can be 0 */ +- if (localip[0] != 0) { +- if (inet_aton(localip, &cliaddr.sin_addr) == 0) +- err_quit("invalid IP address: %s", localip); +- } else +- cliaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */ +- +- if (bind(fd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) < 0) +- err_sys("bind() error"); ++ if (af_46 == AF_INET) { ++ bzero(&cliaddr4, sizeof(cliaddr4)); ++ cliaddr4.sin_family = AF_INET; ++ /* can be 0 */ ++ cliaddr4.sin_port = htons(bindport); ++ if (localip[0] != 0) { ++ if (inet_aton(localip, &cliaddr4.sin_addr) == 0) ++ err_quit("invalid IP address: %s", ++ localip); ++ } else { ++ /* wildcard */ ++ cliaddr4.sin_addr.s_addr = htonl(INADDR_ANY); ++ } ++ if (bind(fd, (struct sockaddr *) &cliaddr4, ++ sizeof(cliaddr4)) < 0) { ++ err_sys("bind() error"); ++ } ++ } else { ++ bzero(&cliaddr6, sizeof(cliaddr6)); ++ cliaddr6.sin6_len = sizeof(struct sockaddr_in6); ++ cliaddr6.sin6_family = AF_INET6; ++ /* can be 0 */ ++ cliaddr6.sin6_port = htons(bindport); ++ ++ /* Fixme: localip not implemented for IPv6 */ ++ cliaddr6.sin6_addr = in6addr_any; ++ ++ /* Fixme: Want to set IPV6_BINDANY? */ ++ ++ if (bind(fd, (struct sockaddr *) &cliaddr6, ++ sizeof(cliaddr6)) < 0) { ++ err_sys("bind() error"); ++ } ++ } + } +- ++ ++ /* Fixme: Does not work */ ++ //join_mcast_client(fd, &cliaddr4, &cliaddr6, &servaddr4, &servaddr6); ++ + /* Need to allocate buffers before connect(), since they can affect + * TCP options (window scale, etc.). + */ +@@ -96,13 +186,21 @@ int cliopen(char *host, char *port) + /* + * Connect to the server. Required for TCP, optional for UDP. + */ +- + if (udp == 0 || connectudp) { + for ( ; ; ) { +- if (connect(fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) +- == 0) ++ if (AF_INET == af_46) { ++ if (connect(fd, (struct sockaddr *) &servaddr4, ++ sizeof(servaddr4)) == 0) + break; /* all OK */ +- if (errno == EINTR) /* can happen with SIGIO */ ++ } else { ++ servaddr6.sin6_len = ++ sizeof(struct sockaddr_in6); ++ servaddr6.sin6_family = AF_INET6; ++ if (connect(fd, (struct sockaddr *) &servaddr6, ++ sizeof(servaddr6)) == 0) ++ break; /* all OK */ ++ } ++ if (errno == EINTR) /* can happen with SIGIO */ + continue; + if (errno == EISCONN) /* can happen with SIGIO */ + break; +@@ -114,16 +212,38 @@ int cliopen(char *host, char *port) + /* Call getsockname() to find local address bound to socket: + TCP ephemeral port was assigned by connect() or bind(); + UDP ephemeral port was assigned by bind(). */ +- i = sizeof(cliaddr); +- if (getsockname(fd, (struct sockaddr *) &cliaddr, &i) < 0) +- err_sys("getsockname() error"); +- +- /* Can't do one fprintf() since inet_ntoa() stores +- the result in a static location. */ +- fprintf(stderr, "connected on %s.%d ", +- INET_NTOA(cliaddr.sin_addr), ntohs(cliaddr.sin_port)); +- fprintf(stderr, "to %s.%d\n", +- INET_NTOA(servaddr.sin_addr), ntohs(servaddr.sin_port)); ++ if (AF_INET == af_46) { ++ socklen = sizeof(cliaddr4); ++ if (getsockname(fd, ++ (struct sockaddr *) &cliaddr4, &socklen) < 0) { ++ err_sys("getsockname() error"); ++ } ++ /* Can't do one fprintf() since inet_ntoa() stores ++ the result in a static location. */ ++ fprintf(stderr, "connected on %s.%d ", ++ INET_NTOA(cliaddr4.sin_addr), ++ ntohs(cliaddr4.sin_port)); ++ fprintf(stderr, "to %s.%d\n", ++ INET_NTOA(servaddr4.sin_addr), ++ ntohs(servaddr4.sin_port)); ++ } else { ++ socklen = sizeof(cliaddr6); ++ if (getsockname(fd, ++ (struct sockaddr *) &cliaddr6, &socklen) < 0) { ++ err_sys("getsockname() error"); ++ } ++ ++ inet_ntop(AF_INET6, ++ &cliaddr6.sin6_addr.__u6_addr.__u6_addr8, ++ inaddr_buf, sizeof(inaddr_buf)); ++ fprintf(stderr, "connected on %s.%d ", ++ inaddr_buf, ntohs(cliaddr6.sin6_port)); ++ inet_ntop(AF_INET6, ++ &servaddr6.sin6_addr.__u6_addr.__u6_addr8, ++ inaddr_buf, sizeof(inaddr_buf)); ++ fprintf(stderr, "to %s.%d\n", ++ inaddr_buf, ntohs(servaddr6.sin6_port)); ++ } + } + + sockopts(fd, 1); /* some options get set after connect() */ Added: head/net/sock/files/patch-src__loopudp.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/net/sock/files/patch-src__loopudp.c Tue May 24 16:59:54 2016 (r415801) @@ -0,0 +1,261 @@ +--- src/loopudp.c.orig 2010-05-28 00:03:25 UTC ++++ src/loopudp.c +@@ -21,17 +21,28 @@ + void + loop_udp(int sockfd) + { +- int maxfdp1, nread, ntowrite, stdineof, clilen, servlen, flags; ++ int maxfdp1, nread, ntowrite, stdineof, clilen, flags; ++ socklen_t servlen; + fd_set rset; +- struct sockaddr_in cliaddr; /* for UDP server */ +- struct sockaddr_in servaddr; /* for UDP client */ ++ struct sockaddr_in cliaddr4; /* for IPv4 UDP server */ ++ struct sockaddr_in6 cliaddr6; /* for IPv6 UDP server */ ++ /* ++ * The original local variable servaddr, and later servaddr4 and ++ * servaddr6, were not initialized before use. Using the initialized ++ * global sockaddr structs allows the sendto() code, below, to work ++ * correctly. This was a problem with the original IPv4 code, and ++ * later the IPv6 code. ++ */ ++ //struct sockaddr_in servaddr4; /* for IPv4 UDP client */ ++ //struct sockaddr_in6 servaddr6; /* for IPv6 UDP client */ ++ char inaddr_buf[INET6_ADDRSTRLEN]; + +- struct iovec iov[1]; +- struct msghdr msg; ++ struct iovec iov[1]; ++ struct msghdr msg; + #ifdef HAVE_MSGHDR_MSG_CONTROL + #ifdef IP_RECVDSTADDR /* 4.3BSD Reno and later */ + static struct cmsghdr *cmptr = NULL; /* malloc'ed */ +- struct in_addr dstinaddr; /* for UDP server */ ++ struct in_addr dstinaddr; /* for UDP server */ + #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(struct in_addr)) + #endif /* IP_RECVDSTADDR */ + +@@ -68,8 +79,10 @@ loop_udp(int sockfd) + err_sys("shutdown() error"); + + FD_CLR(STDIN_FILENO, &rset); +- stdineof = 1; /* don't read stdin anymore */ +- continue; /* back to select() */ ++ /* don't read stdin anymore */ ++ stdineof = 1; ++ /* back to select() */ ++ continue; + } + break; /* default: stdin EOF -> done */ + } +@@ -77,23 +90,43 @@ loop_udp(int sockfd) + if (crlf) { + ntowrite = crlf_add(wbuf, writelen, rbuf, nread); + if (connectudp) { +- if (write(sockfd, wbuf, ntowrite) != ntowrite) ++ if (write(sockfd, wbuf, ntowrite) != ++ ntowrite) { + err_sys("write error"); ++ } + } else { +- if (sendto(sockfd, wbuf, ntowrite, 0, +- (struct sockaddr *) &servaddr, sizeof(servaddr)) +- != ntowrite) +- err_sys("sendto error"); ++ if (af_46 == AF_INET) { ++ if (sendto(sockfd, wbuf, ntowrite, 0, ++ (struct sockaddr *)&servaddr4, ++ sizeof(servaddr4)) != ntowrite) { ++ err_sys("sendto error"); ++ } ++ } else { ++ if (sendto(sockfd, wbuf, ntowrite, 0, ++ (struct sockaddr *)&servaddr6, ++ sizeof(servaddr6)) != ntowrite) { ++ err_sys("sendto error"); ++ } ++ } + } + } else { + if (connectudp) { + if (write(sockfd, rbuf, nread) != nread) + err_sys("write error"); + } else { +- if (sendto(sockfd, rbuf, nread, 0, +- (struct sockaddr *) &servaddr, sizeof(servaddr)) +- != nread) +- err_sys("sendto error"); ++ if (af_46 == AF_INET) { ++ if (sendto(sockfd, rbuf, nread, 0, ++ (struct sockaddr *)&servaddr4, ++ sizeof(servaddr4)) != nread) { ++ err_sys("sendto error"); ++ } ++ } else { ++ if (sendto(sockfd, rbuf, nread, 0, ++ (struct sockaddr *)&servaddr6, ++ sizeof(servaddr6)) != nread) { ++ err_sys("sendto error"); ++ } ++ } + } + } + } +@@ -101,35 +134,54 @@ loop_udp(int sockfd) + if (FD_ISSET(sockfd, &rset)) { + /* data to read from socket */ + if (server) { +- clilen = sizeof(cliaddr); +-#ifndef MSG_TRUNC /* vanilla BSD sockets */ ++ if (af_46 == AF_INET) { ++ clilen = sizeof(cliaddr4); ++ } else { ++ clilen = sizeof(cliaddr6); ++ } ++ ++#ifndef MSG_TRUNC /* vanilla BSD sockets */ ++ ++ /* Fixme: Not ported for IPv6 */ ++ /* Not compiled in for FreeBSD 8.4 */ + nread = recvfrom(sockfd, rbuf, readlen, 0, +- (struct sockaddr *) &cliaddr, &clilen); +- ++ (struct sockaddr *) &cliaddr4, &clilen); ++ + #else /* 4.3BSD Reno and later; use recvmsg() to get at MSG_TRUNC flag */ +- /* Also lets us get at control information (destination address) */ +- ++ /* Also lets us get at control information (destination address) */ ++ ++ /* FreeBSD 8.4 */ + iov[0].iov_base = rbuf; + iov[0].iov_len = readlen; +- msg.msg_iov = iov; +- msg.msg_iovlen = 1; +- msg.msg_name = (caddr_t) &cliaddr; +- msg.msg_namelen = clilen; +- ++ msg.msg_iov = iov; ++ msg.msg_iovlen = 1; ++ if (af_46 == AF_INET) { ++ msg.msg_name = (caddr_t) &cliaddr4; ++ } else { ++ msg.msg_name = (caddr_t) &cliaddr6; ++ } ++ msg.msg_namelen = clilen; ++ + #ifdef HAVE_MSGHDR_MSG_CONTROL + #ifdef IP_RECVDSTADDR ++ /* FreeBSD 8.4 */ + if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL) + err_sys("malloc error for control buffer"); + +- msg.msg_control = (caddr_t) cmptr; /* for dest address */ ++ /* for dest address */ ++ msg.msg_control = (caddr_t) cmptr; + msg.msg_controllen = CONTROLLEN; + #else +- msg.msg_control = (caddr_t) 0; /* no ancillary data */ ++ /* Not used for FreeBSD 8.4 */ ++ /* no ancillary data */ ++ msg.msg_control = (caddr_t) 0; + msg.msg_controllen = 0; + #endif /* IP_RECVDSTADDR */ + #endif + #ifdef HAVE_MSGHDR_MSG_FLAGS +- msg.msg_flags = 0; /* flags returned here */ ++ /* FreeBSD 8.4 */ ++ /* flags returned here */ ++ msg.msg_flags = 0; + #endif + nread = recvmsg(sockfd, &msg, 0); + #endif /* MSG_TRUNC */ +@@ -137,22 +189,39 @@ loop_udp(int sockfd) + err_sys("datagram receive error"); + + if (verbose) { +- printf("from %s", INET_NTOA(cliaddr.sin_addr)); ++ if (af_46 == AF_INET) { ++ printf("from %s", ++ INET_NTOA(cliaddr4.sin_addr)); ++ } else { ++ inet_ntop(AF_INET6, ++ &cliaddr6.sin6_addr. ++ __u6_addr.__u6_addr8, ++ inaddr_buf, ++ sizeof(inaddr_buf)); ++ printf("from %s", inaddr_buf); ++ } + #ifdef HAVE_MSGHDR_MSG_CONTROL + #ifdef IP_RECVDSTADDR ++ /* ++ * Fixme: not ported for IPv6 ++ * Fixme: recvdstaddr fails (earlier, ++ * in setsockopt()) for IPv6 under ++ * FreeBSD 8.4 ++ */ + if (recvdstaddr) { + if (cmptr->cmsg_len != CONTROLLEN) + err_quit("control length (%d) != %d", +- cmptr->cmsg_len, CONTROLLEN); ++ cmptr->cmsg_len, CONTROLLEN); + if (cmptr->cmsg_level != IPPROTO_IP) + err_quit("control level != IPPROTO_IP"); + if (cmptr->cmsg_type != IP_RECVDSTADDR) + err_quit("control type != IP_RECVDSTADDR"); + bcopy(CMSG_DATA(cmptr), &dstinaddr, +- sizeof(struct in_addr)); ++ sizeof(struct in_addr)); + bzero(cmptr, CONTROLLEN); + +- printf(", to %s", INET_NTOA(dstinaddr)); ++ printf(", to %s", ++ INET_NTOA(dstinaddr)); + } + #endif /* IP_RECVDSTADDR */ + #endif /* HAVE_MSGHDR_MSG_CONTROL */ +@@ -178,15 +247,37 @@ loop_udp(int sockfd) + } + + } else { +- /* Must use recvfrom() for unconnected UDP client */ +- servlen = sizeof(servaddr); +- nread = recvfrom(sockfd, rbuf, readlen, 0, +- (struct sockaddr *) &servaddr, &servlen); +- if (nread < 0) ++ /* ++ * Must use recvfrom() for unconnected ++ * UDP client ++ */ ++ /* Fixme: not tested on FreeBSD 8.4 */ ++ if (af_46 == AF_INET) { ++ servlen = sizeof(servaddr4); ++ nread = recvfrom(sockfd, rbuf, readlen, ++ 0, (struct sockaddr *)&servaddr4, ++ &servlen); ++ } else { ++ servlen = sizeof(servaddr6); ++ nread = recvfrom(sockfd, rbuf, readlen, ++ 0, (struct sockaddr *)&servaddr6, ++ &servlen); ++ } ++ if (nread < 0) { + err_sys("datagram recvfrom() error"); +- ++ } + if (verbose) { +- printf("from %s", INET_NTOA(servaddr.sin_addr)); ++ if (af_46 == AF_INET) { ++ printf("from %s", ++ INET_NTOA(servaddr4.sin_addr)); ++ } else { ++ inet_ntop(AF_INET6, ++ &servaddr6.sin6_addr. ++ __u6_addr.__u6_addr8, ++ inaddr_buf, ++ sizeof(inaddr_buf)); ++ printf("from %s", inaddr_buf); ++ } + printf(": "); + fflush(stdout); + } Added: head/net/sock/files/patch-src__main.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/net/sock/files/patch-src__main.c Tue May 24 16:59:54 2016 (r415801) @@ -0,0 +1,60 @@ +--- src/main.c.orig 2010-05-28 00:03:25 UTC ++++ src/main.c +@@ -23,9 +23,10 @@ + char *host; /* hostname or dotted-decimal string */ + char *port; + +- /* DefinE global variables */ ++ /* Define global variables */ ++int af_46 = AF_INET; /* AF_INET or AF_INET6 */ + int bindport; /* 0 or TCP or UDP port number to bind */ +- /* set by -b or -l options */ ++ /* set by -b or -l options */ + int broadcast; /* SO_BROADCAST */ + int cbreak; /* set terminal to cbreak mode */ + int chunkwrite; /* write in small chunks; not all-at-once */ +@@ -76,7 +77,8 @@ int urgwrite; /* write urgent byte af + int verbose; /* each -v increments this by 1 */ + int usewritev; /* use writev() instead of write() */ + +-struct sockaddr_in cliaddr, servaddr; ++struct sockaddr_in cliaddr4, servaddr4; ++struct sockaddr_in6 cliaddr6, servaddr6; + + static void usage(const char *); + +@@ -90,13 +92,16 @@ main(int argc, char *argv[]) + usage(""); + + opterr = 0; /* don't want getopt() writing to stderr */ +- while ( (c = getopt(argc, argv, "2b:cf:g:hij:kl:n:op:q:r:st:uvw:x:y:ABCDEFG:H:IJ:KL:NO:P:Q:R:S:TU:VWX:YZ")) != -1) { ++ while ( (c = getopt(argc, argv, "26b:cf:g:hij:kl:n:op:q:r:st:uvw:x:y:ABCDEFG:H:IJ:KL:NO:P:Q:R:S:TU:VWX:YZ")) != -1) { + switch (c) { + #ifdef IP_ONESBCAST + case '2': /* use 255.255.255.255 as broadcast address */ + onesbcast = 1; + break; + #endif ++ case '6': /* use IPv6 */ ++ af_46 = AF_INET6; ++ break; + + case 'b': + bindport = atoi(optarg); +@@ -309,7 +314,7 @@ main(int argc, char *argv[]) + } + } + +- /* check for options that don't make sense */ ++ /* check for options that don't make sense */ + if (udp && halfclose) + usage("can't specify -h and -u"); + if (udp && debug) +@@ -439,6 +444,7 @@ usage(const char *msg) + #ifdef IP_ONESBCAST + " -2 IP_ONESBCAST option (255.255.255.255 for broadcast\n" + #endif ++" -6 use IPv6 instead of IPv4\n" + ); + + if (msg[0] != 0) Added: head/net/sock/files/patch-src__multicast.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/net/sock/files/patch-src__multicast.c Tue May 24 16:59:54 2016 (r415801) @@ -0,0 +1,111 @@ +--- src/multicast.c.orig 2010-05-28 00:03:25 UTC ++++ src/multicast.c +@@ -10,24 +10,96 @@ + + #include "sock.h" + ++/* ++ * Works for IPv4 and IPv6. ++ * For IPv4, the server is able to join a multicast group such as 224.0.0.1. ++ * The client is able to connect to the same multicast address and port ++ * assigned to the server. The client can then send data, which the server ++ * receives. ++ * For IPv6, the server is able to join a multicast group of the form ff02::n. ++ * The client is never able to connect to that address/port, however. ++ */ + void +-join_mcast(int fd, struct sockaddr_in *sin) ++join_mcast_server(int fd, struct sockaddr_in *sin, struct sockaddr_in6 *sin6) + { + #ifdef IP_ADD_MEMBERSHIP /* only include if host supports mcasting */ +- u_long inaddr; +- struct ip_mreq mreq; ++ u_long inaddr; ++ struct ip_mreq mreq; ++ struct ipv6_mreq mreq6; + +- inaddr = sin->sin_addr.s_addr; +- if (IN_MULTICAST(inaddr) == 0) +- return; /* not a multicast address */ ++ if (af_46 == AF_INET) { ++ inaddr = sin->sin_addr.s_addr; ++ /* ++ * FreeBSD 8.4: IN_MULTICAST() test fails in the original code ++ * because it was testing inaddr with the wrong endianness. ++ * Fixed in this version of the code, at least for FreeBSD. ++ */ ++ inaddr = ntohl(inaddr); + +- mreq.imr_multiaddr.s_addr = inaddr; +- mreq.imr_interface.s_addr = htonl(INADDR_ANY); /* need way to change */ +- if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, +- sizeof(mreq)) == -1 ) +- err_sys("IP_ADD_MEMBERSHIP error"); ++ if (IN_MULTICAST(inaddr) == 0) { ++ return; /* not a multicast address */ ++ } ++ } else { ++ if (IN6_IS_ADDR_MULTICAST(&(sin6->sin6_addr)) == 0) { ++ return; /* not a multicast address */ ++ } ++ } ++ ++ if (af_46 == AF_INET) { ++ mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr; ++ /* need way to change */ ++ mreq.imr_interface.s_addr = htonl(INADDR_ANY); ++ if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, ++ sizeof(mreq)) == -1 ) { ++ err_sys("IP_ADD_MEMBERSHIP error"); ++ } ++ } else { ++ memset((char *)&mreq6, 0, sizeof(mreq6)); ++ mreq6.ipv6mr_multiaddr = sin6->sin6_addr; ++ mreq6.ipv6mr_interface = sin6->sin6_scope_id; ++ if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, ++ sizeof(mreq6)) == -1 ) { ++ err_sys("IP_ADD_MEMBERSHIP error"); ++ } ++ } + + if (verbose) +- fprintf(stderr, "multicast group joined\n"); ++ fprintf(stderr, "multicast group joined\n"); ++#endif /* IP_ADD_MEMBERSHIP */ ++} ++ ++/* ++ * Added for IPv6. Fixme: Does not work at present. ++ * The client is currently unable to connect to the multicast address/port ++ * which was joined by the server. A function similar to this may be needed ++ * to permit that connection to be made. ++ */ ++void ++join_mcast_client(int fd, ++ struct sockaddr_in *cli_sin, struct sockaddr_in6 *cli_sin6, ++ struct sockaddr_in *serv_sin, struct sockaddr_in6 *serv_sin6) ++{ ++#ifdef IP_ADD_MEMBERSHIP /* only include if host supports mcasting */ ++ struct ipv6_mreq mreq6; ++ ++ if (af_46 == AF_INET6) { ++ if (IN6_IS_ADDR_MULTICAST(&(serv_sin6->sin6_addr)) == 0) { ++ return; /* not a multicast address */ ++ } ++ } ++ ++ if (af_46 == AF_INET6) { ++ memset((char *)&mreq6, 0, sizeof(mreq6)); ++ mreq6.ipv6mr_multiaddr = serv_sin6->sin6_addr; ++ mreq6.ipv6mr_interface = serv_sin6->sin6_scope_id; ++ if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, ++ sizeof(mreq6)) == -1 ) { ++ err_sys("IP_ADD_MEMBERSHIP error"); ++ } ++ } ++ ++ if (verbose) { ++ fprintf(stderr, "multicast group joined\n"); ++ } + #endif /* IP_ADD_MEMBERSHIP */ + } Added: head/net/sock/files/patch-src__servopen.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/net/sock/files/patch-src__servopen.c Tue May 24 16:59:54 2016 (r415801) @@ -0,0 +1,282 @@ +--- src/servopen.c.orig 2010-05-28 00:03:25 UTC ++++ src/servopen.c +@@ -19,38 +19,67 @@ + int + servopen(char *host, char *port) + { +- int fd, newfd, i, on, pid; +- char *protocol; ++ int fd, newfd, i, on, pid; ++ char *protocol; + struct in_addr inaddr; + struct servent *sp; ++ socklen_t len; ++ char inaddr_buf[INET6_ADDRSTRLEN]; + + protocol = udp ? "udp" : "tcp"; + +- /* Initialize the socket address structure */ +- bzero(&servaddr, sizeof(servaddr)); +- servaddr.sin_family = AF_INET; ++ /* Initialize the socket address structure */ ++ bzero(&servaddr4, sizeof(servaddr4)); ++ servaddr4.sin_family = AF_INET; + +- /* Caller normally wildcards the local Internet address, meaning +- a connection will be accepted on any connected interface. +- We only allow an IP address for the "host", not a name. */ +- if (host == NULL) +- servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* wildcard */ +- else { +- if (inet_aton(host, &inaddr) == 0) +- err_quit("invalid host name for server: %s", host); +- servaddr.sin_addr = inaddr; ++ bzero(&servaddr6, sizeof(servaddr6)); ++ servaddr6.sin6_family = AF_INET6; ++ ++ /* ++ * Caller normally wildcards the local Internet address, meaning ++ * a connection will be accepted on any connected interface. ++ * We only allow an IP address for the "host", not a name. ++ */ ++ if (host == NULL) { ++ if (AF_INET == af_46) { ++ /* wildcard */ ++ servaddr4.sin_addr.s_addr = htonl(INADDR_ANY); ++ } else { ++ /* wildcard */ ++ servaddr6.sin6_addr = in6addr_any; ++ } ++ } else { ++ if (AF_INET == af_46) { ++ if (inet_pton(AF_INET, host, &inaddr) == 0) { ++ err_quit("invalid host name for server: %s", ++ host); ++ } ++ /* IPv4 address */ ++ servaddr4.sin_addr = inaddr; ++ } else { ++ if (inet_pton(AF_INET6, host, inaddr_buf) == 0) { ++ err_quit("invalid host name for server: %s", ++ host); ++ } ++ /* IPv6 address */ ++ memcpy(&servaddr6.sin6_addr, inaddr_buf, ++ sizeof(struct in6_addr)); ++ } + } + +- /* See if "port" is a service name or number */ ++ /* See if "port" is a service name or number */ + if ( (i = atoi(port)) == 0) { + if ( (sp = getservbyname(port, protocol)) == NULL) +- err_ret("getservbyname() error for: %s/%s", port, protocol); +- +- servaddr.sin_port = sp->s_port; +- } else +- servaddr.sin_port = htons(i); ++ err_ret("getservbyname() error for: %s/%s", port, ++ protocol); ++ servaddr4.sin_port = sp->s_port; ++ servaddr6.sin6_port = sp->s_port; ++ } else { ++ servaddr4.sin_port = htons(i); ++ servaddr6.sin6_port = htons(i); ++ } + +- if ( (fd = socket(AF_INET, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0) ++ if ( (fd = socket(af_46, udp ? SOCK_DGRAM : SOCK_STREAM, 0)) < 0) + err_sys("socket() error"); + + if (reuseaddr) { +@@ -67,28 +96,37 @@ servopen(char *host, char *port) + } + #endif + +- /* Bind our well-known port so the client can connect to us. */ +- if (bind(fd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) +- err_sys("can't bind local address"); ++ /* Bind our well-known port so the client can connect to us. */ ++ if (AF_INET == af_46) { ++ if (bind(fd, (struct sockaddr *) &servaddr4, ++ sizeof(servaddr4)) < 0) { ++ err_sys("can't bind local address"); ++ } ++ } else { ++ if (bind(fd, (struct sockaddr *) &servaddr6, ++ sizeof(servaddr6)) < 0) { ++ err_sys("can't bind local address"); ++ } ++ } + +- join_mcast(fd, &servaddr); ++ join_mcast_server(fd, &servaddr4, &servaddr6); + + if (udp) { + buffers(fd); + +- if (foreignip[0] != 0) { /* connect to foreignip/port# */ +- bzero(&cliaddr, sizeof(cliaddr)); +- if (inet_aton(foreignip, &cliaddr.sin_addr) == 0) ++ /* Fixme: Not ported for IPv6 */ ++ if (foreignip[0] != 0) { /* connect to foreignip/port# */ ++ bzero(&cliaddr4, sizeof(cliaddr4)); ++ if (inet_aton(foreignip, &cliaddr4.sin_addr) == 0) + err_quit("invalid IP address: %s", foreignip); +- cliaddr.sin_family = AF_INET; +- cliaddr.sin_port = htons(foreignport); +- /* connect() for datagram socket doesn't appear to allow +- wildcarding of either IP address or port number */ ++ cliaddr4.sin_family = AF_INET; ++ cliaddr4.sin_port = htons(foreignport); ++ /* connect() for datagram socket doesn't appear to allow ++ wildcarding of either IP address or port number */ + +- if (connect(fd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) +- < 0) ++ if (connect(fd, (struct sockaddr *) &cliaddr4, ++ sizeof(cliaddr4)) < 0) + err_sys("connect() error"); +- + } + + sockopts(fd, 1); +@@ -96,58 +134,108 @@ servopen(char *host, char *port) + return(fd); /* nothing else to do */ + } + +- buffers(fd); /* may set receive buffer size; must do here to get +- correct window advertised on SYN */ ++ buffers(fd); /* may set receive buffer size; must do here to ++ get correct window advertised on SYN */ + sockopts(fd, 0); /* only set some socket options for fd */ + + listen(fd, listenq); + +- if (pauselisten) +- sleep_us(pauselisten*1000); /* lets connection queue build up */ ++ if (pauselisten) { ++ /* lets connection queue build up */ ++ sleep_us(pauselisten*1000); ++ } + +- if (dofork) +- TELL_WAIT(); /* initialize synchronization primitives */ ++ if (dofork) { ++ /* initialize synchronization primitives */ ++ TELL_WAIT(); ++ } + + for ( ; ; ) { +- i = sizeof(cliaddr); +- if ( (newfd = accept(fd, (struct sockaddr *) &cliaddr, &i)) < 0) +- err_sys("accept() error"); ++ if (AF_INET == af_46) { ++ len = sizeof(cliaddr4); ++ if ( (newfd = accept(fd, (struct sockaddr *) &cliaddr4, ++ &len)) < 0) { ++ err_sys("accept() error"); ++ } ++ } else { ++ len = sizeof(cliaddr6); ++ if ( (newfd = accept(fd, (struct sockaddr *) &cliaddr6, ++ &len)) < 0) { ++ err_sys("accept() error"); ++ } ++ } + + if (dofork) { + if ( (pid = fork()) < 0) + err_sys("fork error"); + + if (pid > 0) { +- close(newfd); /* parent closes connected socket */ +- WAIT_CHILD(); /* wait for child to output to terminal */ +- continue; /* and back to for(;;) for another accept() */ ++ /* parent closes connected socket */ ++ close(newfd); ++ /* wait for child to output to terminal */ ++ WAIT_CHILD(); ++ /* and back to for(;;) for another accept() */ ++ continue; + } else { +- close(fd); /* child closes listening socket */ ++ /* child closes listening socket */ ++ close(fd); + } + } + +- /* child (or iterative server) continues here */ ++ /* child (or iterative server) continues here */ + if (verbose) { +- /* Call getsockname() to find local address bound to socket: +- local internet address is now determined (if multihomed). */ +- i = sizeof(servaddr); +- if (getsockname(newfd, (struct sockaddr *) &servaddr, &i) < 0) +- err_sys("getsockname() error"); ++ /* ++ * Call getsockname() to find local address bound ++ * to socket: local internet address is now ++ * determined (if multihomed). ++ */ ++ if (AF_INET == af_46) { ++ len = sizeof(servaddr4); ++ if (getsockname(newfd, ++ (struct sockaddr *)&servaddr4, &len) < 0) { ++ err_sys("getsockname() error"); ++ } + +- /* Can't do one fprintf() since inet_ntoa() stores +- the result in a static location. */ +- fprintf(stderr, "connection on %s.%d ", +- INET_NTOA(servaddr.sin_addr), ntohs(servaddr.sin_port)); +- fprintf(stderr, "from %s.%d\n", +- INET_NTOA(cliaddr.sin_addr), ntohs(cliaddr.sin_port)); ++ /* ++ * Can't do one fprintf() since inet_ntoa() ++ * stores the result in a static location. ++ */ ++ fprintf(stderr, "connection on %s.%d ", ++ INET_NTOA(servaddr4.sin_addr), ++ ntohs(servaddr4.sin_port)); ++ fprintf(stderr, "from %s.%d\n", ++ INET_NTOA(cliaddr4.sin_addr), ++ ntohs(cliaddr4.sin_port)); ++ } else { ++ len = sizeof(servaddr6); ++ if (getsockname(newfd, ++ (struct sockaddr *)&servaddr6, &len) < 0) { ++ err_sys("getsockname() error"); ++ } ++ inet_ntop(AF_INET6, ++ &servaddr6.sin6_addr.__u6_addr.__u6_addr8, ++ inaddr_buf, sizeof(inaddr_buf)); ++ fprintf(stderr, "connection on %s.%d ", ++ inaddr_buf, ntohs(servaddr6.sin6_port)); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***