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