From dbfecb5be6966baaa2d75c579c56a046bc1265cd Mon Sep 17 00:00:00 2001 From: Erik Ekman Date: Sat, 9 Jun 2007 16:18:59 +0000 Subject: [PATCH] #6 reworked encoding --- src/base32.c | 150 ++++++++++++++++++-------------- src/base32.h | 6 +- src/encoding.c | 230 ++++++++++--------------------------------------- src/encoding.h | 13 ++- src/iodine.c | 32 +++++-- src/iodined.c | 49 ++++++++--- src/login.c | 1 + src/user.c | 1 + src/user.h | 1 + src/version.h | 2 +- 10 files changed, 210 insertions(+), 275 deletions(-) diff --git a/src/base32.c b/src/base32.c index 7357604..790d3f3 100644 --- a/src/base32.c +++ b/src/base32.c @@ -18,140 +18,160 @@ #include #include +#include "encoding.h" #include "base32.h" static const char cb32[] = "abcdefghijklmnopqrstuvwxyz0123456789"; +static unsigned char rev32[128]; +static int reverse_init = 0; + +static struct encoder base32_encoder = +{ + "BASE32", + base32_encode, + base32_decode, + base32_handles_dots, + base32_handles_dots +}; + +struct encoder +*get_base32_encoder() +{ + return &base32_encoder; +} int -base32_encode(char **buf, size_t *buflen, const void *data, size_t size) +base32_handles_dots() +{ + return 0; +} + +int +base32_encode(char *buf, size_t *buflen, const void *data, size_t size) { size_t newsize; - char *newbuf; - char *s; - char *p; - char *q; + size_t maxsize; + unsigned char *s; + unsigned char *p; + unsigned char *q; int i; - newsize = 8 * (size / 5 + 1) + 1; - if (newsize > *buflen) { - if ((newbuf = realloc(*buf, newsize)) == NULL) { - free(*buf); - *buf = NULL; - *buflen = 0; - return 0; - } + memset(buf, 0, *buflen); - *buf = newbuf; - *buflen = newsize; + /* how many chars can we encode within the buf */ + maxsize = 5 * (*buflen / 8 - 1) - 1; + /* how big will the encoded data be */ + newsize = 8 * (size / 5 + 1) + 1; + /* if the buffer is too small, eat some of the data */ + if (*buflen < newsize) { + size = maxsize; } - p = s = *buf; - q = (char*)data; + p = s = (unsigned char *) buf; + q = (unsigned char *)data; for(i=0;i> 3)]; - p[1] = cb32[((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6)]; + p[0] = cb32[((q[0] & 0xf8) >> 3)]; + p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))]; p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0'; p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0'; p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0'; - p[5] = (i+3 < size) ? cb32[((q[3] & 0x3e) >> 2)] : '\0'; - p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) > 5)] : '\0'; + p[5] = (i+3 < size) ? cb32[((q[3] & 0x7c) >> 2)] : '\0'; + p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) >> 5)] : '\0'; p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0'; q += 5; p += 8; } *p = 0; - return strlen(s); + + /* store number of bytes from data that was used */ + *buflen = size; + + return strlen(buf) - 1; } #define DECODE_ERROR 0xffffffff +#define REV32(x) rev32[(int) (x)] static int -pos(char c) +decode_token(const unsigned char *t, unsigned char *data, size_t len) { - const char *p; - for (p = cb32; *p; p++) - if (*p == c) - return p - cb32; - return -1; -} - -static int -decode_token(const char *t, char *data) -{ - int len; - - len = strlen(t); - if (len < 2) return 0; - data[0] = ((pos(t[0]) & 0x1f) << 3) | - ((pos(t[1]) & 0x1c) >> 2); + data[0] = ((REV32(t[0]) & 0x1f) << 3) | + ((REV32(t[1]) & 0x1c) >> 2); if (len < 4) return 1; - data[1] = ((pos(t[1]) & 0x03) << 6) | - ((pos(t[2]) & 0x1f) << 1) | - ((pos(t[3]) & 0x10) >> 4); + data[1] = ((REV32(t[1]) & 0x03) << 6) | + ((REV32(t[2]) & 0x1f) << 1) | + ((REV32(t[3]) & 0x10) >> 4); if (len < 5) return 2; - data[2] = ((pos(t[3]) & 0x0f) << 4) | - ((pos(t[4]) & 0x1e) >> 1); + data[2] = ((REV32(t[3]) & 0x0f) << 4) | + ((REV32(t[4]) & 0x1e) >> 1); if (len < 7) return 3; - data[3] = ((pos(t[4]) & 0x01) << 7) | - ((pos(t[5]) & 0x1f) << 2) | - ((pos(t[6]) & 0x18) >> 3); + data[3] = ((REV32(t[4]) & 0x01) << 7) | + ((REV32(t[5]) & 0x1f) << 2) | + ((REV32(t[6]) & 0x18) >> 3); if (len < 8) return 4; - data[4] = ((pos(t[6]) & 0x07) << 5) | - ((pos(t[7]) & 0x1f)); + data[4] = ((REV32(t[6]) & 0x07) << 5) | + ((REV32(t[7]) & 0x1f)); return 5; } int -base32_decode(void **buf, size_t *buflen, const char *str) +base32_decode(void *buf, size_t *buflen, const char *str, size_t slen) { unsigned char *q; size_t newsize; + size_t maxsize; const char *p; - char *newbuf; + unsigned char c; int len; - - newsize = 5 * (strlen(str) / 8 + 1) + 1; - if (newsize > *buflen) { - if ((newbuf = realloc(*buf, newsize)) == NULL) { - free(*buf); - *buf = NULL; - *buflen = 0; - return 0; - } + int i; - *buf = newbuf; - *buflen = newsize; + if (!reverse_init) { + for (i = 0; i < 32; i++) { + c = cb32[i]; + rev32[(int) c] = i; + } + reverse_init = 1; + } + + /* chars needed to decode slen */ + newsize = 5 * (slen / 8 + 1) + 1; + /* encoded chars that fit in buf */ + maxsize = 8 * (*buflen / 5 + 1) + 1; + /* if the buffer is too small, eat some of the data */ + if (*buflen < newsize) { + slen = maxsize; } - q = *buf; + q = buf; for (p = str; *p && strchr(cb32, *p); p += 8) { - len = decode_token(p, (char *) q); + len = decode_token((unsigned char *) p, (unsigned char *) q, slen); q += len; + slen -= 8; if (len < 5) break; } *q = '\0'; - return q - (unsigned char *) *buf; + return q - (unsigned char *) buf; } diff --git a/src/base32.h b/src/base32.h index be3b7ea..9fce044 100644 --- a/src/base32.h +++ b/src/base32.h @@ -17,7 +17,9 @@ #ifndef __BASE32_H__ #define __BASE32_H__ -int base32_encode(char **, size_t *, const void *, size_t); -int base32_decode(void **, size_t *, const char *); +struct encoder *get_base32_encoder(void); +int base32_handles_dots(); +int base32_encode(char *, size_t *, const void *, size_t); +int base32_decode(void *, size_t *, const char *, size_t); #endif diff --git a/src/encoding.c b/src/encoding.c index 4de10c6..11ca96f 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -14,207 +14,71 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include -#include #include +#include "encoding.h" -/* For FreeBSD */ -#ifndef MIN -#define MIN(a,b) ((a)<(b)?(a):(b)) -#endif - -#define SPACING 63 -#define ENC_CHUNK 8 -#define RAW_CHUNK 5 - -static const char base32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ98765-"; -static const char padder[] = " 1234"; -static char reverse32[128]; -static int reverse_init = 0; - -/* Eat 5 bytes from src, write 8 bytes to dest */ -static void -encode_chunk(char *dest, const char *src) +int +inline_dotify(char *buf, size_t buflen) { - unsigned char c; + unsigned dots; + unsigned pos; + unsigned total; + char *reader, *writer; - *dest++ = base32[(*src & 0xF8) >> 3]; /* 1111 1000 first byte */ + total = strlen(buf); + dots = total / 62; - c = (*src++ & 0x07) << 2; /* 0000 0111 first byte */ - c |= ((*src & 0xC0) >> 6); /* 1100 0000 second byte */ - *dest++ = base32[(int) c]; + writer = buf; + writer += total; + writer += dots; - *dest++ = base32[(*src & 0x3E) >> 1]; /* 0011 1110 second byte */ + total += dots; + if (strlen(buf) + dots > buflen) { + writer = buf; + writer += buflen; + total = buflen; + } - c = (*src++ & 0x01) << 4; /* 0000 0001 second byte */ - c |= ((*src & 0xF0) >> 4); /* 1111 0000 third byte */ - *dest++ = base32[(int) c]; - - c = (*src++ & 0x0F) << 1; /* 0000 1111 third byte */ - c |= ((*src & 0x80) >> 7); /* 1000 0000 fourth byte */ - *dest++ = base32[(int) c]; - - *dest++ = base32[(*src & 0x7C) >> 2]; /* 0111 1100 fourth byte */ + reader = writer - dots; + pos = (unsigned) (reader - buf) + 1; - c = (*src++ & 0x03) << 3; /* 0000 0011 fourth byte */ - c |= ((*src & 0xE0) >> 5); /* 1110 0000 fifth byte */ - *dest++ = base32[(int) c]; - - *dest++ = base32[*src++ & 0x1F]; /* 0001 1111 fifth byte */ -} - -/* Eat 8 bytes from src, write 5 bytes to dest */ -static void -decode_chunk(char *dest, char *src) -{ - unsigned char c; - int i; - - if (!reverse_init) { - for (i = 0; i < 32; i++) { - c = base32[i]; - reverse32[(int) c] = i; + while (dots) { + if (pos % 62 == 0) { + *writer-- = '.'; + dots--; } - reverse_init = 1; + *writer-- = *reader--; + pos--; } - c = reverse32[(int) *src++] << 3; /* Take bits 11111 from byte 1 */ - c |= (reverse32[(int) *src] & 0x1C) >> 2; /* Take bits 11100 from byte 2 */ - *dest++ = c; - - c = (reverse32[(int) *src++] & 0x3) << 6; /* Take bits 00011 from byte 2 */ - c |= reverse32[(int) *src++] << 1; /* Take bits 11111 from byte 3 */ - c |= (reverse32[(int) *src] & 0x10) >> 4; /* Take bits 10000 from byte 4 */ - *dest++ = c; - - c = (reverse32[(int) *src++] & 0xF) << 4; /* Take bits 01111 from byte 4 */ - c |= (reverse32[(int) *src] & 0x1E) >> 1; /* Take bits 11110 from byte 5 */ - *dest++ = c; - - c = reverse32[(int) *src++] << 7; /* Take bits 00001 from byte 5 */ - c |= reverse32[(int) *src++] << 2; /* Take bits 11111 from byte 6 */ - c |= (reverse32[(int) *src] & 0x18) >> 3; /* Take bits 11000 from byte 7 */ - *dest++ = c; - - c = (reverse32[(int) *src++] & 0x7) << 5; /* Take bits 00111 from byte 7 */ - c |= reverse32[(int) *src++]; /* Take bits 11111 from byte 8 */ - *dest++ = c; + /* return new length of string */ + return total; } -int -encode_data(const char *buf, const size_t len, int space, char *dest) +int +inline_undotify(char *buf, size_t len) { - int final; - int write; - int realwrite; - int chunks; - int leftovers; - int i; - char encoded[255]; - char padding[5]; - const char *dp; - char *pp; - char *ep; + unsigned pos; + unsigned dots; + char *reader, *writer; - space -= space / SPACING; - chunks = (space - 1) / ENC_CHUNK; - while ((chunks + 1) * ENC_CHUNK + 1 > space) { - chunks--; - } - write = RAW_CHUNK * chunks; - write = MIN(write, len); /* do not use more bytes than is available; */ - final = (write == len); /* is this the last block? */ - chunks = write / RAW_CHUNK; - leftovers = write % RAW_CHUNK; + writer = buf; + reader = writer; - memset(encoded, 0, sizeof(encoded)); - ep = encoded; - dp = buf; - for (i = 0; i < chunks; i++) { - encode_chunk(ep, dp); - ep += ENC_CHUNK; - dp += RAW_CHUNK; - } - realwrite = ENC_CHUNK * chunks; - memset(padding, 0, sizeof(padding)); - pp = padding; - if (leftovers) { - pp += RAW_CHUNK - leftovers; - memcpy(pp, dp, leftovers); + pos = 0; + dots = 0; - pp = padding; - *ep++ = padder[leftovers]; - encode_chunk(ep, pp); - - realwrite += ENC_CHUNK + 1; /* plus padding character */ - } - ep = encoded; - if (len > 0) { - for (i = 1; i <= realwrite; i++) { - if (i % SPACING == 0) { - *dest++ = '.'; - } - *dest++ = *ep++; - } - } - - return write; -} - -int -decode_data(char *dest, int size, const char *src, char *srcend) -{ - int len; - int i; - int chunks; - int padded; - char encoded[255]; - char padding[5]; - int enclen; - char *pp; - char *ep; - - memset(encoded, 0, sizeof(encoded)); - memset(dest, 0, size); - - /* First byte is not encoded */ - *dest++ = *src++; - len = 1; - - ep = encoded; - enclen = 0; - while(enclen < sizeof(encoded) && src < srcend) { - if(*src == '.') { - src++; + while (pos < len) { + if (*reader == '.') { + reader++; + pos++; + dots++; continue; } - - *ep++ = *src++; - enclen++; + *writer++ = *reader++; + pos++; } - chunks = enclen / 8; - padded = enclen % 8; - - ep = encoded; - for (i = 0; i < chunks-1; i++) { - decode_chunk(dest, ep); - dest += RAW_CHUNK; - ep += ENC_CHUNK; - len += RAW_CHUNK; - } - /* Read last chunk */ - if (padded) { - pp = padding; - padded = *ep++ - '0'; - decode_chunk(pp, ep); - pp += RAW_CHUNK - padded; - memcpy(dest, pp, padded); - len += padded; - } else { - decode_chunk(dest, ep); - len += RAW_CHUNK; - } - - return len; + + /* return new length of string */ + return len - dots; } - diff --git a/src/encoding.h b/src/encoding.h index 2e4351b..6f7418e 100644 --- a/src/encoding.h +++ b/src/encoding.h @@ -17,7 +17,16 @@ #ifndef _ENCODING_H_ #define _ENCODING_H_ -int encode_data(const char *, const size_t, int, char *); -int decode_data(char *, int, const char *, char *); +int inline_dotify(char *, size_t); +int inline_undotify(char *, size_t); + +struct encoder { + char name[8]; + int (*encode) (char *, size_t *, const void *, size_t); + int (*decode) (void *, size_t *, const char *, size_t); + int (*places_dots) (void); + int (*eats_dots) (void); +}; #endif /* _ENCODING_H_ */ + diff --git a/src/iodine.c b/src/iodine.c index 651bc0c..7dfe3ba 100644 --- a/src/iodine.c +++ b/src/iodine.c @@ -35,6 +35,8 @@ #endif #include "common.h" +#include "encoding.h" +#include "base32.h" #include "dns.h" #include "login.h" #include "tun.h" @@ -62,6 +64,8 @@ static int packetpos; static int packetlen; static uint16_t chunkid; +static struct encoder *enc; + static void sighandler(int sig) { @@ -92,23 +96,31 @@ build_hostname(char *buf, size_t buflen, const char *data, const size_t datalen, const char *topdomain) { - int consumed; - int avail; + int encsize; + unsigned space; char *b; - avail = MIN(0xFF, buflen) - strlen(topdomain) - 2; - memset(buf, 0, buflen); - b = buf; - - consumed = encode_data(data, datalen, avail, b); + space = MIN(0xFF, buflen) - strlen(topdomain) - 2; + if (!enc->places_dots()) + space -= (space / 62); /* space for dots */ + + memset(buf, 0, buflen); + + encsize = enc->encode(buf, &space, data, datalen); + + if (!enc->places_dots()) + inline_dotify(buf, buflen); + + b = buf; b += strlen(buf); + if (*b != '.') *b++ = '.'; strncpy(b, topdomain, strlen(topdomain)+1); - - return consumed; + + return space; } int @@ -522,6 +534,8 @@ main(int argc, char **argv) newroot = NULL; device = NULL; chunkid = 0; + + enc = get_base32_encoder(); while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) { switch(choice) { diff --git a/src/iodined.c b/src/iodined.c index 4d5ff1c..942980a 100644 --- a/src/iodined.c +++ b/src/iodined.c @@ -34,10 +34,11 @@ #include "common.h" #include "dns.h" +#include "encoding.h" +#include "base32.h" #include "user.h" #include "login.h" #include "tun.h" -#include "encoding.h" #include "version.h" int running = 1; @@ -46,6 +47,8 @@ char *topdomain; char password[33]; +struct encoder *b32; + int my_mtu; in_addr_t my_ip; @@ -123,6 +126,14 @@ send_version_response(int fd, version_ack_t ack, uint32_t payload, struct user * write_dns(fd, &u->q, out, sizeof(out)); } +static int +unpack_data(char *buf, size_t buflen, char *data, size_t datalen, struct encoder *enc) +{ + if (!enc->eats_dots()) + datalen = inline_undotify(data, datalen); + return enc->decode(buf, &buflen, data, datalen); +} + static int tunnel_dns(int tun_fd, int dns_fd) { @@ -133,6 +144,7 @@ tunnel_dns(int tun_fd, int dns_fd) char logindata[16]; char out[64*1024]; char in[64*1024]; + char unpacked[64*1024]; char *tmp[2]; int userid; int touser; @@ -145,14 +157,15 @@ tunnel_dns(int tun_fd, int dns_fd) return 0; if(in[0] == 'V' || in[0] == 'v') { + read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32); /* Version greeting, compare and send ack/nak */ if (read > 4) { /* Received V + 32bits version */ - version = (((in[1] & 0xff) << 24) | - ((in[2] & 0xff) << 16) | - ((in[3] & 0xff) << 8) | - ((in[4] & 0xff))); + version = (((unpacked[0] & 0xff) << 24) | + ((unpacked[1] & 0xff) << 16) | + ((unpacked[2] & 0xff) << 8) | + ((unpacked[3] & 0xff))); if (version == VERSION) { userid = find_available_user(); @@ -161,6 +174,7 @@ tunnel_dns(int tun_fd, int dns_fd) memcpy(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen); memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query)); users[userid].addrlen = dummy.q.fromlen; + users[userid].encoder = get_base32_encoder(); send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]); users[userid].q.id = 0; } else { @@ -174,8 +188,9 @@ tunnel_dns(int tun_fd, int dns_fd) send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy); } } else if(in[0] == 'L' || in[0] == 'l') { + read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32); /* Login phase, handle auth */ - userid = in[1]; + userid = unpacked[0]; if (userid < 0 || userid >= USERS) { write_dns(dns_fd, &(dummy.q), "BADIP", 5); return 0; /* illegal id */ @@ -187,7 +202,7 @@ tunnel_dns(int tun_fd, int dns_fd) memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) { write_dns(dns_fd, &(dummy.q), "BADIP", 5); } else { - if (read >= 18 && (memcmp(logindata, in+2, 16) == 0)) { + if (read >= 18 && (memcmp(logindata, unpacked+1, 16) == 0)) { /* Login ok, send ip/mtu info */ tempip.s_addr = my_ip; @@ -208,8 +223,9 @@ tunnel_dns(int tun_fd, int dns_fd) } } } else if(in[0] == 'P' || in[0] == 'p') { + read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32); /* Ping packet, store userid */ - userid = in[1]; + userid = unpacked[0]; if (userid < 0 || userid >= USERS) { write_dns(dns_fd, &(dummy.q), "BADIP", 5); return 0; /* illegal id */ @@ -237,12 +253,16 @@ tunnel_dns(int tun_fd, int dns_fd) memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) { write_dns(dns_fd, &(dummy.q), "BADIP", 5); } else { + /* decode with this users encoding */ + read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, + users[userid].encoder); + users[userid].last_pkt = time(NULL); memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query)); users[userid].addrlen = dummy.q.fromlen; - memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, in + 1, read - 1); - users[userid].inpacket.len += read - 1; - users[userid].inpacket.offset += read - 1; + memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, unpacked, read); + users[userid].inpacket.len += read; + users[userid].inpacket.offset += read; if (code & 1) { outlen = sizeof(out); @@ -351,10 +371,11 @@ read_dns(int fd, struct query *q, char *buf, int buflen) if (r > 0) { dns_decode(buf, buflen, q, QR_QUERY, packet, r); domain = strstr(q->name, topdomain); - rv = decode_data(buf, buflen, q->name, domain); + rv = (int) (domain - q->name); + memcpy(buf, q->name, MIN(rv, buflen)); q->fromlen = addrlen; memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen); - } else if (r < 0) { + } else if (r < 0) { /* Error */ perror("recvfrom"); rv = 0; @@ -438,6 +459,8 @@ main(int argc, char **argv) listen_ip = INADDR_ANY; port = 53; + b32 = get_base32_encoder(); + memset(password, 0, 33); srand(time(NULL)); diff --git a/src/login.c b/src/login.c index b3f942a..a5cde37 100644 --- a/src/login.c +++ b/src/login.c @@ -47,5 +47,6 @@ login_calculate(char *buf, int buflen, char *pass, int seed) md5_init(&ctx); md5_append(&ctx, temp, 32); md5_finish(&ctx, (unsigned char *) buf); + } diff --git a/src/user.c b/src/user.c index ed809b8..53eb4d2 100644 --- a/src/user.c +++ b/src/user.c @@ -23,6 +23,7 @@ #include #include "common.h" +#include "encoding.h" #include "user.h" struct user users[USERS]; diff --git a/src/user.h b/src/user.h index b947ea4..2d0d2ad 100644 --- a/src/user.h +++ b/src/user.h @@ -30,6 +30,7 @@ struct user { struct query q; struct packet inpacket; struct packet outpacket; + struct encoder *encoder; }; extern struct user users[USERS]; diff --git a/src/version.h b/src/version.h index 8b9f6ca..3742134 100644 --- a/src/version.h +++ b/src/version.h @@ -19,7 +19,7 @@ /* This is the version of the network protocol It is usually equal to the latest iodine version number */ -#define VERSION 0x00000400 +#define VERSION 0x00000401 #endif /* _VERSION_H_ */