acess.ld
TEST_*
+!TEST_*.c
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] $*
obj-native/%.no: %.c
@mkdir -p $(dir $@)
@echo [CC Native] -o $@
- @$(NCC) -g -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF
[email protected] '-D_SysDebug(f,v...)=fprintf(stderr,"DEBUG "f"\n",##v)' -include stdio.h
+ @$(NCC) -g -c $< -o $@ -Wall -std=gnu99 -MD -MP -MF
[email protected] '-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 $@
--- /dev/null
+#ifndef _UTEST_COMMON_H_
+#define _UTEST_COMMON_H_
+
+#include <stdlib.h>
+
+// --- 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
+
* - Tests for printf.c
*/
#include <stdio.h>
+#include <string.h>
+#include <utest_common.h>
-#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;
}
*/
#include <stdio.h>
#include <string.h>
-
-#define ASSERT(cnd) printf("ASSERT: "#cnd" == %s\n", ((cnd) ? "pass" : "FAIL"))
+#include <utest_common.h>
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'));
}
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)
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
+++ /dev/null
-/*
- */
-#include "include/dns.h"
-#include <string.h>
-#include <stdio.h>
-#include <stdint.h>
-
-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,
- };
-
-#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 )
- {
- case 0:
- TEST_REL_INT(0, ==, strcmp(name, "au."));
- break;
- }
- (*stagep) += 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) );
- return 0;
-}
-
-int main(void)
-{
- int rv = 0;
- // - Name Encode
- // - Name Decode
- // - Response parsing
- rv |= test_response_parse_1();
- return rv;
-}
--- /dev/null
+/*
+ */
+#include <utest_common.h>
+#include "include/dns_int.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+
+// 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
+};
+
+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;
+ int curstage = *stagep;
+ *stagep = -1;
+ switch( curstage )
+ {
+ case 0:
+ TEST_REL_INT(0, ==, strcmp(name, "w.au."));
+ break;
+ case 1:
+ TEST_REL_INT(0, ==, strcmp(name, "x.au."));
+ break;
+ }
+ *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;
+}
+
+int main(void)
+{
+ int rv = 0;
+ // - Name Encode
+ // - Name Decode
+ // - Response parsing
+ rv |= test_response_parse_1();
+ rv |= test_response_parse_2();
+ return rv;
+}
#include <acess/fd_set.h> // FD_SET
#include <net.h>
#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
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;
-}
-
--- /dev/null
+/*
+ */
+
+#include "include/dns.h"
+#include "include/dns_int.h"
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+// === 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;
+}
* \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);
--- /dev/null
+/*
+ */
+#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
+