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
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 }
Generated on Tue Jul 12 2022 18:53:40 by 1.7.2