From db55040ba8814edf681d4ccc12ad8955d8aa404a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 17 Feb 2015 12:30:31 +0800 Subject: [PATCH] Usermode/utests - Fix DNS utest, update libc utests to new format (no more EXP files) --- Usermode/Libraries/.gitignore | 1 + Usermode/Libraries/Makefile.tpl | 9 +- .../Libraries/_utest_include/utest_common.h | 23 ++ Usermode/Libraries/libc.so_src/TEST_printf.c | 50 ++-- Usermode/Libraries/libc.so_src/TEST_string.c | 65 ++-- Usermode/Libraries/libc.so_src/TEST_strtoi.c | 12 +- Usermode/Libraries/libnet.so_src/Makefile | 4 +- .../{TEST_dns.c => TEST_dns_proto.c} | 60 +++- Usermode/Libraries/libnet.so_src/dns.c | 264 +--------------- Usermode/Libraries/libnet.so_src/dns_proto.c | 281 ++++++++++++++++++ .../Libraries/libnet.so_src/include/dns.h | 3 +- .../Libraries/libnet.so_src/include/dns_int.h | 14 + 12 files changed, 449 insertions(+), 337 deletions(-) create mode 100644 Usermode/Libraries/_utest_include/utest_common.h rename Usermode/Libraries/libnet.so_src/{TEST_dns.c => TEST_dns_proto.c} (62%) create mode 100644 Usermode/Libraries/libnet.so_src/dns_proto.c create mode 100644 Usermode/Libraries/libnet.so_src/include/dns_int.h diff --git a/Usermode/Libraries/.gitignore b/Usermode/Libraries/.gitignore index 7836cbd6..b6e2b7c6 100644 --- a/Usermode/Libraries/.gitignore +++ b/Usermode/Libraries/.gitignore @@ -1,2 +1,3 @@ acess.ld TEST_* +!TEST_*.c diff --git a/Usermode/Libraries/Makefile.tpl b/Usermode/Libraries/Makefile.tpl index de263f52..8706a0a8 100644 --- a/Usermode/Libraries/Makefile.tpl +++ b/Usermode/Libraries/Makefile.tpl @@ -63,9 +63,12 @@ _libs: $(HEADERS) utest: utest-build utest-run -utest-build: $(UTESTS:%=TEST_%) +utest-build: _ $(UTESTS:%=TEST_%) -utest-run: $(UTESTS:%=runtest-%) +utest-run: _ $(UTESTS:%=runtest-%) + +_: + @true $(UTESTS:%=runtest-%): runtest-%: TEST_% @echo --- [TEST] $* @@ -132,7 +135,7 @@ $(OUTPUTDIR)Libs/%: obj-native/%.no: %.c @mkdir -p $(dir $@) @echo [CC Native] -o $@ - @$(NCC) -g -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF $@.dep '-D_SysDebug(f,v...)=fprintf(stderr,"DEBUG "f"\n",##v)' -include stdio.h + @$(NCC) -g -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF $@.dep '-D_SysDebug(f,v...)=fprintf(stderr,"DEBUG "f"\n",##v)' -include stdio.h -I $(ACESSDIR)/Usermode/Libraries/_utest_include/ TEST_%: obj-native/TEST_%.no obj-native/%.no @echo [CC Native] -o $@ diff --git a/Usermode/Libraries/_utest_include/utest_common.h b/Usermode/Libraries/_utest_include/utest_common.h new file mode 100644 index 00000000..0b96586f --- /dev/null +++ b/Usermode/Libraries/_utest_include/utest_common.h @@ -0,0 +1,23 @@ +#ifndef _UTEST_COMMON_H_ +#define _UTEST_COMMON_H_ + +#include + +// --- Test assertions +#define TEST_REL_(_ty, _fmt, exp, rel, have) do { \ + _ty a = (exp);\ + _ty b = (have);\ + if( !(a rel b) ) { \ + fprintf(stderr, "TEST_REL_INT("#exp" {%"_fmt"} "#rel" "#have" {%"_fmt"}) FAILED\n", \ + a, b); \ + return 1; \ + } \ +} while(0) +#define TEST_REL_INT(exp, rel, have) TEST_REL_(int, "i", exp, rel, have) +#define TEST_REL_PTR(exp, rel, have) TEST_REL_(const void*, "p", exp, rel, have) + +// -- Header hooks (allowing inclusion of general headers) +#define SYSCALL(rt, name) rt name() { fprintf(stderr, "BUG: Calling syscall '"#name"' in unit test\n"); exit(2); } + +#endif + diff --git a/Usermode/Libraries/libc.so_src/TEST_printf.c b/Usermode/Libraries/libc.so_src/TEST_printf.c index 43766944..c1cdd797 100644 --- a/Usermode/Libraries/libc.so_src/TEST_printf.c +++ b/Usermode/Libraries/libc.so_src/TEST_printf.c @@ -6,32 +6,40 @@ * - Tests for printf.c */ #include +#include +#include -#define TST(_name, fmt, val) \ - printf(_name" %"fmt" '"#val"': '"fmt"'\n", val) +#define TST(_name, exp, fmt, val...) do { \ + char buf[64]; \ + snprintf(buf, sizeof(buf), fmt, ##val); \ + if( strcmp(buf, exp) != 0 ) { \ + fprintf(stderr, "FAIL: exp '%s' != got '%s'\n", exp, buf);\ + exit(1); \ + } \ +} while(0) int main(int argc, char *argv[]) { - printf("Hello World!\n"); - TST("String", "%s", "teststring"); - TST("String", "%.5s", "teststring"); - TST("String", "%10.5s", "teststring"); - TST("String", "%-10.5s", "teststring"); + TST("None", "Hello World!\n", "Hello World!\n"); + TST("String", "teststring", "%s", "teststring"); + TST("String", "tests", "%.5s", "teststring"); + TST("String", " tests", "%10.5s", "teststring"); + TST("String", "tests ", "%-10.5s", "teststring"); - TST("Integer", "%i", 1234); - TST("Integer", "%d", 1234); - TST("Integer", "%u", 1234); + TST("Integer", "1234", "%i", 1234); + TST("Integer", "1234", "%d", 1234); + TST("Integer", "1234", "%u", 1234); - TST("Float", "%f", 3.1414926535); - TST("Float", "%f", 10.0); - TST("Float", "%f", -0.0); - TST("Float", "%.10f", 3.1414926535); - TST("Float", "%e", 3.1415926535); - TST("Float", "%g", 3.1415926535); - TST("Float", "%E", 1000000000.00); - TST("Float", "%a", 16.0); - TST("Float", "%a", 1024.0); - TST("Float", "%a", 1023.0); - TST("Float", "%A", 1000000000.00); + TST("Float", "3.141593", "%f", 3.1415926535); + TST("Float", "10.000000", "%f", 10.0); + TST("Float", "-0.000000", "%f", -0.0); + TST("Float", "3.1415926535", "%.10f", 3.1415926535); + TST("Float", "3.141593e+00", "%e", 3.1415926535); + TST("Float", "3.14159", "%g", 3.1415926535); + TST("Float", "1.000000E+09", "%E", 1000000000.00); + TST("Float", "0x1p+4", "%a", 16.0); + TST("Float", "0x1p+10", "%a", 1024.0); + TST("Float", "0x1.ff8p+9", "%a", 1023.0); + TST("Float", "0X1.DCD65P+29", "%A", 1000000000.00); return 0; } diff --git a/Usermode/Libraries/libc.so_src/TEST_string.c b/Usermode/Libraries/libc.so_src/TEST_string.c index 4ecca307..eb940c7e 100644 --- a/Usermode/Libraries/libc.so_src/TEST_string.c +++ b/Usermode/Libraries/libc.so_src/TEST_string.c @@ -2,50 +2,55 @@ */ #include #include - -#define ASSERT(cnd) printf("ASSERT: "#cnd" == %s\n", ((cnd) ? "pass" : "FAIL")) +#include int main() { - ASSERT(strcmp("hello", "world") < 0); - ASSERT(strcmp("hello", "hello") == 0); - ASSERT(strcmp("wello", "hello") > 0); - ASSERT(strcmp("\xff", "\1") > 0); - ASSERT(strcmp("\1", "\xff") < 0); - ASSERT(strcmp("Hello", "hello") < 0); + TEST_REL_INT(0, > , strcmp("hello", "world")); + TEST_REL_INT(0, ==, strcmp("hello", "hello")); + TEST_REL_INT(0, < , strcmp("wello", "hello")); + TEST_REL_INT(0, < , strcmp("\xff", "\1")); + TEST_REL_INT(0, > , strcmp("\1", "\xff")); + TEST_REL_INT(0, > , strcmp("Hello", "hello")); - ASSERT(strncmp("hello world", "hello", 5) == 0); + TEST_REL_INT(0, ==, strncmp("hello world", "hello", 5)); - ASSERT(strcasecmp("hello", "world") < 0); - ASSERT(strcasecmp("hello", "hello") == 0); - ASSERT(strcasecmp("wello", "hello") > 0); - ASSERT(strcasecmp("\xff", "\1") > 0); - ASSERT(strcasecmp("\1", "\xff") < 0); - ASSERT(strcasecmp("Hello", "hello") == 0); - ASSERT(strcasecmp("Hello", "Hello") == 0); - ASSERT(strcasecmp("hellO", "Hello") == 0); + TEST_REL_INT(0, > , strcasecmp("hello", "world")); + TEST_REL_INT(0, ==, strcasecmp("hello", "hello")); + TEST_REL_INT(0, < , strcasecmp("wello", "hello")); + TEST_REL_INT(0, < , strcasecmp("\xff", "\1")); + TEST_REL_INT(0, > , strcasecmp("\1", "\xff")); + TEST_REL_INT(0, ==, strcasecmp("Hello", "hello")); + TEST_REL_INT(0, ==, strcasecmp("Hello", "Hello")); + TEST_REL_INT(0, ==, strcasecmp("hellO", "Hello")); char buf[13]; memset(buf, 127, sizeof(buf)); - ASSERT(buf[0] == 127); ASSERT(buf[4] == 127); + TEST_REL_INT(127, ==, buf[0]); + TEST_REL_INT(127, ==, buf[4]); strncpy(buf, "hello", 4); - ASSERT(buf[3] == 'l'); ASSERT(buf[4] == 127); + TEST_REL_INT('l', ==, buf[3]); + TEST_REL_INT(127, ==, buf[4]); strncpy(buf, "hello", 8); - ASSERT(buf[4] == 'o'); ASSERT(buf[5] == '\0'); ASSERT(buf[7] == '\0'); ASSERT(buf[8] == 127); + TEST_REL_INT('o', ==, buf[4]); + TEST_REL_INT('\0', ==, buf[5]); + TEST_REL_INT('\0', ==, buf[7]); + TEST_REL_INT(127, ==, buf[8]); memset(buf, 0, 13); - ASSERT(buf[0] == 0); ASSERT(buf[12] == 0); + TEST_REL_INT(0, ==, buf[0]); + TEST_REL_INT(0, ==, buf[12]); - ASSERT(memchr("\xffhello", 'x', 6) == NULL); + TEST_REL_PTR(NULL, ==, memchr("\xffhello", 'x', 6)); const char *teststr_foo = "foo"; - ASSERT(strchr(teststr_foo, 'f') == teststr_foo+0); - ASSERT(strchr(teststr_foo, 'o') == teststr_foo+1); - ASSERT(strchr(teststr_foo, '\0') == teststr_foo+3); - ASSERT(strchr(teststr_foo, 'X') == NULL); - ASSERT(strrchr(teststr_foo, 'f') == teststr_foo+0); - ASSERT(strrchr(teststr_foo, 'o') == teststr_foo+2); - ASSERT(strrchr(teststr_foo, '\0') == teststr_foo+3); - ASSERT(strrchr(teststr_foo, 'X') == NULL); + TEST_REL_PTR(teststr_foo+0, ==, strchr(teststr_foo, 'f')); + TEST_REL_PTR(teststr_foo+1, ==, strchr(teststr_foo, 'o')); + TEST_REL_PTR(teststr_foo+3, ==, strchr(teststr_foo, '\0')); + TEST_REL_PTR(NULL, ==, strchr(teststr_foo, 'X')); + TEST_REL_PTR(teststr_foo+0, ==, strrchr(teststr_foo, 'f')); + TEST_REL_PTR(teststr_foo+2, ==, strrchr(teststr_foo, 'o')); + TEST_REL_PTR(teststr_foo+3, ==, strrchr(teststr_foo, '\0')); + TEST_REL_PTR(NULL, ==, strrchr(teststr_foo, 'X')); } diff --git a/Usermode/Libraries/libc.so_src/TEST_strtoi.c b/Usermode/Libraries/libc.so_src/TEST_strtoi.c index e0658087..cf2d2698 100644 --- a/Usermode/Libraries/libc.so_src/TEST_strtoi.c +++ b/Usermode/Libraries/libc.so_src/TEST_strtoi.c @@ -18,14 +18,20 @@ char *end;\ errno = 0;\ t ret = strto##class(in, &end, base); \ - if( ret != exp ) \ + if( ret != exp ) { \ fprintf(stderr, "FAIL strto"#class"('%s') != "#exp" (act "fmt")\n", in, ret);\ - if( end != in+ofs ) \ + exit(1); \ + } \ + if( end != in+ofs ) { \ fprintf(stderr, "FAIL strto"#class"('%s') returned wrong end: %p (+%zi) instead of %p (+%zi)\n",\ in,end,end-in,in+ofs,(size_t)ofs);\ - if( exp_errno != errno ) \ + exit(1); \ + } \ + if( exp_errno != errno ) { \ fprintf(stderr, "FAIL strto"#class"('%s') returned wrong errno, exp '%s', got '%s'\n",\ in, strerror(exp_errno), strerror(errno));\ + exit(1); \ + } \ }while(0) #define PRIMEBUF(fmt, val) buf_len = snprintf(buf, sizeof(buf), fmt, val) diff --git a/Usermode/Libraries/libnet.so_src/Makefile b/Usermode/Libraries/libnet.so_src/Makefile index 10d5b962..ef733703 100644 --- a/Usermode/Libraries/libnet.so_src/Makefile +++ b/Usermode/Libraries/libnet.so_src/Makefile @@ -7,9 +7,9 @@ CFLAGS += -Wall LDFLAGS += -lc -soname libnet.so OBJ = main.o address.o socket.o -OBJ += hostnames.o dns.o +OBJ += hostnames.o dns.o dns_proto.o BIN = libnet.so -UTESTS = dns +UTESTS = dns_prot include ../Makefile.tpl diff --git a/Usermode/Libraries/libnet.so_src/TEST_dns.c b/Usermode/Libraries/libnet.so_src/TEST_dns_proto.c similarity index 62% rename from Usermode/Libraries/libnet.so_src/TEST_dns.c rename to Usermode/Libraries/libnet.so_src/TEST_dns_proto.c index 26b36bf5..49ba0232 100644 --- a/Usermode/Libraries/libnet.so_src/TEST_dns.c +++ b/Usermode/Libraries/libnet.so_src/TEST_dns_proto.c @@ -1,43 +1,70 @@ /* */ -#include "include/dns.h" +#include +#include "include/dns_int.h" #include #include #include -extern int DNS_int_ParseResponse(const void* packet, size_t return_len, void *info, handle_record_t* handle_record_t); - // Complex response from "Q ssh.ucc.asn.au A IN" const uint8_t test_packet_1[] = { 0xac, 0x00, 0x80, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x03, 0x73, 0x73, 0x68, 0x03, 0x75, 0x63, 0x63, 0x03, 0x61, 0x73, 0x6e, 0x02, 0x61, 0x75, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x77, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x78, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x79, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x61, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x7a, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x62, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x75, 0xc0, 0x18, 0xc0, 0x18, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x01, 0x76, 0xc0, 0x18, 0xc0, 0x2c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc0, 0x05, 0xc0, 0x3c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc2, 0x05, 0xc0, 0x4c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc4, 0x05, 0xc0, 0x5c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x3a, 0x41, 0xfe, 0x49, 0xc0, 0x6c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x25, 0xd1, 0xc6, 0x05, 0xc0, 0x7c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0x3a, 0x41, 0xfd, 0x49, 0xc0, 0x8c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0xd3, 0x1d, 0x85, 0x20, 0xc0, 0x9c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0xe6, 0xd6, 0x00, 0x04, 0xca, 0x0c, 0x1f, 0x8d, }; +const uint8_t test_packet_2[] ={ + 0xac,0x00,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x03,0x73,0x73,0x68,0x03,0x75,0x63,0x63,0x03,0x61,0x73,0x6e,0x02,0x61,0x75,0x00,0x00,0x01,0x00,0x01,0xc0,0x0c,0x00,0x01,0x00,0x01,0x00,0x00,0x0e,0x10,0x00,0x04,0x82,0x5f,0x0d,0x0b +}; -#define TEST_REL_INT(exp, rel, have) do { \ - int a = (exp);\ - int b = (have);\ - if( !(a rel b) ) { \ - fprintf(stderr, "TEST_REL_INT("#exp" "#rel" "#exp") FAILED l=%i r=%i", \ - a, b); \ - return 1; \ - } \ -} while(0) - int test_response_parse_1_cb(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) { int* stagep = info; - switch( *stagep ) + int curstage = *stagep; + *stagep = -1; + switch( curstage ) { case 0: - TEST_REL_INT(0, ==, strcmp(name, "au.")); + TEST_REL_INT(0, ==, strcmp(name, "w.au.")); + break; + case 1: + TEST_REL_INT(0, ==, strcmp(name, "x.au.")); break; } - (*stagep) += 1; + *stagep = curstage + 1; return 0; } int test_response_parse_1(void) { int stage = 0; TEST_REL_INT(0, ==, DNS_int_ParseResponse(test_packet_1, sizeof(test_packet_1), &stage, test_response_parse_1_cb) ); + TEST_REL_INT(stage, ==, 8); + return 0; +} + +int test_response_parse_2_cb(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) +{ + int* stagep = info; + int curstage = *stagep; + *stagep = -1; + switch( curstage ) + { + case 0: + TEST_REL_INT(0, ==, strcmp(name, "ssh.ucc.asn.au.")); + TEST_REL_INT(TYPE_A, ==, type); + TEST_REL_INT(CLASS_IN, ==, class); + TEST_REL_INT(4, ==, rdlength); + TEST_REL_INT(130, ==, ((uint8_t*)rdata)[0]); + TEST_REL_INT( 95, ==, ((uint8_t*)rdata)[1]); + TEST_REL_INT( 13, ==, ((uint8_t*)rdata)[2]); + TEST_REL_INT( 11, ==, ((uint8_t*)rdata)[3]); + break; + } + *stagep = curstage + 1; + return 0; +} +int test_response_parse_2(void) +{ + int stage = 0; + TEST_REL_INT(0, ==, DNS_int_ParseResponse(test_packet_2, sizeof(test_packet_2), &stage, test_response_parse_2_cb) ); + TEST_REL_INT(stage, ==, 1); return 0; } @@ -48,5 +75,6 @@ int main(void) // - Name Decode // - Response parsing rv |= test_response_parse_1(); + rv |= test_response_parse_2(); return rv; } diff --git a/Usermode/Libraries/libnet.so_src/dns.c b/Usermode/Libraries/libnet.so_src/dns.c index 3bb9c355..9ac9198b 100644 --- a/Usermode/Libraries/libnet.so_src/dns.c +++ b/Usermode/Libraries/libnet.so_src/dns.c @@ -13,40 +13,16 @@ #include // FD_SET #include #include "include/dns.h" +#include "include/dns_int.h" // === PROTOTYPES === //int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info); -int DNS_int_ParseResponse(const void* packet, size_t return_len, void *info, handle_record_t* handle_record_t); -size_t DNS_EncodeName(void *buf, const char *dotted_name); -int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space); -int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p); - -static uint16_t get16(const void *buf); -static uint32_t get32(const void *buf); -static size_t put16(void *buf, uint16_t val); - // === CODE === int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info) { - int namelen = DNS_EncodeName(NULL, name); - assert(namelen < 256); - size_t pos = 0; - char packet[ 512 ]; - assert( (6*2) + (namelen + 2*2) < 512 ); - // - Header - pos += put16(packet + pos, 0xAC00); // Identifier (arbitary) - pos += put16(packet + pos, (0 << 0) | (0 << 1) | (1 << 8) ); // Op : Query, Standard, Recursion - pos += put16(packet + pos, 1); // QDCount - pos += put16(packet + pos, 0); // ANCount - pos += put16(packet + pos, 0); // NSCount - pos += put16(packet + pos, 0); // ARCount - // - Question - pos += DNS_EncodeName(packet + pos, name); - pos += put16(packet + pos, type); // QType - pos += put16(packet + pos, class); // QClass - - assert(pos <= sizeof(packet)); + char packet[512]; + size_t packlen = DNS_int_EncodeQuery(packet, sizeof(packet), name, type, class); // Send and wait for reply // - Lock @@ -102,237 +78,3 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT return DNS_int_ParseResponse(packet, return_len, info, handle_record); } -int DNS_int_ParseResponse(const void* buf, size_t return_len, void *info, handle_record_t* handle_record) -{ - const uint8_t* packet = buf; - char rr_name[256]; - unsigned int id = get16(packet + 0); - if( id != 0xAC00 ) { - _SysDebug("DNS_Query - Packet ID mismatch"); - return 2; - } - unsigned int flags = get16(packet + 2); - unsigned int qd_count = get16(packet + 4); - unsigned int an_count = get16(packet + 6); - unsigned int ns_count = get16(packet + 8); - unsigned int ar_count = get16(packet + 10); - size_t pos = 6*2; - // TODO: Can I safely assert / fail if qd_count is non-zero? - // - Questions, ignored - for( unsigned int i = 0; i < qd_count; i ++ ) { - int rv = DNS_DecodeName(rr_name, packet, pos, return_len); - if( rv < 0 ) { - _SysDebug("DNS_Query - Parse error in QD"); - return 1; - } - pos += rv + 2*2; - } - // - Answers, pass on to handler - for( unsigned int i = 0; i < an_count; i ++ ) - { - enum eTypes type; - enum eClass class; - uint32_t ttl; - size_t rdlength; - int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); - if( rv < 0 ) { - _SysDebug("DNS_Query - Parse error in AN"); - return 1; - } - pos += rv; - - handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength); - } - // Authority Records (should all be NS records) - for( unsigned int i = 0; i < ns_count; i ++ ) - { - size_t rdlength; - int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, NULL, NULL, NULL, &rdlength); - if( rv < 0 ) { - _SysDebug("DNS_Query - Parse error in NS"); - return 1; - } - pos += rv; - } - // - Additional records, pass to handler - for( unsigned int i = 0; i < ar_count; i ++ ) - { - enum eTypes type; - enum eClass class; - uint32_t ttl; - size_t rdlength; - int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); - if( rv < 0 ) { - _SysDebug("DNS_Query - Parse error in AR"); - return 1; - } - pos += rv; - - handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength); - } - - return 0; -} - -/// Encode a dotted name as a DNS name -size_t DNS_EncodeName(void *buf, const char *dotted_name) -{ - size_t ret = 0; - const char *str = dotted_name; - uint8_t *buf8 = buf; - while( *str ) - { - const char *next = strchr(str, '.'); - size_t seg_len = (next ? next - str : strlen(str)); - if( seg_len > 63 ) { - // Oops, too long (truncate) - seg_len = 63; - } - if( seg_len == 0 && next != NULL ) { - // '..' encountered, invalid (skip) - str = next+1; - continue ; - } - - if( buf8 ) - { - buf8[ret] = seg_len; - memcpy(buf8+ret+1, str, seg_len); - } - ret += 1 + seg_len; - - if( next == NULL ) { - // No trailing '.', assume it's there? Yes, need to be NUL terminated - if(buf8) buf8[ret] = 0; - ret ++; - break; - } - else { - str = next + 1; - } - } - return ret; -} - -// Decode a name (including trailing . for root) -int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space) -{ - int consumed = 0; - int out_pos = 0; - const uint8_t *buf8 = (const uint8_t*)buf + ofs; - for( ;; ) - { - if( ofs + consumed + 1 > space ) { - _SysDebug("DNS_DecodeName - Len byte OOR space=%i", space); - return -1; - } - uint8_t seg_len = *buf8; - buf8 ++; - consumed ++; - // Done - if( seg_len == 0 ) - break; - if( (seg_len & 0xC0) == 0xC0 ) - { - // Backreference, the rest of the name is a backref - char tmp[256]; - int ref_ofs = get16(buf8 - 1) & 0x3FFF; - consumed += 1, buf8 += 1; // Only one, previous inc still applies - _SysDebug("DNS_DecodeName - Nested at %i", ref_ofs); - if( DNS_DecodeName(tmp, buf, ref_ofs, space) < 0 ) - return -1; - memcpy(dotted_name+out_pos, tmp, strlen(tmp)); - out_pos += strlen(tmp); - break; - } - // Protocol violation (segment too long) - if( seg_len >= 64 ) { - _SysDebug("DNS_DecodeName - Seg too long %i", seg_len); - return -1; - } - // Protocol violation (overflowed end of buffer) - if( ofs + consumed + seg_len > space ) { - _SysDebug("DNS_DecodeName - Seg OOR %i+%i>%i", consumed, seg_len, space); - return -1; - } - // Protocol violation (name was too long) - if( out_pos + seg_len + 1 > 255 ) { - _SysDebug("DNS_DecodeName - Dotted name too long %i+%i+1 > %i", - out_pos, seg_len, 255); - return -1; - } - - _SysDebug("DNS_DecodeName : Seg %i '%.*s'", seg_len, seg_len, buf8); - - // Read segment - memcpy(dotted_name + out_pos, buf8, seg_len); - buf8 += seg_len; - consumed += seg_len; - out_pos += seg_len; - - // Place '.' - dotted_name[out_pos] = '.'; - out_pos ++; - } - dotted_name[out_pos] = '\0'; - _SysDebug("DNS_DecodeName - '%s', consumed = %i", dotted_name, consumed); - return consumed; -} - -// Parse a Resource Record -int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p) -{ - const uint8_t *buf8 = buf; - size_t consumed = 0; - - // 1. Name - int rv = DNS_DecodeName(name_p, buf, ofs, space); - if(rv < 0) return -1; - - ofs += rv, consumed += rv; - - if( type_p ) - *type_p = get16(buf8 + ofs); - ofs += 2, consumed += 2; - - if( class_p ) - *class_p = get16(buf8 + ofs); - ofs += 2, consumed += 2; - - if( ttl_p ) - *ttl_p = get32(buf + ofs); - ofs += 4, consumed += 4; - - size_t rdlength = get16(buf + ofs); - if( rdlength_p ) - *rdlength_p = rdlength; - ofs += 2, consumed += 2; - - _SysDebug("DNS_int_ParseRR - name='%s', rdlength=%i", name_p, rdlength); - - return consumed + rdlength; -} - -static uint16_t get16(const void *buf) { - const uint8_t* buf8 = buf; - uint16_t rv = 0; - rv |= (uint16_t)buf8[0] << 8; - rv |= (uint16_t)buf8[1] << 0; - return rv; -} -static uint32_t get32(const void *buf) { - const uint8_t* buf8 = buf; - uint32_t rv = 0; - rv |= (uint32_t)buf8[0] << 24; - rv |= (uint32_t)buf8[1] << 16; - rv |= (uint32_t)buf8[2] << 8; - rv |= (uint32_t)buf8[3] << 0; - return rv; -} -static size_t put16(void *buf, uint16_t val) { - uint8_t* buf8 = buf; - buf8[0] = val >> 8; - buf8[1] = val & 0xFF; - return 2; -} - diff --git a/Usermode/Libraries/libnet.so_src/dns_proto.c b/Usermode/Libraries/libnet.so_src/dns_proto.c new file mode 100644 index 00000000..ce3cfb3e --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/dns_proto.c @@ -0,0 +1,281 @@ +/* + */ + +#include "include/dns.h" +#include "include/dns_int.h" +#include +#include +#include + +// === PROTOTYPES === +extern int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p); + +static uint16_t get16(const void *buf); +static uint32_t get32(const void *buf); +static size_t put16(void *buf, uint16_t val); + +// === CODE === +size_t DNS_int_EncodeQuery(void *buf, size_t bufsize, const char *name, enum eTypes type, enum eClass class) +{ + int namelen = DNS_EncodeName(NULL, name); + if( namelen >= 256 ) { + _SysDebug("DNS_int_EncodeQuery - ERROR: Name encoded to >= 256 bytes"); + return 0; + } + size_t pos = 0; + uint8_t *packet = buf; + if( (6*2) + (namelen + 2*2) > bufsize ) { + _SysDebug("DNS_int_EncodeQuery - ERROR: Passed buffer too small"); + return 0; + } + // - Header + pos += put16(packet + pos, 0xAC00); // Identifier (arbitary) + pos += put16(packet + pos, (0 << 0) | (0 << 1) | (1 << 8) ); // Op : Query, Standard, Recursion + pos += put16(packet + pos, 1); // QDCount + pos += put16(packet + pos, 0); // ANCount + pos += put16(packet + pos, 0); // NSCount + pos += put16(packet + pos, 0); // ARCount + // - Question + pos += DNS_EncodeName(packet + pos, name); + pos += put16(packet + pos, type); // QType + pos += put16(packet + pos, class); // QClass + + assert(pos <= bufsize); + return pos; +} + +int DNS_int_ParseResponse(const void* buf, size_t return_len, void *info, handle_record_t* handle_record) +{ + const uint8_t* packet = buf; + char rr_name[256]; + unsigned int id = get16(packet + 0); + if( id != 0xAC00 ) { + _SysDebug("DNS_Query - Packet ID mismatch"); + return 2; + } + unsigned int flags = get16(packet + 2); + unsigned int qd_count = get16(packet + 4); + unsigned int an_count = get16(packet + 6); + unsigned int ns_count = get16(packet + 8); + unsigned int ar_count = get16(packet + 10); + size_t pos = 6*2; + // TODO: Can I safely assert / fail if qd_count is non-zero? + // - Questions, ignored + for( unsigned int i = 0; i < qd_count; i ++ ) { + int rv = DNS_DecodeName(rr_name, packet, pos, return_len); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in QD"); + return 1; + } + pos += rv + 2*2; + } + // - Answers, pass on to handler + for( unsigned int i = 0; i < an_count; i ++ ) + { + enum eTypes type; + enum eClass class; + uint32_t ttl; + size_t rdlength; + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in AN"); + return 1; + } + pos += rv; + + if( handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength) ) + return 0; + } + // Authority Records (should all be NS records) + for( unsigned int i = 0; i < ns_count; i ++ ) + { + size_t rdlength; + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, NULL, NULL, NULL, &rdlength); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in NS"); + return 1; + } + pos += rv; + } + // - Additional records, pass to handler + for( unsigned int i = 0; i < ar_count; i ++ ) + { + enum eTypes type; + enum eClass class; + uint32_t ttl; + size_t rdlength; + int rv = DNS_int_ParseRR(packet, pos, return_len, rr_name, &type, &class, &ttl, &rdlength); + if( rv < 0 ) { + _SysDebug("DNS_Query - Parse error in AR"); + return 1; + } + pos += rv; + + if( handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength) ) + return 0; + } + + return 0; +} + +/// Encode a dotted name as a DNS name +size_t DNS_EncodeName(void *buf, const char *dotted_name) +{ + size_t ret = 0; + const char *str = dotted_name; + uint8_t *buf8 = buf; + while( *str ) + { + const char *next = strchr(str, '.'); + size_t seg_len = (next ? next - str : strlen(str)); + if( seg_len > 63 ) { + // Oops, too long (truncate) + seg_len = 63; + } + if( seg_len == 0 && next != NULL ) { + // '..' encountered, invalid (skip) + str = next+1; + continue ; + } + + if( buf8 ) + { + buf8[ret] = seg_len; + memcpy(buf8+ret+1, str, seg_len); + } + ret += 1 + seg_len; + + if( next == NULL ) { + // No trailing '.', assume it's there? Yes, need to be NUL terminated + if(buf8) buf8[ret] = 0; + ret ++; + break; + } + else { + str = next + 1; + } + } + return ret; +} + +// Decode a name (including trailing . for root) +int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space) +{ + int consumed = 0; + int out_pos = 0; + const uint8_t *buf8 = (const uint8_t*)buf + ofs; + for( ;; ) + { + if( ofs + consumed + 1 > space ) { + _SysDebug("DNS_DecodeName - Len byte OOR space=%zi", space); + return -1; + } + uint8_t seg_len = *buf8; + buf8 ++; + consumed ++; + // Done + if( seg_len == 0 ) + break; + if( (seg_len & 0xC0) == 0xC0 ) + { + // Backreference, the rest of the name is a backref + char tmp[256]; + int ref_ofs = get16(buf8 - 1) & 0x3FFF; + consumed += 1, buf8 += 1; // Only one, previous inc still applies + //_SysDebug("DNS_DecodeName - Nested at %i", ref_ofs); + if( DNS_DecodeName(tmp, buf, ref_ofs, space) < 0 ) + return -1; + memcpy(dotted_name+out_pos, tmp, strlen(tmp)); + out_pos += strlen(tmp); + break; + } + // Protocol violation (segment too long) + if( seg_len >= 64 ) { + _SysDebug("DNS_DecodeName - Seg too long %i", seg_len); + return -1; + } + // Protocol violation (overflowed end of buffer) + if( ofs + consumed + seg_len > space ) { + _SysDebug("DNS_DecodeName - Seg OOR %i+%i>%zi", consumed, seg_len, space); + return -1; + } + // Protocol violation (name was too long) + if( out_pos + seg_len + 1 > 255 ) { + _SysDebug("DNS_DecodeName - Dotted name too long %i+%i+1 > %i", + out_pos, seg_len, 255); + return -1; + } + + //_SysDebug("DNS_DecodeName : Seg %i '%.*s'", seg_len, seg_len, buf8); + + // Read segment + memcpy(dotted_name + out_pos, buf8, seg_len); + buf8 += seg_len; + consumed += seg_len; + out_pos += seg_len; + + // Place '.' + dotted_name[out_pos] = '.'; + out_pos ++; + } + dotted_name[out_pos] = '\0'; + //_SysDebug("DNS_DecodeName - '%s', consumed = %i", dotted_name, consumed); + return consumed; +} + +// Parse a Resource Record +int DNS_int_ParseRR(const void *buf, size_t ofs, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p) +{ + const uint8_t *buf8 = buf; + size_t consumed = 0; + + // 1. Name + int rv = DNS_DecodeName(name_p, buf, ofs, space); + if(rv < 0) return -1; + + ofs += rv, consumed += rv; + + if( type_p ) + *type_p = get16(buf8 + ofs); + ofs += 2, consumed += 2; + + if( class_p ) + *class_p = get16(buf8 + ofs); + ofs += 2, consumed += 2; + + if( ttl_p ) + *ttl_p = get32(buf + ofs); + ofs += 4, consumed += 4; + + size_t rdlength = get16(buf + ofs); + if( rdlength_p ) + *rdlength_p = rdlength; + ofs += 2, consumed += 2; + + _SysDebug("DNS_int_ParseRR - name='%s', rdlength=%zi", name_p, rdlength); + + return consumed + rdlength; +} + +static uint16_t get16(const void *buf) { + const uint8_t* buf8 = buf; + uint16_t rv = 0; + rv |= (uint16_t)buf8[0] << 8; + rv |= (uint16_t)buf8[1] << 0; + return rv; +} +static uint32_t get32(const void *buf) { + const uint8_t* buf8 = buf; + uint32_t rv = 0; + rv |= (uint32_t)buf8[0] << 24; + rv |= (uint32_t)buf8[1] << 16; + rv |= (uint32_t)buf8[2] << 8; + rv |= (uint32_t)buf8[3] << 0; + return rv; +} +static size_t put16(void *buf, uint16_t val) { + uint8_t* buf8 = buf; + buf8[0] = val >> 8; + buf8[1] = val & 0xFF; + return 2; +} diff --git a/Usermode/Libraries/libnet.so_src/include/dns.h b/Usermode/Libraries/libnet.so_src/include/dns.h index dc7a58b4..61daeacd 100644 --- a/Usermode/Libraries/libnet.so_src/include/dns.h +++ b/Usermode/Libraries/libnet.so_src/include/dns.h @@ -39,8 +39,9 @@ enum eClass * \param class Record class (may not be equal to requested) * \param rdlength Length of data pointed to by 'rdata' * \param rdata Record data + * \return Non-zero terminates parsing */ -typedef void handle_record_t(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata); +typedef int handle_record_t(void *info, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata); int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info); diff --git a/Usermode/Libraries/libnet.so_src/include/dns_int.h b/Usermode/Libraries/libnet.so_src/include/dns_int.h new file mode 100644 index 00000000..0e20ea10 --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/include/dns_int.h @@ -0,0 +1,14 @@ +/* + */ +#ifndef _DNS_INT_H_ +#define _DNS_INT_H_ + +#include "dns.h" + +extern size_t DNS_int_EncodeQuery(void *buf, size_t bufsize, const char *name, enum eTypes type, enum eClass class); +extern int DNS_int_ParseResponse(const void* packet, size_t return_len, void *info, handle_record_t* handle_record_t); + +extern size_t DNS_EncodeName(void *buf, const char *dotted_name); +extern int DNS_DecodeName(char dotted_name[256], const void *buf, size_t ofs, size_t space); +#endif + -- 2.20.1