/*
- * Encrypting tunnel for userv-ipif tunnels, actual implementation
- *
+ * Encrypting tunnel for userv-ipif tunnels, actual core implementation
+ */
+/*
* usage:
* udptunnel-forwarder <optchars>
* <public-local-fd> <private-in-fd> <private-out-fd>
* <encdec-keys-fd>
- * <mtu> <keepalive> <timeout>
+ * <mtu> <keepalive> <timeout> <reannounce>
* <public-remote-addr> [<public-remote-port>]
- * <mech1> [<mech1-params> ...]
- * <mech2> [<mech2-params> ...]
+ * |<mech1> [<mech1-params> ...]
+ * |<mech2> [<mech2-params> ...]
* ''
*
* Remote addr may '' to mean wait to receive a packet and reply to
*
* <optchars> 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
* 12 usage error
* 16 bad trouble
*/
+/*
+ * This file is part of ipif, part of userv-utils
+ *
+ * Copyright 1996-2013 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright 1998 David Damerell <damerell@chiark.greenend.org.uk>
+ * Copyright 1999,2003
+ * Chancellor Masters and Scholars of the University of Cambridge
+ * Copyright 2010 Tony Finch <fanf@dotat.at>
+ *
+ * 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 <sys/socket.h>
#include <netinet/in.h>
#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;
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;
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; i<skipbefore) fputs(" ..",stdout);
- for (i=0, p=ptr; i<sz; i++, p++) fprintf(" %02x",*p);
- for (i=0; i<skipafter) fputs(" ..",stdout);
+
+ for (i=0; i<spc_offset; i++, j++) fputs(j&3 ? " " : " ",stdout);
+ for (i=0; i<skipbefore; i++, j++) fputs(j&3 ? ".." : " ..",stdout);
+ for (i=0, p=ptr; i<sz; i++, j++, p++) printf(j&3 ? "%02x" : " %02x",*p);
+
fputc('\n',stdout);
}
+static void cdebugbuf(int mechno /*or -1*/, const char *msg,
+ const struct buffer *buf, int spc_offset, int dot_offset) {
+ cdebughex(mechno, msg, buf->start, buf->size, buf->start - buf->base,
+ spc_offset, dot_offset);
+}
+
void get_random(void *ptr, size_t sz) {
static FILE *randfile;
}
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) {
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);
}
}
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++)
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;
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 ||
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) {
nextsendka= now() + keepalive;
- for (i=0; i<n_mechs; i++) mechs[i]->encode(md_out[i],&buf_out);
+ cdebugbuf(-1, "encode", &buf_out, 4,0);
+ for (i=0; i<n_mechs; i++) {
+ mechs[i]->encode(md_out[i],&buf_out);
+ cdebugbuf(i, "encode", &buf_out, 4,0);
+ }
assert(public_remote_specd);
setnonblock(public_local_fd,1);
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;
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();
mtu2= getarg_ulong() * 2;
keepalive= getarg_ulong();
timeout= getarg_ulong();
+ reannounce= getarg_ulong();
arg= getarg_string();
if (*arg) {
}
maxprefix= 0;
- for (i=0; i<n_mechs; i++) {
- mechs[i]= getarg_mech();
- }
- for (i=0; i<n_mechs; i++) {
- cdebug(i,"encrypt setup");
- mechs[i]->encsetup(&md_in[i], &maxprefix, &maxsuffix);
- }
- for (i=0; i<n_mechs; i++) {
- cdebug(i,"decrypt setup");
- mechs[i]->decsetup(&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;
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;