Usermode/libnet - Starting work on DNS resolver
authorJohn Hodge (sonata) <[email protected]>
Sun, 15 Feb 2015 12:38:39 +0000 (20:38 +0800)
committerJohn Hodge (sonata) <[email protected]>
Sun, 15 Feb 2015 12:38:39 +0000 (20:38 +0800)
Usermode/Libraries/libnet.so_src/Makefile
Usermode/Libraries/libnet.so_src/address.c
Usermode/Libraries/libnet.so_src/dns.c [new file with mode: 0644]
Usermode/Libraries/libnet.so_src/include/dns.h [new file with mode: 0644]
Usermode/Libraries/libnet.so_src/include_exp/net.h
Usermode/Libraries/libnet.so_src/socket.c

index 29abaaa..8bbf403 100644 (file)
@@ -6,7 +6,7 @@ CPPFLAGS +=
 CFLAGS   += -Wall
 LDFLAGS  += -lc -soname libnet.so
 
 CFLAGS   += -Wall
 LDFLAGS  += -lc -soname libnet.so
 
-OBJ = main.o address.o socket.o
+OBJ = main.o address.o socket.o dns.o
 BIN = libnet.so
 
 include ../Makefile.tpl
 BIN = libnet.so
 
 include ../Makefile.tpl
index 8887362..d103e64 100644 (file)
@@ -7,7 +7,7 @@
  */
 #include <net.h>
 #include <stdint.h>
  */
 #include <net.h>
 #include <stdint.h>
-//#include <stdio.h>
+#include <stdio.h>     // sprintf
 #include <stdlib.h>
 #define DEBUG  0
 
 #include <stdlib.h>
 #define DEBUG  0
 
diff --git a/Usermode/Libraries/libnet.so_src/dns.c b/Usermode/Libraries/libnet.so_src/dns.c
new file mode 100644 (file)
index 0000000..43213a4
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Acess2 Networking Toolkit
+ * By John Hodge (thePowersGang)
+ * 
+ * dns.c
+ * - Hostname<->Address resolution
+ */
+#include <stddef.h>    // size_t / NULL
+#include <stdint.h>    // uint*_t
+#include <string.h>    // memcpy, strchrnul
+#include <assert.h>
+#include <net.h>
+#include "include/dns.h"
+
+// === PROTOTYPES ===
+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);
+static uint16_t        get16(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) );       // Op : Query, Standard, no other flags
+       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));
+       
+       // Send and wait for reply
+       // - Lock
+       //  > TODO: Lock DNS queries
+       // - Send
+       int sock = Net_OpenSocket_UDP(ServerAType, ServerAddr, 53, 0);
+       if( sock < 0 ) {
+               // Connection failed
+               // TODO: Correctly report this failure with a useful error code
+               return 1;
+       }
+       int rv = _SysWrite(sock, packet, pos);
+       if( rv != pos ) {
+               // 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 ) {
+               // TODO: Error reporting
+               _SysClose(sock);
+               return 1;
+       }
+       _SysClose(sock);
+       // - Release
+       //  > TODO: Lock DNS queries
+       
+       // For each response in the answer (and additional) sections, call the passed callback
+       char    rr_name[256];
+       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;
+       // 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;
+       }
+       // - 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 - pos, rr_name, &type, &class, &ttl, &rdlength);
+               if( rv < 0 ) {
+                       return 1;
+               }
+               pos += rv;
+               
+               handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos);
+       }
+       // 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);
+               if( rv < 0 ) {
+                       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 - pos, rr_name, &type, &class, &ttl, &rdlength);
+               if( rv < 0 ) {
+                       return 1;
+               }
+               pos += rv;
+               
+               handle_record(info, rr_name, type, class, ttl, rdlength, packet + pos);
+       }
+
+       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 space)
+{
+       int consumed = 0;
+       int out_pos = 0;
+       const uint8_t *buf8 = buf;
+       while( *buf8 && space > 0 )
+       {
+               if( consumed + 1 > space )      return -1;
+               uint8_t seg_len = *buf8;
+               buf8 ++;
+               consumed ++;
+               // Protocol violation (overflowed end of buffer)
+               if( consumed + seg_len > space )
+                       return -1;
+               // Protocol violation (segment too long)
+               if( seg_len >= 64 )
+                       return -1;
+               // Protocol violation (name was too long)
+               if( out_pos + seg_len + 1 > sizeof(dotted_name)-1 )
+                       return -1;
+               
+               // Read segment
+               memcpy(dotted_name + out_pos, buf8, seg_len);
+               buf8 += seg_len;
+               consumed += seg_len;
+               
+               // Place '.'
+               dotted_name[out_pos+seg_len+1] = '.';
+               // Increment output counter
+               out_pos += seg_len + 1;
+       }
+       
+       dotted_name[out_pos] = '\0';
+       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)
+{
+       const uint8_t   *buf8 = buf;
+       size_t  consumed = 0;
+       
+       // 1. Name
+       int rv = DNS_DecodeName(name_p, buf8, space);
+       if(rv < 0)      return -1;
+       
+       buf8 += rv, consumed += rv;
+       
+       if( type_p )
+               *type_p = get16(buf8);
+       buf8 += 2, consumed += 2;
+       
+       if( class_p )
+               *class_p = get16(buf8);
+       buf8 += 2, consumed += 2;
+       
+       return consumed;
+}
+
+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;
+       return rv;
+}
+static size_t put16(void *buf, uint16_t val) {
+       uint8_t* buf8 = buf;
+       buf8[0] = val & 0xFF;
+       buf8[1] = val >> 8;
+       return 2;
+}
+
diff --git a/Usermode/Libraries/libnet.so_src/include/dns.h b/Usermode/Libraries/libnet.so_src/include/dns.h
new file mode 100644 (file)
index 0000000..1f2dd61
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ */
+#ifndef _DNS_H_
+#define _DNS_H_
+
+enum eTypes
+{
+       TYPE_A = 1,
+       TYPE_NS = 2,
+       TYPE_CNAME = 5,
+       TYPE_SOA = 6,
+       TYPE_NULL = 10,
+       TYPE_PTR = 12,
+       TYPE_HINFO = 13,
+       TYPE_MX = 15,
+       TYPE_TXT = 16,
+       QTYPE_STAR = 255,
+};
+
+enum eClass
+{
+       CLASS_IN,
+       CLASS_CH,       // "Chaos"
+       CLASS_STAR = 255,
+};
+
+/**
+ * \brief Handler for a DNS record obtained by DNS_Query
+ * \param info Value passed as the last argument to DNS_Query
+ * \param name NUL-terminated name associated with the returned record
+ * \param type Record type (may not be equal to requested)
+ * \param class        Record class (may not be equal to requested)
+ * \param rdlength     Length of data pointed to by 'rdata'
+ * \param rdata        Record data
+ */
+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);
+
+int DNS_Query(int ServerAType, const void *ServerAddr, const char *name, enum eTypes type, enum eClass class, handle_record_t* handle_record, void *info);
+
+#endif
+
index 5fe4ba1..f02c0a4 100644 (file)
@@ -53,8 +53,31 @@ extern char  *Net_GetInterface(int AddrType, void *Addr);
  * Opens a file using /Devices/ip/routes/@<AddrType>:<Addr>/<SocketName>
  * 
  */
  * Opens a file using /Devices/ip/routes/@<AddrType>:<Addr>/<SocketName>
  * 
  */
-extern int     Net_OpenSocket(int AddrType, void *Addr, const char *SocketName);
+extern int     Net_OpenSocket(int AddrType, const void *Addr, const char *SocketName);
 
 
-extern int     Net_OpenSocket_TCPC(int AddrType, void *Addr, int Port);
+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);
+
+
+/**
+ * \name Hostnames
+ * \brief Handling of hostname resolution
+ * \{
+ */
+
+/**
+ * \brief Returns an address for the specified hostname
+ * \note Picks randomly if multiple addresses are present
+ */
+extern int     Net_Lookup_AnyAddr(const char *Name, int AddrType, void *Addr);
+
+/**
+ */
+extern int     Net_Lookup_Name(int AddrType, const void *Addr, char *Dest[256]);
+
+/**
+ * \}
+ */
 
 #endif
 
 #endif
index 85f7e54..68335ac 100644 (file)
 #include <stdint.h>
 #include <acess/sys.h>
 
 #include <stdint.h>
 #include <acess/sys.h>
 
-int Net_OpenSocket(int AddrType, void *Addr, const char *Filename)
+enum {
+       UDP_IOCTL_GETSETLPORT = 4,
+       UDP_IOCTL_GETSETRPORT,
+       UDP_IOCTL_GETSETRMASK,
+       UDP_IOCTL_SETRADDR,
+};
+
+int Net_OpenSocket(int AddrType, const void *Addr, const char *Filename)
 {
         int    addrLen = Net_GetAddressSize(AddrType);
 {
         int    addrLen = Net_GetAddressSize(AddrType);
-        int    i;
-       uint8_t *addrBuffer = Addr;
        char    hexAddr[addrLen*2+1];
        
        char    hexAddr[addrLen*2+1];
        
-       for( i = 0; i < addrLen; i ++ )
-               sprintf(hexAddr+i*2, "%02x", addrBuffer[i]);
+       {
+               const uint8_t   *addrBuffer = Addr;
+               for( unsigned int i = 0; i < addrLen; i ++ )
+                       sprintf(hexAddr+i*2, "%02x", addrBuffer[i]);
+       }
        
        if(Filename)
        {
        
        if(Filename)
        {
@@ -37,14 +45,27 @@ int Net_OpenSocket(int AddrType, void *Addr, const char *Filename)
        }
 }
 
        }
 }
 
-int Net_OpenSocket_TCPC(int AddrType, void *Addr, int Port)
+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
 {
        int fd = Net_OpenSocket(AddrType, Addr, "tcpc");
        if( fd == -1 )  return -1;
        
        _SysIOCtl(fd, 5, &Port);        // Remote Port
-        _SysIOCtl(fd, 6, Addr);        // Remote address
+        _SysIOCtl(fd, 6, (void*)Addr); // Remote address (kernel shouldn't modify)
        _SysIOCtl(fd, 7, NULL); // connect
        return fd;
 }
 
        _SysIOCtl(fd, 7, NULL); // connect
        return fd;
 }
 
+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
+       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)
+       return fd;
+}
+

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