Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 17:10:13 by
