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 dnsname.c Source File

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 }