X-Git-Url: https://git.distorted.org.uk/~mdw/userv-utils/blobdiff_plain/09966b4959fa31ea3f6746b6b6583907744484e1..f2add8c1b19c46ff78655278643c3c2851db7566:/ipif/forwarder.c diff --git a/ipif/forwarder.c b/ipif/forwarder.c index 015afbd..d92fdd9 100644 --- a/ipif/forwarder.c +++ b/ipif/forwarder.c @@ -1,14 +1,15 @@ /* - * Encrypting tunnel for userv-ipif tunnels, actual implementation - * + * Encrypting tunnel for userv-ipif tunnels, actual core implementation + */ +/* * usage: * udptunnel-forwarder * * - * + * * [] - * [ ...] - * [ ...] + * | [ ...] + * | [ ...] * '' * * Remote addr may '' to mean wait to receive a packet and reply to @@ -17,9 +18,13 @@ * * is zero or more of * w means generate and write encdec keys, rather than reading them - * D means do crypto debug (use with care!) + * K means do crypto debug (use with care!) + * + * encdec keys datastream has keys for packets from key datastream + * writer to reader first, then keys for packets from reader to + * writer. * - * Every must be numeric. There is very little argument checking. + * Every addr or port must be numeric. There is very little argument checking. * * Exit status: * SIGALARM timed out @@ -29,6 +34,28 @@ * 12 usage error * 16 bad trouble */ +/* + * This file is part of ipif, part of userv-utils + * + * Copyright 1996-2013 Ian Jackson + * Copyright 1998 David Damerell + * Copyright 1999,2003 + * Chancellor Masters and Scholars of the University of Cambridge + * Copyright 2010 Tony Finch + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with userv-utils; if not, see http://www.gnu.org/licenses/. + */ #include #include @@ -49,10 +76,11 @@ #define MAXMECHS 10 static size_t buffer_size; +static struct utsname uname_result; static const char *opt_chars; static int public_local_fd, private_in_fd, private_out_fd; -static int mtu2, keepalive, timeout; +static int mtu2, keepalive, timeout, reannounce; static int public_remote_specd; static struct sockaddr_in public_remote; static int encdec_keys_fd, encdec_keys_write, crypto_debug; @@ -60,7 +88,7 @@ static int n_mechs; static const struct mechanism *mechs[MAXMECHS]; static struct mechdata *md_in[MAXMECHS], *md_out[MAXMECHS]; -static size_t maxprefix, maxsuffix; +static int maxprefix, maxsuffix; static struct buffer buf_in, buf_out; static unsigned char *accum_buf; @@ -70,27 +98,38 @@ static time_t nextsendka; static void cdebug(int mechno /*or -1*/, const char *msg) { if (!crypto_debug) return; - printf("%s: CRYPTO: %-20s encrypt setup\n", - programid, - mechno >= 0 ? mechs[i]->name : "", + printf("%-8.8s: CRYPTO: %-20s %s\n", + uname_result.nodename, + mechno >= 0 ? mechs[mechno]->name : "", msg); } -static void cdebughex(int mechno /*or -1*/, const char *msg, - size_t skipbefore, const void *ptr, size_t sz, size_t skipafter) { +static void cdebughex(int mechno /*or -1*/, const char *msg, const void *ptr, + size_t sz, size_t skipbefore, + int spc_offset, int dot_offset) { const unsigned char *p; + size_t i; + unsigned j= dot_offset; if (!crypto_debug) return; - printf("%s: CRYPTO: %-20s %s", - programid, - mechno >= 0 ? mechs[i]->name : "", + printf("%-8.8s: CRYPTO: %-20s %-10s", + uname_result.nodename, + mechno >= 0 ? mechs[mechno]->name : "", msg); - for (i=0; istart, buf->size, buf->start - buf->base, + spc_offset, dot_offset); +} + void get_random(void *ptr, size_t sz) { static FILE *randfile; @@ -103,10 +142,10 @@ void get_random(void *ptr, size_t sz) { } r= fread(ptr,1,sz,randfile); - if (r == sz) return; - (ferror(randfile) ? sysfail : fail)("cannot read random number generator"); + if (r != sz) + (ferror(randfile) ? sysfail : fail)("cannot read random number generator"); - cdebughex(-1, "get_random", ptr, sz, 0,0); + cdebughex(-1, "get_random", ptr, sz, 0,0,0); } void random_key(void *ptr, size_t sz) { @@ -115,6 +154,7 @@ void random_key(void *ptr, size_t sz) { write_must(encdec_keys_fd,ptr,sz,"write keys datastream"); } else { read_must(encdec_keys_fd,ptr,sz,"read keys datastream"); + cdebughex(-1, "random_key", ptr, sz, 0,0,0); } } @@ -128,12 +168,9 @@ static void setnonblock(int fd, int nonblock) { if (r==-1) sysfail("fcntl F_SETFL"); } -static const struct mechanism *getarg_mech(void) { - const char *name; +static const struct mechanism *find_mech(const char *name) { const struct mechanism *mech, *const *mechlist; - name= getarg_string(); - for (mechlist= mechanismlists; *mechlist; mechlist++) @@ -146,9 +183,12 @@ static const struct mechanism *getarg_mech(void) { static void inbound(void) { static int any_recvd; + static time_t nextreann; + static unsigned long npackets, nbytes; struct sockaddr_in this_saddr; - int r, i, different, this_saddrlen; + size_t this_saddrlen; + int r, i, different; const char *emsg; buf_in.start= buf_in.base+1; @@ -173,14 +213,22 @@ static void inbound(void) { assert(r <= buf_in.size); buf_in.size= r; + cdebugbuf(-1, "decode", &buf_in, 3,0); for (i=n_mechs-1; i>=0; i--) { emsg= mechs[i]->decode(md_in[i],&buf_in); if (emsg) { - fprintf(stderr, "%s: bad packet: %s: %s\n", programid, mechs[i]->name, emsg); + if (*emsg) + fprintf(stderr, "%s: bad packet: %s: %s\n", + programid, mechs[i]->name, emsg); + else + cdebug(i,"silently discarded"); return; } + cdebugbuf(i, "decode", &buf_in, 3,0); } + npackets++; + nbytes += buf_in.size; alarm(timeout); different= (!public_remote_specd || @@ -207,8 +255,22 @@ static void inbound(void) { diag("tunnel open"); + } else if (reannounce && now() >= nextreann) { + + fprintf(stderr, "%s: tunnel still open: received %lu packets, %lu bytes\n", + programid, npackets, nbytes); + + } else { + + goto no_set_reann; /* only reset this if we don't print a message. */ + } + if (reannounce) + nextreann= now() + reannounce; + +no_set_reann: + any_recvd= 1; if (!buf_in.size || *buf_in.start != 0300) { @@ -232,7 +294,11 @@ static void sendpacket(const unsigned char *message, size_t size) { nextsendka= now() + keepalive; - for (i=0; iencode(md_out[i],&buf_out); + cdebugbuf(-1, "encode", &buf_out, 4,0); + for (i=0; iencode(md_out[i],&buf_out); + cdebugbuf(i, "encode", &buf_out, 4,0); + } assert(public_remote_specd); setnonblock(public_local_fd,1); @@ -280,8 +346,9 @@ static void outbound(void) { int main(int argc, const char *const *const argv_in) { const char *arg; + const char *const *argv_save; + const char *const *argv_done; struct pollfd pollfds[2]; - struct utsname uname_result; int i, polltimeout, r; time_t tnow; @@ -291,8 +358,8 @@ int main(int argc, const char *const *const argv_in) { sprintf(programid, PROGRAM ": %.*s", SYS_NMLN, uname_result.nodename); opt_chars= getarg_string(); - encdec_keys_write= !!strchr(opt_chars,"w"); - crypto_debug= !!strchr(opt_chars,"D"); + encdec_keys_write= !!strchr(opt_chars,'w'); + crypto_debug= !!strchr(opt_chars,'K'); public_local_fd= getarg_ulong(); private_in_fd= getarg_ulong(); @@ -302,6 +369,7 @@ int main(int argc, const char *const *const argv_in) { mtu2= getarg_ulong() * 2; keepalive= getarg_ulong(); timeout= getarg_ulong(); + reannounce= getarg_ulong(); arg= getarg_string(); if (*arg) { @@ -317,17 +385,34 @@ int main(int argc, const char *const *const argv_in) { } maxprefix= 0; - for (i=0; iencsetup(&md_in[i], &maxprefix, &maxsuffix); - } - for (i=0; idecsetup(&md_out[i]); + i= 0; + while ((arg= *++argv)) { + arg_assert(*arg++ == '|'); + arg_assert(i <= MAXMECHS); + mechs[i]= find_mech(arg); + + cdebug(i,"writer->reader setup"); + argv_save= argv; + + if (encdec_keys_write) + mechs[i]->encsetup(&md_out[i], &maxprefix, &maxsuffix); + else + mechs[i]->decsetup(&md_in[i]); + + argv_done= argv; + argv= argv_save; + cdebug(i,"reader->writer setup"); + + if (encdec_keys_write) + mechs[i]->decsetup(&md_in[i]); + else + mechs[i]->encsetup(&md_out[i], &maxprefix, &maxsuffix); + + assert(argv == argv_done); + + i++; } + n_mechs= i; if (maxprefix<1) maxprefix= 1; if (maxsuffix<1) maxsuffix= 1; @@ -349,7 +434,8 @@ int main(int argc, const char *const *const argv_in) { if (keepalive) { tnow= now(); - if (tnow >= nextsendka && public_remote_specd) sendpacket("\300",1); + if (tnow >= nextsendka && public_remote_specd) + sendpacket((unsigned char*)"\300",1); polltimeout= (nextsendka - tnow)*1000; } else { polltimeout= -1;