Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

udp/dns/dnsserver.cpp

Committer:
andrewboyson
Date:
2017-07-03
Revision:
22:914b970356f0
Parent:
13:9cd54f7db57a
Child:
32:679654f2d023

File content as of revision 22:914b970356f0:

#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)
    {
        if (DEBUG) LogTimeF("DnsServerHandleQuery length %d too long\r\n",  *pSize);
        return DO_NOTHING;
    }
    if (DnsHdrQdcount >   4)
    {
        if (DEBUG) 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;
}