Skip to content

Commit

Permalink
dns: fix name read and write, parse escape characters
Browse files Browse the repository at this point in the history
  • Loading branch information
pinheadmz committed Dec 21, 2021
1 parent 34457f4 commit 58bb9b3
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 51 deletions.
128 changes: 91 additions & 37 deletions src/dns.c
Original file line number Diff line number Diff line change
Expand Up @@ -2131,15 +2131,30 @@ hsk_dns_name_parse(
for (j = off; j < off + c; j++) {
uint8_t b = data[j];

// Hack because we're
// using c-strings.
if (b == 0x00)
b = 0xff;

// This allows for double-dots
// too easily in our design.
if (b == 0x2e)
b = 0xfe;
switch (b) {
// Escape special characters
case 0x2e /*.*/:
case 0x28 /*(*/:
case 0x29 /*)*/:
case 0x3b /*;*/:
case 0x20 /* */:
case 0x40 /*@*/:
case 0x22 /*"*/:
case 0x5c /*\\*/:
if (name)
sprintf(&name[noff], "\\%c", (char)b);

noff += 2;
continue;
default:
if (b < 0x20 || b > 0x7e) {
if (name)
sprintf(&name[noff], "\\%03d", b);

noff += 4;
continue;
}
}

if (name)
name[noff] = b;
Expand Down Expand Up @@ -2223,22 +2238,53 @@ hsk_dns_name_serialize(
int i;
char *s;
int size_adjust = 0;
bool escaped = false;
size_t max = strlen(name) - 1;

for (s = (char *)name, i = 0; *s; s++, i++) {
// Check for escaped byte codes and adjust length measurement.
if (name[i] == '\\') {
if (!isdigit(name[++i]) ||
!isdigit(name[++i]) ||
!isdigit(name[++i])) {
*len = off;
return false;
// Check the next three bytes (if within string length)
// for three-digit code which must encode a one-byte value.
if (i + 3 <= max &&
isdigit(name[i + 1]) &&
isdigit(name[i + 2]) &&
isdigit(name[i + 3])) {
uint16_t value = (name[i + 1] - 0x30) * 100;
value += (name[i + 2] - 0x30) * 10;
value += (name[i + 3] - 0x30);

// Bad escape, byte code out of range.
if (value > 0xff) {
*len = off;
return false;
}

// The next three characters don't count towards final size.
size_adjust += 2;
s += 2;
i += 2;

// Escaped dot by byte code
if (value == 0x2e)
escaped = true;
}

size_adjust += 3;
s += 3;
// Literal escaped dot
if (i + 1 <= max && name[i + 1] == 0x2e)
escaped = true;

// Remove single slash and skip next character.
size_adjust += 1;
s += 1;
i += 1;

continue;
}

if (name[i] == '.') {
if (i > 0 && name[i - 1] == '.') {
if (i > 0 && name[i - 1] == '.' && !escaped) {
// Multiple dots (escaped dot is ok)
*len = off;
return false;
}
Expand Down Expand Up @@ -2283,30 +2329,36 @@ hsk_dns_name_serialize(
int j;
for (j = begin; j < i; j++) {
char ch = name[j];
// Check for escaped byte codes and process into output result
if (ch == '\\') {
// Read the next three digits and form a single byte
uint16_t value = (name[++j] - 0x30) * 100;
value += (name[++j] - 0x30) * 10;
value += (name[++j] - 0x30);

if (value > 0xff) {
*len = off;
return false;
// Check the next three bytes (if within label length)
// for three-digit code which must encode a one-byte value.
if (j + 3 <= i &&
isdigit(name[j + 1]) &&
isdigit(name[j + 2]) &&
isdigit(name[j + 3])) {
// Compute byte from next three characters.
uint16_t value = (name[++j] - 0x30) * 100;
value += (name[++j] - 0x30) * 10;
value += (name[++j] - 0x30);

// Bad escape, byte code out of range.
if (value > 0xff) {
*len = off;
return false;
}

// Write
data[off++] = value;
continue;
} else {
// Remove single slash and write next character
// as long as there is a next character.
if (j + 1 < i)
ch = name[++j];
}

data[off++] = value;
size -= 3;
continue;
}

// 0xff -> NUL
if (ch == -1)
ch = '\0';

// 0xfe -> .
if (ch == -2)
ch = '.';

data[off++] = ch;
}
} else {
Expand All @@ -2316,6 +2368,8 @@ hsk_dns_name_serialize(
begin = i + 1;
size_adjust = 0;
}

escaped = false;
}

if (i > HSK_DNS_MAX_NAME) {
Expand Down
113 changes: 100 additions & 13 deletions test/data/name_serialization_vectors.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
typedef struct name_serializtion_vector {
char *name;
uint8_t expected_data[24];
int expected_len;
size_t expected_len;
bool success;
char *parsed;
} name_serializtion_vector_t;


Expand All @@ -21,52 +22,138 @@ static const name_serializtion_vector_t name_serializtion_vectors[] = {
0x06, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x00
},
8,
true
true,
"abcdef."
},
{
"abc.def.",
{
0x03, 0x61, 0x62, 0x63, 0x03, 0x64, 0x65, 0x66, 0x00
},
9,
true
true,
"abc.def."
},
{
"abcdef\\000.",
{
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x00, 0x00
},
9,
true
true,
"abcdef\\000."
},
{
"abcdef\\255.",
{
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0xff, 0x00
},
9,
true
true,
"abcdef\\255."
},
{
"abcdef\\256.",
{},
0,
false, // bad escape (value > 0xff)
NULL
},
{
"abcdef\\LOL.",
{
0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66
0x09, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x4c, 0x4f, 0x4c, 0x00
},
7,
false
11,
true,
"abcdefLOL."
},
{
"abcdef\\LOL.",
"abc\\031def.",
{
0x07, 0x61, 0x62, 0x63, 0x1f, 0x64, 0x65, 0x66, 0x00
},
9,
true,
"abc\\031def."
},
{
"abc\\\\def.",
{
0x07, 0x61, 0x62, 0x63, 0x5c, 0x64, 0x65, 0x66, 0x00
},
9,
true,
"abc\\\\def."
},
{
"\\999.",
{},
0,
false
false, // bad escape (value > 0xff)
NULL
},
{
"abc\\032def.",
"\\\\999.",
{
0x07, 0x61, 0x62, 0x63, 0x20, 0x64, 0x65, 0x66, 0x00
0x04, 0x5c, 0x39, 0x39, 0x39, 0x00
},
6,
true,
"\\\\999."
},
{
"\\\\222.",
{
0x04, 0x5c, 0x32, 0x32, 0x32, 0x00
},
6,
true,
"\\\\222."
},
{
"abc\\\\999.",
{
0x07, 0x61, 0x62, 0x63, 0x5c, 0x39, 0x39, 0x39, 0x00
},
9,
true
true,
"abc\\\\999."
},
{
"abc\\\\99.",
{
0x06, 0x61, 0x62, 0x63, 0x5c, 0x39, 0x39, 0x00
},
8,
true,
"abc\\\\99."
},
{
"abc\\\\.",
{
0x04, 0x61, 0x62, 0x63, 0x5c, 0x00
},
6,
true,
"abc\\\\."
},
{
"\\..",
{
0x01, 0x2e, 0x00
},
3,
true,
"\\.."
},
{
"\\046.",
{
0x01, 0x2e, 0x00
},
3,
true,
"\\.."
}
};
37 changes: 36 additions & 1 deletion test/hnsd-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ test_name_serialize() {
name_serializtion_vector_t name_serializtion_vector = name_serializtion_vectors[i];

uint8_t data[24] = {0};
int len;
int len = 0;

printf(" %s\n", name_serializtion_vector.name);

Expand All @@ -96,12 +96,46 @@ test_name_serialize() {
&len,
NULL
);


// printf("len: %d expected_len: %d\n",len,name_serializtion_vector.expected_len);
// print_array(name_serializtion_vector.expected_data, name_serializtion_vector.expected_len);
// print_array(data, name_serializtion_vector.expected_len);

assert(name_serializtion_vector.success == success);
assert(len == name_serializtion_vector.expected_len);
assert(memcmp(data, name_serializtion_vector.expected_data, len) == 0);
}
}

void
test_name_parse() {
printf("test_name_parse\n");

for (int i = 0; i < ARRAY_SIZE(name_serializtion_vectors); i++) {
name_serializtion_vector_t name_serializtion_vector = name_serializtion_vectors[i];

char name[255];

if (!name_serializtion_vector.parsed)
continue;

printf(" %s\n", name_serializtion_vector.name);

uint8_t *ptr = (uint8_t *)&name_serializtion_vector.expected_data;
size_t len = name_serializtion_vector.expected_len;

int ret = hsk_dns_name_parse(
(uint8_t **)&ptr,
&len,
NULL,
name
);
assert(ret == strlen(name_serializtion_vector.parsed));
assert(strcmp(name_serializtion_vector.parsed, name) == 0);
}
}

void
test_decode_resource() {
printf("test_decode_resource\n");
Expand Down Expand Up @@ -239,6 +273,7 @@ main() {
test_base32();
test_pointer_to_ip();
test_name_serialize();
test_name_parse();
test_decode_resource();
test_next_name();
test_prev_name();
Expand Down

0 comments on commit 58bb9b3

Please sign in to comment.