1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /** @defgroup dnscore System core functions
36  *  @brief System core functions
37  *
38  * @{ */
39 
40 #include "dnscore/dnscore-config.h"
41 #include <stddef.h>
42 #include <unistd.h>
43 #include <dnscore/message-viewer.h>
44 
45 #include "dnscore/counter_output_stream.h"
46 #include "dnscore/format.h"
47 #include "dnscore/message.h"
48 #include "dnscore/packet_reader.h"
49 
50 static char* message_section_names[4] =
51 {
52     "QUESTION SECTION", "ANSWER SECTION", "AUTHORITY SECTION", "ADDITIONAL SECTION"
53 };
54 
55 static char* message_section_update_names[4] =
56 {
57     "ZONE", "PREREQUISITES", "UPDATE RECORDS", "ADDITIONAL RECORDS"
58 };
59 
60 static char* message_count_names[4] =
61 {
62     "QUERY", "ANSWER", "AUTHORITY", "ADDITIONAL"
63 };
64 
65 static char* message_count_update_names[4] =
66 {
67     "ZONE", "PREREQUISITES", "UPDATE", "ADDITIONAL"
68 };
69 
70 
71 ya_result
message_print_format_dig_buffer(output_stream * os_,const u8 * buffer,u32 length,u16 view_mode_with)72 message_print_format_dig_buffer(output_stream *os_, const u8 *buffer, u32 length, u16 view_mode_with)
73 {
74     ya_result                                                  return_value;
75 
76     /*
77      * There is no padding support for formats on complex types (padding is ignored)
78      * Doing it would be relatively expensive for it's best doing it manually when needed (afaik: only here)
79      */
80 
81     counter_output_stream_data                                     counters;
82     output_stream                                                       cos;
83     counter_output_stream_init(os_, &cos, &counters);
84 
85     output_stream                                                *os = &cos;
86 
87     packet_unpack_reader_data                                          purd;
88 
89     u8                          record_wire[MAX_DOMAIN_LENGTH + 10 + 65535];
90 
91     /*    ------------------------------------------------------------    */
92 
93     /* Init packet reader with buffer. length and offset in the buffer */
94 
95     packet_reader_init_at(&purd, buffer, length, DNS_HEADER_LENGTH);
96 
97     /* 1. GET ID */
98     u16 id           = MESSAGE_ID(buffer);
99 
100 
101     /* 2. GET OPCODE AND RCODE */
102     u8 opcode_shifted= MESSAGE_OP(buffer);
103     u8 opcode        = opcode_shifted >> OPCODE_SHIFT;
104 
105     u8 rcode         = MESSAGE_RCODE(buffer);
106 
107     const char *opcode_txt = dns_message_opcode_get_name(opcode);
108     const char *status_txt = dns_message_rcode_get_name(rcode);
109 
110 
111     /* 3. GET VALUES OF THE SECTIONS */
112     u16 count[4];
113     count[0] = ntohs(MESSAGE_QD(buffer));
114     count[1] = ntohs(MESSAGE_AN(buffer));
115     count[2] = ntohs(MESSAGE_NS(buffer));
116     count[3] = ntohs(MESSAGE_AR(buffer));
117 
118 
119     /* 4. GET THE NAMES FOR THE PRESENTATION */
120     char **count_name   = (opcode_shifted != OPCODE_UPDATE)? message_count_names   : message_count_update_names;
121     char **section_name = (opcode_shifted != OPCODE_UPDATE)? message_section_names : message_section_update_names;
122 
123 
124     /* 5. FILL THE STREAM */
125 
126     /* fill the information of the header of a DNS packet */
127     osformat(os, ";; ->>HEADER<<- opcode: %s, status: %s, id: %hd\n", opcode_txt, status_txt, ntohs(id));
128     osformat(os, ";; flags: ");
129 
130     if(MESSAGE_QR(buffer) != 0) osprint(os, "qr ");
131     if(MESSAGE_AA(buffer) != 0) osprint(os, "aa ");
132     if(MESSAGE_TC(buffer) != 0) osprint(os, "tc ");
133     if(MESSAGE_RD(buffer) != 0) osprint(os, "rd ");
134     if(MESSAGE_RA(buffer) != 0) osprint(os, "ra ");
135     if(MESSAGE_ZF(buffer) != 0) osprint(os, "zf ");
136     if(MESSAGE_AD(buffer) != 0) osprint(os, "ad ");
137     if(MESSAGE_CD(buffer) != 0) osprint(os, "cd ");
138 
139     osformat(os, "%s: %hd, %s: %hd, %s: %hd, %s: %hd\n",
140              count_name[0], count[0],
141              count_name[1], count[1],
142              count_name[2], count[2],
143              count_name[3], count[3]
144              );
145 
146     {
147         u32 section_idx = 0;
148 
149         /* Print SECTION name */
150 
151         if(message_viewer_requires_section(section_idx, view_mode_with))
152         {
153             osformat(os, "\n;; %s:\n", section_name[section_idx]);
154         }
155 
156         for(u16 n = count[section_idx]; n > 0; n--)
157         {
158             /* 1. GET EVERYTHING FROM THE BUFFER FOR QUESTION + OFFSET packet reader */
159 
160             /* Retrieve QNAME from packet reader */
161             if(FAIL(return_value = packet_reader_read_fqdn(&purd, record_wire, sizeof(record_wire))))
162             {
163                 return return_value;
164             }
165 
166             /* Retrieve QTYPE from packet reader */
167             u16 rtype;
168             if(FAIL(return_value = packet_reader_read_u16(&purd, &rtype)))
169             {
170                 return return_value;
171             }
172 
173             /* Retrieve QCLASS from packet reader */
174             u16 rclass;
175             if(FAIL(return_value = packet_reader_read_u16(&purd, &rclass)))
176             {
177                 return return_value;
178             }
179 
180             /* Print everything from QUESTION SECTION */
181 
182 
183             if(message_viewer_requires_section(section_idx, view_mode_with))
184             {
185                 u64 next = counters.write_count + 24 + 8;
186 
187                 /* write NAME + alignment for next item */
188                 osformat(os, ";%{dnsname}", record_wire);
189                 while(counters.write_count < next)
190                 {
191                     output_stream_write_u8(os, (u8)' ');
192                 }
193                 output_stream_write_u8(os, (u8)' ');
194 
195                 next = counters.write_count + 7;
196 
197                 /* write CLASS + alignment for next item */
198                 osformat(os, "%7{dnsclass}", &rclass);
199                 while(counters.write_count < next)
200                 {
201                     output_stream_write_u8(os, (u8)' ');
202                 }
203                 output_stream_write_u8(os, (u8)' ');
204 
205 //                next = counters.write_count + 7;
206 
207                 /* write TYPE */
208                 osformatln(os, "%7{dnstype}", &rtype);
209             }
210         }
211         osprintln(os, "");
212     }
213 
214 
215     for(u32 section_idx = 1; section_idx < 4; section_idx++)
216     {
217         if(message_viewer_requires_section(section_idx, view_mode_with))
218         {
219             osformat(os, ";; %s:\n", section_name[section_idx]);
220         }
221 
222         for(u16 n = count[section_idx]; n > 0; n--)
223         {
224             /* Get next record and put the packet reader offset on the next record */
225             if(FAIL(return_value = packet_reader_read_record(&purd, record_wire, sizeof(record_wire))))
226             {
227                 return return_value;
228             }
229 
230             /* Initialize the values needed for printing */
231             u8 *rname      = record_wire;
232             u8 *rdata      = rname + dnsname_len(rname);
233             u16 rtype      = GET_U16_AT(rdata[0]);
234             u16 rclass     = GET_U16_AT(rdata[2]);
235             u32 rttl       = ntohl(GET_U32_AT(rdata[4]));
236             u16 rdata_size = ntohs(GET_U16_AT(rdata[8]));
237 
238             if(section_idx == 3)
239             {
240                 if(rtype == TYPE_OPT)
241                 {
242                     continue;
243                 }
244                 else if(rtype == TYPE_TSIG)
245                 {
246                     continue;
247                 }
248             }
249 
250             /** @todo 20130530 gve -- test that rdata_size matches the record size */
251 
252             rdata         += 10;
253 
254             u64 next       = counters.write_count + 24;
255 
256             /* Starting printing */
257             if(message_viewer_requires_section(section_idx, view_mode_with))
258             {
259                 /* write NAME + alignment for next item */
260                 osformat(os, "%{dnsname}", rname);
261                 while(counters.write_count < next)
262                 {
263                     output_stream_write_u8(os, (u8)' ');
264                 }
265                 output_stream_write_u8(os, (u8)' ');
266 
267                 /* write TTL + alignment for next item */
268                 osformat(os, "%7d", rttl);
269                 output_stream_write_u8(os, (u8)' ');
270 
271                 next = counters.write_count + 7;
272 
273                 /* write CLASS + alignment for next item */
274                 osformat(os, "%7{dnsclass}", &rclass);
275                 while(counters.write_count < next)
276                 {
277                     output_stream_write_u8(os, (u8)' ');
278                 }
279                 output_stream_write_u8(os, (u8)' ');
280 
281                 next = counters.write_count + 7;
282 
283                 /* write TYPE + alignment for next item */
284                 osformat(os, "%7{dnstype} ", &rtype);
285                 while(counters.write_count < next)
286                 {
287                     output_stream_write_u8(os, (u8)' ');
288                 }
289                 output_stream_write_u8(os, (u8)' ');
290 
291                 /* write RDATA */
292                 osprint_rdata(os, rtype, rdata, rdata_size);
293 
294                 osprintln(os, "");
295             }
296         }
297         if(message_viewer_requires_section(section_idx, view_mode_with))
298         {
299             osprintln(os, "");
300         }
301     }
302 
303     return 0;
304 }
305 
306 
307 ya_result
message_print_format_dig(output_stream * os,const u8 * buffer,u32 length,u16 view_mode_with,long time_duration)308 message_print_format_dig(output_stream *os, const u8 *buffer, u32 length, u16 view_mode_with, long time_duration)
309 {
310     ya_result                                                  return_value;
311 
312     time_t                                                            timep;
313 
314     /*    ------------------------------------------------------------    */
315 
316     osformat(os, ";; global options: \n");
317     osformat(os, ";; Got answer:\n");
318 
319     if(FAIL(return_value = message_print_format_dig_buffer(os, buffer, length, view_mode_with)))
320     {
321         return return_value;
322     }
323 
324     time(&timep);
325 
326     if(time_duration >= 0)
327     {
328         osformat(os, ";; Query time: %ld msec\n", time_duration);
329     }
330 
331     /** @todo 20130530 gve -- still need to implemented the server viewable line */
332 //    osformat(os, ";; SERVER: %{hostaddr}(%{hostaddr})\n", config->server, config->server);
333 
334     osformat(os, ";; WHEN: %s", ctime(&timep));
335     if(time_duration >= 0)
336     {
337         osformat(os, ";; MSG SIZE rcvd: %ld\n", length);
338     }
339     else
340     {
341         osformat(os, ";; MSG SIZE: %ld\n", length);
342     }
343     osformat(os, "\n");
344 
345     return OK;
346 }
347