Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Revision:
13:9cd54f7db57a
Child:
22:914b970356f0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/udp/dns/dnsserver.cpp	Mon May 01 18:20:55 2017 +0000
@@ -0,0 +1,143 @@
+#include    "mbed.h"
+#include  "dnshdr.h"
+#include "dnsname.h"
+#include     "net.h"
+#include     "dns.h"
+#include     "log.h"
+#include    "dhcp.h"
+#include   "slaac.h"
+#include      "io.h"
+
+#define DEBUG false
+
+int DnsServerHandleQuery(int dnsProtocol, int *pSize) //Received an mdns or llmnr query on port 5353 or 5355
+{    
+    if (DEBUG) DnsHdrLog("server received query", dnsProtocol);
+    
+    if (       *pSize > 512) { LogTimeF("DnsServerHandleQuery length %d too long\r\n",  *pSize); return DO_NOTHING; }
+    if (DnsHdrQdcount >   4) { LogTimeF("DnsServerHandleQuery too many queries %d\r\n", *pSize); return DO_NOTHING; }
+    
+    char *p = DnsHdrData;
+    
+    char iEncodedName;
+    bool isMe = false;
+    int  types[4];
+    bool mdnsUnicastReply = false;
+    
+    //Get the questions
+    DnsHdrAncount = 0;
+    for (int q = 0; q < DnsHdrQdcount; q++)
+    {
+        iEncodedName = DnsNameIndexFromPointer(p);
+        int nameLength = DnsNameLength(p);
+        if (!nameLength) return DO_NOTHING;
+        if (!q) isMe = DnsNameCompare(p, NetName); //get the name: rtc.local; 3.1.168.192.inaddr.arpa; etc
+        p += nameLength;                           //Skip past the name
+        p++ ;                                      //skip the first byte of the type
+        char recordType = *p++;                    //read the record type
+        if (*p++ & 0x80) mdnsUnicastReply = true;  //Check the 15th bit (UNICAST-RESPONSE)
+        p += 1;                                    //skip the class
+        
+        types[q] = recordType;
+        
+        if (DEBUG)
+        {
+            switch (recordType)
+            {
+                case DNS_RECORD_A:    LogF("  for IP4 address\r\n"); break;
+                case DNS_RECORD_PTR:  LogF("  for name\r\n");        break;
+                case DNS_RECORD_AAAA: LogF("  for IP6 address\r\n"); break;
+                default:              LogF("  for unrecognised record type %d\r\n", recordType); break;
+            }
+            char text[256];
+            DnsNameDecode(iEncodedName, sizeof(text), text);
+            LogF("  Name     %s\r\n", text);
+        }    
+    }
+    if (!isMe) return DO_NOTHING;
+    
+    //Respond to the questions
+    for (int q = 0; q < DnsHdrQdcount; q++)
+    {
+        switch (types[q])
+        {
+            case DNS_RECORD_A:
+                if (p - DnsHdrPacket > 500)
+                {
+                    LogTimeF("DNS server ip4 query reply is getting too big\r\n");
+                    return DO_NOTHING;
+                }
+                DnsHdrAncount++;
+                //Name
+                DnsNameEncode(NetName, &p);
+                
+                //16 bit Type
+                *p++ = 0; //MSB type
+                *p++ = DNS_RECORD_A;
+                
+                //Class
+                *p++ = dnsProtocol == DNS_PROTOCOL_MDNS ? 0x80 : 0; //Set the 15th bit (CACHE_FLUSH) to 1 if MDNS
+                *p++ = 1;                                           //QCLASS_IN = 1 - internet
+                
+                 //32 bit TTL seconds
+                *p++ = 0;
+                *p++ = 0;
+                *p++ = 4; //1024 seconds
+                *p++ = 0;
+                
+                //16bit length in bytes
+                *p++ = 0;
+                *p++ = 4;
+                
+                //Value
+                memcpy(p, &DhcpLocalIp, 4);
+                p += 4;
+                break;
+                
+            case DNS_RECORD_AAAA:
+                if (p - DnsHdrPacket > 500)
+                {
+                    LogTimeF("DNS server Ip6 query reply is getting too big\r\n");
+                    return DO_NOTHING;
+                }
+                DnsHdrAncount++;
+                //Name
+                DnsNameEncode(NetName, &p);
+                
+                //16 bit Type
+                *p++ = 0; //MSB type
+                *p++ = DNS_RECORD_AAAA;
+                
+                //Class
+                *p++ = dnsProtocol == DNS_PROTOCOL_MDNS ? 0x80 : 0; //Set the 15th bit (CACHE_FLUSH) to 1 if MDNS
+                *p++ = 1;                                           //QCLASS_IN = 1 - internet
+                
+                 //32 bit TTL seconds
+                *p++ = 0;
+                *p++ = 0;
+                *p++ = 4; //1024 seconds
+                *p++ = 0;
+                
+                //16bit length in bytes
+                *p++ = 0;
+                *p++ = 16;
+                
+                //Value
+                memcpy(p, SlaacLinkLocalIp, 16);
+                p += 16;
+                break;
+        }
+    }
+    if (!DnsHdrAncount) return DO_NOTHING;
+    
+    DnsHdrIsReply         = true;
+    DnsHdrIsAuthoritative = true;
+    DnsHdrWrite();
+    
+    *pSize = p - DnsHdrPacket;
+    
+    if (DEBUG) DnsHdrLog("server sending reply", dnsProtocol);
+
+    if (dnsProtocol == DNS_PROTOCOL_MDNS && !mdnsUnicastReply) return MULTICAST_MDNS;
+    return UNICAST;
+}