iodine/src/encoding.c

161 lines
4.2 KiB
C
Raw Normal View History

2006-08-12 23:24:59 +00:00
/*
2014-06-01 06:46:42 +00:00
* Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
* 2006-2009 Bjorn Andersson <flex@kryo.se>
2006-08-12 23:24:59 +00:00
*
* Permission to use, copy, modify, and/or distribute this software for any
2006-08-12 23:24:59 +00:00
* 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.
*/
2006-08-13 17:15:24 +00:00
#include <string.h>
#include "common.h"
2007-06-09 16:18:59 +00:00
#include "encoding.h"
2006-08-12 23:24:59 +00:00
size_t
2015-08-29 05:03:08 +00:00
get_raw_length_from_dns(size_t enc_bytes, struct encoder *enc, const char *topdomain)
/* Returns the maximum length of raw data that can be encoded into enc_bytes */
{
2015-08-29 05:03:08 +00:00
/* 2 byte for something - seems necessary */
size_t enc_datalen = enc_bytes - strlen(topdomain) - 2;
/* Number of dots in length of encoded data */
2015-08-29 05:03:08 +00:00
size_t dots = 1;
if (!enc->eats_dots()) /* Dots are not included in encoded data length */
2015-08-29 05:03:08 +00:00
dots += enc_datalen / (DNS_MAXLABEL);
enc_datalen -= dots;
return enc->get_raw_length(enc_datalen);
}
size_t
2015-08-29 05:03:08 +00:00
get_encoded_dns_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 */
2015-08-29 05:03:08 +00:00
size_t len = enc->get_encoded_length(raw_bytes);
if (!enc->places_dots())
2015-08-29 05:03:08 +00:00
dots += len / DNS_MAXLABEL; /* number of dots needed in data */
return len + dots + strlen(topdomain);
}
2015-08-29 05:03:08 +00:00
size_t
build_hostname(uint8_t *buf, size_t buflen, const uint8_t *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
2015-08-29 05:03:08 +00:00
* Encoded data is placed into buf. */
{
2015-08-29 05:03:08 +00:00
size_t space, enc;
uint8_t *b;
buflen -= header_len;
2015-08-29 05:03:08 +00:00
buf += header_len;
maxlen -= header_len;
memset(buf, 0, buflen);
2014-06-01 06:34:18 +00:00
2015-08-29 05:03:08 +00:00
maxlen = MIN(maxlen, buflen);
/* 1 byte for dot before topdomain + 1 byte extra for something */
space = maxlen - strlen(topdomain) - (maxlen / DNS_MAXLABEL) - 2;
enc = encoder->encode(buf, &space, data, datalen);
// warnx("build_hostname: enc %lu, predicted %lu; maxlen %lu, header %lu, datalen %lu, space %lu",
// encdata_len, encoder->get_encoded_length(datalen), maxlen, header_len, datalen, space);
if (!encoder->places_dots())
2015-08-29 05:03:08 +00:00
enc = inline_dotify(buf - header_len, buflen + header_len) - header_len;
2015-08-29 05:03:08 +00:00
b = buf + enc;
/* move b back one step to see if the dot is there */
b--;
2014-06-01 06:34:18 +00:00
if (*b != '.')
*++b = '.';
b++;
/* move b ahead of the string so we can copy to it */
2015-08-29 05:03:08 +00:00
strncpy((char *)b, topdomain, strlen(topdomain)+1);
// warnx("build_hostname: host '%s' (sl %lu, actual %lu), topdomain '%s'",
// buf - header_len, strlen(buf - header_len), encdata_len + header_len + strlen(topdomain)+1, b);
return space;
}
2007-06-09 16:38:31 +00:00
2015-08-29 05:03:08 +00:00
size_t
unpack_data(uint8_t *buf, size_t buflen, uint8_t *data, size_t datalen, struct encoder *enc)
2007-06-09 16:38:31 +00:00
{
if (!enc->eats_dots())
datalen = inline_undotify(data, datalen);
return enc->decode(buf, &buflen, data, datalen);
}
2015-08-29 05:03:08 +00:00
size_t
inline_dotify(uint8_t *buf, size_t buflen)
2006-08-13 17:15:24 +00:00
{
2007-06-09 16:18:59 +00:00
unsigned dots;
2015-08-29 05:03:08 +00:00
size_t pos, total;
uint8_t *reader, *writer;
2007-06-09 16:18:59 +00:00
2015-08-29 05:03:08 +00:00
total = strlen((char *)buf);
dots = total / DNS_MAXLABEL;
2007-06-09 16:18:59 +00:00
writer = buf;
writer += total;
writer += dots;
total += dots;
2015-08-29 05:03:08 +00:00
if (strlen((char *)buf) + dots > buflen) {
2007-06-09 16:18:59 +00:00
writer = buf;
writer += buflen;
total = buflen;
2006-08-13 17:15:24 +00:00
}
2007-06-09 16:18:59 +00:00
reader = writer - dots;
2015-08-29 05:03:08 +00:00
pos = (reader - buf) + 1;
2006-08-12 23:24:59 +00:00
2007-06-09 16:18:59 +00:00
while (dots) {
*writer-- = *reader--;
pos--;
2015-08-29 05:03:08 +00:00
if (pos % DNS_MAXLABEL == 0) {
2007-06-09 16:18:59 +00:00
*writer-- = '.';
dots--;
2006-08-12 23:24:59 +00:00
}
}
2007-06-09 16:18:59 +00:00
/* return new length of string */
return total;
2006-08-12 23:24:59 +00:00
}
2015-08-29 05:03:08 +00:00
size_t
inline_undotify(uint8_t *buf, size_t len)
2006-08-12 23:24:59 +00:00
{
2015-08-29 05:03:08 +00:00
size_t pos;
2007-06-09 16:18:59 +00:00
unsigned dots;
2015-08-29 05:03:08 +00:00
uint8_t *reader, *writer;
2006-08-12 23:24:59 +00:00
2007-06-09 16:18:59 +00:00
writer = buf;
reader = writer;
2007-06-09 16:18:59 +00:00
pos = 0;
dots = 0;
2007-02-08 20:32:17 +00:00
2007-06-09 16:18:59 +00:00
while (pos < len) {
if (*reader == '.') {
reader++;
pos++;
dots++;
2006-08-12 23:24:59 +00:00
continue;
}
2007-06-09 16:18:59 +00:00
*writer++ = *reader++;
pos++;
2006-08-13 17:15:24 +00:00
}
2014-06-01 06:34:18 +00:00
2007-06-09 16:18:59 +00:00
/* return new length of string */
return len - dots;
2006-08-12 23:24:59 +00:00
}