chiark / gitweb /
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 3a91258ce7a77fbd882e7be5ae1112ca18e88b54..e939919e1f58ebcd06f460835cfa040e71f4f789 100644 (file)
@@ -119,9 +119,11 @@ Both
 .I local-port
 and
 .I remote-port
-must be numbers;
+may be numbers or UDP service names;
 .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
@@ -131,6 +133,16 @@ peer.  The two peers must use
 .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 .
index 2530f15118a99336a07825b7daba21afcff66b7e..6acf2a1df4b996ccc3bafe99da87ffcfe4fe336e 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;
 
-  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 ((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));
-  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));
-  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));
-  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);
+  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 {
@@ -550,6 +559,8 @@ const struct cmdtab {
   void (*func)(unsigned /*ac*/, char **/*av*/);
 } cmdtab[] = {
   { "peer",    addpeer },
+  { "peer4",   addpeer4 },
+  { "peer6",   addpeer6 },
   { "include", include },
   { "filt",    addfilter },
   { "lfilt",   addlfilter },
@@ -609,7 +620,7 @@ Options:\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\