X-Git-Url: https://git.distorted.org.uk/~mdw/userv-utils/blobdiff_plain/1fb3cba0b41ae774f83c11d2a9c23b12b2c87d1a..0f91e8747cef1e27788ddce4b32563e0c105dbb3:/ipif/forwarder.c?ds=sidebyside diff --git a/ipif/forwarder.c b/ipif/forwarder.c index ae32786..793ad24 100644 --- a/ipif/forwarder.c +++ b/ipif/forwarder.c @@ -1,20 +1,28 @@ /* * Encrypting tunnel for userv-ipif tunnels, actual implementation - * + */ +/* * usage: - * udptunnel-forwarder - * + * udptunnel-forwarder + * + * + * * [] - * - * [ ...] - * [ ...] + * | [ ...] + * | [ ...] * '' * * Remote addr may '' to mean wait to receive a packet and reply to * whereever we get a good packet from first, in which case port * should not be specified. * - * is '' to mean read, anything else to mean write. + * is zero or more of + * w means generate and write encdec keys, rather than reading them + * 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. * @@ -26,6 +34,23 @@ * 12 usage error * 16 bad trouble */ +/* + * Copyright (C) 2000 Ian Jackson + * + * 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 2 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, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ #include #include @@ -41,20 +66,19 @@ #include #include -#include "mech.h" +#include "forwarder.h" #define MAXMECHS 10 -#define PROGRAM "udptunnel-forwarder" -char programid[SYS_NMLN+sizeof(PROGRAM)+3]; -static const char *const *argv; 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; +static int encdec_keys_fd, encdec_keys_write, crypto_debug; static int n_mechs; static const struct mechanism *mechs[MAXMECHS]; @@ -67,41 +91,38 @@ static size_t accum_used, accum_avail; static time_t nextsendka; - -void arg_assert_fail(const char *msg) { - fprintf(stderr, PROGRAM ": argument error: %s\n",msg); - exit(12); -} - -void sysfail(const char *msg) { - fprintf(stderr, "%s: fatal system error: %s: %s\n", programid, msg, strerror(errno)); - exit(8); -} - -void fail(const char *msg) { - fprintf(stderr, "%s: fatal error: %s\n", programid, msg); - exit(4); +static void cdebug(int mechno /*or -1*/, const char *msg) { + if (!crypto_debug) return; + printf("%-8.8s: CRYPTO: %-20s %s\n", + uname_result.nodename, + mechno >= 0 ? mechs[mechno]->name : "", + msg); } -void sysdiag(const char *msg) { - fprintf(stderr, "%s: system/network error: %s: %s\n", programid, msg, strerror(errno)); -} +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("%-8.8s: CRYPTO: %-20s %-10s", + uname_result.nodename, + mechno >= 0 ? mechs[mechno]->name : "", + msg); -void diag(const char *msg) { - fprintf(stderr, "%s: %s\n", programid, msg); -} + for (i=0; istart, buf->size, buf->start - buf->base, + spc_offset, dot_offset); } void get_random(void *ptr, size_t sz) { @@ -116,27 +137,23 @@ 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"); -const char *getarg_string(void) { - const char *arg; - - arg= *++argv; - arg_assert(arg); - return arg; + cdebughex(-1, "get_random", ptr, sz, 0,0,0); } -unsigned long getarg_ulong(void) { - char *ep; - unsigned long ul; - - ul= strtoul(getarg_string(),&ep,0); - arg_assert(!*ep); - return ul; +void random_key(void *ptr, size_t sz) { + if (encdec_keys_write) { + get_random(ptr,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); + } } + static void setnonblock(int fd, int nonblock) { int r; @@ -146,12 +163,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++) @@ -164,55 +178,69 @@ 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; const char *emsg; - alarm(timeout); - + buf_in.start= buf_in.base+1; + buf_in.size= buffer_size-2; + setnonblock(public_local_fd,1); this_saddrlen= sizeof(this_saddr); - r= recvfrom(public_local_fd, buf_in.base, buffer_size-1, 0, + r= recvfrom(public_local_fd, buf_in.start, buf_in.size, 0, &this_saddr, &this_saddrlen); if (!r) { diag("empty ciphertext"); return; } if (r<0) { - if (errno != EAGAIN && errno != EINTR) sysdiag("receive"); + if (errno != EAGAIN && errno != EINTR) { sysdiag("receive"); sleep(1); } return; } if (this_saddr.sin_family != AF_INET) { - fprintf(stderr,"%s: received unknown AF %lu", + fprintf(stderr,"%s: received unknown AF %lu\n", programid, (unsigned long)this_saddr.sin_family); return; } assert(this_saddrlen == sizeof(this_saddr)); - buf_in.size= buffer_size; - buf_in.start= buf_in.base; + 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); } - different= !public_remote_specd || - memcmp(&this_saddr,&public_remote,sizeof(this_saddr)); + npackets++; + nbytes += buf_in.size; + alarm(timeout); + + different= (!public_remote_specd || + public_remote.sin_addr.s_addr != this_saddr.sin_addr.s_addr || + public_remote.sin_port != this_saddr.sin_port); if (different) { if (public_remote_specd==2) { - fprintf(stderr, "%s: packet from unexpected sender %s:%lu", + fprintf(stderr, "%s: packet from unexpected sender %s:%lu\n", programid, inet_ntoa(this_saddr.sin_addr), - (unsigned long)this_saddr.sin_port); + (unsigned long)ntohs(this_saddr.sin_port)); return; } - fprintf(stderr, "%s: tunnel open with peer %s:%lu", + fprintf(stderr, "%s: tunnel open with peer %s:%lu\n", programid, inet_ntoa(this_saddr.sin_addr), - (unsigned long)this_saddr.sin_port); + (unsigned long)ntohs(this_saddr.sin_port)); nextsendka= now(); public_remote_specd= 1; memcpy(&public_remote,&this_saddr,sizeof(public_remote)); @@ -221,25 +249,34 @@ 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. */ + } - any_recvd= 1; + if (reannounce) + nextreann= now() + reannounce; - buf_in.start[buf_in.size]= 0300; - *--buf_in.start= 0300; - buf_in.size+= 2; +no_set_reann: - setnonblock(private_in_fd,0); - while (buf_in.size) { - r= write(private_in_fd, buf_in.start, buf_in.size); - assert(r && r <= buf_in.size); - if (r<0) { - if (errno == EINTR) continue; - sysfail("write down"); - } - buf_in.start += r; - buf_in.size -= r; + any_recvd= 1; + + if (!buf_in.size || *buf_in.start != 0300) { + *--buf_in.start= 0300; + buf_in.size++; } + if (buf_in.start[buf_in.size-1] != 0300) { + buf_in.start[buf_in.size++]= 0300; + } + + setnonblock(private_in_fd,0); + write_must(private_in_fd, buf_in.start, buf_in.size, "write down"); } static void sendpacket(const unsigned char *message, size_t size) { @@ -251,7 +288,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); @@ -284,7 +325,7 @@ static void outbound(void) { after_eaten= accum_buf; while ((delim= memchr(after_eaten, 0300, accum_used))) { this_packet= delim - after_eaten; - sendpacket(after_eaten, this_packet); + if (this_packet) sendpacket(after_eaten, this_packet); accum_used -= this_packet+1; after_eaten = delim+1; } @@ -299,8 +340,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; @@ -308,28 +350,63 @@ int main(int argc, const char *const *const argv_in) { if (uname(&uname_result)) { perror(PROGRAM ": uname failed"); exit(16); } 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,'K'); + public_local_fd= getarg_ulong(); + private_in_fd= getarg_ulong(); + private_out_fd= getarg_ulong(); + encdec_keys_fd= getarg_ulong(); + mtu2= getarg_ulong() * 2; keepalive= getarg_ulong(); timeout= getarg_ulong(); - private_in_fd= getarg_ulong(); - private_out_fd= getarg_ulong(); + reannounce= getarg_ulong(); arg= getarg_string(); if (*arg) { public_remote_specd= 1; + public_remote.sin_family= AF_INET; arg_assert(inet_aton(arg,&public_remote.sin_addr)); - public_remote.sin_port= getarg_ulong(); + public_remote.sin_port= htons(getarg_ulong()); } - encdec_keys_fd= getarg_ulong(); - encdec_keys_write= !!*getarg_string(); + if (crypto_debug) { + diag("crypto debugging enabled!"); + setvbuf(stdout,0,_IOLBF,0); + } 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; @@ -351,7 +428,7 @@ int main(int argc, const char *const *const argv_in) { if (keepalive) { tnow= now(); - if (tnow >= nextsendka) sendpacket("\300",1); + if (tnow >= nextsendka && public_remote_specd) sendpacket("\300",1); polltimeout= (nextsendka - tnow)*1000; } else { polltimeout= -1; @@ -362,7 +439,7 @@ int main(int argc, const char *const *const argv_in) { if (r==-1 && errno==EINTR) continue; if (r==-1) sysfail("poll"); - if (pollfds[0].revents & POLLIN) inbound(); - if (pollfds[1].revents & POLLOUT) outbound(); + if (pollfds[0].revents & (POLLIN|POLLERR)) inbound(); + if (pollfds[1].revents & (POLLIN|POLLERR)) outbound(); } }