Applied patch from #88, thanks a lot!

This commit is contained in:
J. A. Bezemer
2009-12-29 20:00:57 +00:00
committed by Erik Ekman
parent 1a26a91db3
commit b177901d38
19 changed files with 2813 additions and 1054 deletions

View File

@@ -1,4 +1,4 @@
COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o md5.o common.o
COMMONOBJS = tun.o dns.o read.o encoding.o login.o base32.o base64.o base64u.o base128.o md5.o common.o
CLIENTOBJS = iodine.o client.o util.o
CLIENT = ../bin/iodine
SERVEROBJS = iodined.o user.o fw_query.o
@@ -30,7 +30,17 @@ $(SERVER): $(COMMONOBJS) $(SERVEROBJS)
@echo CC $<
@$(CC) $(CFLAGS) $< -o $@
base64u.o client.o iodined.o: base64u.h
base64u.c: base64.c
@echo Making $@
@echo '/* No use in editing, produced by Makefile! */' > $@
@sed -e 's/\(base64\)/\1u/ig ; s/0123456789+/0123456789_/' < $< >> $@
base64u.h: base64.h
@echo Making $@
@echo '/* No use in editing, produced by Makefile! */' > $@
@sed -e 's/\(base64\)/\1u/ig ; s/0123456789+/0123456789_/' < $< >> $@
clean:
@echo "Cleaning src/"
@rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core
@rm -f $(CLIENT){,.exe} $(SERVER){,.exe} *~ *.o *.core base64u.*

291
src/base128.c Normal file
View File

@@ -0,0 +1,291 @@
/*
* Copyright (C) 2009 J.A.Bezemer@opensourcepartners.nl
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* raw 76543210 76543210 76543210 76543210 76543210 76543210 76543210
* enc 65432106 54321065 43210654 32106543 21065432 10654321 06543210
* ^ ^ ^ ^ ^ ^ ^ ^
*
* 0001 1 0001 1
* 0011 3 0011 3
* 0111 7 0111 7
* 1111 f 0110 6
* 1110 e 0100 4
* 1100 c
* 1000 8
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "encoding.h"
#include "base128.h"
#define BLKSIZE_RAW 7
#define BLKSIZE_ENC 8
/* Don't use '-' (restricted to middle of labels), prefer iso_8859-1
* accent chars since they might readily be entered in normal use,
* don't use 254-255 because of possible function overloading in DNS systems.
*/
static const unsigned char cb128[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
"\274\275\276\277"
"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
"\360\361\362\363\364\365\366\367\370\371\372\373\374\375";
static unsigned char rev128[256];
static int reverse_init = 0;
static int base128_encode(char *, size_t *, const void *, size_t);
static int base128_decode(void *, size_t *, const char *, size_t);
static int base128_handles_dots();
static int base128_blksize_raw();
static int base128_blksize_enc();
static struct encoder base128_encoder =
{
"Base128",
base128_encode,
base128_decode,
base128_handles_dots,
base128_handles_dots,
base128_blksize_raw,
base128_blksize_enc
};
struct encoder
*get_base128_encoder()
{
return &base128_encoder;
}
static int
base128_handles_dots()
{
return 0;
}
static int
base128_blksize_raw()
{
return BLKSIZE_RAW;
}
static int
base128_blksize_enc()
{
return BLKSIZE_ENC;
}
inline static void
base128_reverse_init()
{
int i;
unsigned char c;
if (!reverse_init) {
memset (rev128, 0, 256);
for (i = 0; i < 128; i++) {
c = cb128[i];
rev128[(int) c] = i;
}
reverse_init = 1;
}
}
static int
base128_encode(char *buf, size_t *buflen, const void *data, size_t size)
/*
* Fills *buf with max. *buflen characters, encoding size bytes of *data.
*
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
* to hold the trailing '\0'.
*
* return value : #bytes filled in buf (excluding \0)
* sets *buflen to : #bytes encoded from data
*/
{
unsigned char *ubuf = (unsigned char *) buf;
unsigned char *udata = (unsigned char *) data;
int iout = 0; /* to-be-filled output char */
int iin = 0; /* one more than last input byte that can be
successfully decoded */
/* Note: Don't bother to optimize manually. GCC optimizes
better(!) when using simplistic array indexing. */
while (1) {
if (iout >= *buflen || iin >= size)
break;
ubuf[iout] = cb128[((udata[iin] & 0xfe) >> 1)];
iout++;
if (iout >= *buflen || iin >= size) {
iout--; /* previous char is useless */
break;
}
ubuf[iout] = cb128[((udata[iin] & 0x01) << 6) |
((iin + 1 < size) ?
((udata[iin + 1] & 0xfc) >> 2) : 0)];
iin++; /* 0 complete, iin=1 */
iout++;
if (iout >= *buflen || iin >= size)
break;
ubuf[iout] = cb128[((udata[iin] & 0x03) << 5) |
((iin + 1 < size) ?
((udata[iin + 1] & 0xf8) >> 3) : 0)];
iin++; /* 1 complete, iin=2 */
iout++;
if (iout >= *buflen || iin >= size)
break;
ubuf[iout] = cb128[((udata[iin] & 0x07) << 4) |
((iin + 1 < size) ?
((udata[iin + 1] & 0xf0) >> 4) : 0)];
iin++; /* 2 complete, iin=3 */
iout++;
if (iout >= *buflen || iin >= size)
break;
ubuf[iout] = cb128[((udata[iin] & 0x0f) << 3) |
((iin + 1 < size) ?
((udata[iin + 1] & 0xe0) >> 5) : 0)];
iin++; /* 3 complete, iin=4 */
iout++;
if (iout >= *buflen || iin >= size)
break;
ubuf[iout] = cb128[((udata[iin] & 0x1f) << 2) |
((iin + 1 < size) ?
((udata[iin + 1] & 0xc0) >> 6) : 0)];
iin++; /* 4 complete, iin=5 */
iout++;
if (iout >= *buflen || iin >= size)
break;
ubuf[iout] = cb128[((udata[iin] & 0x3f) << 1) |
((iin + 1 < size) ?
((udata[iin + 1] & 0x80) >> 7) : 0)];
iin++; /* 5 complete, iin=6 */
iout++;
if (iout >= *buflen || iin >= size)
break;
ubuf[iout] = cb128[(udata[iin] & 0x7f)];
iin++; /* 6 complete, iin=7 */
iout++;
}
ubuf[iout] = '\0';
/* store number of bytes from data that was used */
*buflen = iin;
return iout;
}
#define REV128(x) rev128[(int) (x)]
static int
base128_decode(void *buf, size_t *buflen, const char *str, size_t slen)
/*
* Fills *buf with max. *buflen bytes, decoded from slen chars in *str.
* Decoding stops early when *str contains \0.
* Illegal encoded chars are assumed to decode to zero.
*
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
* to hold a trailing '\0' that is added (though *buf will usually
* contain full-binary data).
*
* return value : #bytes filled in buf (excluding \0)
*/
{
unsigned char *ustr = (unsigned char *) str;
unsigned char *ubuf = (unsigned char *) buf;
int iout = 0; /* to-be-filled output byte */
int iin = 0; /* next input char to use in decoding */
base128_reverse_init ();
/* Note: Don't bother to optimize manually. GCC optimizes
better(!) when using simplistic array indexing. */
while (1) {
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV128(ustr[iin]) & 0x7f) << 1) |
((REV128(ustr[iin + 1]) & 0x40) >> 6);
iin++; /* 0 used up, iin=1 */
iout++;
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV128(ustr[iin]) & 0x3f) << 2) |
((REV128(ustr[iin + 1]) & 0x60) >> 5);
iin++; /* 1 used up, iin=2 */
iout++;
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV128(ustr[iin]) & 0x1f) << 3) |
((REV128(ustr[iin + 1]) & 0x70) >> 4);
iin++; /* 2 used up, iin=3 */
iout++;
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV128(ustr[iin]) & 0x0f) << 4) |
((REV128(ustr[iin + 1]) & 0x78) >> 3);
iin++; /* 3 used up, iin=4 */
iout++;
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV128(ustr[iin]) & 0x07) << 5) |
((REV128(ustr[iin + 1]) & 0x7c) >> 2);
iin++; /* 4 used up, iin=5 */
iout++;
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV128(ustr[iin]) & 0x03) << 6) |
((REV128(ustr[iin + 1]) & 0x7e) >> 1);
iin++; /* 5 used up, iin=6 */
iout++;
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV128(ustr[iin]) & 0x01) << 7) |
((REV128(ustr[iin + 1]) & 0x7f));
iin += 2; /* 6,7 used up, iin=8 */
iout++;
}
ubuf[iout] = '\0';
return iout;
}

22
src/base128.h Normal file
View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2009 J.A.Bezemer@opensourcepartners.nl
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef __BASE128_H__
#define __BASE128_H__
struct encoder *get_base128_encoder(void);
#endif

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -28,10 +29,11 @@ static const char cb32[] =
"abcdefghijklmnopqrstuvwxyz012345";
static const char cb32_ucase[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
static unsigned char rev32[128];
static unsigned char rev32[256];
static int reverse_init = 0;
static int base32_decode(void *, size_t *, const char *, size_t);
static int base32_encode(char *, size_t *, const void *, size_t);
static int base32_decode(void *, size_t *, const char *, size_t);
static int base32_handles_dots();
static int base32_blksize_raw();
static int base32_blksize_enc();
@@ -71,14 +73,14 @@ base32_blksize_enc()
return BLKSIZE_ENC;
}
static void
inline static void
base32_reverse_init()
{
int i;
unsigned char c;
static int reverse_init = 0;
if (!reverse_init) {
memset (rev32, 0, 256);
for (i = 0; i < 32; i++) {
c = cb32[i];
rev32[(int) c] = i;
@@ -104,123 +106,165 @@ b32_8to5(int in)
static int
base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
/*
* Fills *buf with max. *buflen characters, encoding size bytes of *data.
*
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
* to hold the trailing '\0'.
*
* return value : #bytes filled in buf (excluding \0)
* sets *buflen to : #bytes encoded from data
*/
{
size_t newsize;
size_t maxsize;
unsigned char *p;
unsigned char *q;
int i;
unsigned char *udata = (unsigned char *) data;
int iout = 0; /* to-be-filled output char */
int iin = 0; /* one more than last input byte that can be
successfully decoded */
memset(buf, 0, *buflen);
/* Note: Don't bother to optimize manually. GCC optimizes
better(!) when using simplistic array indexing. */
/* how many chars can we encode within the buf */
maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC);
/* how big will the encoded data be */
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW);
if (size % BLKSIZE_RAW) {
newsize += BLKSIZE_ENC;
}
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
size = maxsize;
while (1) {
if (iout >= *buflen || iin >= size)
break;
buf[iout] = cb32[((udata[iin] & 0xf8) >> 3)];
iout++;
if (iout >= *buflen || iin >= size) {
iout--; /* previous char is useless */
break;
}
buf[iout] = cb32[((udata[iin] & 0x07) << 2) |
((iin + 1 < size) ?
((udata[iin + 1] & 0xc0) >> 6) : 0)];
iin++; /* 0 complete, iin=1 */
iout++;
if (iout >= *buflen || iin >= size)
break;
buf[iout] = cb32[((udata[iin] & 0x3e) >> 1)];
iout++;
if (iout >= *buflen || iin >= size) {
iout--; /* previous char is useless */
break;
}
buf[iout] = cb32[((udata[iin] & 0x01) << 4) |
((iin + 1 < size) ?
((udata[iin + 1] & 0xf0) >> 4) : 0)];
iin++; /* 1 complete, iin=2 */
iout++;
if (iout >= *buflen || iin >= size)
break;
buf[iout] = cb32[((udata[iin] & 0x0f) << 1) |
((iin + 1 < size) ?
((udata[iin + 1] & 0x80) >> 7) : 0)];
iin++; /* 2 complete, iin=3 */
iout++;
if (iout >= *buflen || iin >= size)
break;
buf[iout] = cb32[((udata[iin] & 0x7c) >> 2)];
iout++;
if (iout >= *buflen || iin >= size) {
iout--; /* previous char is useless */
break;
}
buf[iout] = cb32[((udata[iin] & 0x03) << 3) |
((iin + 1 < size) ?
((udata[iin + 1] & 0xe0) >> 5) : 0)];
iin++; /* 3 complete, iin=4 */
iout++;
if (iout >= *buflen || iin >= size)
break;
buf[iout] = cb32[((udata[iin] & 0x1f))];
iin++; /* 4 complete, iin=5 */
iout++;
}
p = (unsigned char *) buf;
q = (unsigned char *)data;
for(i=0;i<size;i+=BLKSIZE_RAW) {
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] & 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 += BLKSIZE_RAW;
p += BLKSIZE_ENC;
}
*p = 0;
buf[iout] = '\0';
/* store number of bytes from data that was used */
*buflen = size;
*buflen = iin;
return strlen(buf);
return iout;
}
#define DECODE_ERROR 0xffffffff
#define REV32(x) rev32[(int) (x)]
static int
decode_token(const unsigned char *t, unsigned char *data, size_t len)
{
if (len < 2)
return 0;
data[0] = ((REV32(t[0]) & 0x1f) << 3) |
((REV32(t[1]) & 0x1c) >> 2);
if (len < 4)
return 1;
data[1] = ((REV32(t[1]) & 0x03) << 6) |
((REV32(t[2]) & 0x1f) << 1) |
((REV32(t[3]) & 0x10) >> 4);
if (len < 5)
return 2;
data[2] = ((REV32(t[3]) & 0x0f) << 4) |
((REV32(t[4]) & 0x1e) >> 1);
if (len < 7)
return 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] = ((REV32(t[6]) & 0x07) << 5) |
((REV32(t[7]) & 0x1f));
return 5;
}
static int
base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
/*
* Fills *buf with max. *buflen bytes, decoded from slen chars in *str.
* Decoding stops early when *str contains \0.
* Illegal encoded chars are assumed to decode to zero.
*
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
* to hold a trailing '\0' that is added (though *buf will usually
* contain full-binary data).
*
* return value : #bytes filled in buf (excluding \0)
*/
{
unsigned char *q;
size_t newsize;
size_t maxsize;
const char *p;
int len;
unsigned char *ubuf = (unsigned char *) buf;
int iout = 0; /* to-be-filled output byte */
int iin = 0; /* next input char to use in decoding */
base32_reverse_init();
/* chars needed to decode slen */
newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
/* encoded chars that fit in buf */
maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
slen = maxsize;
}
base32_reverse_init ();
q = buf;
for (p = str; *p && strchr(cb32, *p); p += BLKSIZE_ENC) {
len = decode_token((unsigned char *) p, (unsigned char *) q, slen);
q += len;
slen -= BLKSIZE_ENC;
if (len < BLKSIZE_RAW)
/* Note: Don't bother to optimize manually. GCC optimizes
better(!) when using simplistic array indexing. */
while (1) {
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
}
*q = '\0';
return q - (unsigned char *) buf;
}
ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) |
((REV32(str[iin + 1]) & 0x1c) >> 2);
iin++; /* 0 used up, iin=1 */
iout++;
if (iout >= *buflen || iin + 2 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0' ||
str[iin + 2] == '\0')
break;
ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) |
((REV32(str[iin + 1]) & 0x1f) << 1) |
((REV32(str[iin + 2]) & 0x10) >> 4);
iin += 2; /* 1,2 used up, iin=3 */
iout++;
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV32(str[iin]) & 0x0f) << 4) |
((REV32(str[iin + 1]) & 0x1e) >> 1);
iin++; /* 3 used up, iin=4 */
iout++;
if (iout >= *buflen || iin + 2 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0' ||
str[iin + 2] == '\0')
break;
ubuf[iout] = ((REV32(str[iin]) & 0x01) << 7) |
((REV32(str[iin + 1]) & 0x1f) << 2) |
((REV32(str[iin + 2]) & 0x18) >> 3);
iin += 2; /* 4,5 used up, iin=6 */
iout++;
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV32(str[iin]) & 0x07) << 5) |
((REV32(str[iin + 1]) & 0x1f));
iin += 2; /* 6,7 used up, iin=8 */
iout++;
}
ubuf[iout] = '\0';
return iout;
}

View File

@@ -1,5 +1,6 @@
/*
* Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
* Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -19,15 +20,16 @@
#include <string.h>
#include "encoding.h"
#include "common.h"
#include "base64.h"
#define BLKSIZE_RAW 3
#define BLKSIZE_ENC 4
/* Note: the "unofficial" char is last here, which means that the \377 pattern
in DOWNCODECCHECK1 ('Y' request) will properly test it. */
static const char cb64[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+";
static unsigned char rev64[128];
static unsigned char rev64[256];
static int reverse_init = 0;
static int base64_encode(char *, size_t *, const void *, size_t);
@@ -36,8 +38,6 @@ static int base64_handles_dots();
static int base64_blksize_raw();
static int base64_blksize_enc();
#define REV64(x) rev64[(int) (x)]
static struct encoder base64_encoder =
{
"Base64",
@@ -73,122 +73,133 @@ base64_blksize_enc()
return BLKSIZE_ENC;
}
static int
base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
inline static void
base64_reverse_init()
{
size_t newsize;
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 = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC);
/* how big will the encoded data be */
newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW);
if (size % BLKSIZE_RAW) {
newsize += BLKSIZE_ENC;
}
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
size = maxsize;
}
p = s = (unsigned char *) buf;
q = (unsigned char *)data;
for(i=0;i<size;i+=BLKSIZE_RAW) {
p[0] = cb64[((q[0] & 0xfc) >> 2)];
p[1] = cb64[(((q[0] & 0x03) << 4) | ((q[1] & 0xf0) >> 4))];
p[2] = (i+1 < size) ? cb64[((q[1] & 0x0f) << 2 ) | ((q[2] & 0xc0) >> 6)] : '\0';
p[3] = (i+2 < size) ? cb64[(q[2] & 0x3f)] : '\0';
q += BLKSIZE_RAW;
p += BLKSIZE_ENC;
}
*p = 0;
/* store number of bytes from data that was used */
*buflen = size;
return strlen(buf);
}
#define DECODE_ERROR 0xffffffff
static int
decode_token(const unsigned char *t, unsigned char *data, size_t len)
{
if (len < 2)
return 0;
data[0] = ((REV64(t[0]) & 0x3f) << 2) |
((REV64(t[1]) & 0x30) >> 4);
if (len < 3)
return 1;
data[1] = ((REV64(t[1]) & 0x0f) << 4) |
((REV64(t[2]) & 0x3c) >> 2);
if (len < 4)
return 2;
data[2] = ((REV64(t[2]) & 0x03) << 6) |
(REV64(t[3]) & 0x3f);
return 3;
}
static int
base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
{
unsigned char *q;
size_t newsize;
size_t maxsize;
const char *p;
unsigned char c;
unsigned char block[BLKSIZE_ENC];
int len;
int i;
if (!reverse_init) {
memset (rev64, 0, 256);
for (i = 0; i < 64; i++) {
c = cb64[i];
rev64[(int) c] = i;
}
reverse_init = 1;
}
/* chars needed to decode slen */
newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
/* encoded chars that fit in buf */
maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1;
/* if the buffer is too small, eat some of the data */
if (*buflen < newsize) {
slen = maxsize;
}
q = buf;
for (p = str; *p; p += BLKSIZE_ENC) {
/* since the str is const, we unescape in another buf */
for (i = 0; i < BLKSIZE_ENC; i++) {
block[i] = p[i];
}
len = decode_token(block, (unsigned char *) q, slen);
q += len;
slen -= BLKSIZE_ENC;
if (len < BLKSIZE_RAW)
break;
}
*q = '\0';
return q - (unsigned char *) buf;
}
static int
base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
/*
* Fills *buf with max. *buflen characters, encoding size bytes of *data.
*
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
* to hold the trailing '\0'.
*
* return value : #bytes filled in buf (excluding \0)
* sets *buflen to : #bytes encoded from data
*/
{
unsigned char *udata = (unsigned char *) data;
int iout = 0; /* to-be-filled output char */
int iin = 0; /* one more than last input byte that can be
successfully decoded */
/* Note: Don't bother to optimize manually. GCC optimizes
better(!) when using simplistic array indexing. */
while (1) {
if (iout >= *buflen || iin >= size)
break;
buf[iout] = cb64[((udata[iin] & 0xfc) >> 2)];
iout++;
if (iout >= *buflen || iin >= size) {
iout--; /* previous char is useless */
break;
}
buf[iout] = cb64[((udata[iin] & 0x03) << 4) |
((iin + 1 < size) ?
((udata[iin + 1] & 0xf0) >> 4) : 0)];
iin++; /* 0 complete, iin=1 */
iout++;
if (iout >= *buflen || iin >= size)
break;
buf[iout] = cb64[((udata[iin] & 0x0f) << 2 ) |
((iin + 1 < size) ?
((udata[iin + 1] & 0xc0) >> 6) : 0)];
iin++; /* 1 complete, iin=2 */
iout++;
if (iout >= *buflen || iin >= size)
break;
buf[iout] = cb64[(udata[iin] & 0x3f)];
iin++; /* 2 complete, iin=3 */
iout++;
}
buf[iout] = '\0';
/* store number of bytes from data that was used */
*buflen = iin;
return iout;
}
#define REV64(x) rev64[(int) (x)]
static int
base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
/*
* Fills *buf with max. *buflen bytes, decoded from slen chars in *str.
* Decoding stops early when *str contains \0.
* Illegal encoded chars are assumed to decode to zero.
*
* NOTE: *buf space should be at least 1 byte _more_ than *buflen
* to hold a trailing '\0' that is added (though *buf will usually
* contain full-binary data).
*
* return value : #bytes filled in buf (excluding \0)
*/
{
unsigned char *ubuf = (unsigned char *) buf;
int iout = 0; /* to-be-filled output byte */
int iin = 0; /* next input char to use in decoding */
base64_reverse_init ();
/* Note: Don't bother to optimize manually. GCC optimizes
better(!) when using simplistic array indexing. */
while (1) {
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) |
((REV64(str[iin + 1]) & 0x30) >> 4);
iin++; /* 0 used up, iin=1 */
iout++;
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) |
((REV64(str[iin + 1]) & 0x3c) >> 2);
iin++; /* 1 used up, iin=2 */
iout++;
if (iout >= *buflen || iin + 1 >= slen ||
str[iin] == '\0' || str[iin + 1] == '\0')
break;
ubuf[iout] = ((REV64(str[iin]) & 0x03) << 6) |
(REV64(str[iin + 1]) & 0x3f);
iin += 2; /* 2,3 used up, iin=4 */
iout++;
}
ubuf[iout] = '\0';
return iout;
}

File diff suppressed because it is too large Load Diff

View File

@@ -27,9 +27,11 @@ void client_set_nameserver(const char *cp, int port);
void client_set_topdomain(const char *cp);
void client_set_password(const char *cp);
void set_qtype(char *qtype);
char *get_qtype();
void set_downenc(char *encoding);
void client_set_selecttimeout(int select_timeout);
void client_set_lazymode(int lazy_mode);
void client_set_hostname_maxlen(int i);
int client_handshake(int dns_fd, int raw_mode, int autodetect_frag_size, int fragsize);
int client_tunnel(int tun_fd, int dns_fd);

View File

@@ -74,6 +74,9 @@ extern const unsigned char raw_header[RAW_HDR_LEN];
# define DONT_FRAG_VALUE 1
#endif
#define T_UNSET 65432
/* Unused RR type; "private use" range, see http://www.bind9.net/dns-parameters */
struct packet
{
int len; /* Total packet length */
@@ -89,10 +92,12 @@ struct query {
unsigned short type;
unsigned short rcode;
unsigned short id;
unsigned short iddupe; /* only used for dupe checking */
struct in_addr destination;
struct sockaddr from;
int fromlen;
unsigned short id2;
struct sockaddr from2;
int fromlen2;
};
enum connection {

292
src/dns.c
View File

@@ -39,6 +39,8 @@
#include "encoding.h"
#include "read.h"
int dnsc_use_edns0 = 1;
#define CHECKLEN(x) if (buflen - (p-buf) < (x)) return 0
int
@@ -48,6 +50,7 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
short name;
char *p;
int len;
int ancnt;
if (buflen < sizeof(HEADER))
return 0;
@@ -68,7 +71,6 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
switch (qr) {
case QR_ANSWER:
header->ancount = htons(1);
header->qdcount = htons(1);
name = 0xc000 | ((p - buf) & 0x3fff);
@@ -81,56 +83,115 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
putshort(&p, C_IN);
/* Answer section */
CHECKLEN(10);
putshort(&p, name);
if (q->type == T_A)
putshort(&p, T_CNAME); /* answer CNAME to A question */
else
putshort(&p, q->type);
putshort(&p, C_IN);
putlong(&p, 0); /* TTL */
if (q->type == T_CNAME || q->type == T_A || q->type == T_MX) {
if (q->type == T_CNAME || q->type == T_A) {
/* data is expected to be like "Hblabla.host.name.com\0" */
char *startp = p;
char *startp;
int namelen;
CHECKLEN(10);
putshort(&p, name);
if (q->type == T_A)
/* answer CNAME to A question */
putshort(&p, T_CNAME);
else
putshort(&p, q->type);
putshort(&p, C_IN);
putlong(&p, 0); /* TTL */
startp = p;
p += 2; /* skip 2 bytes length */
CHECKLEN(2);
if (q->type == T_MX)
putshort(&p, 10); /* preference */
putname(&p, buflen - (p - buf), data);
CHECKLEN(0);
namelen = p - startp;
namelen -= 2;
putshort(&startp, namelen);
ancnt = 1;
} else if (q->type == T_MX || q->type == T_SRV) {
/* Data is expected to be like
"Hblabla.host.name.com\0Hanother.com\0\0"
For SRV, see RFC2782.
*/
char *mxdata = data;
char *startp;
int namelen;
ancnt = 1;
while (1) {
CHECKLEN(10);
putshort(&p, name);
putshort(&p, q->type);
putshort(&p, C_IN);
putlong(&p, 0); /* TTL */
startp = p;
p += 2; /* skip 2 bytes length */
CHECKLEN(2);
putshort(&p, 10 * ancnt); /* preference */
if (q->type == T_SRV) {
/* weight, port (5060 = SIP) */
CHECKLEN(4);
putshort(&p, 10);
putshort(&p, 5060);
}
putname(&p, buflen - (p - buf), mxdata);
CHECKLEN(0);
namelen = p - startp;
namelen -= 2;
putshort(&startp, namelen);
mxdata = mxdata + strlen(mxdata) + 1;
if (*mxdata == '\0')
break;
ancnt++;
}
} else if (q->type == T_TXT) {
/* TXT has binary or base-X data */
char *startp = p;
char *startp;
int txtlen;
CHECKLEN(10);
putshort(&p, name);
putshort(&p, q->type);
putshort(&p, C_IN);
putlong(&p, 0); /* TTL */
startp = p;
p += 2; /* skip 2 bytes length */
puttxtbin(&p, buflen - (p - buf), data, datalen);
CHECKLEN(0);
txtlen = p - startp;
txtlen -= 2;
putshort(&startp, txtlen);
ancnt = 1;
} else {
/* NULL has raw binary data */
CHECKLEN(10);
putshort(&p, name);
putshort(&p, q->type);
putshort(&p, C_IN);
putlong(&p, 0); /* TTL */
datalen = MIN(datalen, buflen - (p - buf));
CHECKLEN(2);
putshort(&p, datalen);
CHECKLEN(datalen);
putdata(&p, data, datalen);
CHECKLEN(0);
ancnt = 1;
}
header->ancount = htons(ancnt);
break;
case QR_QUERY:
/* Note that iodined also uses this for forward queries */
header->qdcount = htons(1);
header->arcount = htons(1);
datalen = MIN(datalen, buflen - (p - buf));
putname(&p, datalen, data);
@@ -141,6 +202,9 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
/* EDNS0 to advertise maximum response length
(even CNAME/A/MX, 255+255+header would be >512) */
if (dnsc_use_edns0) {
header->arcount = htons(1);
/*XXX START adjust indent 1 tab forward*/
CHECKLEN(11);
putbyte(&p, 0x00); /* Root */
putshort(&p, 0x0029); /* OPT */
@@ -148,6 +212,9 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
putshort(&p, 0x0000); /* Higher bits/edns version */
putshort(&p, 0x8000); /* Z */
putshort(&p, 0x0000); /* Data length */
/*XXX END adjust indent 1 tab forward*/
}
break;
}
@@ -159,13 +226,14 @@ dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_
int
dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain)
/* Only used when iodined gets an NS type query */
/* Mostly same as dns_encode_a_response() below */
{
HEADER *header;
int len;
short name;
short topname;
short nsname;
char *domain;
char *ipp;
int domain_len;
char *p;
@@ -193,13 +261,16 @@ dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomai
/* pointer to start of name */
name = 0xc000 | ((p - buf) & 0x3fff);
domain = strstr(q->name, topdomain);
if (domain) {
domain_len = (int) (domain - q->name);
} else {
domain_len = strlen(q->name) - strlen(topdomain);
if (domain_len < 0 || domain_len == 1)
return -1;
}
/* pointer to start of topdomain */
if (strcasecmp(q->name + domain_len, topdomain))
return -1;
if (domain_len >= 1 && q->name[domain_len - 1] != '.')
return -1;
/* pointer to start of topdomain; instead of dots at the end
we have length-bytes in front, so total length is the same */
topname = 0xc000 | ((p - buf + domain_len) & 0x3fff);
/* Query section */
@@ -233,12 +304,72 @@ dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomai
putshort(&p, 4); /* Data length */
/* ugly hack to output IP address */
domain = (char *) &q->destination;
ipp = (char *) &q->destination;
CHECKLEN(4);
putbyte(&p, *domain++);
putbyte(&p, *domain++);
putbyte(&p, *domain++);
putbyte(&p, *domain);
putbyte(&p, *(ipp++));
putbyte(&p, *(ipp++));
putbyte(&p, *(ipp++));
putbyte(&p, *ipp);
len = p - buf;
return len;
}
int
dns_encode_a_response(char *buf, size_t buflen, struct query *q)
/* Only used when iodined gets an A type query for ns.topdomain or www.topdomain */
/* Mostly same as dns_encode_ns_response() above */
{
HEADER *header;
int len;
short name;
char *ipp;
char *p;
if (buflen < sizeof(HEADER))
return 0;
memset(buf, 0, buflen);
header = (HEADER*)buf;
header->id = htons(q->id);
header->qr = 1;
header->opcode = 0;
header->aa = 1;
header->tc = 0;
header->rd = 0;
header->ra = 0;
p = buf + sizeof(HEADER);
header->qdcount = htons(1);
header->ancount = htons(1);
/* pointer to start of name */
name = 0xc000 | ((p - buf) & 0x3fff);
/* Query section */
putname(&p, buflen - (p - buf), q->name); /* Name */
CHECKLEN(4);
putshort(&p, q->type); /* Type */
putshort(&p, C_IN); /* Class */
/* Answer section */
CHECKLEN(12);
putshort(&p, name); /* Name */
putshort(&p, q->type); /* Type */
putshort(&p, C_IN); /* Class */
putlong(&p, 3600); /* TTL */
putshort(&p, 4); /* Data length */
/* ugly hack to output IP address */
ipp = (char *) &q->destination;
CHECKLEN(4);
putbyte(&p, *(ipp++));
putbyte(&p, *(ipp++));
putbyte(&p, *(ipp++));
putbyte(&p, *ipp);
len = p - buf;
return len;
@@ -276,6 +407,7 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
int id;
int rv;
q->id2 = 0;
rv = 0;
header = (HEADER*)packet;
@@ -324,19 +456,22 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
}
if (ancount < 1) {
/* We may get both CNAME and A, then ancount=2 */
/* DNS errors like NXDOMAIN have ancount=0 and
stop here. CNAME may also have A; MX/SRV may have
multiple results. */
return -1;
}
/* Assume that first answer is NULL/CNAME that we wanted */
readname(packet, packetlen, &data, name, sizeof(name));
CHECKLEN(10);
readshort(packet, &data, &type);
readshort(packet, &data, &class);
readlong(packet, &data, &ttl);
readshort(packet, &data, &rlen);
/* Here type is still the question type */
if (type == T_NULL) {
/* Assume that first answer is what we wanted */
readname(packet, packetlen, &data, name, sizeof(name));
CHECKLEN(10);
readshort(packet, &data, &type);
readshort(packet, &data, &class);
readlong(packet, &data, &ttl);
readshort(packet, &data, &rlen);
rv = MIN(rlen, sizeof(rdata));
rv = readdata(packet, &data, rdata, rv);
if (rv >= 2 && buf) {
@@ -346,9 +481,15 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
rv = 0;
}
}
if ((type == T_CNAME || type == T_MX) && buf) {
if (type == T_MX)
data += 2; /* skip preference */
else if ((type == T_A || type == T_CNAME) && buf) {
/* Assume that first answer is what we wanted */
readname(packet, packetlen, &data, name, sizeof(name));
CHECKLEN(10);
readshort(packet, &data, &type);
readshort(packet, &data, &class);
readlong(packet, &data, &ttl);
readshort(packet, &data, &rlen);
memset(name, 0, sizeof(name));
readname(packet, packetlen, &data, name, sizeof(name) - 1);
name[sizeof(name)-1] = '\0';
@@ -356,7 +497,74 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
buf[buflen - 1] = '\0';
rv = strlen(buf);
}
if (type == T_TXT && buf) {
else if ((type == T_MX || type == T_SRV) && buf) {
/* We support 250 records, 250*(255+header) ~= 64kB.
Only exact 10-multiples are accepted, and gaps in
numbering are not jumped over (->truncated).
Hopefully DNS servers won't mess around too much.
*/
char names[250][QUERY_NAME_SIZE];
char *rdatastart;
short pref;
int i;
int offset;
memset(names, 0, sizeof(names));
for (i=0; i < ancount; i++) {
readname(packet, packetlen, &data, name, sizeof(name));
CHECKLEN(12);
readshort(packet, &data, &type);
readshort(packet, &data, &class);
readlong(packet, &data, &ttl);
readshort(packet, &data, &rlen);
rdatastart = data;
readshort(packet, &data, &pref);
if (type == T_SRV) {
/* skip weight, port */
data += 4;
CHECKLEN(0);
}
if (pref % 10 == 0 && pref >= 10 &&
pref < 2500) {
readname(packet, packetlen, &data,
names[pref / 10 - 1],
QUERY_NAME_SIZE - 1);
names[pref / 10 - 1][QUERY_NAME_SIZE-1] = '\0';
}
/* always trust rlen, not name encoding */
data = rdatastart + rlen;
CHECKLEN(0);
}
/* output is like Hname10.com\0Hname20.com\0\0 */
offset = 0;
i = 0;
while (names[i][0] != '\0') {
int l = MIN(strlen(names[i]), buflen-offset-2);
if (l <= 0)
break;
memcpy(buf + offset, names[i], l);
offset += l;
*(buf + offset) = '\0';
offset++;
i++;
}
*(buf + offset) = '\0';
rv = offset;
}
else if (type == T_TXT && buf) {
/* Assume that first answer is what we wanted */
readname(packet, packetlen, &data, name, sizeof(name));
CHECKLEN(10);
readshort(packet, &data, &type);
readshort(packet, &data, &class);
readlong(packet, &data, &ttl);
readshort(packet, &data, &rlen);
rv = readtxtbin(packet, &data, rlen, rdata, sizeof(rdata));
if (rv >= 1) {
rv = MIN(rv, buflen);
@@ -365,6 +573,8 @@ dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, siz
rv = 0;
}
}
/* Here type is the answer type (note A->CNAME) */
if (q != NULL)
q->type = type;
break;

View File

@@ -24,8 +24,11 @@ typedef enum {
QR_ANSWER = 1
} qr_t;
extern int dnsc_use_edns0;
int dns_encode(char *, size_t, struct query *, qr_t, char *, size_t);
int dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain);
int dns_encode_a_response(char *buf, size_t buflen, struct query *q);
unsigned short dns_get_id(char *packet, size_t packetlen);
int dns_decode(char *, size_t, struct query *, qr_t, char *, size_t);

View File

@@ -21,13 +21,15 @@
int
build_hostname(char *buf, size_t buflen,
const char *data, const size_t datalen,
const char *topdomain, struct encoder *encoder)
const char *topdomain, struct encoder *encoder, int maxlen)
{
int encsize;
size_t space;
char *b;
space = MIN(0xFF, buflen) - strlen(topdomain) - 7;
space = MIN(maxlen, buflen) - strlen(topdomain) - 8;
/* 8 = 5 max header length + 1 dot before topdomain + 2 safety */
if (!encoder->places_dots())
space -= (space / 57); /* space for dots */

View File

@@ -17,6 +17,13 @@
#ifndef _ENCODING_H_
#define _ENCODING_H_
/* All-0, all-1, 01010101, 10101010: each 4 times to make sure the pattern
spreads across multiple encoded chars -> 16 bytes total.
Followed by 32 bytes from my /dev/random; should be enough.
*/
#define DOWNCODECCHECK1 "\000\000\000\000\377\377\377\377\125\125\125\125\252\252\252\252\201\143\310\322\307\174\262\027\137\117\316\311\111\055\122\041\141\251\161\040\045\263\006\163\346\330\104\060\171\120\127\277"
#define DOWNCODECCHECK1_LEN 48
struct encoder {
char name[8];
int (*encode) (char *, size_t *, const void *, size_t);
@@ -27,7 +34,7 @@ struct encoder {
int (*blocksize_encoded)(void);
};
int build_hostname(char *, size_t, const char *, const size_t, const char *, struct encoder *);
int build_hostname(char *, size_t, const char *, const size_t, const char *, struct encoder *, int);
int unpack_data(char *, size_t, char *, size_t, struct encoder *);
int inline_dotify(char *, size_t);
int inline_undotify(char *, size_t);

View File

@@ -61,7 +61,7 @@ usage() {
extern char *__progname;
fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] "
"[-P password] [-m maxfragsize] [-T type] [-O enc] [-L 0|1] [-I sec] "
"[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] "
"[-z context] [-F pidfile] [nameserver] topdomain\n", __progname);
exit(2);
}
@@ -72,21 +72,25 @@ help() {
fprintf(stderr, "iodine IP over DNS tunneling client\n");
fprintf(stderr, "Usage: %s [-v] [-h] [-f] [-r] [-u user] [-t chrootdir] [-d device] "
"[-P password] [-m maxfragsize] [-T type] [-O enc] [-L 0|1] [-I sec] "
"[-P password] [-m maxfragsize] [-M maxlen] [-T type] [-O enc] [-L 0|1] [-I sec] "
"[-z context] [-F pidfile] [nameserver] topdomain\n", __progname);
fprintf(stderr, "Options to try if connection doesn't work:\n");
fprintf(stderr, " -T force dns type: NULL, TXT, SRV, MX, CNAME, A (default: autodetect)\n");
fprintf(stderr, " -O force downstream encoding for -T other than NULL: Base32, Base64, Base64u,\n");
fprintf(stderr, " Base128, or (only for TXT:) Raw (default: autodetect)\n");
fprintf(stderr, " -I max interval between requests (default 4 sec) to prevent DNS timeouts\n");
fprintf(stderr, " -L 1: use lazy mode for low-latency (default). 0: don't (implies -I1)\n");
fprintf(stderr, " -m max size of downstream fragments (default: autodetect)\n");
fprintf(stderr, " -M max size of upstream hostnames (~100-255, default: 255)\n");
fprintf(stderr, " -r to skip raw UDP mode attempt\n");
fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n");
fprintf(stderr, "Other options:\n");
fprintf(stderr, " -v to print version info and exit\n");
fprintf(stderr, " -h to print this help and exit\n");
fprintf(stderr, " -f to keep running in foreground\n");
fprintf(stderr, " -r to skip raw UDP mode attempt\n");
fprintf(stderr, " -u name to drop privileges and run as user 'name'\n");
fprintf(stderr, " -t dir to chroot to directory dir\n");
fprintf(stderr, " -d device to set tunnel device name\n");
fprintf(stderr, " -P password used for authentication (max 32 chars will be used)\n");
fprintf(stderr, " -m maxfragsize, to limit size of downstream packets\n");
fprintf(stderr, " -T dns type: NULL (default, fastest), TXT, CNAME, A (CNAME answer), MX\n");
fprintf(stderr, " -O downstream encoding (!NULL): Base32(default), Base64, or Raw (only TXT)\n");
fprintf(stderr, " -L 1: try lazy mode for low-latency (default). 0: don't (implies -I1)\n");
fprintf(stderr, " -I max interval between requests (default 4 sec) to prevent server timeouts\n");
fprintf(stderr, " -z context, to apply specified SELinux context after initialization\n");
fprintf(stderr, " -F pidfile to write pid to a file\n");
fprintf(stderr, "nameserver is the IP number/hostname of the relaying nameserver. if absent, /etc/resolv.conf is used\n");
@@ -131,6 +135,7 @@ main(int argc, char **argv)
int raw_mode;
int lazymode;
int selecttimeout;
int hostname_maxlen;
nameserv_addr = NULL;
topdomain = NULL;
@@ -152,6 +157,7 @@ main(int argc, char **argv)
raw_mode = 1;
lazymode = 1;
selecttimeout = 4;
hostname_maxlen = 0xFF;
#ifdef WINDOWS32
WSAStartup(req_version, &wsa_data);
@@ -168,7 +174,7 @@ main(int argc, char **argv)
__progname++;
#endif
while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:F:T:O:L:I:")) != -1) {
while ((choice = getopt(argc, argv, "vfhru:t:d:P:m:M:F:T:O:L:I:")) != -1) {
switch(choice) {
case 'v':
version();
@@ -203,6 +209,13 @@ main(int argc, char **argv)
autodetect_frag_size = 0;
max_downstream_frag_size = atoi(optarg);
break;
case 'M':
hostname_maxlen = atoi(optarg);
if (hostname_maxlen > 255)
hostname_maxlen = 255;
if (hostname_maxlen < 10)
hostname_maxlen = 10;
break;
case 'z':
context = optarg;
break;
@@ -283,6 +296,7 @@ main(int argc, char **argv)
client_set_selecttimeout(selecttimeout);
client_set_lazymode(lazymode);
client_set_topdomain(topdomain);
client_set_hostname_maxlen(hostname_maxlen);
if (username != NULL) {
#ifndef WINDOWS32
@@ -315,17 +329,20 @@ main(int argc, char **argv)
signal(SIGINT, sighandler);
signal(SIGTERM, sighandler);
fprintf(stderr, "Sending DNS queries for %s to %s\n",
topdomain, nameserv_addr);
if (client_handshake(dns_fd, raw_mode, autodetect_frag_size, max_downstream_frag_size)) {
retval = 1;
goto cleanup2;
}
if (client_get_conn() == CONN_DNS_NULL) {
fprintf(stderr, "Sending queries for %s to %s\n", topdomain, nameserv_addr);
} else {
if (client_get_conn() == CONN_RAW_UDP) {
fprintf(stderr, "Sending raw traffic directly to %s\n", client_get_raw_addr());
}
fprintf(stderr, "Connection setup complete, transmitting data.\n");
if (foreground == 0)
do_detach();

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,14 @@
lead to massive dropping in multi-user situations with high traffic. */
#define DNSCACHE_LEN 4
/* Undefine to disable. MUST be less than 7; also see comments in iodined.c */
/* Undefine to disable. Should be less than 18; also see comments in iodined.c */
#define QMEMPING_LEN 30
/* Max advisable: 64k/2 = 32000. Total mem usage: QMEMPING_LEN * USERS * 6 bytes */
#define QMEMDATA_LEN 15
/* Max advisable: 36/2 = 18. Total mem usage: QMEMDATA_LEN * USERS * 6 bytes */
struct user {
char id;
@@ -35,7 +42,6 @@ struct user {
in_addr_t tun_ip;
struct in_addr host;
struct query q;
struct query q_prev;
struct query q_sendrealsoon;
int q_sendrealsoon_new;
struct packet inpacket;
@@ -48,6 +54,12 @@ struct user {
int fragsize;
enum connection conn;
int lazy;
unsigned char qmemping_cmc[QMEMPING_LEN * 4];
unsigned short qmemping_type[QMEMPING_LEN];
int qmemping_lastfilled;
unsigned char qmemdata_cmc[QMEMDATA_LEN * 4];
unsigned short qmemdata_type[QMEMDATA_LEN];
int qmemdata_lastfilled;
#ifdef OUTPACKETQ_LEN
struct packet outpacketq[OUTPACKETQ_LEN];
int outpacketq_nexttouse;

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 0x00000501
#define VERSION 0x00000502
#endif /* _VERSION_H_ */