X-Git-Url: https://git.distorted.org.uk/~mdw/tripe/blobdiff_plain/9f90c1f6d21867ca0e1a2b42a9514299221cbe1d..HEAD:/proxy/tripe-mitm.c diff --git a/proxy/tripe-mitm.c b/proxy/tripe-mitm.c index ab05a882..648296ee 100644 --- a/proxy/tripe-mitm.c +++ b/proxy/tripe-mitm.c @@ -97,6 +97,7 @@ static peer peers[2]; static unsigned npeer = 0; static key_file keys; static grand *rng; +static const char *delim = ":"; #define PASS(f, buf, sz) ((f) ? (f)->func((f), (buf), (sz)) : (void)0) #define RND(i) (rng->ops->range(rng, (i))) @@ -114,43 +115,76 @@ 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; + const char *outf, *serv; + FILE *fp; + union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } addr; + socklen_t salen; + int err; peer *p; - int fd; + int fd, port; - 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)); + if (*av[1] == '?') { serv = "0"; outf = av[1] + 1; } + else { serv = av[1]; outf = 0; } + aihint.ai_family = ai1->ai_family; + aihint.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; + if ((err = getaddrinfo(0, serv, &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)); + if (outf) { + salen = sizeof(addr); + if (getsockname(fd, &addr.sa, &salen)) + die(1, "getsockname: %s", strerror(errno)); + switch (addr.sa.sa_family) { + case AF_INET: port = ntohs(addr.sin.sin_port); break; + case AF_INET6: port = ntohs(addr.sin6.sin6_port); break; + default: assert(0); + } + fp = fopen(outf, "w"); + if (!fp) die(1, "fopen(%s): %s", outf, strerror(errno)); + fprintf(fp, "%d\n", port); + fclose(fp); + } 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 { @@ -549,6 +583,8 @@ const struct cmdtab { void (*func)(unsigned /*ac*/, char **/*av*/); } cmdtab[] = { { "peer", addpeer }, + { "peer4", addpeer4 }, + { "peer6", addpeer6 }, { "include", include }, { "filt", addfilter }, { "lfilt", addlfilter }, @@ -568,11 +604,11 @@ static void parse(char *p) unsigned c = 0; const struct cmdtab *ct; - p = strtok(p, ":"); + p = strtok(p, delim); if (!p || *p == '#') return; do { v[c++] = p; - p = strtok(0, ":"); + p = strtok(0, delim); } while (p && c < AVMAX - 1); v[c] = 0; for (ct = cmdtab; ct->name; ct++) { @@ -590,7 +626,7 @@ static void version(FILE *fp) { pquis(fp, "$, TrIPE version " VERSION "\n"); } static void usage(FILE *fp) - { pquis(fp, "Usage: $ [-k KEYRING] DIRECTIVE...\n"); } + { pquis(fp, "Usage: $ [-d CHAR] [-k KEYRING] DIRECTIVE...\n"); } static void help(FILE *fp) { @@ -604,10 +640,11 @@ Options:\n\ -v, --version Show the version number.\n\ -u, --usage Show terse usage summary.\n\ \n\ +-d, --delimiter=CHAR Use CHAR rather than `:' as delimiter.\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\ @@ -638,14 +675,20 @@ int main(int argc, char *argv[]) { "help", 0, 0, 'h' }, { "version", 0, 0, 'v' }, { "usage", 0, 0, 'u' }, + { "delimiter", OPTF_ARGREQ, 0, 'd' }, { "keyring", OPTF_ARGREQ, 0, 'k' }, { 0, 0, 0, 0 } }; - if ((i = mdwopt(argc, argv, "hvuk:", opt, 0, 0, 0)) < 0) break; + if ((i = mdwopt(argc, argv, "hvud:k:", opt, 0, 0, 0)) < 0) break; switch (i) { case 'h': help(stdout); exit(0); case 'v': version(stdout); exit(0); case 'u': usage(stdout); exit(0); + case 'd': + if (!optarg[0] || optarg[1]) + die(1, "delimiter must be a single character"); + delim = optarg; + break; case 'k': kfname = optarg; break; default: f |= f_bogus; break; }