diff --git a/src/base128.c b/src/base128.c index be7ba86..4e8e409 100644 --- a/src/base128.c +++ b/src/base128.c @@ -57,6 +57,7 @@ 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 size_t base128_encoded_length(size_t inputlen); static struct encoder base128_encoder = { @@ -66,7 +67,9 @@ static struct encoder base128_encoder = base128_handles_dots, base128_handles_dots, base128_blksize_raw, - base128_blksize_enc + base128_blksize_enc, + base128_encoded_length, + base128_raw_length }; struct encoder @@ -93,6 +96,18 @@ base128_blksize_enc() return BLKSIZE_ENC; } +static size_t +base128_encoded_length(size_t inputlen) +{ + return (BLKSIZE_ENC * inputlen) / BLKSIZE_RAW + ((BLKSIZE_ENC * inputlen) % BLKSIZE_RAW) ? 1 : 0; +} + +static size_t +base128_raw_length(size_t inputlen) +{ + return (BLKSIZE_RAW * inputlen) / BLKSIZE_ENC + ((BLKSIZE_RAW * inputlen) % BLKSIZE_ENC) ? 1 : 0; +} + inline static void base128_reverse_init() { diff --git a/src/base32.c b/src/base32.c index a058d38..a49963d 100644 --- a/src/base32.c +++ b/src/base32.c @@ -38,6 +38,9 @@ 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(); +static size_t base32_encoded_length(size_t inputlen); +static size_t base32_raw_length(size_t inputlen); + static struct encoder base32_encoder = { @@ -47,7 +50,9 @@ static struct encoder base32_encoder = base32_handles_dots, base32_handles_dots, base32_blksize_raw, - base32_blksize_enc + base32_blksize_enc, + base32_encoded_length, + base32_raw_length }; struct encoder @@ -74,6 +79,19 @@ base32_blksize_enc() return BLKSIZE_ENC; } +static size_t +base32_encoded_length(size_t inputlen) +{ + return (BLKSIZE_ENC * inputlen) / BLKSIZE_RAW + ((BLKSIZE_ENC * inputlen) % BLKSIZE_RAW) ? 1 : 0; +} + +static size_t +base32_raw_length(size_t inputlen) +{ + return (BLKSIZE_RAW * inputlen) / BLKSIZE_ENC + ((BLKSIZE_RAW * inputlen) % BLKSIZE_ENC) ? 1 : 0; +} + + inline static void base32_reverse_init() { diff --git a/src/base64.c b/src/base64.c index 7834731..c57a3f6 100644 --- a/src/base64.c +++ b/src/base64.c @@ -38,6 +38,7 @@ static int base64_decode(void *, size_t *, const char *, size_t); static int base64_handles_dots(); static int base64_blksize_raw(); static int base64_blksize_enc(); +static size_t base64_encoded_length(size_t inputlen); static struct encoder base64_encoder = { @@ -47,7 +48,9 @@ static struct encoder base64_encoder = base64_handles_dots, base64_handles_dots, base64_blksize_raw, - base64_blksize_enc + base64_blksize_enc, + base64_encoded_length, + base64_raw_length }; struct encoder @@ -74,6 +77,18 @@ base64_blksize_enc() return BLKSIZE_ENC; } +static size_t +base64_encoded_length(size_t inputlen) +{ + return (BLKSIZE_ENC * inputlen) / BLKSIZE_RAW + ((BLKSIZE_ENC * inputlen) % BLKSIZE_RAW) ? 1 : 0; +} + +static size_t +base64_raw_length(size_t inputlen) +{ + return (BLKSIZE_RAW * inputlen) / BLKSIZE_ENC + ((BLKSIZE_RAW * inputlen) % BLKSIZE_ENC) ? 1 : 0; +} + inline static void base64_reverse_init() { diff --git a/src/encoding.c b/src/encoding.c index c954e1d..58530b4 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -19,19 +19,43 @@ #include "common.h" #include "encoding.h" +size_t +get_raw_length(size_t enc_bytes, struct encoder *enc, const char *topdomain) +/* Returns the maximum length of raw data that can be encoded into max_enc_bytes */ +{ + size_t enc_datalen = enc_bytes - strlen(topdomain); + /* Number of dots in length of encoded data */ + size_t dots = enc_datalen / (DNS_MAXLABEL + 1); + if (!enc->eats_dots()) /* Dots are not included in encoded data length */ + enc_datalen -= dots; + return enc->get_raw_length(enc_datalen); +} + +size_t +get_encoded_length(size_t raw_bytes, struct encoder *enc, const char *topdomain) +/* Returns length of encoded data from original data length orig_len; */ +{ + size_t dots = 1; /* dot before topdomain */ + size_t len = enc->get_encoded_length(raw_bytes) + strlen(topdomain); + if (!enc->places_dots()) + dots += len / 63; /* number of dots needed in data */ + return len; +} + int -build_hostname(char *buf, size_t buflen, - const char *data, const size_t datalen, - const char *topdomain, struct encoder *encoder, size_t maxlen) +build_hostname(char *buf, size_t buflen, const char *data, const size_t datalen, + const char *topdomain, struct encoder *encoder, size_t maxlen, size_t header_len) +/* Builds DNS-compatible hostname for data using specified encoder and topdomain + * NB: Does not account for header length. Data is encoded at start of buf to + * (buf + MIN(maxlen, buflen)). */ { size_t space; char *b; - space = MIN(maxlen, buflen) - strlen(topdomain) - DOWNSTREAM_HDR + 3; - /* max header length + 1 dot before topdomain + 2 safety */ - - if (!encoder->places_dots()) - space -= (space / 57); /* space for dots */ + space = get_encoded_length(MIN(maxlen, buflen), encoder, topdomain); + buf += header_len; + buflen -= header_len; + maxlen -= header_len; memset(buf, 0, buflen); @@ -72,7 +96,7 @@ inline_dotify(char *buf, size_t buflen) char *reader, *writer; total = strlen(buf); - dots = total / 57; + dots = total / 63; writer = buf; writer += total; @@ -91,7 +115,7 @@ inline_dotify(char *buf, size_t buflen) while (dots) { *writer-- = *reader--; pos--; - if (pos % 57 == 0) { + if (pos % 63 == 0) { *writer-- = '.'; dots--; } diff --git a/src/encoding.h b/src/encoding.h index b38d0d6..584d697 100644 --- a/src/encoding.h +++ b/src/encoding.h @@ -25,6 +25,8 @@ #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 +#define DNS_MAXLABEL 63 + struct encoder { char name[8]; int (*encode) (char *, size_t *, const void *, size_t); @@ -33,8 +35,13 @@ struct encoder { int (*eats_dots) (void); int (*blocksize_raw)(void); int (*blocksize_encoded)(void); + size_t (*get_encoded_length)(size_t); + size_t (*get_raw_length)(size_t); }; +size_t get_raw_length(size_t enc_bytes, struct encoder *enc, const char *topdomain); +size_t get_encoded_length(size_t raw_bytes, struct encoder *enc, const char *topdomain); + int build_hostname(char *, size_t, const char *, const size_t, const char *, struct encoder *, size_t); int unpack_data(char *, size_t, char *, size_t, struct encoder *); int inline_dotify(char *, size_t);