From 47828bd9813b146e8569355b3083847299dd8729 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Fri, 29 Sep 2017 10:08:52 +0100 Subject: [PATCH] server/, mon/: Introduce transport of TrIPE over IPv6. This depends on ADNS for IPv6 name resolution. --- mon/tripemon.in | 19 ++++++++++++++++--- server/addrmap.c | 14 ++++++++++++++ server/peer.c | 6 ++++++ server/servutil.c | 3 +++ server/tripe-admin.5.in | 31 +++++++++++++++++++++++++++---- server/tripe.8.in | 11 ++++++++++- server/tripe.c | 14 ++++++++++++-- server/tripe.h | 4 +++- svc/tripe-ifup.in | 15 ++++++++++----- 9 files changed, 101 insertions(+), 16 deletions(-) diff --git a/mon/tripemon.in b/mon/tripemon.in index 593b2e8b..1c70d1ff 100644 --- a/mon/tripemon.in +++ b/mon/tripemon.in @@ -323,13 +323,17 @@ class Peer (MonitorObject): def _setaddr(me, addr): """Set the peer's address.""" - if addr[0] == 'INET': + if addr[0] in ['INET', 'INET6']: af, ipaddr, port = addr try: name, _ = S.getnameinfo((ipaddr, int(port)), S.NI_NUMERICSERV | S.NI_NAMEREQD) except S.gaierror: - me.addr = '%s %s:%s' % (af, ipaddr, port) + me.addr = '%s %s%s%s:%s' % (af, + af == 'INET6' and '[' or '', + ipaddr, + af == 'INET6' and ']' or '', + port) else: me.addr = '%s %s:%s [%s]' % (af, name, port, ipaddr) else: @@ -1044,6 +1048,8 @@ class AddPeerDialog (MyDialog): * e_name, e_addr, e_port, c_keepalive, l_tunnel: widgets in the dialog """ + AFS = ['ANY', 'INET', 'INET6'] + def __init__(me): """Initialize the dialogue.""" MyDialog.__init__(me, 'Add peer', @@ -1059,8 +1065,13 @@ class AddPeerDialog (MyDialog): me.e_name = table.labelled('Name', ValidatingEntry(r'^[^\s.:]+$', '', 16), width = 3) + me.l_af = table.labelled('Family', combo_box_text(), + newlinep = True, width = 3) + for af in me.AFS: + me.l_af.append_text(af) + me.l_af.set_active(0) me.e_addr = table.labelled('Address', - ValidatingEntry(r'^[a-zA-Z0-9.-]+$', '', 24), + ValidatingEntry(r'^[a-zA-Z0-9.-:]+$', '', 24), newlinep = True) me.e_port = table.labelled('Port', ValidatingEntry(numericvalidate(0, 65535), @@ -1106,7 +1117,9 @@ class AddPeerDialog (MyDialog): """Handle an OK press: create the peer.""" try: t = me.l_tunnel.get_active() + afix = me.l_af.get_active() me._addpeer(me.e_name.get_text(), + me.AFS[afix], me.e_addr.get_text(), me.e_port.get_text(), keepalive = (me.c_keepalive.get_active() and diff --git a/server/addrmap.c b/server/addrmap.c index 6091dbfc..76a358ea 100644 --- a/server/addrmap.c +++ b/server/addrmap.c @@ -74,11 +74,21 @@ void am_destroy(addrmap *m) static uint32 hash(const addr *a) { + size_t i; + uint32 h; + switch (a->sa.sa_family) { case AF_INET: return (U32(0x4eaac1b7ul*AF_INET + 0xa5dbc837ul*a->sin.sin_addr.s_addr + 0x3b049e83ul*a->sin.sin_port)); + case AF_INET6: + for (i = 0, h = 0; i < 16; i++) + h = 0x6bd26a67ul*h + a->sin6.sin6_addr.s6_addr[i]; + return (U32(0x4eaac1b7ul*AF_INET6 + + 0xa5dbc837ul*h + + 0x1d94eab4ul*a->sin6.sin6_scope_id + + 0x3b049e83ul*a->sin6.sin6_port)); default: abort(); } @@ -99,6 +109,10 @@ static int addreq(const addr *a, const addr *b) case AF_INET: return (a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr && a->sin.sin_port == b->sin.sin_port); + case AF_INET6: + return (!memcmp(a->sin6.sin6_addr.s6_addr, + b->sin6.sin6_addr.s6_addr, 16) && + a->sin6.sin6_port == b->sin6.sin6_port); default: abort(); } diff --git a/server/peer.c b/server/peer.c index 34bfb6c4..94629213 100644 --- a/server/peer.c +++ b/server/peer.c @@ -791,6 +791,7 @@ void p_init(struct addrinfo *ailist) { int fd; int len = PKBUFSZ; + int yes = 1; int i; struct addrinfo *ai; unsigned port, lastport = 0; @@ -813,6 +814,11 @@ void p_init(struct addrinfo *ailist) if ((fd = socket(ai->ai_family, SOCK_DGRAM, 0)) < 0) die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno)); + if (i == AFIX_INET6 && + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) { + die(EXIT_FAILURE, "failed to set IPv6-only state: %s", + strerror(errno)); + } assert(ai->ai_addrlen <= sizeof(a)); memcpy(&a, ai->ai_addr, ai->ai_addrlen); if ((port = getport(&a)) == 0 && lastport) setport(&a, lastport); diff --git a/server/servutil.c b/server/servutil.c index a4de3784..f95541a8 100644 --- a/server/servutil.c +++ b/server/servutil.c @@ -160,6 +160,7 @@ 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(); } } @@ -178,6 +179,7 @@ unsigned getport(addr *a) { switch (a->sa.sa_family) { case AF_INET: return (ntohs(a->sin.sin_port)); break; + case AF_INET6: return (ntohs(a->sin6.sin6_port)); break; default: abort(); } } @@ -186,6 +188,7 @@ void setport(addr *a, unsigned port) { switch (a->sa.sa_family) { case AF_INET: a->sin.sin_port = htons(port); break; + case AF_INET6: a->sin6.sin6_port = htons(port); break; default: abort(); } } diff --git a/server/tripe-admin.5.in b/server/tripe-admin.5.in index 44af6a58..81dd570d 100644 --- a/server/tripe-admin.5.in +++ b/server/tripe-admin.5.in @@ -275,6 +275,16 @@ is always in numeric dotted-quad form, and the is given as a plain decimal number. On input, DNS hostnames and symbolic port names are permitted; if omitted, the default port 4070 is used. +.TP +.BI "INET6 " address " \fR[" port \fR] +An Internet socket, naming an IPv6 address and UDP port. On output, the +.I address +is always in numeric hex-and-colons form, and the +.I port +is given as a plain decimal number. On input, DNS hostnames and +symbolic port names may be permitted, depending on how +.B tripe +was compiled; if omitted, the default port 4070 is used. .PP If, on input, no recognized address family token is found, the following tokens are assumed to represent an @@ -490,12 +500,16 @@ tunnel interface. If is the MTU of the path to the peer, then the tunnel MTU should be .IP .I MTU -\- 29 \- +\- +.I header-length +\- 9 \- .I bulk-overhead .PP -allowing 20 bytes of IP header, 8 bytes of UDP header, a packet type -octet, and the bulk-crypto transform overhead (which includes the -sequence number). +allowing +.I header-length += 20 (IPv4) or 40 (IPv6) bytes of IP header, 8 bytes of UDP header, a +packet type octet, and the bulk-crypto transform overhead (which +includes the sequence number). .RE .SP .BI "BGCANCEL " tag @@ -1019,6 +1033,15 @@ An unknown watch option was requested. An error occurred during the attempt to become a daemon, as reported by .IR message . .SP +.BI "disabled-address-family " afam +(For +.B ADD +and +.BR PORT .) +The address family +.I afam +is supported, but was disabled using command-line arguments. +.SP .BI "invalid-port " number (For .BR ADD .) diff --git a/server/tripe.8.in b/server/tripe.8.in index aaaf2678..8b786828 100644 --- a/server/tripe.8.in +++ b/server/tripe.8.in @@ -37,7 +37,7 @@ tripe \- a simple VPN daemon .SH "SYNOPSIS" . .B tripe -.RB [ \-DF ] +.RB [ \-46DF ] .RB [ \-d .IR dir ] .RB [ \-b @@ -165,6 +165,15 @@ Writes to standard output a list of the configured tunnel drivers, one per line, and exits with status 0. This is intended for the use of the start-up script, so that it can check that it will actually work. .TP +.B "\-4, \-\-ipv4" +Use only IPv4 addresses. The server will resolve names only to IPv4 +addresses, and not attempt to create IPv6 sockets. +.TP +.B "\-6, \-\-ipv6" +Use only IPv6 addresses. The server will resolve names only to IPv6 +addresses, and not attempt to create IPv4 sockets. Note that v6-mapped +IPv4 addresses won't work either. +.TP .B "\-D, \-\-daemon" Dissociates from its terminal and starts running in the background after completing the initialization procedure described above. If running as diff --git a/server/tripe.c b/server/tripe.c index d8a6cc13..565c83dd 100644 --- a/server/tripe.c +++ b/server/tripe.c @@ -91,6 +91,8 @@ Options:\n\ -u, --usage Display pointless usage message.\n\ --tunnels Display IP tunnel drivers and exit.\n\ \n\ +-4, --ipv4 Transport over IPv4 only.\n\ +-6, --ipv6 Transport over IPv6 only.\n\ -D, --daemon Run in the background.\n\ -F, --foreground Quit when stdin reports end-of-file.\n\ -d, --directory=DIR Switch to directory DIR [default " CONFIGDIR "].\n\ @@ -141,7 +143,7 @@ int main(int argc, char *argv[]) if ((p = getenv("TRIPESOCK")) != 0) csock = p; tun_default = tunnels[0]; - aihint.ai_family = AF_INET; + aihint.ai_family = AF_UNSPEC; for (;;) { static const struct option opts[] = { @@ -150,6 +152,8 @@ int main(int argc, char *argv[]) { "usage", 0, 0, 'u' }, { "tunnels", 0, 0, '0' }, + { "ipv4", 0, 0, '4' }, + { "ipv6", 0, 0, '6' }, { "daemon", 0, 0, 'D' }, { "foreground", 0, 0, 'F' }, { "uid", OPTF_ARGREQ, 0, 'U' }, @@ -172,7 +176,7 @@ int main(int argc, char *argv[]) { 0, 0, 0, 0 } }; - i = mdwopt(argc, argv, "hvuDFU:G:b:n:p:d:k:K:t:a:m:" T("T:"), + i = mdwopt(argc, argv, "hvu46DFU:G:b:n:p:d:k:K:t:a:m:" T("T:"), opts, 0, 0, 0); if (i < 0) break; @@ -187,6 +191,12 @@ int main(int argc, char *argv[]) usage(stdout); exit(0); + case '4': + aihint.ai_family = AF_INET; + break; + case '6': + aihint.ai_family = AF_INET6; + break; case 'D': f |= f_daemon; break; diff --git a/server/tripe.h b/server/tripe.h index f447be50..29403993 100644 --- a/server/tripe.h +++ b/server/tripe.h @@ -420,7 +420,8 @@ extern const bulkops bulktab[]; /* --- The address-family table --- */ #define ADDRFAM(_) \ - _(INET, want_ipv4) + _(INET, want_ipv4) \ + _(INET6, want_ipv6) enum { #define ENUM(af, qf) AFIX_##af, @@ -445,6 +446,7 @@ extern const struct addrfam { typedef union addr { struct sockaddr sa; struct sockaddr_in sin; + struct sockaddr_in6 sin6; } addr; /* --- Mapping keyed on addresses --- */ diff --git a/svc/tripe-ifup.in b/svc/tripe-ifup.in index 032142c5..e9e9cb92 100644 --- a/svc/tripe-ifup.in +++ b/svc/tripe-ifup.in @@ -46,11 +46,16 @@ fi peer=$1 ifname=$2 family=$3; shift 3 ## Parse the address family. +case "$family" in + INET) ipsz=20 ;; + INET6) ipsz=40 ;; + *) echo >&2 "$0: unknown address family $family"; exit 1 ;; +esac case "$family,$#" in - INET,1) addr=$1 port=4070 ;; - INET,2) addr=$1 port=$2 ;; - INET,*) echo >&2 "$0: bad INET address"; exit 1 ;; - *) echo >&2 "$0: unknown address family $family"; exit 1 ;; + INET,1 | INET6,1) addr=$1 port=4070 ;; + INET,2 | INET6,2) addr=$1 port=$2 ;; + INET,* | INET6,*) echo >&2 "$0: bad $family address"; exit 1 ;; + *) echo >&2 "$0: unknown address family $family"; exit 1 ;; esac ###-------------------------------------------------------------------------- @@ -137,7 +142,7 @@ case $haveaddr4,$haveaddr6 in mtu=$P_MTU;; *) pathmtu=$(pathmtu "$addr") - mtu=$(expr "$pathmtu" - 29 - $A_BULK_OVERHEAD) + mtu=$(( $pathmtu - $ipsz - 9 - $A_BULK_OVERHEAD )) ;; esac try ip link set dev "$ifname" up mtu "$mtu" -- 2.11.0