proxy/tripe-mitm.c: Support for IPv6.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 13 Sep 2017 10:11:01 +0000 (11:11 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 28 Jun 2018 23:25:14 +0000 (00:25 +0100)
Now we're using getaddrinfo(3), we can also allow service names for
ports, but this is rather incidental.

proxy/tripe-mitm.8.in
proxy/tripe-mitm.c

index 3a91258..e939919 100644 (file)
@@ -119,9 +119,11 @@ Both
 .I local-port
 and
 .I remote-port
 .I local-port
 and
 .I remote-port
-must be numbers;
+may be numbers or UDP service names;
 .I remote-addr
 .I remote-addr
-may be a hostname or an IP address in dotted-quad format.  Exactly two
+may be a hostname, an IPv4 address in dotted-quad format, or an IPv6
+address in hex-and-colons format (this last obviously requires selecting
+a different delimeter character).  Exactly two
 .B peer
 directives must be present.  The one first registered is the
 .I left
 .B peer
 directives must be present.  The one first registered is the
 .I left
@@ -131,6 +133,16 @@ peer.  The two peers must use
 .I different
 local ports.
 .TP
 .I different
 local ports.
 .TP
+.BI peer4: name : local-port : remote-addr : remote-port
+As for
+.I peer
+(see above), but force the use of IPv4.
+.TP
+.BI peer6: name : local-port : remote-addr : remote-port
+As for
+.I peer
+(see above), but force the use of IPv6.
+.TP
 .BI include: file
 Read more directives from
 .IR file .
 .BI include: file
 Read more directives from
 .IR file .
index 2530f15..6acf2a1 100644 (file)
@@ -115,43 +115,52 @@ static void dopacket(int fd, unsigned mode, void *vv)
   }
 }
 
   }
 }
 
-static void addpeer(unsigned ac, char **av)
+static void addpeer_common(const char *cmd, int af, unsigned ac, char **av)
 {
 {
-  struct hostent *h;
-  struct sockaddr_in sin;
-  int len = PKBUFSZ;
+  struct addrinfo aihint = { 0 }, *ai0, *ai1;
+  int len = PKBUFSZ, yes = 1;
+  int err;
   peer *p;
   int fd;
 
   peer *p;
   int fd;
 
-  if (ac != 4) die(1, "syntax: peer:NAME:PORT:ADDR:PORT");
-  if (npeer >= 2) die(1, "enough peers already");
+  if (ac != 4) die(1, "syntax: %s:NAME:PORT:ADDR:PORT", cmd);
   if (!key_bytag(&keys, av[0])) die(1, "no key named `%s'", av[0]);
   p = &peers[npeer++];
   p->name = xstrdup(av[0]);
   if (!key_bytag(&keys, av[0])) die(1, "no key named `%s'", av[0]);
   p = &peers[npeer++];
   p->name = xstrdup(av[0]);
-  if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
+  aihint.ai_family = af;
+  aihint.ai_socktype = SOCK_DGRAM;
+  aihint.ai_flags = AI_ADDRCONFIG;
+  if ((err = getaddrinfo(av[2], av[3], &aihint, &ai1)) != 0)
+    die(1, "getaddrinfo(`%s', `%s'): %s", av[2], av[3], gai_strerror(err));
+  aihint.ai_family = ai1->ai_family;
+  aihint.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
+  if ((err = getaddrinfo(0, av[1], &aihint, &ai0)) != 0)
+    die(1, "getaddrinfo(passive, `%s'): %s", av[1], gai_strerror(err));
+  if ((fd = socket(ai1->ai_family, SOCK_DGRAM, ai1->ai_protocol)) < 0)
     die(1, "socket: %s", strerror(errno));
     die(1, "socket: %s", strerror(errno));
-  fdflags(fd, O_NONBLOCK, O_NONBLOCK, FD_CLOEXEC, FD_CLOEXEC);
-  memset(&sin, 0, sizeof(sin));
-  sin.sin_family = AF_INET;
-  sin.sin_addr.s_addr = INADDR_ANY;
-  sin.sin_port = htons(atoi(av[1]));
-  if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)))
+  if (ai1->ai_family == AF_INET6) {
+    if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)))
+      die(1, "setsockopt: %s", strerror(errno));
+  }
+  if (bind(fd, ai0->ai_addr, ai0->ai_addrlen))
     die(1, "bind: %s", strerror(errno));
     die(1, "bind: %s", strerror(errno));
-  memset(&sin, 0, sizeof(sin));
-  sin.sin_family = AF_INET;
-  if ((h = gethostbyname(av[2])) == 0)
-    die(1, "gethostbyname `%s'", av[2]);
   if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) ||
       setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len)))
     die(1, "setsockopt: %s", strerror(errno));
   if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) ||
       setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &len, sizeof(len)))
     die(1, "setsockopt: %s", strerror(errno));
-  memcpy(&sin.sin_addr, h->h_addr, sizeof(sin.sin_addr));
-  sin.sin_port = htons(atoi(av[3]));
-  if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)))
+  if (connect(fd, ai1->ai_addr, ai1->ai_addrlen))
     die(1, "connect: %s", strerror(errno));
   sel_initfile(&sel, &p->sf, fd, SEL_READ, dopacket, p);
   sel_addfile(&p->sf);
     die(1, "connect: %s", strerror(errno));
   sel_initfile(&sel, &p->sf, fd, SEL_READ, dopacket, p);
   sel_addfile(&p->sf);
+  freeaddrinfo(ai0); freeaddrinfo(ai1);
 }
 
 }
 
+static void addpeer(unsigned ac, char **av)
+  { addpeer_common("peer", AF_UNSPEC, ac, av); }
+static void addpeer4(unsigned ac, char **av)
+  { addpeer_common("peer4", AF_INET, ac, av); }
+static void addpeer6(unsigned ac, char **av)
+  { addpeer_common("peer6", AF_INET6, ac, av); }
+
 /*----- Fork filter -------------------------------------------------------*/
 
 typedef struct forknode {
 /*----- Fork filter -------------------------------------------------------*/
 
 typedef struct forknode {
@@ -550,6 +559,8 @@ const struct cmdtab {
   void (*func)(unsigned /*ac*/, char **/*av*/);
 } cmdtab[] = {
   { "peer",    addpeer },
   void (*func)(unsigned /*ac*/, char **/*av*/);
 } cmdtab[] = {
   { "peer",    addpeer },
+  { "peer4",   addpeer4 },
+  { "peer6",   addpeer6 },
   { "include", include },
   { "filt",    addfilter },
   { "lfilt",   addlfilter },
   { "include", include },
   { "filt",    addfilter },
   { "lfilt",   addlfilter },
@@ -609,7 +620,7 @@ Options:\n\
 -k, --keyring=FILE     Fetch keys from FILE.\n\
 \n\
 Directives:\n\
 -k, --keyring=FILE     Fetch keys from FILE.\n\
 \n\
 Directives:\n\
-  peer:NAME:LOCAL-PORT:REMOTE-ADDR:REMOTE-PORT\n\
+  peer{,4,6}:NAME:LOCAL-PORT:REMOTE-ADDR:REMOTE-PORT\n\
   include:FILE\n\
   {,l,r}filt:FILTER:ARGS:...\n\
   next:TAG\n\
   include:FILE\n\
   {,l,r}filt:FILTER:ARGS:...\n\
   next:TAG\n\