A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.

Dependents:   oldheating gps motorhome heating

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dnsserver.c Source File

dnsserver.c

00001 #include <stdbool.h>
00002 #include <string.h>
00003 
00004 #include      "dns.h"
00005 #include   "dnshdr.h"
00006 #include  "dnsname.h"
00007 #include "dnslabel.h"
00008 #include      "net.h"
00009 #include "net-this.h"
00010 #include   "action.h"
00011 #include      "log.h"
00012 #include     "dhcp.h"
00013 #include    "slaac.h"
00014 #include      "ip4.h"
00015 #include      "ip6.h"
00016 
00017 bool DnsServerTrace = false;
00018 
00019 #define RECORD_NONE               0
00020 #define RECORD_PTR4               1
00021 #define RECORD_PTR6_LINK_LOCAL    2
00022 #define RECORD_PTR6_UNIQUE_LOCAL  3
00023 #define RECORD_PTR6_GLOBAL        4
00024 #define RECORD_A                  5
00025 #define RECORD_AAAA_LINK_LOCAL    6
00026 #define RECORD_AAAA_UNIQUE_LOCAL  7
00027 #define RECORD_AAAA_GLOBAL        8
00028 
00029 #define MAX_ANSWERS 4
00030 
00031 //Set by 'initialise'
00032 static char* p;               //Position relative to DnsHdrData and is updated while both reading questions and writing answers
00033 static char  myFullName[100]; //The name, adjusted to include the domain if needed by the protocol, used when reading and when writing
00034 static int   myFullNameLength;
00035 
00036 //Set by readQuestions and used by answerQuestions
00037 static int   answers[MAX_ANSWERS];
00038 static int   answerCount = 0;
00039 static bool  mdnsUnicastReply;
00040 
00041 static int readQuestions()
00042 {
00043     p = DnsHdrData;
00044     mdnsUnicastReply = false;
00045     
00046     //Get the questions
00047     answerCount = 0;
00048     for (int i = 0; i < DnsHdrQdcount; i++)
00049     {
00050         //Bomb out if there are too many answers
00051         if (answerCount >= MAX_ANSWERS)
00052         {
00053             if (DnsServerTrace) LogTimeF("DnsServer-readQuestions - exceeded %d answers\r\n", MAX_ANSWERS);
00054             break;
00055         }
00056         
00057         //Bomb out if we are tending to overrun the buffer
00058         if (p - DnsHdrData > DnsHdrDataLength)
00059         {
00060             if (DnsServerTrace) LogTimeF("DnsServer-readQuestions - overrunning the buffer of %d bytes\r\n", DnsHdrDataLength);
00061             return -1;
00062         }
00063         
00064         //Node name
00065         int nameLength = DnsNameLength(p);
00066         if (!nameLength)
00067         {
00068             if (DnsServerTrace) LogTimeF("DnsServer-readQuestions namelength is zero\r\n");
00069             return -1;
00070         }
00071         bool nodeIsName  = DnsNameComparePtr(p, myFullName);
00072         bool nodeIsAddr4 = DnsNameCompareIp4(p, DhcpLocalIp);
00073         bool nodeIsLocl6 = DnsNameCompareIp6(p, SlaacLinkLocalIp);
00074         bool nodeIsUniq6 = DnsNameCompareIp6(p, SlaacUniqueLocalIp);
00075         bool nodeIsGlob6 = DnsNameCompareIp6(p, SlaacGlobalIp);
00076         p += nameLength;                          //Skip past the name
00077                 
00078         //Type
00079         p++ ;                                     //skip the first byte of the type
00080         char recordType = *p++;                   //read the record type
00081         
00082         //Class
00083         if (*p++ & 0x80) mdnsUnicastReply = true; //check the class 15th bit (UNICAST-RESPONSE)
00084         p++;                                      //skip the class
00085         
00086         //Handle the questions
00087         if (nodeIsName && recordType == DNS_RECORD_A   )   answers[answerCount++] = RECORD_A;
00088         if (nodeIsName && recordType == DNS_RECORD_AAAA)
00089         {
00090                                                            answers[answerCount++] = RECORD_AAAA_LINK_LOCAL;
00091                                 if (SlaacUniqueLocalIp[0]) answers[answerCount++] = RECORD_AAAA_UNIQUE_LOCAL;
00092                                 if (SlaacGlobalIp     [0]) answers[answerCount++] = RECORD_AAAA_GLOBAL;
00093         }
00094         if (nodeIsAddr4 && recordType == DNS_RECORD_PTR )  answers[answerCount++] = RECORD_PTR4;
00095         if (nodeIsLocl6 && recordType == DNS_RECORD_PTR )  answers[answerCount++] = RECORD_PTR6_LINK_LOCAL;
00096         if (nodeIsUniq6 && recordType == DNS_RECORD_PTR )  answers[answerCount++] = RECORD_PTR6_UNIQUE_LOCAL;
00097         if (nodeIsGlob6 && recordType == DNS_RECORD_PTR )  answers[answerCount++] = RECORD_PTR6_GLOBAL;
00098     }
00099     return 0;
00100 }
00101 static int addAnswers(int dnsProtocol)
00102 {    
00103     //Go through each answer
00104     DnsHdrAncount = 0;
00105     for (int i = 0; i < answerCount; i++)
00106     {                
00107         //Bomb out if we are tending to overrun the buffer
00108         if (p - DnsHdrData > DnsHdrDataLength)
00109         {
00110             if (DnsServerTrace) LogTimeF("DnsServer-addAnswers - reply is getting too big\r\n");
00111             return -1;
00112         }
00113                 
00114         //Encode the node name
00115         switch (answers[i])
00116         {
00117             case RECORD_A:                 DnsNameEncodePtr(myFullName,         &p); break;
00118             case RECORD_AAAA_LINK_LOCAL:   DnsNameEncodePtr(myFullName,         &p); break;
00119             case RECORD_AAAA_UNIQUE_LOCAL: DnsNameEncodePtr(myFullName,         &p); break;
00120             case RECORD_AAAA_GLOBAL:       DnsNameEncodePtr(myFullName,         &p); break;
00121             case RECORD_PTR4:              DnsNameEncodeIp4(DhcpLocalIp,        &p); break;
00122             case RECORD_PTR6_LINK_LOCAL:   DnsNameEncodeIp6(SlaacLinkLocalIp,   &p); break;
00123             case RECORD_PTR6_UNIQUE_LOCAL: DnsNameEncodeIp6(SlaacUniqueLocalIp, &p); break;
00124             case RECORD_PTR6_GLOBAL:       DnsNameEncodeIp6(SlaacGlobalIp,      &p); break;
00125         }
00126         
00127         //Add the 16 bit type
00128         *p++ = 0;
00129         switch (answers[i])
00130         {
00131             case RECORD_A:                 *p++ = DNS_RECORD_A;    break;
00132             case RECORD_AAAA_LINK_LOCAL:   *p++ = DNS_RECORD_AAAA; break;
00133             case RECORD_AAAA_UNIQUE_LOCAL: *p++ = DNS_RECORD_AAAA; break;
00134             case RECORD_AAAA_GLOBAL:       *p++ = DNS_RECORD_AAAA; break;
00135             case RECORD_PTR4:              *p++ = DNS_RECORD_PTR;  break;
00136             case RECORD_PTR6_LINK_LOCAL:   *p++ = DNS_RECORD_PTR;  break;
00137             case RECORD_PTR6_UNIQUE_LOCAL: *p++ = DNS_RECORD_PTR;  break;
00138             case RECORD_PTR6_GLOBAL:       *p++ = DNS_RECORD_PTR;  break;
00139         }
00140         
00141         //Add the class
00142         char mdns = dnsProtocol == DNS_PROTOCOL_MDNS ? 0x80 : 0; //Set the 15th bit (CACHE_FLUSH) of the class to 1 if MDNS
00143         *p++ = mdns; *p++ = 1;                                   //16 bit Class LSB QCLASS_IN = 1 - internet
00144         
00145         //Add the TTL
00146         *p++ =    0; *p++ = 0; *p++ = 4; *p++ = 0;               //32 bit TTL seconds - 1024
00147         
00148         
00149         //Add the 16 bit payload length
00150         *p++ = 0;
00151         switch (answers[i])
00152         {
00153             case RECORD_A:                 *p++ =  4;                   break;
00154             case RECORD_AAAA_LINK_LOCAL:   *p++ = 16;                   break;
00155             case RECORD_AAAA_UNIQUE_LOCAL: *p++ = 16;                   break;
00156             case RECORD_AAAA_GLOBAL:       *p++ = 16;                   break;
00157             case RECORD_PTR4:              *p++ = myFullNameLength + 2; break; //add a byte for the initial length and another for the terminating zero length
00158             case RECORD_PTR6_LINK_LOCAL:   *p++ = myFullNameLength + 2; break;
00159             case RECORD_PTR6_UNIQUE_LOCAL: *p++ = myFullNameLength + 2; break;
00160             case RECORD_PTR6_GLOBAL:       *p++ = myFullNameLength + 2; break;
00161         }
00162         
00163         //Add the payload
00164         switch (answers[i])
00165         {
00166             case RECORD_A:                 memcpy(p, &DhcpLocalIp,        4); p +=  4; break;
00167             case RECORD_AAAA_LINK_LOCAL:   memcpy(p, SlaacLinkLocalIp,   16); p += 16; break;
00168             case RECORD_AAAA_UNIQUE_LOCAL: memcpy(p, SlaacUniqueLocalIp, 16); p += 16; break;
00169             case RECORD_AAAA_GLOBAL:       memcpy(p, SlaacGlobalIp,      16); p += 16; break;
00170             case RECORD_PTR4:              DnsNameEncodePtr(myFullName, &p);           break;
00171             case RECORD_PTR6_LINK_LOCAL:   DnsNameEncodePtr(myFullName, &p);           break;
00172             case RECORD_PTR6_UNIQUE_LOCAL: DnsNameEncodePtr(myFullName, &p);           break;
00173             case RECORD_PTR6_GLOBAL:       DnsNameEncodePtr(myFullName, &p);           break;
00174         }
00175         //Increment the number of good answers to send
00176         DnsHdrAncount++;
00177     }
00178     return 0;
00179 }
00180 
00181 int DnsServerHandleQuery(void (*traceback)(void), int dnsProtocol, void* pPacketTx, int *pSizeTx) //Received an mdns or llmnr query on port 5353 or 5355
00182 {            
00183     myFullNameLength = DnsLabelMakeFullNameFromName(dnsProtocol, NET_NAME, sizeof(myFullName), myFullName);
00184     
00185     if (readQuestions()) return DO_NOTHING;
00186     if (!answerCount) return DO_NOTHING;
00187     
00188     if (DnsServerTrace || NetTraceHostGetMatched())
00189     {
00190         if (NetTraceNewLine) Log("\r\n");
00191         LogTimeF("DnsServer received query\r\n");
00192         if (NetTraceStack) traceback();
00193         DnsHdrLog(dnsProtocol);
00194     }
00195     
00196     char* pRx = DnsHdrData;
00197     char* pEndRx = p;
00198     int qdcount = DnsHdrQdcount;
00199     int nscount = DnsHdrNscount;
00200     int arcount = DnsHdrArcount;
00201     
00202     DnsHdrSetup(pPacketTx, *pSizeTx);
00203     p = DnsHdrData; 
00204     
00205     //Add the questions if this is not MDNS
00206     if (dnsProtocol == DNS_PROTOCOL_MDNS)
00207     {
00208         DnsHdrQdcount = 0;
00209         DnsHdrNscount = 0;
00210         DnsHdrArcount = 0;
00211     }
00212     else
00213     {
00214         DnsHdrQdcount = qdcount;
00215         DnsHdrNscount = nscount;
00216         DnsHdrArcount = arcount;
00217         while (pRx < pEndRx) *p++ = *pRx++;
00218     }
00219     
00220 
00221     if (addAnswers(dnsProtocol)) return DO_NOTHING;
00222     
00223     DnsHdrIsReply          = true;
00224     DnsHdrIsAuthoritative  = false;
00225     if (dnsProtocol == DNS_PROTOCOL_MDNS) DnsHdrIsAuthoritative  = true; //See rfc6762 18.4
00226     DnsHdrIsRecursiveQuery = false;
00227     
00228     DnsHdrWrite();
00229     
00230     *pSizeTx = p - DnsHdrPacket;
00231     
00232     if (DnsServerTrace || NetTraceHostGetMatched()) DnsHdrLog(dnsProtocol);
00233 
00234     int dest;
00235     if (dnsProtocol == DNS_PROTOCOL_MDNS && !mdnsUnicastReply) dest = MULTICAST_MDNS;
00236     else                                                       dest =   UNICAST;
00237     
00238     return ActionMakeFromDestAndTrace(dest, (NetTraceStack && DnsServerTrace) || NetTraceHostGetMatched());
00239 }