diff --git a/Usermode/Libraries/.gitignore b/Usermode/Libraries/.gitignore
index 7836cbd6e071cabafab830a071fb478a5b54c0d3..b6e2b7c6c3995a951d6322e74a05344d06504be8 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 de263f52d569b58ef74c761f058b0f09b758600c..8706a0a8963c486e59a55797f48b6cda1dda0fdb 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 0000000000000000000000000000000000000000..0b96586ffd4245deff03d1f92d581651944c2ebd
--- /dev/null
+++ b/Usermode/Libraries/_utest_include/utest_common.h
@@ -0,0 +1,23 @@
+#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
+
diff --git a/Usermode/Libraries/libc.so_src/TEST_printf.c b/Usermode/Libraries/libc.so_src/TEST_printf.c
index 43766944b8ec755c61cfb9fcd414a70c0c22d968..c1cdd797694276eeb21e570263918d477e1386d0 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 <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;
 }
diff --git a/Usermode/Libraries/libc.so_src/TEST_string.c b/Usermode/Libraries/libc.so_src/TEST_string.c
index 4ecca307d684819ece57ff7b12de56fe12834f64..eb940c7edc9fb6a3de7ec070ac47b68784bbcd52 100644
--- a/Usermode/Libraries/libc.so_src/TEST_string.c
+++ b/Usermode/Libraries/libc.so_src/TEST_string.c
@@ -2,50 +2,55 @@
  */
 #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'));
 }
 
diff --git a/Usermode/Libraries/libc.so_src/TEST_strtoi.c b/Usermode/Libraries/libc.so_src/TEST_strtoi.c
index e06580872615fe727e3548c7cd1971a455791bb4..cf2d2698ebc24649157adce39fcdeb84c4973ad8 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 10d5b9620d45e8c01fc8fb6b77b5bc4f173a1640..ef733703e942de6360da9acf673c296be741c572 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 26b36bf50481273e33c8fca0febdd67c0f92d572..49ba023215f5852be14df74037ee3b1d49a17265 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 <utest_common.h>
+#include "include/dns_int.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, 
 	};
+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 3bb9c35575c767834d28031d4e8e7b234f4fd52e..9ac9198b2ec1929e12de61566838cfcdf589057c 100644
--- a/Usermode/Libraries/libnet.so_src/dns.c
+++ b/Usermode/Libraries/libnet.so_src/dns.c
@@ -13,40 +13,16 @@
 #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
@@ -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 0000000000000000000000000000000000000000..ce3cfb3ee7e189a1b48a6a3c20c4c11201a95048
--- /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 <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;
+}
diff --git a/Usermode/Libraries/libnet.so_src/include/dns.h b/Usermode/Libraries/libnet.so_src/include/dns.h
index dc7a58b4f220440e9c6d5bb355240f9a944a2327..61daeacd587c5c9c90624fb80708b2e2feab311b 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 0000000000000000000000000000000000000000..0e20ea102e1939c98ebb4334faf0382f2b19867f
--- /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
+