dns_debug.c
Go to the documentation of this file.
1 /**
2  * @file dns_debug.c
3  * @brief Data logging functions for debugging purpose (DNS)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.6
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL DNS_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "dns/dns_debug.h"
37 #include "netbios/nbns_client.h"
38 #include "netbios/nbns_responder.h"
39 #include "netbios/nbns_common.h"
40 #include "debug.h"
41 
42 //Check TCP/IP stack configuration
43 #if (DNS_TRACE_LEVEL >= TRACE_LEVEL_DEBUG)
44 
45 
46 /**
47  * @brief Dump DNS message for debugging purpose
48  * @param[in] message Pointer to the DNS message
49  * @param[in] length Length of the DNS message
50  **/
51 
52 void dnsDumpMessage(const DnsHeader *message, size_t length)
53 {
54  uint_t i;
55  size_t pos;
56 
57  //Malformed DNS message?
58  if(length < sizeof(DnsHeader))
59  return;
60 
61  //Dump DNS message header
62  TRACE_DEBUG(" Identifier (ID) = %" PRIu16 "\r\n", ntohs(message->id));
63  TRACE_DEBUG(" Query Response (QR) = %" PRIu8 "\r\n", message->qr);
64  TRACE_DEBUG(" Opcode (OPCODE) = %" PRIu8 "\r\n", message->opcode);
65  TRACE_DEBUG(" Authoritative Answer (AA) = %" PRIu8 "\r\n", message->aa);
66  TRACE_DEBUG(" TrunCation (TC) = %" PRIu8 "\r\n", message->tc);
67  TRACE_DEBUG(" Recursion Desired (RD) = %" PRIu8 "\r\n", message->rd);
68  TRACE_DEBUG(" Recursion Available (RA) = %" PRIu8 "\r\n", message->ra);
69  TRACE_DEBUG(" Reserved (Z) = %" PRIu8 "\r\n", message->z);
70  TRACE_DEBUG(" Response Code (RCODE) = %" PRIu8 "\r\n", message->rcode);
71  TRACE_DEBUG(" Question Count (QDCOUNT) = %" PRIu8 "\r\n", ntohs(message->qdcount));
72  TRACE_DEBUG(" Answer Count (ANCOUNT) = %" PRIu8 "\r\n", ntohs(message->ancount));
73  TRACE_DEBUG(" Name Server Count (NSCOUNT) = %" PRIu8 "\r\n", ntohs(message->nscount));
74  TRACE_DEBUG(" Additional Record Count (ARCOUNT) = %" PRIu8 "\r\n", ntohs(message->arcount));
75 
76  //Point to the first question
77  pos = sizeof(DnsHeader);
78 
79  //Debug message
80  TRACE_DEBUG(" Questions\r\n");
81 
82  //Parse questions
83  for(i = 0; i < ntohs(message->qdcount); i++)
84  {
85  //Dump current question
86  pos = dnsDumpQuestion(message, length, pos);
87  //Any error to report?
88  if(pos == 0)
89  return;
90  }
91 
92  //Debug message
93  TRACE_DEBUG(" Answer RRs\r\n");
94 
95  //Parse answer resource records
96  for(i = 0; i < ntohs(message->ancount); i++)
97  {
98  //Dump current resource record
100  //Any error to report?
101  if(pos == 0)
102  return;
103  }
104 
105  //Debug message
106  TRACE_DEBUG(" Authority RRs\r\n");
107 
108  //Parse authority resource records
109  for(i = 0; i < ntohs(message->nscount); i++)
110  {
111  //Dump current resource record
112  pos = dnsDumpResourceRecord(message, length, pos);
113  //Any error to report?
114  if(pos == 0)
115  return;
116  }
117 
118  //Debug message
119  TRACE_DEBUG(" Additional RRs\r\n");
120 
121  //Parse additional resource records
122  for(i = 0; i < ntohs(message->arcount); i++)
123  {
124  //Dump current resource record
125  pos = dnsDumpResourceRecord(message, length, pos);
126  //Any error to report?
127  if(pos == 0)
128  return;
129  }
130 }
131 
132 
133 /**
134  * @brief Dump DNS question for debugging purpose
135  * @param[in] message Pointer to the DNS message
136  * @param[in] length Length of the DNS message
137  * @param[in] pos Offset of the question to decode
138  * @return Offset to the next question
139  **/
140 
141 size_t dnsDumpQuestion(const DnsHeader *message, size_t length, size_t pos)
142 {
143  size_t n;
144  DnsQuestion *question;
145 
146  //Parse domain name
147  n = dnsParseName(message, length, pos, 0);
148  //Invalid name?
149  if(n == 0)
150  return 0;
151 
152  //Make sure the DNS question is valid
153  if((n + sizeof(DnsQuestion)) > length)
154  return 0;
155 
156  //Point to the corresponding entry
157  question = DNS_GET_QUESTION(message, n);
158 
159  //NB question found?
160  if(ntohs(question->qtype) == DNS_RR_TYPE_NB)
161  {
162 #if (NBNS_CLIENT_SUPPORT == ENABLED || NBNS_RESPONDER_SUPPORT == ENABLED)
163 #if (IPV4_SUPPORT == ENABLED)
164  char_t buffer[16];
165 
166  //Decode NetBIOS name
167  pos = nbnsParseName((NbnsHeader *) message, length, pos, buffer);
168  //Invalid NetBIOS name?
169  if(pos == 0)
170  return 0;
171 
172  //Dump Name field
173  TRACE_DEBUG(" Name (QNAME) = %s\r\n", buffer);
174 #endif
175 #endif
176  }
177  else
178  {
179  //Debug message
180  TRACE_DEBUG(" Name (QNAME) = ");
181 
182  //Dump domain name
183  pos = dnsDumpName(message, length, pos, 0);
184  //Invalid name?
185  if(pos == 0)
186  return 0;
187 
188  //Terminate with a line feed
189  TRACE_DEBUG("\r\n");
190  }
191 
192  //Dump DNS question
193  TRACE_DEBUG(" Query Type (QTYPE) = %" PRIu16 "\r\n", ntohs(question->qtype));
194  TRACE_DEBUG(" Query Class (QCLASS) = %" PRIu16 "\r\n", ntohs(question->qclass));
195 
196  //Point to the next question
197  n += sizeof(DnsQuestion);
198  //Return the current position
199  return n;
200 }
201 
202 
203 /**
204  * @brief Dump DNS resource record for debugging purpose
205  * @param[in] message Pointer to the DNS message
206  * @param[in] length Length of the DNS message
207  * @param[in] pos Offset of the question to decode
208  * @return Offset to the next question
209  **/
210 
212  size_t pos)
213 {
214  size_t n;
215  DnsResourceRecord *record;
216  DnsSrvResourceRecord *srvRecord;
217 
218  //Parse domain name
219  n = dnsParseName(message, length, pos, 0);
220  //Invalid name?
221  if(n == 0)
222  return 0;
223 
224  //Point to the corresponding entry
225  record = DNS_GET_RESOURCE_RECORD(message, n);
226 
227  //Make sure the resource record is valid
228  if((n + sizeof(DnsResourceRecord)) > length)
229  return 0;
230  if((n + sizeof(DnsResourceRecord) + ntohs(record->rdlength)) > length)
231  return 0;
232 
233  //NB resource record found?
234  if(ntohs(record->rtype) == DNS_RR_TYPE_NB)
235  {
236 #if (NBNS_CLIENT_SUPPORT == ENABLED || NBNS_RESPONDER_SUPPORT == ENABLED)
237 #if (IPV4_SUPPORT == ENABLED)
238  char_t buffer[16];
239 
240  //Decode NetBIOS name
241  pos = nbnsParseName((NbnsHeader *) message, length, pos, buffer);
242  //Invalid NetBIOS name?
243  if(pos == 0)
244  return 0;
245 
246  //Dump Name field
247  TRACE_DEBUG(" Name (NAME) = %s\r\n", buffer);
248 #endif
249 #endif
250  }
251  else
252  {
253  //Debug message
254  TRACE_DEBUG(" Name (NAME) = ");
255 
256  //Dump domain name
257  pos = dnsDumpName(message, length, pos, 0);
258  //Invalid name?
259  if(pos == 0)
260  return 0;
261 
262  //Terminate with a line feed
263  TRACE_DEBUG("\r\n");
264  }
265 
266  //Dump DNS resource record
267  TRACE_DEBUG(" Query Type (TYPE) = %" PRIu16 "\r\n", ntohs(record->rtype));
268  TRACE_DEBUG(" Query Class (CLASS) = %" PRIu16 "\r\n", ntohs(record->rclass));
269  TRACE_DEBUG(" Time-To-Live (TTL) = %" PRIu32 "\r\n", ntohl(record->ttl));
270  TRACE_DEBUG(" Data Length (RDLENGTH) = %" PRIu16 "\r\n", ntohs(record->rdlength));
271 
272  //Dump resource data
273 #if (IPV4_SUPPORT == ENABLED)
274  if(ntohs(record->rtype) == DNS_RR_TYPE_A &&
275  ntohs(record->rdlength) == sizeof(Ipv4Addr))
276  {
278 
279  //Copy IPv4 address
280  ipv4CopyAddr(&ipAddr, record->rdata);
281  //Dump IPv4 address
282  TRACE_DEBUG(" Data (RDATA) = %s\r\n", ipv4AddrToString(ipAddr, NULL));
283  }
284  else
285 #endif
286 #if (IPV6_SUPPORT == ENABLED)
287  if(ntohs(record->rtype) == DNS_RR_TYPE_AAAA &&
288  ntohs(record->rdlength) == sizeof(Ipv6Addr))
289  {
291 
292  //Copy IPv6 address
293  ipv6CopyAddr(&ipAddr, record->rdata);
294  //Dump IPv6 address
295  TRACE_DEBUG(" Data (RDATA) = %s\r\n", ipv6AddrToString(&ipAddr, NULL));
296  }
297  else
298 #endif
299  if(ntohs(record->rtype) == DNS_RR_TYPE_PTR)
300  {
301  //Dump SRV resource record
302  TRACE_DEBUG(" Domain Name (PTRDNAME) = ");
303 
304  //Dump domain name
305  pos = dnsDumpName(message, length, n + sizeof(DnsResourceRecord), 0);
306  //Invalid domain name?
307  if(pos == 0)
308  return 0;
309 
310  //Terminate with a line feed
311  TRACE_DEBUG("\r\n");
312  }
313  else if(ntohs(record->rtype) == DNS_RR_TYPE_SRV)
314  {
315  //Cast resource record
316  srvRecord = (DnsSrvResourceRecord *) record;
317 
318  //Dump SRV resource record
319  TRACE_DEBUG(" Priority = %" PRIu16 "\r\n", ntohs(srvRecord->priority));
320  TRACE_DEBUG(" Weight = %" PRIu16 "\r\n", ntohs(srvRecord->weight));
321  TRACE_DEBUG(" Port = %" PRIu16 "\r\n", ntohs(srvRecord->port));
322  TRACE_DEBUG(" Target = ");
323 
324  //Dump target name
325  pos = dnsDumpName(message, length, n + sizeof(DnsSrvResourceRecord), 0);
326  //Invalid domain name?
327  if(pos == 0)
328  return 0;
329 
330  //Terminate with a line feed
331  TRACE_DEBUG("\r\n");
332  }
333  else
334  {
335  //Dump resource data
336  TRACE_DEBUG(" Data (RDATA)\r\n");
337  TRACE_DEBUG_ARRAY(" ", record->rdata, ntohs(record->rdlength));
338  }
339 
340  //Point to the next resource record
341  n += sizeof(DnsResourceRecord) + ntohs(record->rdlength);
342 
343  //Return the current position
344  return n;
345 }
346 
347 
348 /**
349  * @brief Dump a domain name that uses the DNS name encoding
350  * @param[in] message Pointer to the DNS message
351  * @param[in] length Length of the DNS message
352  * @param[in] pos Offset of the name to decode
353  * @param[in] level Current level of recursion
354  * @return The position of the resource record that immediately follows the domain name
355  **/
356 
357 size_t dnsDumpName(const DnsHeader *message, size_t length, size_t pos,
358  uint_t level)
359 {
360  size_t n;
361  size_t pointer;
362  uint8_t *src;
363 
364  //Recursion limit exceeded?
365  if(level >= DNS_NAME_MAX_RECURSION)
366  return 0;
367 
368  //Cast the input DNS message to byte array
369  src = (uint8_t *) message;
370 
371  //Parse encoded domain name
372  while(pos >= sizeof(DnsHeader) && pos < length)
373  {
374  //Check label length
375  if(src[pos] == DNS_END_TAG)
376  {
377  //Return the position of the resource record that is immediately
378  //following the domain name
379  return (pos + 1);
380  }
381  else if(src[pos] >= DNS_COMPRESSION_TAG)
382  {
383  //Malformed DNS message?
384  if((pos + 1) >= length)
385  return 0;
386 
387  //Read the most significant byte of the pointer
388  pointer = (src[pos] & ~DNS_COMPRESSION_TAG) << 8;
389  //Read the least significant byte of the pointer
390  pointer |= src[pos + 1];
391 
392  //Dump the remaining part of the domain name
393  if(!dnsDumpName(message, length, pointer, level + 1))
394  {
395  //Domain name decoding failed
396  return 0;
397  }
398 
399  //Return the position of the resource record that is immediately
400  //following the domain name
401  return (pos + 2);
402  }
403  else if(src[pos] <= DNS_LABEL_MAX_SIZE)
404  {
405  //Get the length of the current label
406  n = src[pos++];
407 
408  //Malformed DNS message?
409  if((pos + n) > length)
410  return 0;
411 
412  //Dump label
413  for(; n > 0; n--, pos++)
414  {
415  TRACE_DEBUG("%c", src[pos]);
416  }
417 
418  //Append a separator if necessary
419  if(pos < length && src[pos] != DNS_END_TAG)
420  {
421  TRACE_DEBUG(".");
422  }
423  }
424  else
425  {
426  //Domain name decoding failed
427  return 0;
428  }
429  }
430 
431  //Domain name decoding failed
432  return 0;
433 }
434 
435 #endif
char_t * ipv6AddrToString(const Ipv6Addr *ipAddr, char_t *str)
Convert a binary IPv6 address to a string representation.
Definition: ipv6.c:2325
size_t dnsParseName(const DnsHeader *message, size_t length, size_t pos, uint_t level)
Decode a domain name that uses the DNS name encoding.
Definition: dns_common.c:131
uint8_t pointer
Definition: icmp.h:234
DnsSrvResourceRecord
Definition: dns_common.h:274
size_t nbnsParseName(const NbnsHeader *message, size_t length, size_t pos, char_t *dest)
Decode a NetBIOS name.
Definition: nbns_common.c:223
#define DNS_END_TAG
Definition: dns_common.h:60
uint8_t message[]
Definition: chap.h:154
Ipv6Addr
Definition: ipv6.h:282
DnsHeader
Definition: dns_common.h:204
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:324
size_t dnsDumpResourceRecord(const DnsHeader *message, size_t length, size_t pos)
Dump DNS resource record for debugging purpose.
Definition: dns_debug.c:211
#define DNS_NAME_MAX_RECURSION
Definition: dns_common.h:39
size_t dnsDumpName(const DnsHeader *message, size_t length, size_t pos, uint_t level)
Dump a domain name that uses the DNS name encoding.
Definition: dns_debug.c:357
NbnsHeader
Definition: nbns_common.h:131
@ DNS_RR_TYPE_NB
NetBIOS name.
Definition: dns_common.h:150
#define DNS_GET_QUESTION(message, offset)
Definition: dns_common.h:65
#define DNS_GET_RESOURCE_RECORD(message, offset)
Definition: dns_common.h:66
Definitions common to NBNS client and NBNS responder.
NBNS client (NetBIOS Name Service)
#define DNS_LABEL_MAX_SIZE
Definition: dns_common.h:49
#define DNS_COMPRESSION_TAG
Definition: dns_common.h:62
@ DNS_RR_TYPE_A
Host address.
Definition: dns_common.h:139
@ DNS_RR_TYPE_PTR
Domain name pointer.
Definition: dns_common.h:144
uint8_t length
Definition: tcp.h:375
void dnsDumpMessage(const DnsHeader *message, size_t length)
Dump DNS message for debugging purpose.
Definition: dns_debug.c:52
#define ntohs(value)
Definition: cpu_endian.h:421
#define TRACE_DEBUG(...)
Definition: debug.h:119
char char_t
Definition: compiler_port.h:55
#define ipv6CopyAddr(destIpAddr, srcIpAddr)
Definition: ipv6.h:132
#define TRACE_DEBUG_ARRAY(p, a, n)
Definition: debug.h:120
uint8_t n
size_t dnsDumpQuestion(const DnsHeader *message, size_t length, size_t pos)
Dump DNS question for debugging purpose.
Definition: dns_debug.c:141
DnsQuestion
Definition: dns_common.h:215
#define ipv4CopyAddr(destIpAddr, srcIpAddr)
Definition: ipv4.h:167
Ipv4Addr ipAddr
Definition: ipcp.h:105
@ DNS_RR_TYPE_SRV
Server selection.
Definition: dns_common.h:152
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
DnsResourceRecord
Definition: dns_common.h:229
char_t * ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
Convert a binary IPv4 address to dot-decimal notation.
Definition: ipv4.c:1516
@ DNS_RR_TYPE_AAAA
IPv6 address.
Definition: dns_common.h:149
Data logging functions for debugging purpose (DNS)
#define ntohl(value)
Definition: cpu_endian.h:422
Debugging facilities.
NBNS responder (NetBIOS Name Service)