mirror of
https://github.com/yarrick/iodine.git
synced 2024-11-22 22:51:27 +00:00
#6 reworked encoding
This commit is contained in:
parent
faea33eaae
commit
dbfecb5be6
146
src/base32.c
146
src/base32.c
|
@ -18,140 +18,160 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "encoding.h"
|
||||||
#include "base32.h"
|
#include "base32.h"
|
||||||
|
|
||||||
static const char cb32[] =
|
static const char cb32[] =
|
||||||
"abcdefghijklmnopqrstuvwxyz0123456789";
|
"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
|
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;
|
size_t newsize;
|
||||||
char *newbuf;
|
size_t maxsize;
|
||||||
char *s;
|
unsigned char *s;
|
||||||
char *p;
|
unsigned char *p;
|
||||||
char *q;
|
unsigned char *q;
|
||||||
int i;
|
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;
|
newsize = 8 * (size / 5 + 1) + 1;
|
||||||
if (newsize > *buflen) {
|
/* if the buffer is too small, eat some of the data */
|
||||||
if ((newbuf = realloc(*buf, newsize)) == NULL) {
|
if (*buflen < newsize) {
|
||||||
free(*buf);
|
size = maxsize;
|
||||||
*buf = NULL;
|
|
||||||
*buflen = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*buf = newbuf;
|
p = s = (unsigned char *) buf;
|
||||||
*buflen = newsize;
|
q = (unsigned char *)data;
|
||||||
}
|
|
||||||
|
|
||||||
p = s = *buf;
|
|
||||||
q = (char*)data;
|
|
||||||
|
|
||||||
for(i=0;i<size;i+=5) {
|
for(i=0;i<size;i+=5) {
|
||||||
p[0] = cb32[(q[0] >> 3)];
|
p[0] = cb32[((q[0] & 0xf8) >> 3)];
|
||||||
p[1] = cb32[((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6)];
|
p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))];
|
||||||
p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0';
|
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[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[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[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[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) >> 5)] : '\0';
|
||||||
p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
|
p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
|
||||||
|
|
||||||
q += 5;
|
q += 5;
|
||||||
p += 8;
|
p += 8;
|
||||||
}
|
}
|
||||||
*p = 0;
|
*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 DECODE_ERROR 0xffffffff
|
||||||
|
#define REV32(x) rev32[(int) (x)]
|
||||||
|
|
||||||
static int
|
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)
|
if (len < 2)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
data[0] = ((pos(t[0]) & 0x1f) << 3) |
|
data[0] = ((REV32(t[0]) & 0x1f) << 3) |
|
||||||
((pos(t[1]) & 0x1c) >> 2);
|
((REV32(t[1]) & 0x1c) >> 2);
|
||||||
|
|
||||||
if (len < 4)
|
if (len < 4)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
data[1] = ((pos(t[1]) & 0x03) << 6) |
|
data[1] = ((REV32(t[1]) & 0x03) << 6) |
|
||||||
((pos(t[2]) & 0x1f) << 1) |
|
((REV32(t[2]) & 0x1f) << 1) |
|
||||||
((pos(t[3]) & 0x10) >> 4);
|
((REV32(t[3]) & 0x10) >> 4);
|
||||||
|
|
||||||
if (len < 5)
|
if (len < 5)
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
data[2] = ((pos(t[3]) & 0x0f) << 4) |
|
data[2] = ((REV32(t[3]) & 0x0f) << 4) |
|
||||||
((pos(t[4]) & 0x1e) >> 1);
|
((REV32(t[4]) & 0x1e) >> 1);
|
||||||
|
|
||||||
if (len < 7)
|
if (len < 7)
|
||||||
return 3;
|
return 3;
|
||||||
|
|
||||||
data[3] = ((pos(t[4]) & 0x01) << 7) |
|
data[3] = ((REV32(t[4]) & 0x01) << 7) |
|
||||||
((pos(t[5]) & 0x1f) << 2) |
|
((REV32(t[5]) & 0x1f) << 2) |
|
||||||
((pos(t[6]) & 0x18) >> 3);
|
((REV32(t[6]) & 0x18) >> 3);
|
||||||
|
|
||||||
if (len < 8)
|
if (len < 8)
|
||||||
return 4;
|
return 4;
|
||||||
|
|
||||||
data[4] = ((pos(t[6]) & 0x07) << 5) |
|
data[4] = ((REV32(t[6]) & 0x07) << 5) |
|
||||||
((pos(t[7]) & 0x1f));
|
((REV32(t[7]) & 0x1f));
|
||||||
|
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
unsigned char *q;
|
||||||
size_t newsize;
|
size_t newsize;
|
||||||
|
size_t maxsize;
|
||||||
const char *p;
|
const char *p;
|
||||||
char *newbuf;
|
unsigned char c;
|
||||||
int len;
|
int len;
|
||||||
|
int i;
|
||||||
|
|
||||||
newsize = 5 * (strlen(str) / 8 + 1) + 1;
|
if (!reverse_init) {
|
||||||
if (newsize > *buflen) {
|
for (i = 0; i < 32; i++) {
|
||||||
if ((newbuf = realloc(*buf, newsize)) == NULL) {
|
c = cb32[i];
|
||||||
free(*buf);
|
rev32[(int) c] = i;
|
||||||
*buf = NULL;
|
}
|
||||||
*buflen = 0;
|
reverse_init = 1;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*buf = newbuf;
|
/* chars needed to decode slen */
|
||||||
*buflen = newsize;
|
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) {
|
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;
|
q += len;
|
||||||
|
slen -= 8;
|
||||||
|
|
||||||
if (len < 5)
|
if (len < 5)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
*q = '\0';
|
*q = '\0';
|
||||||
|
|
||||||
return q - (unsigned char *) *buf;
|
return q - (unsigned char *) buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,9 @@
|
||||||
#ifndef __BASE32_H__
|
#ifndef __BASE32_H__
|
||||||
#define __BASE32_H__
|
#define __BASE32_H__
|
||||||
|
|
||||||
int base32_encode(char **, size_t *, const void *, size_t);
|
struct encoder *get_base32_encoder(void);
|
||||||
int base32_decode(void **, size_t *, const char *);
|
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
|
#endif
|
||||||
|
|
228
src/encoding.c
228
src/encoding.c
|
@ -14,207 +14,71 @@
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <strings.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "encoding.h"
|
||||||
|
|
||||||
/* For FreeBSD */
|
int
|
||||||
#ifndef MIN
|
inline_dotify(char *buf, size_t buflen)
|
||||||
#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)
|
|
||||||
{
|
{
|
||||||
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 */
|
writer = buf;
|
||||||
c |= ((*src & 0xC0) >> 6); /* 1100 0000 second byte */
|
writer += total;
|
||||||
*dest++ = base32[(int) c];
|
writer += dots;
|
||||||
|
|
||||||
*dest++ = base32[(*src & 0x3E) >> 1]; /* 0011 1110 second byte */
|
total += dots;
|
||||||
|
if (strlen(buf) + dots > buflen) {
|
||||||
c = (*src++ & 0x01) << 4; /* 0000 0001 second byte */
|
writer = buf;
|
||||||
c |= ((*src & 0xF0) >> 4); /* 1111 0000 third byte */
|
writer += buflen;
|
||||||
*dest++ = base32[(int) c];
|
total = buflen;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c = reverse32[(int) *src++] << 3; /* Take bits 11111 from byte 1 */
|
reader = writer - dots;
|
||||||
c |= (reverse32[(int) *src] & 0x1C) >> 2; /* Take bits 11100 from byte 2 */
|
pos = (unsigned) (reader - buf) + 1;
|
||||||
*dest++ = c;
|
|
||||||
|
|
||||||
c = (reverse32[(int) *src++] & 0x3) << 6; /* Take bits 00011 from byte 2 */
|
while (dots) {
|
||||||
c |= reverse32[(int) *src++] << 1; /* Take bits 11111 from byte 3 */
|
if (pos % 62 == 0) {
|
||||||
c |= (reverse32[(int) *src] & 0x10) >> 4; /* Take bits 10000 from byte 4 */
|
*writer-- = '.';
|
||||||
*dest++ = c;
|
dots--;
|
||||||
|
}
|
||||||
|
*writer-- = *reader--;
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
|
||||||
c = (reverse32[(int) *src++] & 0xF) << 4; /* Take bits 01111 from byte 4 */
|
/* return new length of string */
|
||||||
c |= (reverse32[(int) *src] & 0x1E) >> 1; /* Take bits 11110 from byte 5 */
|
return total;
|
||||||
*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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
encode_data(const char *buf, const size_t len, int space, char *dest)
|
inline_undotify(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
int final;
|
unsigned pos;
|
||||||
int write;
|
unsigned dots;
|
||||||
int realwrite;
|
char *reader, *writer;
|
||||||
int chunks;
|
|
||||||
int leftovers;
|
|
||||||
int i;
|
|
||||||
char encoded[255];
|
|
||||||
char padding[5];
|
|
||||||
const char *dp;
|
|
||||||
char *pp;
|
|
||||||
char *ep;
|
|
||||||
|
|
||||||
space -= space / SPACING;
|
writer = buf;
|
||||||
chunks = (space - 1) / ENC_CHUNK;
|
reader = writer;
|
||||||
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;
|
|
||||||
|
|
||||||
memset(encoded, 0, sizeof(encoded));
|
pos = 0;
|
||||||
ep = encoded;
|
dots = 0;
|
||||||
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);
|
|
||||||
|
|
||||||
pp = padding;
|
while (pos < len) {
|
||||||
*ep++ = padder[leftovers];
|
if (*reader == '.') {
|
||||||
encode_chunk(ep, pp);
|
reader++;
|
||||||
|
pos++;
|
||||||
realwrite += ENC_CHUNK + 1; /* plus padding character */
|
dots++;
|
||||||
}
|
|
||||||
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++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
*writer++ = *reader++;
|
||||||
*ep++ = *src++;
|
pos++;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
/* return new length of string */
|
||||||
|
return len - dots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,16 @@
|
||||||
#ifndef _ENCODING_H_
|
#ifndef _ENCODING_H_
|
||||||
#define _ENCODING_H_
|
#define _ENCODING_H_
|
||||||
|
|
||||||
int encode_data(const char *, const size_t, int, char *);
|
int inline_dotify(char *, size_t);
|
||||||
int decode_data(char *, int, const char *, char *);
|
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_ */
|
#endif /* _ENCODING_H_ */
|
||||||
|
|
||||||
|
|
28
src/iodine.c
28
src/iodine.c
|
@ -35,6 +35,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "encoding.h"
|
||||||
|
#include "base32.h"
|
||||||
#include "dns.h"
|
#include "dns.h"
|
||||||
#include "login.h"
|
#include "login.h"
|
||||||
#include "tun.h"
|
#include "tun.h"
|
||||||
|
@ -62,6 +64,8 @@ static int packetpos;
|
||||||
static int packetlen;
|
static int packetlen;
|
||||||
static uint16_t chunkid;
|
static uint16_t chunkid;
|
||||||
|
|
||||||
|
static struct encoder *enc;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sighandler(int sig)
|
sighandler(int sig)
|
||||||
{
|
{
|
||||||
|
@ -92,23 +96,31 @@ build_hostname(char *buf, size_t buflen,
|
||||||
const char *data, const size_t datalen,
|
const char *data, const size_t datalen,
|
||||||
const char *topdomain)
|
const char *topdomain)
|
||||||
{
|
{
|
||||||
int consumed;
|
int encsize;
|
||||||
int avail;
|
unsigned space;
|
||||||
char *b;
|
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);
|
memset(buf, 0, buflen);
|
||||||
|
|
||||||
|
encsize = enc->encode(buf, &space, data, datalen);
|
||||||
|
|
||||||
|
if (!enc->places_dots())
|
||||||
|
inline_dotify(buf, buflen);
|
||||||
|
|
||||||
b = buf;
|
b = buf;
|
||||||
|
|
||||||
consumed = encode_data(data, datalen, avail, b);
|
|
||||||
|
|
||||||
b += strlen(buf);
|
b += strlen(buf);
|
||||||
|
|
||||||
if (*b != '.')
|
if (*b != '.')
|
||||||
*b++ = '.';
|
*b++ = '.';
|
||||||
|
|
||||||
strncpy(b, topdomain, strlen(topdomain)+1);
|
strncpy(b, topdomain, strlen(topdomain)+1);
|
||||||
|
|
||||||
return consumed;
|
return space;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -523,6 +535,8 @@ main(int argc, char **argv)
|
||||||
device = NULL;
|
device = NULL;
|
||||||
chunkid = 0;
|
chunkid = 0;
|
||||||
|
|
||||||
|
enc = get_base32_encoder();
|
||||||
|
|
||||||
while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
|
while ((choice = getopt(argc, argv, "vfhu:t:d:P:")) != -1) {
|
||||||
switch(choice) {
|
switch(choice) {
|
||||||
case 'v':
|
case 'v':
|
||||||
|
|
|
@ -34,10 +34,11 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "dns.h"
|
#include "dns.h"
|
||||||
|
#include "encoding.h"
|
||||||
|
#include "base32.h"
|
||||||
#include "user.h"
|
#include "user.h"
|
||||||
#include "login.h"
|
#include "login.h"
|
||||||
#include "tun.h"
|
#include "tun.h"
|
||||||
#include "encoding.h"
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
int running = 1;
|
int running = 1;
|
||||||
|
@ -46,6 +47,8 @@ char *topdomain;
|
||||||
|
|
||||||
char password[33];
|
char password[33];
|
||||||
|
|
||||||
|
struct encoder *b32;
|
||||||
|
|
||||||
int my_mtu;
|
int my_mtu;
|
||||||
in_addr_t my_ip;
|
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));
|
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
|
static int
|
||||||
tunnel_dns(int tun_fd, int dns_fd)
|
tunnel_dns(int tun_fd, int dns_fd)
|
||||||
{
|
{
|
||||||
|
@ -133,6 +144,7 @@ tunnel_dns(int tun_fd, int dns_fd)
|
||||||
char logindata[16];
|
char logindata[16];
|
||||||
char out[64*1024];
|
char out[64*1024];
|
||||||
char in[64*1024];
|
char in[64*1024];
|
||||||
|
char unpacked[64*1024];
|
||||||
char *tmp[2];
|
char *tmp[2];
|
||||||
int userid;
|
int userid;
|
||||||
int touser;
|
int touser;
|
||||||
|
@ -145,14 +157,15 @@ tunnel_dns(int tun_fd, int dns_fd)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if(in[0] == 'V' || in[0] == 'v') {
|
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 */
|
/* Version greeting, compare and send ack/nak */
|
||||||
if (read > 4) {
|
if (read > 4) {
|
||||||
/* Received V + 32bits version */
|
/* Received V + 32bits version */
|
||||||
|
|
||||||
version = (((in[1] & 0xff) << 24) |
|
version = (((unpacked[0] & 0xff) << 24) |
|
||||||
((in[2] & 0xff) << 16) |
|
((unpacked[1] & 0xff) << 16) |
|
||||||
((in[3] & 0xff) << 8) |
|
((unpacked[2] & 0xff) << 8) |
|
||||||
((in[4] & 0xff)));
|
((unpacked[3] & 0xff)));
|
||||||
|
|
||||||
if (version == VERSION) {
|
if (version == VERSION) {
|
||||||
userid = find_available_user();
|
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].host), &(dummy.q.from), dummy.q.fromlen);
|
||||||
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
|
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
|
||||||
users[userid].addrlen = dummy.q.fromlen;
|
users[userid].addrlen = dummy.q.fromlen;
|
||||||
|
users[userid].encoder = get_base32_encoder();
|
||||||
send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
|
send_version_response(dns_fd, VERSION_ACK, users[userid].seed, &users[userid]);
|
||||||
users[userid].q.id = 0;
|
users[userid].q.id = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -174,8 +188,9 @@ tunnel_dns(int tun_fd, int dns_fd)
|
||||||
send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
|
send_version_response(dns_fd, VERSION_NACK, VERSION, &dummy);
|
||||||
}
|
}
|
||||||
} else if(in[0] == 'L' || in[0] == 'l') {
|
} else if(in[0] == 'L' || in[0] == 'l') {
|
||||||
|
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
|
||||||
/* Login phase, handle auth */
|
/* Login phase, handle auth */
|
||||||
userid = in[1];
|
userid = unpacked[0];
|
||||||
if (userid < 0 || userid >= USERS) {
|
if (userid < 0 || userid >= USERS) {
|
||||||
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
|
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
|
||||||
return 0; /* illegal id */
|
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) {
|
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
|
||||||
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
|
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
|
||||||
} else {
|
} 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 */
|
/* Login ok, send ip/mtu info */
|
||||||
|
|
||||||
tempip.s_addr = my_ip;
|
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') {
|
} else if(in[0] == 'P' || in[0] == 'p') {
|
||||||
|
read = unpack_data(unpacked, sizeof(unpacked), &(in[1]), read - 1, b32);
|
||||||
/* Ping packet, store userid */
|
/* Ping packet, store userid */
|
||||||
userid = in[1];
|
userid = unpacked[0];
|
||||||
if (userid < 0 || userid >= USERS) {
|
if (userid < 0 || userid >= USERS) {
|
||||||
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
|
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
|
||||||
return 0; /* illegal id */
|
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) {
|
memcmp(&(users[userid].host), &(dummy.q.from), dummy.q.fromlen) != 0) {
|
||||||
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
|
write_dns(dns_fd, &(dummy.q), "BADIP", 5);
|
||||||
} else {
|
} 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);
|
users[userid].last_pkt = time(NULL);
|
||||||
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
|
memcpy(&(users[userid].q), &(dummy.q), sizeof(struct query));
|
||||||
users[userid].addrlen = dummy.q.fromlen;
|
users[userid].addrlen = dummy.q.fromlen;
|
||||||
memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, in + 1, read - 1);
|
memcpy(users[userid].inpacket.data + users[userid].inpacket.offset, unpacked, read);
|
||||||
users[userid].inpacket.len += read - 1;
|
users[userid].inpacket.len += read;
|
||||||
users[userid].inpacket.offset += read - 1;
|
users[userid].inpacket.offset += read;
|
||||||
|
|
||||||
if (code & 1) {
|
if (code & 1) {
|
||||||
outlen = sizeof(out);
|
outlen = sizeof(out);
|
||||||
|
@ -351,7 +371,8 @@ read_dns(int fd, struct query *q, char *buf, int buflen)
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
dns_decode(buf, buflen, q, QR_QUERY, packet, r);
|
dns_decode(buf, buflen, q, QR_QUERY, packet, r);
|
||||||
domain = strstr(q->name, topdomain);
|
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;
|
q->fromlen = addrlen;
|
||||||
memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
|
memcpy((struct sockaddr*)&q->from, (struct sockaddr*)&from, addrlen);
|
||||||
} else if (r < 0) {
|
} else if (r < 0) {
|
||||||
|
@ -438,6 +459,8 @@ main(int argc, char **argv)
|
||||||
listen_ip = INADDR_ANY;
|
listen_ip = INADDR_ANY;
|
||||||
port = 53;
|
port = 53;
|
||||||
|
|
||||||
|
b32 = get_base32_encoder();
|
||||||
|
|
||||||
memset(password, 0, 33);
|
memset(password, 0, 33);
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
|
||||||
|
|
|
@ -47,5 +47,6 @@ login_calculate(char *buf, int buflen, char *pass, int seed)
|
||||||
md5_init(&ctx);
|
md5_init(&ctx);
|
||||||
md5_append(&ctx, temp, 32);
|
md5_append(&ctx, temp, 32);
|
||||||
md5_finish(&ctx, (unsigned char *) buf);
|
md5_finish(&ctx, (unsigned char *) buf);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "encoding.h"
|
||||||
#include "user.h"
|
#include "user.h"
|
||||||
|
|
||||||
struct user users[USERS];
|
struct user users[USERS];
|
||||||
|
|
|
@ -30,6 +30,7 @@ struct user {
|
||||||
struct query q;
|
struct query q;
|
||||||
struct packet inpacket;
|
struct packet inpacket;
|
||||||
struct packet outpacket;
|
struct packet outpacket;
|
||||||
|
struct encoder *encoder;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct user users[USERS];
|
extern struct user users[USERS];
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
/* This is the version of the network protocol
|
/* This is the version of the network protocol
|
||||||
It is usually equal to the latest iodine version number */
|
It is usually equal to the latest iodine version number */
|
||||||
#define VERSION 0x00000400
|
#define VERSION 0x00000401
|
||||||
|
|
||||||
#endif /* _VERSION_H_ */
|
#endif /* _VERSION_H_ */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue