From 1fb3cba0b41ae774f83c11d2a9c23b12b2c87d1a Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 29 May 2000 17:16:29 +0000 Subject: [PATCH] @@ -1,6 +1,7 @@ + * Embryonic new version of udptunnel. --- changelog | 1 + debian/changelog | 1 + ipif/.cvsignore | 1 + ipif/Makefile | 16 +- ipif/automechgen.sh | 29 ++++ ipif/blowfish.c | 34 ++-- ipif/blowfish.h | 32 ++-- ipif/forwarder.c | 368 ++++++++++++++++++++++++++++++++++++++++++ ipif/forwarder.h | 83 ++++++++++ ipif/mech-blowfish.c | 108 +++++++++++++ ipif/mech-null.c | 11 ++ ipif/mech-pkcs5.c | 72 +++++++++ ipif/mech-sequence.c | 65 ++++++++ ipif/mech-timestamp.c | 68 ++++++++ ipif/udptunnel | 18 ++- 15 files changed, 871 insertions(+), 36 deletions(-) create mode 100755 ipif/automechgen.sh create mode 100644 ipif/forwarder.c create mode 100644 ipif/forwarder.h create mode 100644 ipif/mech-blowfish.c create mode 100644 ipif/mech-null.c create mode 100644 ipif/mech-pkcs5.c create mode 100644 ipif/mech-sequence.c create mode 100644 ipif/mech-timestamp.c diff --git a/changelog b/changelog index 80a0170..0bcd30b 100644 --- a/changelog +++ b/changelog @@ -1,6 +1,7 @@ userv (0.2) unstable; urgency=low * Embryonic new finger program. + * Embryonic new version of udptunnel. -- diff --git a/debian/changelog b/debian/changelog index 80a0170..0bcd30b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ userv (0.2) unstable; urgency=low * Embryonic new finger program. + * Embryonic new version of udptunnel. -- diff --git a/ipif/.cvsignore b/ipif/.cvsignore index 24e1098..03796d0 100644 --- a/ipif/.cvsignore +++ b/ipif/.cvsignore @@ -1 +1,2 @@ service +automech.[ch] diff --git a/ipif/Makefile b/ipif/Makefile index d7bf43f..4637bbc 100644 --- a/ipif/Makefile +++ b/ipif/Makefile @@ -30,7 +30,12 @@ libuserv= $(libdir)/userv etcuserv= $(etcdir)/userv services= $(etcuserv)/services.d -TARGETS= service +TARGETS= service udptunnel-forwarder + +MECHFILES= null pkcs5 timestamp sequence blowfish +MECHOBJS= $(foreach m, $(MECHFILES), mech-$m.o) + +OBJS_FORWARD= forwarder.o $(MECHOBJS) blowfish.o automech.c all: $(TARGETS) @@ -40,3 +45,12 @@ install: all cp ipif $(services)/ipif:new cp -b udptunnel $(bindir)/. set -e; cd $(services); test -f ipif || mv ipif:new ipif + +udptunnel-forwarder: $(OBJS_FORWARD) + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJS_FORWARD) + +automech.c automech.h: automechgen.sh Makefile + ./$< $(MECHFILES) + +forwarder.o $(MECHOBJS) automech.o: mech.h automech.h +blowfish.o mech-blowfish.o: blowfish.h diff --git a/ipif/automechgen.sh b/ipif/automechgen.sh new file mode 100755 index 0000000..bfa1c87 --- /dev/null +++ b/ipif/automechgen.sh @@ -0,0 +1,29 @@ +#!/bin/sh +exec >automech.c.new +exec 3>automech.h.new + +cat <&3 <&3 +done + +cat <&3 < #include @@ -26,8 +25,9 @@ static const blowfish__s init_s; #define GETWORD(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|((p)[3])) #define PUTWORD(w,p) ((p)[0]=(w)>>24,(p)[1]=(w)>>16,(p)[2]=(w)>>8,(p)[3]=(w)) -static void encipher(const struct blowfish_expandedkey *ek, uint32 *xlp, uint32 *xrp) { - uint32 xl, xr; +static void encipher(const struct blowfish_expandedkey *ek, + uint32_t *xlp, uint32_t *xrp) { + uint32_t xl, xr; xl= *xlp; xr= *xrp; @@ -47,8 +47,9 @@ static void encipher(const struct blowfish_expandedkey *ek, uint32 *xlp, uint32 *xlp= xr; } -static void decipher(const struct blowfish_expandedkey *ek, uint32 *xlp, uint32 *xrp) { - uint32 xl, xr; +static void decipher(const struct blowfish_expandedkey *ek, + uint32_t *xlp, uint32_t *xrp) { + uint32_t xl, xr; xl= *xlp; xr= *xrp; @@ -68,9 +69,10 @@ static void decipher(const struct blowfish_expandedkey *ek, uint32 *xlp, uint32 *xrp= xl; } -void blowfish_loadkey(struct blowfish_expandedkey *ek, const uint8 *key, int keybytes) { +void blowfish_loadkey(struct blowfish_expandedkey *ek, + const uint8_t *key, int keybytes) { int i, j; - uint32 data, datal, datar; + uint32_t data, datal, datar; assert(keybytes>0 && keybytes<=BLOWFISH_MAXKEYBYTES); memcpy(ek->s,init_s,sizeof(ek->s)); @@ -103,8 +105,8 @@ void blowfish_loadkey(struct blowfish_expandedkey *ek, const uint8 *key, int key } void blowfish_encrypt(const struct blowfish_expandedkey *ek, - const uint8 plain[], uint8 cipher[]) { - uint32 datal, datar; + const uint8_t plain[], uint8_t cipher[]) { + uint32_t datal, datar; datal= GETWORD(plain); datar= GETWORD(plain+4); @@ -114,8 +116,8 @@ void blowfish_encrypt(const struct blowfish_expandedkey *ek, } void blowfish_decrypt(const struct blowfish_expandedkey *ek, - const uint8 cipher[], uint8 plain[]) { - uint32 datal, datar; + const uint8_t cipher[], uint8_t plain[]) { + uint32_t datal, datar; datal= GETWORD(cipher); datar= GETWORD(cipher+4); @@ -124,14 +126,14 @@ void blowfish_decrypt(const struct blowfish_expandedkey *ek, PUTWORD(datar,plain+4); } -void blowfish_cbc_setiv(struct blowfish_cbc_state *cs, const uint8 iv[]) { +void blowfish_cbc_setiv(struct blowfish_cbc_state *cs, const uint8_t iv[]) { cs->chainl= GETWORD(iv); cs->chainr= GETWORD(iv+4); } void blowfish_cbc_encrypt(struct blowfish_cbc_state *cs, - const uint8 plain[], uint8 cipher[]) { - uint32 datal, datar; + const uint8_t plain[], uint8_t cipher[]) { + uint32_t datal, datar; datal= GETWORD(plain); datar= GETWORD(plain+4); @@ -145,8 +147,8 @@ void blowfish_cbc_encrypt(struct blowfish_cbc_state *cs, } void blowfish_cbc_decrypt(struct blowfish_cbc_state *cs, - const uint8 cipher[], uint8 plain[]) { - uint32 datal, datar, cipherl, cipherr; + const uint8_t cipher[], uint8_t plain[]) { + uint32_t datal, datar, cipherl, cipherr; datal= GETWORD(cipher); datar= GETWORD(cipher+4); diff --git a/ipif/blowfish.h b/ipif/blowfish.h index 8eb3275..af02c07 100644 --- a/ipif/blowfish.h +++ b/ipif/blowfish.h @@ -3,40 +3,46 @@ #ifndef BLOWFISH__H_INCLUDED #define BLOWFISH__H_INCLUDED +#include + #define BLOWFISH_BLOCKBYTES 8 #define BLOWFISH_MAXKEYBYTES 56 #define BLOWFISH__N 16 #define BLOWFISH__PSIZE BLOWFISH__N+2 -typedef uint32 blowfish__p[BLOWFISH__PSIZE]; -typedef uint32 blowfish__s[4][256]; +typedef uint32_t blowfish__p[BLOWFISH__PSIZE]; +typedef uint32_t blowfish__s[4][256]; struct blowfish_expandedkey { blowfish__p p; blowfish__s s; }; +/* It's ok to pass the [_cbc]_(en|de)crypt functions the same + * input and output pointers. + */ + void blowfish_loadkey(struct blowfish_expandedkey *ek, - const uint8 *key, int keybytes); + const uint8_t *key, int keybytes); void blowfish_encrypt(const struct blowfish_expandedkey *ek, - const uint8 plain[BLOWFISH_BLOCKBYTES], - uint8 cipher[BLOWFISH_BLOCKBYTES]); + const uint8_t plain[BLOWFISH_BLOCKBYTES], + uint8_t cipher[BLOWFISH_BLOCKBYTES]); void blowfish_decrypt(const struct blowfish_expandedkey *ek, - const uint8 cipher[BLOWFISH_BLOCKBYTES], - uint8 plain[BLOWFISH_BLOCKBYTES]); + const uint8_t cipher[BLOWFISH_BLOCKBYTES], + uint8_t plain[BLOWFISH_BLOCKBYTES]); struct blowfish_cbc_state { struct blowfish_expandedkey ek; - uint32 chainl, chainr; + uint32_t chainl, chainr; }; void blowfish_cbc_setiv(struct blowfish_cbc_state *cs, - const uint8 iv[BLOWFISH_BLOCKBYTES]); + const uint8_t iv[BLOWFISH_BLOCKBYTES]); void blowfish_cbc_encrypt(struct blowfish_cbc_state *cs, - const uint8 plain[BLOWFISH_BLOCKBYTES], - uint8 cipher[BLOWFISH_BLOCKBYTES]); + const uint8_t plain[BLOWFISH_BLOCKBYTES], + uint8_t cipher[BLOWFISH_BLOCKBYTES]); void blowfish_cbc_decrypt(struct blowfish_cbc_state *cs, - const uint8 cipher[BLOWFISH_BLOCKBYTES], - uint8 plain[BLOWFISH_BLOCKBYTES]); + const uint8_t cipher[BLOWFISH_BLOCKBYTES], + uint8_t plain[BLOWFISH_BLOCKBYTES]); #endif diff --git a/ipif/forwarder.c b/ipif/forwarder.c new file mode 100644 index 0000000..ae32786 --- /dev/null +++ b/ipif/forwarder.c @@ -0,0 +1,368 @@ +/* + * Encrypting tunnel for userv-ipif tunnels, actual implementation + * + * usage: + * 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. + * + * Every must be numeric. There is very little argument checking. + * + * Exit status: + * SIGALARM timed out + * 0 terminated due to outbound packet stream EOF + * 4 other error + * 8 system problem + * 12 usage error + * 16 bad trouble + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "mech.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 int public_local_fd, private_in_fd, private_out_fd; +static int mtu2, keepalive, timeout; +static int public_remote_specd; +static struct sockaddr_in public_remote; +static int encdec_keys_fd, encdec_keys_write; +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 struct buffer buf_in, buf_out; +static unsigned char *accum_buf; +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); +} + +void sysdiag(const char *msg) { + fprintf(stderr, "%s: system/network error: %s: %s\n", programid, msg, strerror(errno)); +} + +void diag(const char *msg) { + fprintf(stderr, "%s: %s\n", programid, msg); +} + +time_t now(void) { + time_t r; + if (time(&r) == (time_t)-1) sysfail("get time of day"); + return r; +} + +void *xmalloc(size_t sz) { + void *r; + r= malloc(sz); + if (!r) sysfail("allocate memory"); + return r; +} + +void get_random(void *ptr, size_t sz) { + static FILE *randfile; + + size_t r; + + if (!randfile) { + randfile= fopen("/dev/urandom","rb"); + if (!randfile && errno==ENOENT) randfile= fopen("/dev/random","rb"); + if (!randfile) sysfail("open random number generator"); + } + + r= fread(ptr,1,sz,randfile); + if (r == sz) return; + (ferror(randfile) ? sysfail : fail)("cannot read random number generator"); +} + +const char *getarg_string(void) { + const char *arg; + + arg= *++argv; + arg_assert(arg); + return arg; +} + +unsigned long getarg_ulong(void) { + char *ep; + unsigned long ul; + + ul= strtoul(getarg_string(),&ep,0); + arg_assert(!*ep); + return ul; +} + +static void setnonblock(int fd, int nonblock) { + int r; + + r= fcntl(fd,F_GETFL); + if (r==-1) sysfail("fcntl F_GETFL"); + r= fcntl(fd,F_SETFL, nonblock ? r|O_NONBLOCK : r&~O_NONBLOCK); + if (r==-1) sysfail("fcntl F_SETFL"); +} + +static const struct mechanism *getarg_mech(void) { + const char *name; + const struct mechanism *mech, *const *mechlist; + + name= getarg_string(); + + for (mechlist= mechanismlists; + *mechlist; + mechlist++) + for (mech= *mechlist; mech->name; mech++) + if (!strcmp(mech->name,name)) return mech; + + fprintf(stderr,"%s: unknown mechanism: %s\n",programid,name); + exit(4); +} + +static void inbound(void) { + static int any_recvd; + + struct sockaddr_in this_saddr; + int r, i, different, this_saddrlen; + const char *emsg; + + alarm(timeout); + + setnonblock(public_local_fd,1); + this_saddrlen= sizeof(this_saddr); + r= recvfrom(public_local_fd, buf_in.base, buffer_size-1, 0, + &this_saddr, &this_saddrlen); + if (!r) { diag("empty ciphertext"); return; } + + if (r<0) { + if (errno != EAGAIN && errno != EINTR) sysdiag("receive"); + return; + } + if (this_saddr.sin_family != AF_INET) { + fprintf(stderr,"%s: received unknown AF %lu", + 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; + 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); + return; + } + } + + different= !public_remote_specd || + memcmp(&this_saddr,&public_remote,sizeof(this_saddr)); + + if (different) { + + if (public_remote_specd==2) { + fprintf(stderr, "%s: packet from unexpected sender %s:%lu", + programid, inet_ntoa(this_saddr.sin_addr), + (unsigned long)this_saddr.sin_port); + return; + } + + fprintf(stderr, "%s: tunnel open with peer %s:%lu", + programid, inet_ntoa(this_saddr.sin_addr), + (unsigned long)this_saddr.sin_port); + nextsendka= now(); + public_remote_specd= 1; + memcpy(&public_remote,&this_saddr,sizeof(public_remote)); + + } else if (!any_recvd) { + + diag("tunnel open"); + + } + + any_recvd= 1; + + buf_in.start[buf_in.size]= 0300; + *--buf_in.start= 0300; + buf_in.size+= 2; + + 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; + } +} + +static void sendpacket(const unsigned char *message, size_t size) { + int i, r; + + buf_out.start= buf_out.base+maxprefix; + buf_out.size= size; + memcpy(buf_out.start, message, size); + + nextsendka= now() + keepalive; + + for (i=0; iencode(md_out[i],&buf_out); + assert(public_remote_specd); + + setnonblock(public_local_fd,1); + for (;;) { + r= sendto(public_local_fd, buf_out.start, buf_out.size, 0, + &public_remote, sizeof(public_remote)); + if (r == buf_out.size) break; + if (r >= 0) { diag("unexpected short send"); return; } + if (errno != EINTR) { sysdiag("send"); return; } + } +} + +static void outbound(void) { + int r; + unsigned char *after_eaten, *delim; + size_t this_packet; + + setnonblock(private_out_fd,1); + + for (;;) { + r= read(private_out_fd, accum_buf + accum_used, accum_avail - accum_used); + if (!r) { diag("outbound datastream closed, quitting"); exit(0); } + if (r<0) { + if (errno == EAGAIN) return; + if (errno == EINTR) continue; + } + accum_used += r; + assert(accum_used<=accum_avail); + + after_eaten= accum_buf; + while ((delim= memchr(after_eaten, 0300, accum_used))) { + this_packet= delim - after_eaten; + sendpacket(after_eaten, this_packet); + accum_used -= this_packet+1; + after_eaten = delim+1; + } + memmove(accum_buf, after_eaten, accum_used); + + if (accum_used == accum_avail) { + diag("missing interpacket delimiter in output datastream"); + accum_used= 0; + } + } +} + +int main(int argc, const char *const *const argv_in) { + const char *arg; + struct pollfd pollfds[2]; + struct utsname uname_result; + int i, polltimeout, r; + time_t tnow; + + argv= argv_in; + + if (uname(&uname_result)) { perror(PROGRAM ": uname failed"); exit(16); } + sprintf(programid, PROGRAM ": %.*s", SYS_NMLN, uname_result.nodename); + + public_local_fd= getarg_ulong(); + mtu2= getarg_ulong() * 2; + keepalive= getarg_ulong(); + timeout= getarg_ulong(); + private_in_fd= getarg_ulong(); + private_out_fd= getarg_ulong(); + + arg= getarg_string(); + if (*arg) { + public_remote_specd= 1; + arg_assert(inet_aton(arg,&public_remote.sin_addr)); + public_remote.sin_port= getarg_ulong(); + } + + encdec_keys_fd= getarg_ulong(); + encdec_keys_write= !!*getarg_string(); + + maxprefix= 0; + for (i=0; iencsetup(&md_in[i], &maxprefix, &maxsuffix); + for (i=0; idecsetup(&md_out[i]); + + if (maxprefix<1) maxprefix= 1; + if (maxsuffix<1) maxsuffix= 1; + buffer_size= mtu2 + maxprefix + maxsuffix; + buf_in.base= xmalloc(buffer_size); + buf_out.base= xmalloc(buffer_size); + accum_avail= mtu2 + 1; + accum_buf= xmalloc(accum_avail); + + alarm(timeout); + + pollfds[0].fd= public_local_fd; + pollfds[0].events= POLLIN; + pollfds[1].fd= private_out_fd; + for (;;) { + pollfds[1].events= public_remote_specd ? POLLIN : 0; + pollfds[0].revents= 0; + pollfds[1].revents= 0; + + if (keepalive) { + tnow= now(); + if (tnow >= nextsendka) sendpacket("\300",1); + polltimeout= (nextsendka - tnow)*1000; + } else { + polltimeout= -1; + } + + r= poll(pollfds,2,polltimeout); + if (!r) continue; + if (r==-1 && errno==EINTR) continue; + if (r==-1) sysfail("poll"); + + if (pollfds[0].revents & POLLIN) inbound(); + if (pollfds[1].revents & POLLOUT) outbound(); + } +} diff --git a/ipif/forwarder.h b/ipif/forwarder.h new file mode 100644 index 0000000..fbaf2e2 --- /dev/null +++ b/ipif/forwarder.h @@ -0,0 +1,83 @@ +/* + */ + +#ifndef MECHS_H +#define MECHS_H + +#include +#include + +#include "automech.h" + +struct buffer { + unsigned char *base; + unsigned char *start; + size_t size; +}; + +struct mechdata; + +typedef void mes_functype(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io); +typedef void mds_functype(struct mechdata **md_r); + +typedef void menc_functype(struct mechdata *md, struct buffer*); +typedef const char *mdec_functype(struct mechdata *md, struct buffer*); + +struct mechanism { + const char *name; + mes_functype *encsetup; + mds_functype *decsetup; + menc_functype *encode; + mdec_functype *decode; +}; + +extern const struct mechanism *const mechanismlists[]; + +/* setup function may call getarg_xxx functions and then + * reads/writes key material to/from fd + * + * setup_in function may increase maxprefix and maxsuffix + * code functions modify buffer in place + * decode function returns message to print + */ + +const char *getarg_string(void); +unsigned long getarg_ulong(void); + +extern char programid[]; + +void *buf_append(struct buffer *buf, size_t amount); +void *buf_prepend(struct buffer *buf, size_t amount); +void *buf_unappend(struct buffer *buf, size_t amount); /* may give 0 */ +void *buf_unprepend(struct buffer *buf, size_t amount); /* may give 0 */ + +void sysfail(const char *msg); +void fail(const char *msg); +void sysdiag(const char *msg); +void diag(const char *msg); + +time_t now(void); +void *xmalloc(size_t sz); +void get_random(void *ptr, size_t sz); +void random_key(void *ptr, size_t sz); + +void arg_assert_fail(const char *msg); +#define arg_assert(v) (v ? (void)0 : arg_assert_fail(#v)) + +#define XMALLOC(variable) ((variable)= xmalloc(sizeof(*(variable)))) + +#define BUF_UNSOMEEND(var,buf,sz,whichend) \ + do { var= whichend(buf,sz); if (!var) return "message truncated"; } while(0) +#define BUF_UNAPPEND(var,buf,sz) BUF_UNSOMEEND(var,buf,sz,buf_unappend) +#define BUF_UNPREPEND(var,buf,sz) BUF_UNSOMEEND(var,buf,sz,buf_unprepend) + +#define STANDARD_MECHANISMLIST(mechstring,filename) \ + const struct mechanism mechlist_##filename []= { \ + STANDARD_MECHANISM(mechstring,filename) \ + { 0 } \ + }; + +#define STANDARD_MECHANISM(mechstring,mechname) \ + { mechstring, mes_##mechname, mds_##mechname, menc_##mechname, mdec_##mechname }, + +#endif diff --git a/ipif/mech-blowfish.c b/ipif/mech-blowfish.c new file mode 100644 index 0000000..898abe6 --- /dev/null +++ b/ipif/mech-blowfish.c @@ -0,0 +1,108 @@ +/* + * Blowfish + * + * arguments: key size in bits (must be multiple of 8) + * + * key values: 8 byte random IV and n byte random key + * + * encoding: do CBC encryption overwriting message + * encoding for MAC: do CBC and prepend last ciphertext block + */ + +#include "mech.h" +#include "blowfish.h" + +struct mechdata { + struct blowfish_cbc_state cbc; +}; + +static void mds_blowfish(struct mechdata **md_r) { + struct mechdata *md; + unsigned long keysize; + unsigned char iv[BLOWFISH_BLOCKBYTES]; + unsigned char key[BLOWFISH_MAXKEYBYTES]; + + md= xmalloc(sizeof(md)); + + keysize= getarg_ulong(); + arg_assert(!(keysize & 7)); + keysize >>= 3; + arg_assert(keysize > 0 && keysize <= BLOWFISH_MAXKEYBYTES); + + random_key(iv,sizeof(iv)); + random_key(key,keysize); + + blowfish_loadkey(&md->cbc.ek, key,keysize); + blowfish_cbc_setiv(&md->cbc, iv); + + *md_r= md; +} + +static void mes_blowfish(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { + mds_blowfish(md_r); +} + +static void mds_bfmac(struct mechdata **md_r) { + mds_blowfish(md_r); +} + +static void mes_bfmac(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { + mds_blowfish(md_r); + *maxprefix_io += BLOWFISH_BLOCKBYTES; +} + +#define MSGSIZE_OUT \ + msgsize= buf->size; \ + arg_assert(!(msgsize & ~BLOWFISH_BLOCKBYTES)); + +#define MSGSIZE_IN \ + msgsize= buf->size; \ + if (msgsize & ~BLOWFISH_BLOCKBYTES) return "not multiple of block size" + +#define FOREACH_BLOCK(func,inptr,outptr) \ + { \ + unsigned char *ptr; \ + ptr= buf->start; \ + while (ptr < buf->start + msgsize) \ + func(&md->cbc,inptr,outptr); \ + } + +static void menc_blowfish(struct mechdata *md, struct buffer *buf) { + unsigned long msgsize; + MSGSIZE_OUT; + FOREACH_BLOCK(blowfish_cbc_encrypt,ptr,ptr); +} + +static const char *mdec_blowfish(struct mechdata *md, struct buffer *buf) { + unsigned long msgsize; + MSGSIZE_IN; + FOREACH_BLOCK(blowfish_cbc_decrypt,ptr,ptr); + return 0; +} + +static void menc_bfmac(struct mechdata *md, struct buffer *buf) { + unsigned long msgsize; + unsigned char outblock[BLOWFISH_BLOCKBYTES]; + + MSGSIZE_OUT; + FOREACH_BLOCK(blowfish_cbc_encrypt,ptr,outblock); + memcpy(buf_prepend(buf,BLOWFISH_BLOCKBYTES), outblock, BLOWFISH_BLOCKBYTES); +} + +static const char *mdec_bfmac(struct mechdata *md, struct buffer *buf) { + unsigned long msgsize; + unsigned char outblock[BLOWFISH_BLOCKBYTES]; + unsigned char *checkblock; + + BUF_UNPREPEND(checkblock,buf,BLOWFISH_BLOCKBYTES); + MSGSIZE_IN; + FOREACH_BLOCK(blowfish_cbc_encrypt,ptr,outblock); + if (memcmp(checkblock,outblock,BLOWFISH_BLOCKBYTES)) return "verify failed"; + return 0; +} + +const struct mechanism mechlist_blowfish[]= { + STANDARD_MECHANISM("blowfish-cbcmac", bfmac) + STANDARD_MECHANISM("blowfish-cbc", blowfish) + { 0 } +}; diff --git a/ipif/mech-null.c b/ipif/mech-null.c new file mode 100644 index 0000000..0e9f8e9 --- /dev/null +++ b/ipif/mech-null.c @@ -0,0 +1,11 @@ +/* + */ + +#include "mech.h" + +static void mes_null(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { } +static void mds_null(struct mechdata **md_r) { } +static void menc_null(struct mechdata *md, struct buffer *buf) { } +static const char *mdec_null(struct mechdata *md, struct buffer *buf) { return 0; } + +STANDARD_MECHANISMLIST("null",null) diff --git a/ipif/mech-pkcs5.c b/ipif/mech-pkcs5.c new file mode 100644 index 0000000..3603276 --- /dev/null +++ b/ipif/mech-pkcs5.c @@ -0,0 +1,72 @@ +/* + * PKCS#5 padding + * + * arguments: block size to pad to, must be power of 2 + * + * encoding: append between 1 and n bytes, all of the same value being + * the number of bytes appended + */ + +#include "mech.h" + +struct mechdata { + unsigned mask; +}; + +static unsigned long setup(struct mechdata **md_r) { + struct mechdata *md; + unsigned long blocksize; + + XMALLOC(md); + + blocksize= getarg_ulong(); + md->mask= blocksize - 1; + arg_assert(!md->mask & blocksize); + arg_assert(blocksize <= 255); + + *md_r= md; + return blocksize; +} + +static void mes_pkcs5(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { + unsigned long blocksize; + + blocksize= setup(md_r); + *maxsuffix_io += blocksize + 1; +} + +static void mds_pkcs5(struct mechdata **md_r) { + setup(md_r); +} + +static void menc_pkcs5(struct mechdata *md, struct buffer *buf) { + unsigned char *pad; + int padlen; + + /* eg with blocksize=4 mask=3 mask+2=5 */ + /* msgsize 20 21 22 23 24 */ + padlen= md->mask - buf->size; /* -17 -18 -19 -16 -17 */ + padlen &= md->mask; /* 3 2 1 0 3 */ + padlen++; /* 4 3 2 1 4 */ + + pad= buf_append(buf,padlen); + memset(pad,padlen,padlen); +} + +static const char *mdec_pkcs5(struct mechdata *md, struct buffer *buf) { + unsigned char *padp; + unsigned padlen; + int i; + + BUF_UNPREPEND(padp,buf,1); + padlen= *padp; + if (!padlen || (padlen & ~md->mask)) return "invalid length"; + + BUF_UNPREPEND(padp,buf,padlen-1); + for (i=0; i + +#include "mech.h" + +struct mechdata { + uint32_t number; + int anyseen; /* decode only */ +}; + +static void mes_sequence(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { + struct mechdata *md; + + XMALLOC(md); + get_random(&md->number,sizeof(md->number)); + *maxprefix_io += 4; + *md_r= md; +} + +static void mds_sequence(struct mechdata **md_r) { + struct mechdata *md; + XMALLOC(md); + md->anyseen= 0; + *md_r= md; +} + +static void menc_sequence(struct mechdata *md, struct buffer *buf) { + md->number++; + *(uint32_t*)buf_prepend(buf,4)= htonl(md->number); +} + +static const char *mdec_check(struct mechdata *md, struct buffer *buf) { + uint32_t *sp, sequence; + + BUF_UNPREPEND(sp,buf,4); + sequence= ntohl(*sp); + + if (md->anyseen) + if (sequence - md->number >= 0x800000UL) return "out of order packet"; + + md->number= sequence; + md->anyseen= 1; + + return 0; +} + +static const char *mdec_skip(struct mechdata *md, struct buffer *buf) { + uint32_t *sp; + BUF_UNPREPEND(sp,buf,4); + return 0; +} + +const struct mechanism mechlist_sequence[]= { + { "nonce32", mes_sequence, mds_sequence, menc_sequence, mdec_skip }, + { "sequence32", mes_sequence, mds_sequence, menc_sequence, mdec_check }, + { 0 } +}; diff --git a/ipif/mech-timestamp.c b/ipif/mech-timestamp.c new file mode 100644 index 0000000..f679b10 --- /dev/null +++ b/ipif/mech-timestamp.c @@ -0,0 +1,68 @@ +/* + * Timestamp mechanism + * + * arguments: + * + * encoding: prepend 4 bytes of UNIX time in network byte order + * + * is maximum age in seconds we will accept a packet (or 0 + * for any age); is maximum future age in seconds we will + * accept a packet (or 0 for any future age). + * + */ + +#include +#include + +#include "mech.h" + +struct mechdata { + uint32_t max_skew, max_age; +}; + +static void mds_timestamp(struct mechdata **md_r) { + struct mechdata *md; + + md= xmalloc(sizeof(md)); + + md->max_skew= getarg_ulong(); + md->max_age= getarg_ulong(); + *md_r= md; +} + +static void mes_timestamp(struct mechdata **md_r, int *maxprefix_io, int *maxsuffix_io) { + mds_timestamp(md_r); + *maxprefix_io += 4; +} + +static void menc_timestamp(struct mechdata *md, struct buffer *buf) { + *(uint32_t*)buf_prepend(buf,4)= htonl(now()); +} + +static const char *mdec_timestamp(struct mechdata *md, struct buffer *buf) { + static char cbuf[40]; + + uint32_t *tp, timestamp, tnow; + long age; + + BUF_UNPREPEND(tp,buf,4); + timestamp= ntohl(*tp); + + tnow= now(); + age= timestamp - tnow; + if (age > 0) { + if (md->max_age && age > md->max_age) { + sprintf(cbuf,"packet too old (%lds)",age); + return cbuf; + } + } else if (age < 0) { + if (md->max_skew && age > md->max_skew) { + sprintf(cbuf,"too much skew (%lds)",-age); + return cbuf; + } + } + + return 0; +} + +STANDARD_MECHANISMLIST("timestamp",timestamp); diff --git a/ipif/udptunnel b/ipif/udptunnel index 17b2d06..d7a0036 100755 --- a/ipif/udptunnel +++ b/ipif/udptunnel @@ -3,20 +3,26 @@ # # usage: # udptunnel -# [ -l[] ... . ] -# , -# , +# [ -l[] ... . +# -e[/...] +# ... +# ] +# , +# , # ,,, # , # # [ [ ...] ] # +# +# <..-addr> may also be hostname +# # may be number or `print' or `silent' # # may number or `command', in which case # must be specified and should run udptunnel at the # remote end; it will be invoked as -# ,print +# ,print # , # ,,, # , @@ -63,7 +69,7 @@ sub warning ($) { warn "$progname - $hostname: $_[0]\n"; } sub eat_addr_port ($) { my ($x) = @_; - @ARGV or quit(", missing"); + @ARGV or quit(", missing"); $_= shift(@ARGV); $_ =~ m/^([^,]+)\,(\d+|$x)$/ or quit("$_: , bad syntax"); return ($1,$2); @@ -96,7 +102,7 @@ while ($ARGV[0] =~ m/^-/) { last if $_ eq '--'; if (s/^-l//) { push @lcmd,$_ if length; - while (@ARGV && ($_= shift @ARGV) ne '-') { push @lcmd, $_; } + while (@ARGV && ($_= shift @ARGV) ne '.') { push @lcmd, $_; } } else { quit("unknown option \`$_'"); } -- 2.30.2