From e7fb711518b5915e2c4791eeb6c83f92b3854abc Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Thu, 28 Sep 2017 02:04:53 +0100 Subject: [PATCH] pkstream/pkstream.c: Enable IPv6 address support. Implement the address-helper branches for IPv6, and set the default address family to `AF_UNSPEC'. Also, introduce command-line switches for limiting address resolution. --- pkstream/pkstream.1.in | 7 +++++++ pkstream/pkstream.c | 46 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/pkstream/pkstream.1.in b/pkstream/pkstream.1.in index cdf8dc5e..757e5cde 100644 --- a/pkstream/pkstream.1.in +++ b/pkstream/pkstream.1.in @@ -37,6 +37,7 @@ pkstream \- forward UDP packets over streams .SH "SYNOPSIS" . .B pkstream +.RB [ \-46 ] .RB [ \-l .IR port ] .RB [ \-p @@ -97,6 +98,12 @@ version number to standard output and exits with status 0. .B "\-u, \-\-usage" Writes a brief usage summary to standard output and exits with status 0. .TP +.B "\-4" +Look up hostnames only as IPv4 addresses. +.TP +.B "\-6" +Look up hostnames only as IPv6 addresses. +.TP .BI "\-l, \-\-listen=" port Listen for connections on the given TCP .IR port . diff --git a/pkstream/pkstream.c b/pkstream/pkstream.c index f07c075b..8b2a058c 100644 --- a/pkstream/pkstream.c +++ b/pkstream/pkstream.c @@ -61,6 +61,7 @@ typedef union addr { struct sockaddr sa; struct sockaddr_in sin; + struct sockaddr_in6 sin6; } addr; DA_DECL(addr_v, addr); @@ -107,6 +108,7 @@ static socklen_t addrsz(const addr *a) { switch (a->sa.sa_family) { case AF_INET: return sizeof(a->sin); + case AF_INET6: return sizeof(a->sin6); default: abort(); } } @@ -114,15 +116,21 @@ static socklen_t addrsz(const addr *a) static int knownafp(int af) { switch (af) { - case AF_INET: return (1); + case AF_INET: case AF_INET6: return (1); default: return (0); } } static int initsock(int fd, int af) { + int yes = 1; + switch (af) { case AF_INET: break; + case AF_INET6: + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) + return (-1); + break; default: abort(); } return (0); @@ -144,6 +152,11 @@ static int addreq(const addr *a, const addr *b) switch (a->sa.sa_family) { case AF_INET: return (a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr); + case AF_INET6: + return (!memcmp(a->sin6.sin6_addr.s6_addr, + b->sin6.sin6_addr.s6_addr, + 16) && + a->sin6.sin6_scope_id == b->sin6.sin6_scope_id); default: abort(); } @@ -157,6 +170,12 @@ static void initaddr(addr *a, int af) a->sin.sin_addr.s_addr = INADDR_ANY; a->sin.sin_port = 0; break; + case AF_INET6: + memset(a->sin6.sin6_addr.s6_addr, 0, 16); + a->sin6.sin6_port = 0; + a->sin6.sin6_flowinfo = 0; + a->sin6.sin6_scope_id = 0; + break; default: abort(); } @@ -167,6 +186,7 @@ static void initaddr(addr *a, int af) static void copyaddr(addr *a, const struct sockaddr *sa, unsigned f) { const struct sockaddr_in *sin; + const struct sockaddr_in6 *sin6; a->sa.sa_family = sa->sa_family; switch (sa->sa_family) { @@ -175,6 +195,15 @@ static void copyaddr(addr *a, const struct sockaddr *sa, unsigned f) if (f&caf_addr) a->sin.sin_addr = sin->sin_addr; if (f&caf_port) a->sin.sin_port = sin->sin_port; break; + case AF_INET6: + sin6 = (const struct sockaddr_in6 *)sa; + if (f&caf_addr) { + a->sin6.sin6_addr = sin6->sin6_addr; + a->sin6.sin6_scope_id = sin6->sin6_scope_id; + } + if (f&caf_port) a->sin6.sin6_port = sin6->sin6_port; + /* ??? flowinfo? */ + break; default: abort(); } @@ -406,7 +435,7 @@ static void parseaddr(const struct addrinfo *aihint, static void usage(FILE *fp) { pquis(fp, - "Usage: $ [-l PORT] [-b ADDR] [-p ADDR] [-c ADDR:PORT]\n\ + "Usage: $ [-46] [-l PORT] [-b ADDR] [-p ADDR] [-c ADDR:PORT]\n\ ADDR:PORT ADDR:PORT\n"); } @@ -425,6 +454,8 @@ Options:\n\ -v, --version Display version number.\n\ -u, --usage Display pointless usage message.\n\ \n\ +-4, --ipv4 Restrict to IPv4 only.\n\ +-6, --ipv6 Restrict to IPv6 only.\n\ -l, --listen=PORT Listen for connections to TCP PORT.\n\ -p, --peer=ADDR Only accept connections from IP ADDR.\n\ -b, --bind=ADDR Bind to ADDR before connecting.\n\ @@ -443,6 +474,7 @@ int main(int argc, char *argv[]) addr bindaddr; const char *connhost = 0; struct addrinfo aihint = { 0 }, *ai, *ailist; + int af = AF_UNSPEC; int fd = -1; int len = 65536; size_t i, n; @@ -458,6 +490,8 @@ int main(int argc, char *argv[]) { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { "usage", 0, 0, 'u' }, + { "ipv4", 0, 0, '4' }, + { "ipv6", 0, 0, '6' }, { "listen", OPTF_ARGREQ, 0, 'l' }, { "peer", OPTF_ARGREQ, 0, 'p' }, { "bind", OPTF_ARGREQ, 0, 'b' }, @@ -466,13 +500,15 @@ int main(int argc, char *argv[]) }; int i; - i = mdwopt(argc, argv, "hvul:p:b:c:", opt, 0, 0, 0); + i = mdwopt(argc, argv, "hvu46l:p:b:c:", opt, 0, 0, 0); if (i < 0) break; switch (i) { case 'h': help(stdout); exit(0); case 'v': version(stdout); exit(0); case 'u': usage(stdout); exit(0); + case '4': af = AF_INET; break; + case '6': af = AF_INET6; break; case 'l': bindsvc = optarg; break; case 'p': DA_PUSH(&peerhosts, optarg); break; case 'b': DA_PUSH(&bindhosts, optarg); break; @@ -489,7 +525,7 @@ int main(int argc, char *argv[]) if (bindsvc && connhost) die(1, "can't listen and connect"); - aihint.ai_family = AF_INET; + aihint.ai_family = af; DA_CREATE(&cw.me); DA_CREATE(&cw.peer); n = DA_LEN(&bindhosts); @@ -557,7 +593,7 @@ int main(int argc, char *argv[]) die(1, "couldn't connect to TCP server: %s", strerror(errno)); } - aihint.ai_family = AF_INET; + aihint.ai_family = af; aihint.ai_socktype = SOCK_DGRAM; aihint.ai_protocol = IPPROTO_UDP; aihint.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; -- 2.11.0