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
dnsname.c
00001 #include <stdint.h> 00002 #include <stdbool.h> 00003 #include <stdio.h> 00004 00005 #include "dnshdr.h" 00006 #include "ctype.h" 00007 #include "log.h" 00008 00009 bool DnsNameTrace = false; 00010 00011 #define MAX_DEPTH 10 00012 00013 static bool isOffset(char c) { return (c & 0xC0) == 0xC0; } 00014 static char* derefOffset(char* p) 00015 { 00016 int offset = (*p & 0x3F) << 8; //Any bits in the upper byte are added 00017 p++; //Move to the lower byte 00018 offset |= *p; //And add it 00019 return DnsHdrPacket + offset; //Return a pointer 00020 } 00021 00022 int DnsNameLength(char* pStart) //Returns 0 on error 00023 { 00024 char* p = pStart; 00025 00026 while (true) 00027 { 00028 if (p >= DnsHdrData + DnsHdrDataLength) 00029 { 00030 if (DnsNameTrace) LogTimeF("DnsNameLength strayed out of the packet\r\n"); 00031 return 0; 00032 } 00033 00034 int length = *p++; 00035 if (length == 0) //Its the last field so finish 00036 { 00037 return p - pStart; 00038 } 00039 else if (isOffset(length)) //it's a pointer so skip the length byte and return 00040 { 00041 p++; 00042 return p - pStart; 00043 } 00044 else //it's a length plus a field eg 3www 00045 { 00046 p += length; 00047 } 00048 } 00049 } 00050 00051 bool DnsNameComparePtr(char* pStart, char* pTarget) 00052 { 00053 char* p = pStart; 00054 00055 int depth = 0; 00056 00057 while (true) 00058 { 00059 if (p >= DnsHdrData + DnsHdrDataLength) 00060 { 00061 if (DnsNameTrace) LogTimeF("DnsNameCompare strayed out of the packet\r\n"); 00062 return false; 00063 } 00064 00065 int length = *p; 00066 if (length == 0) //Its the last field so should be on the target's terminating NUL 00067 { 00068 if (*pTarget) return false; 00069 return true; 00070 } 00071 else if (isOffset(length)) //it's a pointer so go up one 00072 { 00073 depth++; 00074 if (depth > MAX_DEPTH) 00075 { 00076 if (DnsNameTrace) LogTimeF("DnsNameCompare exceeded depth limit\r\n"); 00077 return false; 00078 } 00079 pStart = derefOffset(p); 00080 p = pStart; 00081 } 00082 else //it's a length plus a field eg 3www 00083 { 00084 if (p > pStart) if (*pTarget++ != '.') return false; 00085 p++; 00086 for (int i = 0; i < length; i++) 00087 { 00088 if (toupper(*pTarget++) != toupper(*p++)) return false; 00089 } 00090 } 00091 } 00092 } 00093 bool DnsNameCompareIp4(char *pStart, uint32_t ip) 00094 { 00095 char ipBytes[4]; 00096 int field = 0; 00097 int depth = 0; 00098 char* p = pStart; 00099 while (true) 00100 { 00101 if (p >= DnsHdrData + DnsHdrDataLength) 00102 { 00103 LogTimeF("DnsNameCompareIp4 could not find name end\r\n"); 00104 return false; 00105 } 00106 00107 int length = *p; 00108 if (length == 0) //Its the last field so return the ip if it is the correct length 00109 { 00110 if (field != 6) return false; 00111 return true; 00112 } 00113 else if (isOffset(*p)) //it's a pointer so jump to the new offset eg ^C0 ^0C 00114 { 00115 depth++; 00116 if (depth > MAX_DEPTH) 00117 { 00118 LogTimeF("DnsNameCompareIp4 exceeded depth limit\r\n"); 00119 return false; 00120 } 00121 p = derefOffset(p); 00122 } 00123 else //it's a length plus a field eg 3www 00124 { 00125 p++; // move past the length 00126 if (field <= 3) 00127 { 00128 if (length > 3) return false; // expect 90.1.168.192.in-addr.arpa 00129 int byte = 0; 00130 for (int i = 0; i < length; i++) 00131 { 00132 byte = byte * 10; 00133 if (*p > '9' || *p < '0') return false; // expect 90.1.168.192.in-addr.arpa 00134 byte += *p - '0'; 00135 p++; 00136 } 00137 int ipByte = (ip >> 8 * (3 - field)) & 0xFF; 00138 if (byte != ipByte) return false; 00139 } 00140 else if (field == 4) 00141 { 00142 if (length != 7) return false; // expect 90.1.168.192.in-addr.arpa 00143 p+= length; 00144 } 00145 else if (field == 5) 00146 { 00147 if (length != 4) return false; // expect 90.1.168.192.in-addr.arpa 00148 p+= length; 00149 } 00150 else 00151 { 00152 return false; // expect 90.1.168.192.in-addr.arpa 00153 } 00154 field++; 00155 } 00156 } 00157 } 00158 bool DnsNameCompareIp6(char* pStart, char* pIp) 00159 { 00160 int field = 0; 00161 int depth = 0; 00162 char* p = pStart; 00163 while (true) 00164 { 00165 if (p >= DnsHdrData + DnsHdrDataLength) 00166 { 00167 LogTimeF("DnsNameDecodeIp6 could not find name end\r\n"); 00168 return false; 00169 } 00170 00171 int length = *p; 00172 if (length == 0) //Its the last field so return the ip if it is the correct length 00173 { 00174 if (field != 34) return false; 00175 return true; 00176 } 00177 else if (isOffset(*p)) //it's a pointer so jump to the new offset eg ^C0 ^0C 00178 { 00179 depth++; 00180 if (depth > MAX_DEPTH) 00181 { 00182 LogTimeF("DnsNameDecodeIp6 exceeded depth limit\r\n"); 00183 return false; 00184 } 00185 p = derefOffset(p); 00186 } 00187 else //it's a length plus a field eg 3www 00188 { 00189 p++; // move past the length 00190 if (field <= 31) 00191 { 00192 if (length > 1) return false; // expect 5.8.c.c.0.1.e.f.f.f.2.3.1.1.2.0.8.7.d.0.9.0.f.1.0.7.4.0.1.0.0.2.ip6.arpa 00193 int nibble = 0; 00194 if (*p >= '0' && *p <= '9') nibble = *p - '0'; 00195 else if (*p >= 'a' && *p <= 'f') nibble = *p - 'a' + 10; 00196 else if (*p >= 'A' && *p <= 'F') nibble = *p - 'A' + 10; 00197 else return false; // expect 7.2.d.7.2.f.e.f.f.f.7.f.2.0.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.e.f.ip6.arpa 00198 int target = pIp[15 - (field >> 1)]; 00199 if ((field & 1) == 0) { target &= 0x0F; } 00200 else { target &= 0xF0; target >>=4; } 00201 if (target != nibble) return false; 00202 p += length; 00203 } 00204 else if (field == 32) 00205 { 00206 if (length != 3) return false; // expect 5.8.c.c.0.1.e.f.f.f.2.3.1.1.2.0.8.7.d.0.9.0.f.1.0.7.4.0.1.0.0.2.ip6.arpa 00207 p+= length; 00208 } 00209 else if (field == 33) 00210 { 00211 if (length != 4) return false; // expect 5.8.c.c.0.1.e.f.f.f.2.3.1.1.2.0.8.7.d.0.9.0.f.1.0.7.4.0.1.0.0.2.ip6.arpa 00212 p+= length; 00213 } 00214 else 00215 { 00216 return false; // expect 5.8.c.c.0.1.e.f.f.f.2.3.1.1.2.0.8.7.d.0.9.0.f.1.0.7.4.0.1.0.0.2.ip6.arpa 00217 } 00218 field++; 00219 } 00220 } 00221 } 00222 00223 void DnsNameDecodePtr(char* pStart, char* pName, int lenName) 00224 { 00225 bool nameStarted = false; 00226 int depth = 0; 00227 char* p = pStart; 00228 char* pNameStart = pName; 00229 while (true) 00230 { 00231 if (p >= DnsHdrData + DnsHdrDataLength) 00232 { 00233 *pName = 0; 00234 if (DnsNameTrace) LogTimeF("DnsNameDecodePtr could not find name end\r\n"); 00235 return; 00236 } 00237 00238 int length = *p; 00239 if (length == 0) //Its the last field so terminate the string 00240 { 00241 *pName = 0; 00242 return; 00243 } 00244 else if (isOffset(*p)) //it's a pointer so jump to the new offset eg ^C0 ^0C 00245 { 00246 depth++; 00247 if (depth > MAX_DEPTH) 00248 { 00249 LogTimeF("DnsNameDecodePtr exceeded depth limit\r\n"); 00250 *pName = 0; 00251 return; 00252 } 00253 p = derefOffset(p); 00254 } 00255 else //it's a length plus a field eg 3www 00256 { 00257 if (pName) 00258 { 00259 if (length + 1 > lenName) //Leave room to terminate the string. 00260 //Warning removed as had too many 'amzn.dmgr:9D184A89EEDE554B15EABD4931BB839B:S/FRy5cPXE:914584' alerts 00261 { 00262 *pName = 0; 00263 //LogTimeF("DnsNameDecodePtr decoded name '%s' overran name buffer trying to add %d bytes\r\n", pNameStart, length); 00264 return; 00265 } 00266 lenName -= length + 1; //name chunk plus a '.' 00267 if (nameStarted) *pName++ = '.'; 00268 p++; 00269 for (int i = 0; i < length; i++) *pName++ = *p++; 00270 nameStarted = true; 00271 } 00272 else 00273 { 00274 p += length + 1; 00275 } 00276 } 00277 } 00278 } 00279 void DnsNameLogPtr(char* pStart) 00280 { 00281 bool nameStarted = false; 00282 int depth = 0; 00283 char* p = pStart; 00284 while (true) 00285 { 00286 if (p >= DnsHdrData + DnsHdrDataLength) 00287 { 00288 if (DnsNameTrace) LogTimeF("DnsNameDecodePtr could not find name end\r\n"); 00289 return; 00290 } 00291 00292 int length = *p; 00293 if (length == 0) //Its the last field so terminate the string 00294 { 00295 return; 00296 } 00297 else if (isOffset(*p)) //it's a pointer so jump to the new offset eg ^C0 ^0C 00298 { 00299 depth++; 00300 if (depth > MAX_DEPTH) 00301 { 00302 LogTimeF("DnsNameDecodePtr exceeded depth limit\r\n"); 00303 return; 00304 } 00305 p = derefOffset(p); 00306 } 00307 else //it's a length plus a field eg 3www 00308 { 00309 if (nameStarted) LogChar('.'); 00310 p++; 00311 for (int i = 0; i < length; i++) LogChar(*p++); 00312 nameStarted = true; 00313 } 00314 } 00315 } 00316 void DnsNameDecodeIp4(char* pStart, uint32_t* pIp) 00317 { 00318 int field = 0; 00319 int depth = 0; 00320 char* p = pStart; 00321 while (true) 00322 { 00323 if (p >= DnsHdrData + DnsHdrDataLength) 00324 { 00325 *pIp = 0; 00326 LogTimeF("DnsNameDecodeIp4 could not find name end\r\n"); 00327 return; 00328 } 00329 00330 int length = *p; 00331 if (length == 0) //Its the last field so return the ip if it is the correct length 00332 { 00333 if (field != 6) *pIp = 0; 00334 return; 00335 } 00336 else if (isOffset(*p)) //it's a pointer so jump to the new offset eg ^C0 ^0C 00337 { 00338 depth++; 00339 if (depth > MAX_DEPTH) 00340 { 00341 LogTimeF("DnsNameDecodeIp4 exceeded depth limit\r\n"); 00342 *pIp = 0; 00343 return; 00344 } 00345 p = derefOffset(p); 00346 } 00347 else //it's a length plus a field eg 3www 00348 { 00349 p++; // move past the length 00350 if (field <= 3) 00351 { 00352 if (length > 3) {*pIp = 0; return; } // expect 90.1.168.192.in-addr.arpa 00353 int byte = 0; 00354 for (int i = 0; i < length; i++) 00355 { 00356 byte = byte * 10; 00357 if (*p > '9' || *p < '0') {*pIp = 0; return; } // expect 90.1.168.192.in-addr.arpa 00358 byte += *p - '0'; 00359 p++; 00360 } 00361 *pIp <<= 8; 00362 *pIp |= byte; 00363 } 00364 else if (field == 4) 00365 { 00366 if (length != 7) {*pIp = 0; return; } // expect 90.1.168.192.in-addr.arpa 00367 p+= length; 00368 } 00369 else if (field == 5) 00370 { 00371 if (length != 4) {*pIp = 0; return; } // expect 90.1.168.192.in-addr.arpa 00372 p+= length; 00373 } 00374 else 00375 { 00376 *pIp = 0; return; // expect 90.1.168.192.in-addr.arpa 00377 } 00378 field++; 00379 } 00380 } 00381 } 00382 void DnsNameDecodeIp6(char* pStart, char* pIp) 00383 { 00384 int field = 0; 00385 int depth = 0; 00386 char* p = pStart; 00387 while (true) 00388 { 00389 if (p >= DnsHdrData + DnsHdrDataLength) 00390 { 00391 pIp[0] = 0; 00392 LogTimeF("DnsNameDecodeIp6 could not find name end\r\n"); 00393 return; 00394 } 00395 00396 int length = *p; 00397 if (length == 0) //Its the last field so return the ip if it is the correct length 00398 { 00399 if (field != 34) pIp[0] = 0; 00400 return; 00401 } 00402 else if (isOffset(*p)) //it's a pointer so jump to the new offset eg ^C0 ^0C 00403 { 00404 depth++; 00405 if (depth > MAX_DEPTH) 00406 { 00407 LogTimeF("DnsNameDecodeIp6 exceeded depth limit\r\n"); 00408 *pIp = 0; 00409 return; 00410 } 00411 p = derefOffset(p); 00412 } 00413 else //it's a length plus a field eg 3www 00414 { 00415 p++; // move past the length 00416 if (field <= 31) 00417 { 00418 if (length > 1) {pIp[0] = 0; return; } // expect 5.8.c.c.0.1.e.f.f.f.2.3.1.1.2.0.8.7.d.0.9.0.f.1.0.7.4.0.1.0.0.2.ip6.arpa 00419 int nibble = 0; 00420 if (*p >= '0' && *p <= '9') nibble = *p - '0'; 00421 else if (*p >= 'a' && *p <= 'f') nibble = *p - 'a' + 10; 00422 else if (*p >= 'A' && *p <= 'F') nibble = *p - 'A' + 10; 00423 else {pIp[0] = 0; return; } // expect 5.8.c.c.0.1.e.f.f.f.2.3.1.1.2.0.8.7.d.0.9.0.f.1.0.7.4.0.1.0.0.2.ip6.arpa 00424 if ((field & 1) == 0) 00425 { 00426 pIp[15 - (field >> 1)] = nibble; 00427 } 00428 else 00429 { 00430 nibble <<= 4; 00431 pIp[15 - (field >> 1)] |= nibble; 00432 } 00433 p += length; 00434 } 00435 else if (field == 32) 00436 { 00437 if (length != 3) {pIp[0] = 0; return; } // expect 5.8.c.c.0.1.e.f.f.f.2.3.1.1.2.0.8.7.d.0.9.0.f.1.0.7.4.0.1.0.0.2.ip6.arpa 00438 p+= length; 00439 } 00440 else if (field == 33) 00441 { 00442 if (length != 4) {pIp[0] = 0; return; } // expect 5.8.c.c.0.1.e.f.f.f.2.3.1.1.2.0.8.7.d.0.9.0.f.1.0.7.4.0.1.0.0.2.ip6.arpa 00443 p+= length; 00444 } 00445 else 00446 { 00447 pIp[0] = 0; return; // expect 5.8.c.c.0.1.e.f.f.f.2.3.1.1.2.0.8.7.d.0.9.0.f.1.0.7.4.0.1.0.0.2.ip6.arpa 00448 } 00449 field++; 00450 } 00451 } 00452 } 00453 void DnsNameEncodeIp4(uint32_t ip, char** pp) 00454 { 00455 char* p = *pp; //Get a convenient pointer to the next byte 00456 00457 char* pLen = p; 00458 p++; 00459 00460 *pLen = sprintf(p, "%d", (ip & 0xff000000) >> 24); 00461 p += *pLen; 00462 pLen = p; 00463 p++; 00464 00465 *pLen = sprintf(p, "%d", (ip & 0x00ff0000) >> 16); 00466 p += *pLen; 00467 pLen = p; 00468 p++; 00469 00470 *pLen = sprintf(p, "%d", (ip & 0x0000ff00) >> 8); 00471 p += *pLen; 00472 pLen = p; 00473 p++; 00474 00475 *pLen = sprintf(p, "%d", (ip & 0x000000ff) >> 0); 00476 p += *pLen; 00477 pLen = p; 00478 p++; 00479 00480 *pLen = sprintf(p, "in-addr"); 00481 p += *pLen; 00482 pLen = p; 00483 p++; 00484 00485 *pLen = sprintf(p, "arpa"); 00486 p += *pLen; 00487 pLen = p; 00488 p++; 00489 00490 *pLen = 0; 00491 00492 *pp = p; //Save the convenient pointer back into the pointer to pointer 00493 00494 } 00495 00496 void DnsNameEncodeIp6(char* ip, char** pp) 00497 { 00498 char* p = *pp; //Get a convenient pointer to the next byte 00499 00500 ip += 16; 00501 for (int i = 0; i < 16; i++) 00502 { 00503 ip--; 00504 00505 int v; 00506 00507 *p++ = 1; 00508 v = *ip & 0x0F; 00509 *p++ = v < 10 ? v + '0' : v - 10 + 'a'; 00510 00511 *p++ = 1; 00512 v = *ip >> 4; 00513 *p++ = v < 10 ? v + '0' : v - 10 + 'a'; 00514 } 00515 char* pLen = p; 00516 p++; 00517 00518 *pLen = sprintf(p, "ip6"); 00519 p += *pLen; 00520 pLen = p; 00521 p++; 00522 00523 *pLen = sprintf(p, "arpa"); 00524 p += *pLen; 00525 pLen = p; 00526 p++; 00527 00528 *pLen = 0; 00529 00530 *pp = p; //Save the convenient pointer back into the pointer to pointer 00531 00532 } 00533 00534 void DnsNameEncodePtr(char* pName, char** pp) 00535 { 00536 char* p = *pp; //Get a convenient pointer to the next byte 00537 00538 char* pLen = p; //Record the position of the first length byte 00539 p++; //Move to the start of the first field 00540 00541 while (true) 00542 { 00543 char c = *pName; 00544 switch (c) 00545 { 00546 case 0: 00547 *pLen = p - pLen - 1; 00548 *p = 0; 00549 p++; 00550 *pp = p; //Save the convenient pointer back into the pointer to pointer 00551 return; 00552 case '.': 00553 *pLen = p - pLen - 1; 00554 pLen = p; 00555 p++; 00556 break; 00557 default: 00558 *p = c; 00559 p++; 00560 break; 00561 } 00562 pName++; 00563 } 00564 }
Generated on Tue Jul 12 2022 18:53:40 by 1.7.2