#6 reworked encoding

This commit is contained in:
Erik Ekman 2007-06-09 16:18:59 +00:00
parent faea33eaae
commit dbfecb5be6
10 changed files with 210 additions and 275 deletions

View file

@ -18,140 +18,160 @@
#include <stdlib.h>
#include <string.h>
#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;
memset(buf, 0, *buflen);
/* 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 (newsize > *buflen) {
if ((newbuf = realloc(*buf, newsize)) == NULL) {
free(*buf);
*buf = NULL;
*buflen = 0;
return 0;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
size = maxsize;
}
*buf = newbuf;
*buflen = newsize;
}
p = s = *buf;
q = (char*)data;
p = s = (unsigned char *) buf;
q = (unsigned char *)data;
for(i=0;i<size;i+=5) {
p[0] = cb32[(q[0] >> 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;
int i;
newsize = 5 * (strlen(str) / 8 + 1) + 1;
if (newsize > *buflen) {
if ((newbuf = realloc(*buf, newsize)) == NULL) {
free(*buf);
*buf = NULL;
*buflen = 0;
return 0;
if (!reverse_init) {
for (i = 0; i < 32; i++) {
c = cb32[i];
rev32[(int) c] = i;
}
reverse_init = 1;
}
*buf = newbuf;
*buflen = newsize;
/* 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;
}

View file

@ -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

View file

@ -14,207 +14,71 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdio.h>
#include <strings.h>
#include <string.h>
#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 */
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 */
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;
}
reverse_init = 1;
total += dots;
if (strlen(buf) + dots > buflen) {
writer = buf;
writer += buflen;
total = buflen;
}
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;
reader = writer - dots;
pos = (unsigned) (reader - buf) + 1;
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;
while (dots) {
if (pos % 62 == 0) {
*writer-- = '.';
dots--;
}
*writer-- = *reader--;
pos--;
}
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)
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++;
}
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;
*writer++ = *reader++;
pos++;
}
return len;
/* return new length of string */
return len - dots;
}

View file

@ -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_ */

View file

@ -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;
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;
consumed = encode_data(data, datalen, avail, b);
b += strlen(buf);
if (*b != '.')
*b++ = '.';
strncpy(b, topdomain, strlen(topdomain)+1);
return consumed;
return space;
}
int
@ -523,6 +535,8 @@ main(int argc, char **argv)
device = NULL;
chunkid = 0;
enc = get_base32_encoder();
while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
switch(choice) {
case 'v':

View file

@ -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,7 +371,8 @@ 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) {
@ -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));

View file

@ -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);
}

View file

@ -23,6 +23,7 @@
#include <netinet/in.h>
#include "common.h"
#include "encoding.h"
#include "user.h"
struct user users[USERS];

View file

@ -30,6 +30,7 @@ struct user {
struct query q;
struct packet inpacket;
struct packet outpacket;
struct encoder *encoder;
};
extern struct user users[USERS];

View file

@ -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_ */