Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dns_common.c Source File

dns_common.c

Go to the documentation of this file.
00001 /**
00002  * @file dns_common.c
00003  * @brief Common DNS routines
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL DNS_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <string.h>
00034 #include "core/net.h"
00035 #include "dns/dns_client.h"
00036 #include "dns/dns_common.h"
00037 #include "mdns/mdns_client.h"
00038 #include "mdns/mdns_responder.h"
00039 #include "mdns/mdns_common.h"
00040 #include "debug.h"
00041 
00042 //Check TCP/IP stack configuration
00043 #if (DNS_CLIENT_SUPPORT == ENABLED || MDNS_CLIENT_SUPPORT == ENABLED || \
00044    MDNS_RESPONDER_SUPPORT == ENABLED)
00045 
00046 
00047 /**
00048  * @brief Encode a domain name using the DNS name notation
00049  * @param[in] src Pointer to the domain name to encode
00050  * @param[out] dest Pointer to the encoded domain name (optional parameter)
00051  * @return Length of the encoded domain name
00052  **/
00053 
00054 size_t dnsEncodeName(const char_t *src, uint8_t *dest)
00055 {
00056    uint_t i = 0;
00057    size_t length = 0;
00058 
00059    //Parse input name
00060    while(1)
00061    {
00062       //End of string detected?
00063       if(src[i] == '\0')
00064       {
00065          //Check label length
00066          if(i < 1 || i > DNS_LABEL_MAX_SIZE)
00067             return 0;
00068 
00069          //Save label length
00070          if(dest != NULL)
00071          {
00072             dest[0] = i;
00073             dest[i + 1] = 0;
00074          }
00075 
00076          //Adjust the length of the resulting string
00077          length += i + 2;
00078 
00079          //Stop parsing the input string
00080          return length;
00081       }
00082       //Separator detected?
00083       else if(src[i] == '.')
00084       {
00085          //Check label length
00086          if(i < 1 || i > DNS_LABEL_MAX_SIZE)
00087             return 0;
00088 
00089          //Save label length
00090          if(dest != NULL)
00091             dest[0] = i;
00092 
00093          //Adjust the length of the resulting string
00094          length += i + 1;
00095 
00096          //Advance write pointer
00097          if(dest != NULL)
00098             dest += i + 1;
00099 
00100          //Prepare to decode the next label
00101          src += i + 1;
00102          i = 0;
00103       }
00104       //Any other character?
00105       else
00106       {
00107          //Copy current character
00108          if(dest != NULL)
00109             dest[i + 1] = src[i];
00110 
00111          //Point to the next character
00112          i++;
00113       }
00114    }
00115 }
00116 
00117 
00118 /**
00119  * @brief Decode a domain name that uses the DNS name encoding
00120  * @param[in] message Pointer to the DNS message
00121  * @param[in] length Length of the DNS message
00122  * @param[in] pos Offset of the name to decode
00123  * @param[out] dest Pointer to the decoded name (optional)
00124  * @param[in] level Current level of recursion
00125  * @return The position of the resource record that immediately follows the domain name
00126  **/
00127 
00128 size_t dnsParseName(const DnsHeader *message,
00129    size_t length, size_t pos, char_t *dest, uint_t level)
00130 {
00131    size_t n;
00132    size_t pointer;
00133    uint8_t *src;
00134 
00135    //Recursion limit exceeded?
00136    if(level >= DNS_NAME_MAX_RECURSION)
00137       return 0;
00138 
00139    //Cast the input DNS message to byte array
00140    src = (uint8_t *) message;
00141 
00142    //Parse encoded domain name
00143    while(pos < length)
00144    {
00145       //End marker found?
00146       if(src[pos] == 0)
00147       {
00148          //Properly terminate the string
00149          if(dest != NULL)
00150             *dest = '\0';
00151 
00152          //Return the position of the resource record that
00153          //is immediately following the domain name
00154          return (pos + 1);
00155       }
00156       //Compression tag found?
00157       else if(src[pos] >= DNS_COMPRESSION_TAG)
00158       {
00159          //Malformed DNS message?
00160          if((pos + 1) >= length)
00161             return 0;
00162 
00163          //Read the most significant byte of the pointer
00164          pointer = (src[pos] & ~DNS_COMPRESSION_TAG) << 8;
00165          //Read the least significant byte of the pointer
00166          pointer |= src[pos + 1];
00167 
00168          //Decode the remaining part of the domain name
00169          if(!dnsParseName(message, length, pointer, dest, level + 1))
00170          {
00171             //Domain name decoding failed
00172             return 0;
00173          }
00174 
00175          //Return the position of the resource record that
00176          //is immediately following the domain name
00177          return (pos + 2);
00178       }
00179       //Valid label length?
00180       else if(src[pos] < DNS_LABEL_MAX_SIZE)
00181       {
00182          //Get the length of the current label
00183          n = src[pos++];
00184 
00185          //Malformed DNS message?
00186          if((pos + n) > length)
00187             return 0;
00188 
00189          //The last parameter is optional
00190          if(dest != NULL)
00191          {
00192             //Copy current label
00193             memcpy(dest, src + pos, n);
00194 
00195             //Advance read pointer
00196             pos += n;
00197             //Advance write pointer
00198             dest += n;
00199 
00200             //Append a separator if necessary
00201             if(pos < length && src[pos] != '\0')
00202                *(dest++) = '.';
00203          }
00204          else
00205          {
00206             //Advance read pointer
00207             pos += n;
00208          }
00209       }
00210       //Invalid label length?
00211       else
00212       {
00213          //Properly terminate the string
00214          if(dest != NULL)
00215             *dest = '\0';
00216          //Domain name decoding failed
00217          return 0;
00218       }
00219    }
00220 
00221    //Domain name decoding failed
00222    return 0;
00223 }
00224 
00225 
00226 /**
00227  * @brief Compare domain names
00228  * @param[in] message Pointer to the DNS message
00229  * @param[in] length Length of the DNS message
00230  * @param[in] pos Offset of the encoded domain name
00231  * @param[in] name NULL-terminated string that holds a domain name
00232  * @param[in] level Current level of recursion
00233  * @return The function returns 0 if the domain names match, -1 if the first
00234  *   domain name lexicographically precedes the second name, or 1 if the
00235  *   second domain name lexicographically precedes the first name
00236  **/
00237 
00238 int_t dnsCompareName(const DnsHeader *message, size_t length,
00239    size_t pos, const char_t *name, uint_t level)
00240 {
00241    int_t res;
00242    size_t n;
00243    size_t pointer;
00244    uint8_t *p;
00245 
00246    //Recursion limit exceeded?
00247    if(level >= DNS_NAME_MAX_RECURSION)
00248       return -2;
00249 
00250    //Cast the DNS message to byte array
00251    p = (uint8_t *) message;
00252 
00253    //Parse encoded domain name
00254    while(pos < length)
00255    {
00256       //Retrieve the length of the current label
00257       n = p[pos];
00258 
00259       //End marker found?
00260       if(n == 0)
00261       {
00262          //The domain name which still has remaining data is deemed
00263          //lexicographically later
00264          if(*name != '\0')
00265             return -1;
00266 
00267          //The domain names match each other
00268          return 0;
00269       }
00270       //Compression tag found?
00271       else if(n >= DNS_COMPRESSION_TAG)
00272       {
00273          //Malformed DNS message?
00274          if((pos + 1) >= length)
00275             return FALSE;
00276 
00277          //Read the most significant byte of the pointer
00278          pointer = (p[pos] & ~DNS_COMPRESSION_TAG) << 8;
00279          //Read the least significant byte of the pointer
00280          pointer |= p[pos + 1];
00281 
00282          //Compare the remaining part
00283          res = dnsCompareName(message, length, pointer, name, level + 1);
00284 
00285          //Return comparison result
00286          return res;
00287       }
00288       else
00289       {
00290          //Advance data pointer
00291          pos++;
00292 
00293          //Malformed DNS message?
00294          if((pos + n) > length)
00295             return -2;
00296 
00297          //Compare current label
00298          res = strncasecmp((char_t *) p + pos, name, n);
00299          //Any mismatch?
00300          if(res)
00301             return res;
00302 
00303          //Advance data pointer
00304          pos += n;
00305          name += n;
00306 
00307          //The domain name which still has remaining data is deemed
00308          //lexicographically later
00309          if(*name != '\0' && *name != '.')
00310             return -1;
00311 
00312          //Skip the separator character, if any
00313          if(*name == '.')
00314             name++;
00315       }
00316    }
00317 
00318    //Malformed DNS message
00319    return -2;
00320 }
00321 
00322 
00323 /**
00324  * @brief Compare domain names encoded with DNS notation
00325  * @param[in] message1 Pointer to the first DNS message
00326  * @param[in] length1 Length of the first DNS message
00327  * @param[in] pos1 Offset of the encoded domain name within the first message
00328  * @param[in] message2 Pointer to the second DNS message
00329  * @param[in] length2 Length of the second DNS message
00330  * @param[in] pos2 Offset of the encoded domain name within the second message
00331  * @param[in] level Current level of recursion
00332  * @return The function returns 0 if the domain names match, -1 if the first
00333  *   domain name lexicographically precedes the second name, or 1 if the
00334  *   second domain name lexicographically precedes the first name
00335  **/
00336 
00337 int_t dnsCompareEncodedName(const DnsHeader *message1, size_t length1, size_t pos1,
00338    const DnsHeader *message2, size_t length2, size_t pos2, uint_t level)
00339 {
00340    int_t res;
00341    size_t n;
00342    size_t n1;
00343    size_t n2;
00344    size_t pointer1;
00345    size_t pointer2;
00346    uint8_t *p1;
00347    uint8_t *p2;
00348 
00349    //Recursion limit exceeded?
00350    if(level >= DNS_NAME_MAX_RECURSION)
00351       return -2;
00352 
00353    //Cast DNS messages to byte array
00354    p1 = (uint8_t *) message1;
00355    p2 = (uint8_t *) message2;
00356 
00357    //Compare encoded domain names
00358    while(pos1 < length1 && pos2 < length2)
00359    {
00360       //Retrieve the length of each label
00361       n1 = p1[pos1];
00362       n2 = p2[pos2];
00363 
00364       //End marker found?
00365       if(n1 == 0 || n2 == 0)
00366       {
00367          //The domain name which still has remaining data is deemed
00368          //lexicographically later
00369          if(n1 < n2)
00370             return -1;
00371          else if(n1 > n2)
00372             return 1;
00373 
00374          //The domain names match each other
00375          return 0;
00376       }
00377       //Compression tag found?
00378       else if(n1 >= DNS_COMPRESSION_TAG || n2 >= DNS_COMPRESSION_TAG)
00379       {
00380          //First domain name compressed?
00381          if(n1 >= DNS_COMPRESSION_TAG)
00382          {
00383             //Malformed DNS message?
00384             if((pos1 + 1) >= length1)
00385                return -2;
00386 
00387             //Read the most significant byte of the pointer
00388             pointer1 = (p1[pos1] & ~DNS_COMPRESSION_TAG) << 8;
00389             //Read the least significant byte of the pointer
00390             pointer1 |= p1[pos1 + 1];
00391          }
00392          else
00393          {
00394             //The first domain name is not compressed
00395             pointer1 = pos1;
00396          }
00397 
00398          //Second domain name compressed?
00399          if(n2 >= DNS_COMPRESSION_TAG)
00400          {
00401             //Malformed DNS message?
00402             if((pos2 + 1) >= length2)
00403                return -2;
00404 
00405             //Read the most significant byte of the pointer
00406             pointer2 = (p2[pos2] & ~DNS_COMPRESSION_TAG) << 8;
00407             //Read the least significant byte of the pointer
00408             pointer2 |= p2[pos2 + 1];
00409          }
00410          else
00411          {
00412             //The second domain name is not compressed
00413             pointer2 = pos2;
00414          }
00415 
00416          //Compare the remaining part
00417          res = dnsCompareEncodedName(message1, length1, pointer1,
00418             message2, length2, pointer2, level + 1);
00419 
00420          //Return comparison result
00421          return res;
00422       }
00423       else
00424       {
00425          //Advance data pointer
00426          pos1++;
00427          pos2++;
00428 
00429          //Malformed DNS message?
00430          if((pos1 + n1) > length1 || (pos2 + n2) > length2)
00431             return -2;
00432 
00433          //Compare as much data as possible
00434          n = MIN(n1, n2);
00435 
00436          //Compare labels
00437          res = strncasecmp((char_t *) p1 + pos1, (char_t *) p2 + pos2, n);
00438          //Any mismatch?
00439          if(res)
00440             return res;
00441 
00442          //The domain name which still has remaining data is deemed
00443          //lexicographically later
00444          if(n1 < n2)
00445             return -1;
00446          else if(n1 > n2)
00447             return 1;
00448 
00449          //Advance data pointer
00450          pos1 += n1;
00451          pos2 += n2;
00452       }
00453    }
00454 
00455    //Malformed DNS message
00456    return -2;
00457 }
00458 
00459 #endif
00460