chiark / gitweb /
server/, mon/: Introduce transport of TrIPE over IPv6.
authorMark Wooding <mdw@distorted.org.uk>
Fri, 29 Sep 2017 09:08:52 +0000 (10:08 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 28 Jun 2018 23:29:23 +0000 (00:29 +0100)
This depends on ADNS for IPv6 name resolution.

mon/tripemon.in
server/addrmap.c
server/peer.c
server/servutil.c
server/tripe-admin.5.in
server/tripe.8.in
server/tripe.c
server/tripe.h
svc/tripe-ifup.in

index 593b2e8bda2953f2ee0496eda55ebdb672a6a710..1c70d1ff0f446dbccf1787aaaf1e97f8aefbb58c 100644 (file)
@@ -323,13 +323,17 @@ class Peer (MonitorObject):
 
   def _setaddr(me, addr):
     """Set the peer's address."""
 
   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:
       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:
       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
   """
 
     * 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',
   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.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',
     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),
                                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()
     """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._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
                   me.e_addr.get_text(),
                   me.e_port.get_text(),
                   keepalive = (me.c_keepalive.get_active() and
index 6091dbfc3a779817976d28c799ac660ea94f7122..76a358ea34eec387e54fe419615169f593ad8a35 100644 (file)
@@ -74,11 +74,21 @@ void am_destroy(addrmap *m)
 
 static uint32 hash(const addr *a)
 {
 
 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));
   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();
   }
     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_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();
   }
     default:
       abort();
   }
index 34bfb6c4d2b3653de18bb77424c9e5b409048b6c..94629213ca4e37ea85e30bfc33fd00fba9265fff 100644 (file)
@@ -791,6 +791,7 @@ void p_init(struct addrinfo *ailist)
 {
   int fd;
   int len = PKBUFSZ;
 {
   int fd;
   int len = PKBUFSZ;
+  int yes = 1;
   int i;
   struct addrinfo *ai;
   unsigned port, lastport = 0;
   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 ((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);
     assert(ai->ai_addrlen <= sizeof(a));
     memcpy(&a, ai->ai_addr, ai->ai_addrlen);
     if ((port = getport(&a)) == 0 && lastport) setport(&a, lastport);
index a4de37843152ddbeaa409454852d4168ee31cf17..f95541a8af609216a7f55ebeea32f365d441ba18 100644 (file)
@@ -160,6 +160,7 @@ socklen_t addrsz(const addr *a)
 {
   switch (a->sa.sa_family) {
     case AF_INET: return (sizeof(a->sin));
 {
   switch (a->sa.sa_family) {
     case AF_INET: return (sizeof(a->sin));
+    case AF_INET6: return (sizeof(a->sin6));
     default: abort();
   }
 }
     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;
 {
   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();
   }
 }
     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;
 {
   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();
   }
 }
     default: abort();
   }
 }
index 44af6a5828870a7691268cf8d84d6787ab7a58fd..81dd570d68ccb344bb109670ce33d8a52a8109b7 100644 (file)
@@ -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.
 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
 .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
 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
 .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
 .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
 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 .)
 .BI "invalid-port " number
 (For
 .BR ADD .)
index aaaf2678b99a8cedb07f9909cc829e449cbce11f..8b7868283ad1ea8920c39acaf173a508edd81f76 100644 (file)
@@ -37,7 +37,7 @@ tripe \- a simple VPN daemon
 .SH "SYNOPSIS"
 .
 .B tripe
 .SH "SYNOPSIS"
 .
 .B tripe
-.RB [ \-DF ]
+.RB [ \-46DF ]
 .RB [ \-d
 .IR dir ]
 .RB [ \-b
 .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
 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
 .B "\-D, \-\-daemon"
 Dissociates from its terminal and starts running in the background after
 completing the initialization procedure described above.  If running as
index d8a6cc130efd79d19faba8a2cc24bbf6a8d58c03..565c83dd2d16b6f12d0de7d0ee59e6bbb5e60ae0 100644 (file)
@@ -91,6 +91,8 @@ Options:\n\
 -u, --usage            Display pointless usage message.\n\
     --tunnels          Display IP tunnel drivers and exit.\n\
 \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\
 -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];
   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[] = {
 
   for (;;) {
     static const struct option opts[] = {
@@ -150,6 +152,8 @@ int main(int argc, char *argv[])
       { "usage",       0,              0,      'u' },
       { "tunnels",     0,              0,      '0' },
 
       { "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' },
       { "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 }
     };
 
       { 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;
               opts, 0, 0, 0);
     if (i < 0)
       break;
@@ -187,6 +191,12 @@ int main(int argc, char *argv[])
        usage(stdout);
        exit(0);
 
        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;
       case 'D':
        f |= f_daemon;
        break;
index f447be50bc11a84f58a063557a6e3be4dabb9096..29403993af5a60839745238277ecbf4e9a3b1e76 100644 (file)
@@ -420,7 +420,8 @@ extern const bulkops bulktab[];
 /* --- The address-family table --- */
 
 #define ADDRFAM(_)                                                     \
 /* --- The address-family table --- */
 
 #define ADDRFAM(_)                                                     \
-  _(INET,      want_ipv4)
+  _(INET,      want_ipv4)                                              \
+  _(INET6,     want_ipv6)
 
 enum {
 #define ENUM(af, qf) AFIX_##af,
 
 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;
 typedef union addr {
   struct sockaddr sa;
   struct sockaddr_in sin;
+  struct sockaddr_in6 sin6;
 } addr;
 
 /* --- Mapping keyed on addresses --- */
 } addr;
 
 /* --- Mapping keyed on addresses --- */
index 032142c5716f845e773db8357ac23e0a38ce0c90..e9e9cb929bde385bea97be14f8188808a938d6f8 100644 (file)
@@ -46,11 +46,16 @@ fi
 peer=$1 ifname=$2 family=$3; shift 3
 
 ## Parse the address family.
 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
 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
 
 ###--------------------------------------------------------------------------
 esac
 
 ###--------------------------------------------------------------------------
@@ -137,7 +142,7 @@ case $haveaddr4,$haveaddr6 in
        mtu=$P_MTU;;
       *)
        pathmtu=$(pathmtu "$addr")
        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"
        ;;
     esac
     try ip link set dev "$ifname" up mtu "$mtu"