From 508aa7d2f1f441ab4c9a7cc4540eb418bc2f9da7 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 16 Feb 2015 14:32:12 +0800 Subject: [PATCH] Networking - DNS resolution semi-working --- KernelLand/Kernel/Makefile | 2 +- KernelLand/Modules/IPStack/udp.c | 160 ++++++++++++---- Usermode/Libraries/Makefile.tpl | 8 +- Usermode/Libraries/libnet.so_src/Makefile | 2 + Usermode/Libraries/libnet.so_src/TEST_dns.c | 52 +++++ Usermode/Libraries/libnet.so_src/dns.c | 177 +++++++++++++----- Usermode/Libraries/libnet.so_src/hostnames.c | 10 + .../Libraries/libnet.so_src/include/dns.h | 4 +- .../Libraries/libnet.so_src/include_exp/net.h | 4 + Usermode/Libraries/libnet.so_src/socket.c | 72 ++++++- 10 files changed, 399 insertions(+), 92 deletions(-) create mode 100644 Usermode/Libraries/libnet.so_src/TEST_dns.c diff --git a/KernelLand/Kernel/Makefile b/KernelLand/Kernel/Makefile index 34e6bcfd..895d90f9 100644 --- a/KernelLand/Kernel/Makefile +++ b/KernelLand/Kernel/Makefile @@ -153,7 +153,7 @@ $(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) $(MODS) arch/$(ARCHDIR) @echo "const char gsGitHash[] = \"$(_GITHASH)\";" >> $@ @echo "const int giBuildNumber = $(BUILD_NUM);" >> $@ @echo "const char gsBuildInfo[] = \"Acess2 v$(KERNEL_VERSION) $(ARCH)-$(PLATFORM)\\\\r\\\\n\"" >> $@ - @echo " \"Build $(shell hostname --fqdn):$(BUILD_NUM) Git $(_GITHASH) - $(_GITCHANGED) modified\";" >> $@ + @echo " \"Build $(shell hostname --fqdn):$(BUILD_NUM) $(shell date +%FT%T%z) Git $(_GITHASH) - $(_GITCHANGED) modified\";" >> $@ # Compile rule for buildinfo (needs a special one because it's not a general source file) $(BUILDINFO_OBJ): $(BUILDINFO_SRC) @echo --- CC -o $@ diff --git a/KernelLand/Modules/IPStack/udp.c b/KernelLand/Modules/IPStack/udp.c index 67f60561..b9dd3231 100644 --- a/KernelLand/Modules/IPStack/udp.c +++ b/KernelLand/Modules/IPStack/udp.c @@ -67,13 +67,15 @@ void UDP_Initialise() int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, int Length, void *Buffer) { tUDPHeader *hdr = Buffer; - tUDPChannel *chan; - tUDPPacket *pack; - int len; - for(chan = List; chan; chan = chan->Next) + for(tUDPChannel *chan = List; chan; chan = chan->Next) { // Match local endpoint + LOG("(%p):%i - %s/%i:%i", + chan->Interface, chan->LocalPort, + IPStack_PrintAddress(chan->Remote.AddrType, &chan->Remote.Addr), chan->RemoteMask, + chan->Remote.Port + ); if(chan->Interface && chan->Interface != Interface) continue; if(chan->LocalPort != ntohs(hdr->DestPort)) continue; @@ -93,8 +95,8 @@ int UDP_int_ScanList(tUDPChannel *List, tInterface *Interface, void *Address, in Log_Log("UDP", "Recieved packet for %p", chan); // Create the cached packet - len = ntohs(hdr->Length); - pack = malloc(sizeof(tUDPPacket) + len); + int len = ntohs(hdr->Length); + tUDPPacket *pack = malloc(sizeof(tUDPPacket) + len); pack->Next = NULL; memcpy(&pack->Remote.Addr, Address, IPStack_GetAddressSize(Interface->Type)); pack->Remote.Port = ntohs(hdr->SourcePort); @@ -159,7 +161,11 @@ void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, U { tUDPHeader hdr; - if(Channel->Interface && Channel->Interface->Type != AddrType) return ; + if(Channel->Interface && Channel->Interface->Type != AddrType) { + LOG("Bad interface type for channel packet, IF is %i, but packet is %i", + Channel->Interface->Type, AddrType); + return ; + } // Create the packet hdr.SourcePort = htons( Channel->LocalPort ); @@ -177,6 +183,7 @@ void UDP_SendPacketTo(tUDPChannel *Channel, int AddrType, const void *Address, U IPStack_Buffer_AppendSubBuffer(buffer, Length, 0, Data, NULL, NULL); IPStack_Buffer_AppendSubBuffer(buffer, sizeof(hdr), 0, &hdr, NULL, NULL); // TODO: What if Channel->Interface is NULL here? + ASSERT(Channel->Interface); IPv4_SendPacket(Channel->Interface, *(tIPv4*)Address, IP4PROT_UDP, 0, buffer); break; default: @@ -205,49 +212,59 @@ tVFS_Node *UDP_Channel_Init(tInterface *Interface) return &new->Node; } -/** - * \brief Read from the channel file (wait for a packet) - */ -size_t UDP_Channel_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags) +tUDPPacket *UDP_Channel_WaitForPacket(tUDPChannel *chan, Uint VFSFlags) { - tUDPChannel *chan = Node->ImplPtr; - tUDPPacket *pack; - tUDPEndpoint *ep; - int ofs, addrlen; - - if(chan->LocalPort == 0) { - Log_Notice("UDP", "Channel %p sent with no local port", chan); - return 0; - } - - while(chan->Queue == NULL) Threads_Yield(); + // EVIL - Yield until queue is created (avoids races) + while(chan->Queue == NULL) + Threads_Yield(); for(;;) { - tTime timeout_z = 0, *timeout = (Flags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL; - int rv = VFS_SelectNode(Node, VFS_SELECT_READ, timeout, "UDP_Channel_Read"); - if( rv ) { - errno = (Flags & VFS_IOFLAG_NOBLOCK) ? EWOULDBLOCK : EINTR; + tTime timeout_z = 0, *timeout = (VFSFlags & VFS_IOFLAG_NOBLOCK) ? &timeout_z : NULL; + int rv = VFS_SelectNode(&chan->Node, VFS_SELECT_READ, timeout, "UDP_Channel_Read"); + if( rv == 0 ) { + errno = (VFSFlags & VFS_IOFLAG_NOBLOCK) ? EWOULDBLOCK : EINTR; + return NULL; } SHORTLOCK(&chan->lQueue); if(chan->Queue == NULL) { SHORTREL(&chan->lQueue); continue; } - pack = chan->Queue; + tUDPPacket *pack = chan->Queue; chan->Queue = pack->Next; if(!chan->Queue) { chan->QueueEnd = NULL; - VFS_MarkAvaliable(Node, 0); // Nothing left + VFS_MarkAvaliable(&chan->Node, 0); // Nothing left } SHORTREL(&chan->lQueue); - break; + return pack; + } + // Unreachable +} + +/** + * \brief Read from the channel file (wait for a packet) + */ +size_t UDP_Channel_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer, Uint Flags) +{ + tUDPChannel *chan = Node->ImplPtr; + + if(chan->LocalPort == 0) { + Log_Notice("UDP", "Channel %p sent with no local port", chan); + return 0; + } + + tUDPPacket *pack = UDP_Channel_WaitForPacket(chan, Flags); + if( !pack ) { + return 0; } + size_t addrlen = IPStack_GetAddressSize(pack->Remote.AddrType); + tUDPEndpoint *ep = Buffer; + size_t ofs = 4 + addrlen; + // Check that the header fits - addrlen = IPStack_GetAddressSize(pack->Remote.AddrType); - ep = Buffer; - ofs = 4 + addrlen; if(Length < ofs) { free(pack); Log_Notice("UDP", "Insuficient space for header in buffer (%i < %i)", (int)Length, ofs); @@ -303,6 +320,8 @@ static const char *casIOCtls_Channel[] = { "getset_remoteport", "getset_remotemask", "set_remoteaddr", + "sendto", + "recvfrom", NULL }; /** @@ -354,14 +373,21 @@ int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data) case 6: // getset_remotemask (returns bool success) if(!Data) LEAVE_RET('i', chan->RemoteMask); - if(!CheckMem(Data, sizeof(int))) LEAVE_RET('i', -1); + if(!CheckMem(Data, sizeof(int))) { + LOG("Data pointer invalid"); + LEAVE_RET('i', -1); + } if( !chan->Interface ) { LOG("Can't set remote mask on NULL interface"); LEAVE_RET('i', -1); } - if( *(int*)Data > IPStack_GetAddressSize(chan->Interface->Type) ) + int mask = *(int*)Data; + int addr_bits = IPStack_GetAddressSize(chan->Interface->Type) * 8; + if( mask > addr_bits ) { + LOG("Mask too large (%i > max %i)", mask, addr_bits); LEAVE_RET('i', -1); - chan->RemoteMask = *(int*)Data; + } + chan->RemoteMask = mask; LEAVE('i', chan->RemoteMask); return chan->RemoteMask; @@ -374,9 +400,73 @@ int UDP_Channel_IOCtl(tVFS_Node *Node, int ID, void *Data) LOG("Invalid pointer"); LEAVE_RET('i', -1); } + LOG("Set remote addr %s", IPStack_PrintAddress(chan->Interface->Type, Data)); + chan->Remote.AddrType = chan->Interface->Type; memcpy(&chan->Remote.Addr, Data, IPStack_GetAddressSize(chan->Interface->Type)); LEAVE('i', 0); return 0; + case 8: { // sendto + if(!CheckMem(Data, 2*sizeof(void*)+2)) { + LOG("Data pointer invalid"); + LEAVE_RET('i', -1); + } + const struct sSendToArgs { + const tUDPEndpoint* ep; + const void* buf; + const Uint16 buflen; + } info = *(const struct sSendToArgs*)Data; + LOG("sendto(buf=%p + %u, ep=%p)", info.buf, info.buflen, info.ep); + if(!CheckMem(info.ep, 2+2) || !CheckMem(info.ep, 2+2+IPStack_GetAddressSize(info.ep->AddrType)) ) { + LEAVE_RET('i', -1); + } + if(!CheckMem(info.buf, info.buflen)) { + LEAVE_RET('i', -1); + } + + UDP_SendPacketTo(chan, info.ep->AddrType, &info.ep->Addr, info.ep->Port, + info.buf, (size_t)info.buflen); + + LEAVE_RET('i', info.buflen); } + case 9: { // recvfrom + if(!CheckMem(Data, 2*sizeof(void*)+2)) { + LOG("Data pointer invalid"); + LEAVE_RET('i', -1); + } + const struct sRecvFromArgs { + tUDPEndpoint* ep; + void* buf; + Uint16 buflen; + } info = *(const struct sRecvFromArgs*)Data; + LOG("recvfrom(buf=%p + %u, ep=%p)", info.buf, info.buflen, info.ep); + if(!CheckMem(info.ep, 2+2)) { + LEAVE_RET('i', -1); + } + if(!CheckMem(info.buf, info.buflen)) { + LEAVE_RET('i', -1); + } + + tUDPPacket *pack = UDP_Channel_WaitForPacket(chan, 0); + if( pack == NULL ) { + LOG("No packet"); + LEAVE_RET('i', 0); + } + + size_t addrsize = IPStack_GetAddressSize(pack->Remote.AddrType); + if( !CheckMem(info.ep, 2+2+addrsize) ) { + LOG("Insufficient space for source address"); + free(pack); + LEAVE_RET('i', -1); + } + info.ep->Port = pack->Remote.Port; + info.ep->AddrType = pack->Remote.AddrType; + memcpy(&info.ep->Addr, &pack->Remote.Addr, addrsize); + + size_t retlen = (info.buflen < pack->Length ? info.buflen : pack->Length); + memcpy(info.buf, pack->Data, retlen); + + free(pack); + + LEAVE_RET('i', retlen); } } LEAVE_RET('i', 0); } diff --git a/Usermode/Libraries/Makefile.tpl b/Usermode/Libraries/Makefile.tpl index 8f548bfa..3b8d2f55 100644 --- a/Usermode/Libraries/Makefile.tpl +++ b/Usermode/Libraries/Makefile.tpl @@ -60,17 +60,15 @@ _libs: $(HEADERS) .PHONY: utest utest-build utest-run $(UTESTS:%=runtest-%) -utest: utest-build generate_exp utest-run - -generate_exp: $(UTESTS:%=EXP_%.txt) +utest: utest-build utest-run utest-build: $(UTESTS:%=TEST_%) utest-run: $(UTESTS:%=runtest-%) -$(UTESTS:%=runtest-%): runtest-%: TEST_% EXP_%.txt +$(UTESTS:%=runtest-%): runtest-%: TEST_% @echo --- [TEST] $* - @./TEST_$* | diff EXP_$*.txt - + @./TEST_$* clean: $(RM) $(_BIN) $(_XBIN) $(OBJ) $(_BIN).dsm $(DEPFILES) $(EXTRACLEAN) diff --git a/Usermode/Libraries/libnet.so_src/Makefile b/Usermode/Libraries/libnet.so_src/Makefile index 00bb8783..10d5b962 100644 --- a/Usermode/Libraries/libnet.so_src/Makefile +++ b/Usermode/Libraries/libnet.so_src/Makefile @@ -10,4 +10,6 @@ OBJ = main.o address.o socket.o OBJ += hostnames.o dns.o BIN = libnet.so +UTESTS = dns + include ../Makefile.tpl diff --git a/Usermode/Libraries/libnet.so_src/TEST_dns.c b/Usermode/Libraries/libnet.so_src/TEST_dns.c new file mode 100644 index 00000000..26b36bf5 --- /dev/null +++ b/Usermode/Libraries/libnet.so_src/TEST_dns.c @@ -0,0 +1,52 @@ +/* + */ +#include "include/dns.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, + }; + +#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; +} diff --git a/Usermode/Libraries/libnet.so_src/dns.c b/Usermode/Libraries/libnet.so_src/dns.c index 001ec000..518d4d47 100644 --- a/Usermode/Libraries/libnet.so_src/dns.c +++ b/Usermode/Libraries/libnet.so_src/dns.c @@ -9,14 +9,20 @@ #include // uint*_t #include // memcpy, strchr #include +#include // for _SysSelect +#include // FD_SET #include #include "include/dns.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 space); -int DNS_int_ParseRR(const void *buf, size_t space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p); +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); @@ -49,22 +55,42 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT int sock = Net_OpenSocket_UDP(ServerAType, ServerAddr, 53, 0); if( sock < 0 ) { // Connection failed + _SysDebug("DNS_Query - UDP open failed"); // TODO: Correctly report this failure with a useful error code return 1; } - int rv = _SysWrite(sock, packet, pos); + int rv = Net_UDP_SendTo(sock, 53, ServerAType, ServerAddr, pos, packet); if( rv != pos ) { + _SysDebug("DNS_Query - Write failed"); // TODO: Error reporting _SysClose(sock); return 1; } // - Wait - int return_len = 0; - do { - return_len = _SysRead(sock, packet, sizeof(packet)); - } while( return_len == 0 ); - if( return_len < 0 ) { + { + int nfd = sock + 1; + fd_set fds; + FD_ZERO(&fds); + FD_SET(sock, &fds); + int64_t timeout = 2000; // Give it two seconds, should be long enough + rv = _SysSelect(nfd, &fds, NULL, NULL, &timeout, 0); + if( rv == 0 ) { + // Timeout with no reply, give up + _SysDebug("DNS_Query - Timeout"); + _SysClose(sock); + return 1; + } + if( rv < 0 ) { + // Oops, select failed + _SysDebug("DNS_Query - Select failure"); + _SysClose(sock); + return 1; + } + } + int return_len = Net_UDP_RecvFrom(sock, NULL, NULL, NULL, sizeof(packet), packet); + if( return_len <= 0 ) { // TODO: Error reporting + _SysDebug("DNS_Query - Read failure"); _SysClose(sock); return 1; } @@ -73,17 +99,33 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT // > TODO: Lock DNS queries // For each response in the answer (and additional) sections, call the passed callback + 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); - pos = 6*2; + 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 ++ ) { - pos += DNS_DecodeName(NULL, packet + pos, return_len - pos); - pos += 2*2; + 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 ++ ) @@ -92,20 +134,22 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT enum eClass class; uint32_t ttl; size_t rdlength; - int rv = DNS_int_ParseRR(packet + pos, return_len - pos, rr_name, &type, &class, &ttl, &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); + 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 - pos, rr_name, NULL, NULL, NULL, &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; @@ -117,15 +161,16 @@ int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eT enum eClass class; uint32_t ttl; size_t rdlength; - int rv = DNS_int_ParseRR(packet + pos, return_len - pos, rr_name, &type, &class, &ttl, &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); + handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos - rdlength); } - + return 0; } @@ -170,76 +215,124 @@ size_t DNS_EncodeName(void *buf, const char *dotted_name) } // Decode a name (including trailing . for root) -int DNS_DecodeName(char dotted_name[256], const void *buf, size_t space) +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 = buf; - while( *buf8 && space > 0 ) + const uint8_t *buf8 = (const uint8_t*)buf + ofs; + for( ;; ) { - if( consumed + 1 > space ) return -1; + if( ofs + consumed + 1 > space ) { + _SysDebug("DNS_DecodeName - Len byte OOR space=%i", space); + return -1; + } uint8_t seg_len = *buf8; buf8 ++; consumed ++; - // Protocol violation (overflowed end of buffer) - if( consumed + seg_len > space ) - return -1; + // 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 ) + 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 > sizeof(dotted_name)-1 ) + 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+seg_len+1] = '.'; - // Increment output counter - out_pos += seg_len + 1; + 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 space, char* name_p, enum eTypes* type_p, enum eClass* class_p, uint32_t* ttl_p, size_t* rdlength_p) +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, buf8, space); + int rv = DNS_DecodeName(name_p, buf, ofs, space); if(rv < 0) return -1; - buf8 += rv, consumed += rv; + ofs += rv, consumed += rv; if( type_p ) - *type_p = get16(buf8); - buf8 += 2, consumed += 2; + *type_p = get16(buf8 + ofs); + ofs += 2, consumed += 2; if( class_p ) - *class_p = get16(buf8); - buf8 += 2, consumed += 2; + *class_p = get16(buf8 + ofs); + ofs += 2, consumed += 2; - return consumed; + 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 |= buf8[0]; - rv |= (uint16_t)buf8[1] << 8; + 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 & 0xFF; - buf8[1] = val >> 8; + buf8[0] = val >> 8; + buf8[1] = val & 0xFF; return 2; } diff --git a/Usermode/Libraries/libnet.so_src/hostnames.c b/Usermode/Libraries/libnet.so_src/hostnames.c index 88093de3..c3c96268 100644 --- a/Usermode/Libraries/libnet.so_src/hostnames.c +++ b/Usermode/Libraries/libnet.so_src/hostnames.c @@ -8,7 +8,9 @@ #include #include "include/dns.h" #include +#include // malloc (for loading config) #include +#include // _SysDebug // === TYPES === struct sDNSServer @@ -74,9 +76,16 @@ int int_lookupany_callback(void *info_v, int AddrType, const void *Addr) int Net_Lookup_Addrs(const char *Name, void *cb_info, tNet_LookupAddrs_Callback *callback) { + _SysDebug("Net_Lookup_Addrs(Name='%s')", Name); // 1. Load (if not loaded) the DNS config from "/Acess/Conf/dns" // - "* " for DNS server(s) // - "127.0.0.1 localhost localhost.localdomain" + if( !gaDNSServers ) + { + giNumDNSServers = 1; + gaDNSServers = malloc( 1 * sizeof(gaDNSServers[0]) ); + gaDNSServers[0].AddrType = Net_ParseAddress("192.168.1.1", gaDNSServers[0].AddrData); + } // 2. Check the hosts list for( int i = 0; i < giNumHostEntries; i ++ ) @@ -121,6 +130,7 @@ int Net_Lookup_Addrs(const char *Name, void *cb_info, tNet_LookupAddrs_Callback void int_DNS_callback(void *info_v, const char *name, enum eTypes type, enum eClass class, unsigned int ttl, size_t rdlength, const void *rdata) { struct sDNSCallbackInfo *info = info_v; + _SysDebug("int_DNS_callback(name='%s', type=%i, class=%i)", name, type, class); // Check type matches (if pattern was provided) if( info->desired_type != QTYPE_STAR && type != info->desired_type ) diff --git a/Usermode/Libraries/libnet.so_src/include/dns.h b/Usermode/Libraries/libnet.so_src/include/dns.h index 62204f05..dc7a58b4 100644 --- a/Usermode/Libraries/libnet.so_src/include/dns.h +++ b/Usermode/Libraries/libnet.so_src/include/dns.h @@ -26,8 +26,8 @@ enum eTypes enum eClass { - CLASS_IN, - CLASS_CH, // "Chaos" + CLASS_IN = 1, + CLASS_CH = 3, // "Chaos" QCLASS_STAR = 255, }; diff --git a/Usermode/Libraries/libnet.so_src/include_exp/net.h b/Usermode/Libraries/libnet.so_src/include_exp/net.h index cd2cb6c8..3d33da03 100644 --- a/Usermode/Libraries/libnet.so_src/include_exp/net.h +++ b/Usermode/Libraries/libnet.so_src/include_exp/net.h @@ -6,6 +6,8 @@ #ifndef __LIBNET_H_ #define __LIBNET_H_ +#include + enum { NET_ADDRTYPE_NULL = 0, NET_ADDRTYPE_IPV4 = 4, @@ -58,6 +60,8 @@ extern int Net_OpenSocket(int AddrType, const void *Addr, const char *SocketName extern int Net_OpenSocket_TCPC(int AddrType, const void *Addr, int Port); extern int Net_OpenSocket_UDP(int AddrType, const void *Addr, int RAddr, int LAddr); +extern int Net_UDP_SendTo (int FD, int Port, int AddrType, const void *Addr, size_t Length, const void *Data); +extern int Net_UDP_RecvFrom(int FD, int* Port, int* AddrType, void *Addr, size_t Length, void *Data); /** diff --git a/Usermode/Libraries/libnet.so_src/socket.c b/Usermode/Libraries/libnet.so_src/socket.c index 68335acc..825dc6fe 100644 --- a/Usermode/Libraries/libnet.so_src/socket.c +++ b/Usermode/Libraries/libnet.so_src/socket.c @@ -8,6 +8,7 @@ #include #include #include +#include // memcpy #include enum { @@ -15,6 +16,8 @@ enum { UDP_IOCTL_GETSETRPORT, UDP_IOCTL_GETSETRMASK, UDP_IOCTL_SETRADDR, + UDP_IOCTL_SENDTO, + UDP_IOCTL_RECVFROM, }; int Net_OpenSocket(int AddrType, const void *Addr, const char *Filename) @@ -50,10 +53,16 @@ int Net_OpenSocket_TCPC(int AddrType, const void *Addr, int Port) int fd = Net_OpenSocket(AddrType, Addr, "tcpc"); if( fd == -1 ) return -1; - _SysIOCtl(fd, 5, &Port); // Remote Port - _SysIOCtl(fd, 6, (void*)Addr); // Remote address (kernel shouldn't modify) - _SysIOCtl(fd, 7, NULL); // connect + if( _SysIOCtl(fd, 5, &Port) < 0 ) // Remote Port + goto err; + if( _SysIOCtl(fd, 6, (void*)Addr) < 0 ) // Remote address (kernel shouldn't modify) + goto err; + if( _SysIOCtl(fd, 7, NULL) < 0) // connect + goto err; return fd; +err: + _SysClose(fd); + return -1; } int Net_OpenSocket_UDP(int AddrType, const void *Addr, int RPort, int LPort) @@ -61,11 +70,60 @@ int Net_OpenSocket_UDP(int AddrType, const void *Addr, int RPort, int LPort) int fd = Net_OpenSocket(AddrType, Addr, "udp"); if( fd == -1 ) return -1; - _SysIOCtl(fd, UDP_IOCTL_GETSETLPORT, &LPort); // Remote Port + if( _SysIOCtl(fd, UDP_IOCTL_GETSETLPORT, &LPort) < 0 ) + goto err; + if( _SysIOCtl(fd, UDP_IOCTL_GETSETRPORT, &RPort) < 0 ) + goto err; int maskbits = Net_GetAddressSize(AddrType) * 8; - _SysIOCtl(fd, UDP_IOCTL_GETSETRPORT, &RPort); - _SysIOCtl(fd, UDP_IOCTL_GETSETRMASK, &maskbits); - _SysIOCtl(fd, UDP_IOCTL_SETRADDR, (void*)Addr); // Remote address (kernel shouldn't modify) + if( _SysIOCtl(fd, UDP_IOCTL_GETSETRMASK, &maskbits) < 0 ) + goto err; + if( _SysIOCtl(fd, UDP_IOCTL_SETRADDR, (void*)Addr) < 0 ) // Remote address (kernel shouldn't modify) + goto err; return fd; +err: + _SysClose(fd); + return -1; +} + +int Net_UDP_SendTo(int FD, int Port, int AddrType, const void *Addr, size_t Length, const void *Data) +{ + struct { + uint16_t port; + uint16_t addr_type; + char addr[16]; + } ep; + ep.port = Port; + ep.addr_type = AddrType; + memcpy(ep.addr, Addr, Net_GetAddressSize(AddrType)); + struct { + const void *ep; + const void *buf; + uint16_t len; + } info = { .ep = &ep, .buf = Data, .len = Length }; + + return _SysIOCtl(FD, UDP_IOCTL_SENDTO, &info); +} + +int Net_UDP_RecvFrom(int FD, int* Port, int* AddrType, void *Addr, size_t Length, void *Data) +{ + struct { + uint16_t port; + uint16_t addr_type; + char addr[16]; + } ep; + struct { + void *ep; + void *buf; + uint16_t len; + } info = { .ep = &ep, .buf = Data, .len = Length }; + + int rv = _SysIOCtl(FD, UDP_IOCTL_RECVFROM, &info); + if( rv > 0 ) + { + if(Port) *Port = ep.port; + if(AddrType) *AddrType = ep.addr_type; + if(Addr) memcpy(Addr, ep.addr, Net_GetAddressSize(ep.addr_type)); + } + return rv; } -- 2.20.1