Networking - DNS resolution semi-working
authorJohn Hodge <[email protected]>
Mon, 16 Feb 2015 06:32:12 +0000 (14:32 +0800)
committerJohn Hodge <[email protected]>
Mon, 16 Feb 2015 06:32:12 +0000 (14:32 +0800)
KernelLand/Kernel/Makefile
KernelLand/Modules/IPStack/udp.c
Usermode/Libraries/Makefile.tpl
Usermode/Libraries/libnet.so_src/Makefile
Usermode/Libraries/libnet.so_src/TEST_dns.c [new file with mode: 0644]
Usermode/Libraries/libnet.so_src/dns.c
Usermode/Libraries/libnet.so_src/hostnames.c
Usermode/Libraries/libnet.so_src/include/dns.h
Usermode/Libraries/libnet.so_src/include_exp/net.h
Usermode/Libraries/libnet.so_src/socket.c

index 34e6bcf..895d90f 100644 (file)
@@ -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 $@
index 67f6056..b9dd323 100644 (file)
@@ -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);
 }
index 8f548bf..3b8d2f5 100644 (file)
@@ -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)
index 00bb878..10d5b96 100644 (file)
@@ -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 (file)
index 0000000..26b36bf
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ */
+#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;
+}
index 001ec00..518d4d4 100644 (file)
@@ -9,14 +9,20 @@
 #include <stdint.h>    // uint*_t
 #include <string.h>    // memcpy, strchr
 #include <assert.h>
+#include <acess/sys.h> // for _SysSelect
+#include <acess/fd_set.h>      // FD_SET
 #include <net.h>
 #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;
 }
 
index 88093de..c3c9626 100644 (file)
@@ -8,7 +8,9 @@
 #include <net.h>
 #include "include/dns.h"
 #include <string.h>
+#include <stdlib.h>    // malloc (for loading config)
 #include <stdbool.h>
+#include <acess/sys.h> // _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"
        // - "* <ip> <ip>" 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 )
index 62204f0..dc7a58b 100644 (file)
@@ -26,8 +26,8 @@ enum eTypes
 
 enum eClass
 {
-       CLASS_IN,
-       CLASS_CH,       // "Chaos"
+       CLASS_IN = 1,
+       CLASS_CH = 3,   // "Chaos"
        QCLASS_STAR = 255,
 };
 
index cd2cb6c..3d33da0 100644 (file)
@@ -6,6 +6,8 @@
 #ifndef __LIBNET_H_
 #define __LIBNET_H_
 
+#include <stddef.h>
+
 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);
 
 
 /**
index 68335ac..825dc6f 100644 (file)
@@ -8,6 +8,7 @@
 #include <net.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <string.h>    // memcpy
 #include <acess/sys.h>
 
 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;
 }
 

UCC git Repository :: git.ucc.asn.au