1 #define DNS_C
2 /*
3 * Copyright (C) 2004, 2005 James Antill
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * email: james@and.org
20 */
21 /* dns resolving, meant for async calls ... TCP only atm. */
22
23 #define VSTR_COMPILE_INCLUDE 1
24 #include <vstr.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <getopt.h>
34 #include <string.h>
35 #include <netinet/in.h>
36 #include <netinet/tcp.h>
37 #include <arpa/inet.h>
38 #include <sys/poll.h>
39 #include <netdb.h>
40 #include <sys/time.h>
41 #include <time.h>
42 #include <signal.h>
43
44 /* #define NDEBUG 1 -- not done via. configure atm. */
45 #include <assert.h>
46
47 #include <err.h>
48
49
50 #include <socket_poll.h>
51 #include <timer_q.h>
52
53 #include "dns.h"
54
55 #include "vlg.h"
56
57 #define TRUE 1
58 #define FALSE 0
59
60 #include "app.h"
61
62 #define MAP_MAKE_ENTRY(x) [ DNS_CLASS_ ## x ] = #x
63 static const char *dns_map_class2name[DNS_CLASS_ALL + 1] = {
64 MAP_MAKE_ENTRY(IN),
65 MAP_MAKE_ENTRY(CH),
66 MAP_MAKE_ENTRY(HS),
67 [DNS_CLASS_ALL] = "*"
68 };
69 #undef MAP_MAKE_ENTRY
70
71 #define MAP_MAKE_ENTRY(x) [ DNS_TYPE_IN_ ## x ] = #x
72 static const char *dns_map_type_in2name[DNS_TYPE_ALL + 1] = {
73 MAP_MAKE_ENTRY(A),
74 MAP_MAKE_ENTRY(NS),
75 MAP_MAKE_ENTRY(CNAME),
76 MAP_MAKE_ENTRY(SOA),
77 MAP_MAKE_ENTRY(PTR),
78 MAP_MAKE_ENTRY(MX),
79 MAP_MAKE_ENTRY(TXT),
80 MAP_MAKE_ENTRY(AAAA),
81 MAP_MAKE_ENTRY(SRV),
82 MAP_MAKE_ENTRY(AXFR),
83 MAP_MAKE_ENTRY(IXFR),
84 [DNS_TYPE_ALL] = "*"
85 };
86 #undef MAP_MAKE_ENTRY
87
88 #define MAP_MAKE_ENTRY(x) [ DNS_TYPE_CH_ ## x ] = #x
89 static const char *dns_map_type_ch2name[DNS_TYPE_ALL + 1] = {
90 MAP_MAKE_ENTRY(A),
91 MAP_MAKE_ENTRY(TXT),
92 [DNS_TYPE_ALL] = "*"
93 };
94 #undef MAP_MAKE_ENTRY
95
96 #define MAP_MAKE_ENTRY(x) [ DNS_HDR_R_ ## x ] = #x
97 static const char *dns_map_hdr_r2name[DNS_HDR_RSZ] = {
98 MAP_MAKE_ENTRY(NONE),
99 MAP_MAKE_ENTRY(BFMT),
100 MAP_MAKE_ENTRY(SERV),
101 MAP_MAKE_ENTRY(NAME),
102 MAP_MAKE_ENTRY(NSUP),
103 MAP_MAKE_ENTRY(REFU),
104 };
105 #undef MAP_MAKE_ENTRY
106
dns_get_msg_len(Vstr_base * s1,size_t pos)107 unsigned int dns_get_msg_len(Vstr_base *s1, size_t pos)
108 {
109 if (s1->len < pos + 1)
110 return (0);
111
112 return (2 + get_b_uint16(s1, pos));
113 }
114
dns_name_type_ch(unsigned int num)115 const char *dns_name_type_ch(unsigned int num)
116 {
117 if (num > DNS_TYPE_ALL)
118 return ("");
119
120 if (!dns_map_type_ch2name[num])
121 return ("");
122
123 return (dns_map_type_ch2name[num]);
124 }
125
dns_name_type_in(unsigned int num)126 const char *dns_name_type_in(unsigned int num)
127 {
128 if (num > DNS_TYPE_ALL)
129 return ("");
130
131 if (!dns_map_type_in2name[num])
132 return ("");
133
134 return (dns_map_type_in2name[num]);
135 }
136
dns_name_class(unsigned int num)137 const char *dns_name_class(unsigned int num)
138 {
139 if (num > DNS_CLASS_ALL)
140 return ("");
141
142 if (!dns_map_class2name[num])
143 return ("");
144
145 return (dns_map_class2name[num]);
146 }
147
dns_name_hdr_r(unsigned int num)148 const char *dns_name_hdr_r(unsigned int num)
149 {
150 if (num > DNS_HDR_RSZ)
151 return ("");
152
153 if (!dns_map_hdr_r2name[num])
154 return ("");
155
156 return (dns_map_hdr_r2name[num]);
157 }
158
dns_app_class_type(Vstr_base * out,Vstr_base * pkt,size_t pos,size_t msg_len,unsigned int * dns_class,unsigned int * dns_type)159 static size_t dns_app_class_type(Vstr_base *out, Vstr_base *pkt,
160 size_t pos, size_t msg_len,
161 unsigned int *dns_class,
162 unsigned int *dns_type)
163 {
164 unsigned int cnum = 0;
165 unsigned int tnum = 0;
166
167 if (4 > vstr_sc_posdiff(pos, msg_len))
168 return (msg_len);
169
170 tnum = get_b_uint16(pkt, pos); pos += 2;
171 cnum = get_b_uint16(pkt, pos); pos += 2;
172
173 if (dns_class) *dns_class = cnum;
174 if (dns_type) *dns_type = tnum;
175
176 if (out)
177 {
178 if (dns_name_class(cnum))
179 app_cstr_buf(out, dns_name_class(cnum));
180 else
181 app_fmt(out, "%u", cnum);
182 app_cstr_buf(out, ".");
183 }
184
185 if (out) switch (cnum)
186 {
187 case DNS_CLASS_IN:
188 app_cstr_buf(out, dns_name_type_in(tnum));
189 break;
190 case DNS_CLASS_CH:
191 app_cstr_buf(out, dns_name_type_ch(tnum));
192 break;
193 case DNS_CLASS_ALL:
194 if (tnum == DNS_TYPE_ALL)
195 {
196 app_cstr_buf(out, "*");
197 break;
198 }
199 /* FALL THROUGH */
200 default:
201 app_fmt(out, "%u", tnum);
202 break;
203 }
204
205 return (pos);
206 }
207
dns_app_txt(Vstr_base * out,Vstr_base * pkt,size_t pos,size_t msg_len)208 static size_t dns_app_txt(Vstr_base *out,
209 Vstr_base *pkt, size_t pos, size_t msg_len)
210 {
211 unsigned char tmp = 0;
212
213 while ((pos < msg_len) && (tmp = vstr_export_chr(pkt, pos)))
214 {
215 ++pos;
216 if (tmp > vstr_sc_posdiff(pos, msg_len))
217 tmp = vstr_sc_posdiff(pos, msg_len);
218 if (out) app_fmt(out, "${vstr:%p%zu%zu%u}",
219 pkt, pos, tmp, VSTR_TYPE_ADD_ALL_BUF);
220 pos += tmp;
221 }
222 if (pos <= msg_len)
223 ++pos;
224
225 return (pos);
226 }
227
228 #define OUT_EQ_VLOG() (out == base->io_dbg->out_vstr)
229
dns_app_label(Dns_base * base,Vstr_base * out,Vstr_base * pkt,size_t pos,size_t msg_len)230 static size_t dns_app_label(Dns_base *base, Vstr_base *out,
231 Vstr_base *pkt, size_t pos, size_t msg_len)
232 {
233 unsigned char tmp = 0;
234
235 while ((pos < msg_len) && (tmp = vstr_export_chr(pkt, pos)))
236 {
237 if (DNS_LABEL_IS_PTR(tmp))
238 { /* ptr */
239 if (OUT_EQ_VLOG()) app_cstr_buf(out, " <BAD END>");
240 return (msg_len);
241 }
242
243 /* label */
244 ++pos;
245 if (tmp > vstr_sc_posdiff(pos, msg_len))
246 tmp = vstr_sc_posdiff(pos, msg_len);
247 if (out) app_fmt(out, "${vstr:%p%zu%zu%u}.",
248 pkt, pos, tmp, VSTR_TYPE_ADD_ALL_BUF);
249 pos += tmp;
250 }
251 if (pos <= msg_len)
252 ++pos;
253
254 return (pos);
255 }
256
dns_app_name(Dns_base * base,Vstr_base * out,Vstr_base * pkt,size_t pos,size_t msg_len)257 static size_t dns_app_name(Dns_base *base, Vstr_base *out,
258 Vstr_base *pkt, size_t pos, size_t msg_len)
259 {
260 size_t orig_pos = pos;
261 unsigned char tmp = 0;
262
263 while ((pos < msg_len) && (tmp = vstr_export_chr(pkt, pos)))
264 {
265 if (DNS_LABEL_IS_PTR(tmp))
266 {
267 unsigned int off = get_b_uint16(pkt, pos);
268
269 off &= ~0xC000; /* remove top bits that specifiy it's a ptr */
270 ++off; /* offset is 0 indexed, position is 1 indexed */
271
272 if ((off != orig_pos) && (off < pos))
273 dns_app_name(base, out, pkt, off, msg_len);
274 else if (OUT_EQ_VLOG()) app_cstr_buf(out, " <BAD END>");
275
276 return (pos + 2);
277 }
278
279 ++pos;
280 if (tmp > vstr_sc_posdiff(pos, msg_len))
281 tmp = vstr_sc_posdiff(pos, msg_len);
282 if (out) app_fmt(out, "${vstr:%p%zu%zu%u}.",
283 pkt, pos, tmp, VSTR_TYPE_ADD_ALL_BUF);
284 pos += tmp;
285 }
286 if (pos <= msg_len)
287 ++pos;
288
289 return (pos);
290 }
291
dns_app_ttl(Vstr_base * out,Vstr_base * pkt,size_t pos,size_t msg_len)292 static size_t dns_app_ttl(Vstr_base *out,
293 Vstr_base *pkt, size_t pos, size_t msg_len)
294 {
295 unsigned int num = 0;
296
297 if (4 > vstr_sc_posdiff(pos, msg_len))
298 return (msg_len);
299
300 num = get_b_uint32(pkt, pos);
301 if (out) app_fmt(out, " for %ud %02u:%02u:%02u",
302 (num / (1 * 60 * 60 * 24)),
303 (num / (1 * 60 * 60)) % 24,
304 (num / (1 * 60)) % 60,
305 (num / (1)) % 60);
306
307 return (pos + 4);
308 }
309
dns_app_rr_unknown_data(Dns_base * base,Vstr_base * pkt,size_t pos,size_t msg_len,unsigned int len)310 static size_t dns_app_rr_unknown_data(Dns_base *base,
311 Vstr_base *pkt, size_t pos,
312 size_t msg_len, unsigned int len)
313 {
314 (void)pkt;
315
316 vlg_dbg2(base->io_dbg, " RD: %u %zu\n", len, vstr_sc_posdiff(pos, msg_len));
317
318 if (len <= vstr_sc_posdiff(pos, msg_len))
319 return (pos + len);
320
321 return (msg_len);
322 }
323
dns_app_rr_data(Dns_base * base,Vstr_base * out,Vstr_base * pkt,size_t pos,size_t msg_len,unsigned int dns_class,unsigned int dns_type)324 static size_t dns_app_rr_data(Dns_base *base, Vstr_base *out,
325 Vstr_base *pkt, size_t pos, size_t msg_len,
326 unsigned int dns_class,
327 unsigned int dns_type)
328 {
329 unsigned int len = 0;
330
331 if (2 > vstr_sc_posdiff(pos, msg_len))
332 return (msg_len);
333
334 len = get_b_uint16(pkt, pos); pos += 2;
335
336 if (!len)
337 return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len));
338
339 if (len > (vstr_sc_posdiff(pos, msg_len)))
340 return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len));
341
342 if ((dns_class != DNS_CLASS_IN) && (dns_class != DNS_CLASS_CH))
343 return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len));
344
345 msg_len = vstr_sc_poslast(pos, len);
346 if (dns_class == DNS_CLASS_CH)
347 {
348 if (0) { }
349 else if (dns_type == DNS_TYPE_CH_A)
350 {
351 unsigned int num = 0;
352
353 if (OUT_EQ_VLOG()) app_cstr_buf(out, " NAME: ");
354 pos = dns_app_name(base, out, pkt, pos, msg_len);
355
356 if (2 > vstr_sc_posdiff(pos, msg_len))
357 return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len));
358
359 num = get_b_uint16(pkt, pos); pos += 2;
360 if (OUT_EQ_VLOG()) app_cstr_buf(out, " A: ");
361 if (out) app_fmt(out, " %u", num);
362 }
363 else if (dns_type == DNS_TYPE_CH_TXT)
364 {
365 if (OUT_EQ_VLOG()) app_cstr_buf(out, " TXT: ");
366 pos = dns_app_txt(out, pkt, pos, msg_len);
367 }
368 else
369 return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len));
370 }
371
372 if (dns_class == DNS_CLASS_IN)
373 {
374 if (0) { }
375 else if (dns_type == DNS_TYPE_IN_A)
376 {
377 unsigned char buf[4];
378
379 if (len != 4)
380 return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len));
381
382 vstr_export_buf(pkt, pos, 4, buf, sizeof(buf)); pos += 4;
383 if (OUT_EQ_VLOG()) app_cstr_buf(out, " A: ");
384 if (out) app_fmt(out, "%u.%u.%u.%u", buf[0], buf[1], buf[2], buf[3]);
385 }
386 else if (dns_type == DNS_TYPE_IN_NS)
387 {
388 if (OUT_EQ_VLOG()) app_cstr_buf(out, " NS: ");
389 pos = dns_app_name(base, out, pkt, pos, msg_len);
390 }
391 else if (dns_type == DNS_TYPE_IN_CNAME)
392 {
393 if (OUT_EQ_VLOG()) app_cstr_buf(out, " CNAME: ");
394 pos = dns_app_name(base, out, pkt, pos, msg_len);
395 }
396 else if (dns_type == DNS_TYPE_IN_SOA)
397 {
398 unsigned int num_serial = 0;
399 unsigned int num_refresh = 0;
400 unsigned int num_retry = 0;
401 unsigned int num_expire = 0;
402 unsigned int num_min = 0;
403
404 if (OUT_EQ_VLOG()) app_cstr_buf(out, " SOA:\n");
405 if (OUT_EQ_VLOG()) app_cstr_buf(out, " NS: ");
406 pos = dns_app_name(base, out, pkt, pos, msg_len);
407 if (OUT_EQ_VLOG())
408 app_cstr_buf(out, "\n");
409 else if (out)
410 app_cstr_buf(out, " ");
411 if (OUT_EQ_VLOG()) app_cstr_buf(out, " ROOT: ");
412 pos = dns_app_name(base, out, pkt, pos, msg_len);
413 if (OUT_EQ_VLOG())
414 app_cstr_buf(out, "\n");
415 else if (out)
416 app_cstr_buf(out, " ");
417
418 if (16 > vstr_sc_posdiff(pos, msg_len))
419 return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len));
420
421 num_serial = get_b_uint32(pkt, pos); pos += 4;
422 num_refresh = get_b_uint32(pkt, pos); pos += 4;
423 num_retry = get_b_uint32(pkt, pos); pos += 4;
424 num_expire = get_b_uint32(pkt, pos); pos += 4;
425 num_min = get_b_uint32(pkt, pos); pos += 4;
426 if (OUT_EQ_VLOG())
427 app_fmt(out, " SERIAL: %u REFRESH: %u"
428 " RETRY: %u EXPIRE: %u MIN: %u",
429 num_serial, num_refresh, num_retry, num_expire, num_min);
430 else if (out)
431 app_fmt(out, " %u %u %u %u %u",
432 num_serial, num_refresh, num_retry, num_expire, num_min);
433 }
434 else if (dns_type == DNS_TYPE_IN_PTR)
435 {
436 if (OUT_EQ_VLOG()) app_cstr_buf(out, " PTR: ");
437 pos = dns_app_name(base, out, pkt, pos, msg_len);
438 }
439 else if (dns_type == DNS_TYPE_IN_HINFO)
440 {
441 if (OUT_EQ_VLOG()) app_cstr_buf(out, " CPU: ");
442 pos = dns_app_txt(out, pkt, pos, msg_len);
443 if (out) app_cstr_buf(out, " ");
444 if (OUT_EQ_VLOG()) app_cstr_buf(out, "OS: ");
445 pos = dns_app_txt(out, pkt, pos, msg_len);
446 }
447 else if (dns_type == DNS_TYPE_IN_MX)
448 {
449 unsigned int num = 0;
450
451 if (len < 4)
452 return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len));
453
454 num = get_b_uint16(pkt, pos); pos += 2;
455 if (OUT_EQ_VLOG()) app_cstr_buf(out, " PREF: ");
456 if (out) app_fmt(out, "%u ", num);
457 if (OUT_EQ_VLOG()) app_cstr_buf(out, "NAME: ");
458 pos = dns_app_name(base, out, pkt, pos, msg_len);
459 }
460 else if (dns_type == DNS_TYPE_IN_TXT)
461 {
462 if (OUT_EQ_VLOG()) app_cstr_buf(out, " TXT: ");
463 pos = dns_app_txt(out, pkt, pos, msg_len);
464 }
465 else if (dns_type == DNS_TYPE_IN_SRV)
466 {
467 unsigned int num_pri = 0;
468 unsigned int num_weight = 0;
469 unsigned int num_port = 0;
470
471 if (len < 8)
472 return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len));
473
474 num_pri = get_b_uint16(pkt, pos); pos += 2;
475 num_weight = get_b_uint16(pkt, pos); pos += 2;
476 num_port = get_b_uint16(pkt, pos); pos += 2;
477
478 if (OUT_EQ_VLOG())
479 app_fmt(out, " PRI: %u WEIGHT: %u PORT: %u NAME: ",
480 num_pri, num_weight, num_port);
481 else if (out)
482 app_fmt(out, " %u %u %u ",
483 num_pri, num_weight, num_port);
484
485 pos = dns_app_name(base, out, pkt, pos, msg_len);
486 }
487 else
488 return (dns_app_rr_unknown_data(base, pkt, pos, msg_len, len));
489 }
490
491 return (pos);
492 }
493
dns_dbg_prnt_pkt(Dns_base * base,Vstr_base * pkt)494 void dns_dbg_prnt_pkt(Dns_base *base, Vstr_base *pkt)
495 {
496 size_t pos = 1;
497 unsigned int id = 0;
498 unsigned int flags = 0;
499 unsigned int qdc = 0;
500 unsigned int anc = 0;
501 unsigned int nsc = 0;
502 unsigned int arc = 0;
503 unsigned int scan= 0;
504 const size_t msg_len = pkt->len;
505 int prefix = FALSE;
506
507 if (!base->io_dbg->out_dbg)
508 return;
509
510 prefix = vlg_prefix_set(base->io_dbg, FALSE);
511
512 if (12 <= msg_len)
513 {
514 id = get_b_uint16(pkt, pos); pos += 2;
515 flags = get_b_uint16(pkt, pos); pos += 2;
516 qdc = get_b_uint16(pkt, pos); pos += 2;
517 anc = get_b_uint16(pkt, pos); pos += 2;
518 nsc = get_b_uint16(pkt, pos); pos += 2;
519 arc = get_b_uint16(pkt, pos); pos += 2;
520
521 vlg_dbg1(base->io_dbg, " id=%u\n", id);
522 vlg_dbg1(base->io_dbg, " %*s: op=%u |%s|%s|%s|%s| z=%d ret=%d ->"
523 " qd=%u an=%u ns=%u ar=%u\n",
524 (int)strlen("Response"),
525 ((flags & DNS_HDR_QR) ? "Response" : "Query"),
526 ((flags & DNS_HDR_OPCMASK) >> DNS_HDR_OPCOFF),
527 ((flags & DNS_HDR_AA) ? "AA" : " "),
528 ((flags & DNS_HDR_TC) ? "TC" : " "),
529 ((flags & DNS_HDR_RD) ? "RD" : " "),
530 ((flags & DNS_HDR_RA) ? "RA" : " "),
531 ((flags & DNS_HDR_ZMASK) >> DNS_HDR_ZOFF),
532 ((flags & DNS_HDR_RMASK) >> DNS_HDR_ROFF),
533 qdc, anc, nsc, arc);
534 }
535 else
536 vlg_dbg1(base->io_dbg, "<NO HDR>\n");
537
538 scan = 0;
539 while ((scan++ < qdc) && (6 <= vstr_sc_posdiff(pos, msg_len)))
540 {
541 vlg_dbg1(base->io_dbg, " QUERY(%u/%u): ", scan, qdc);
542 pos = dns_app_label(base, base->io_dbg->out_vstr, pkt, pos, msg_len);
543 vlg_dbg1(base->io_dbg, " ");
544 pos = dns_app_class_type(base->io_dbg->out_vstr, pkt, pos, msg_len,
545 NULL, NULL);
546 vlg_dbg1(base->io_dbg, "\n");
547 }
548
549 scan = 0;
550 while ((scan++ < (anc + nsc + arc)) && (12 <= vstr_sc_posdiff(pos, msg_len)))
551 {
552 unsigned int dns_class = 0;
553 unsigned int dns_type = 0;
554
555 if (0) { }
556 else if (anc && (scan <= (anc)))
557 vlg_dbg1(base->io_dbg, " AN-RR(%u/%u): ", scan, anc);
558 else if (nsc && (scan <= (anc + nsc)))
559 vlg_dbg1(base->io_dbg, " NS-RR(%u/%u): ", scan - anc, nsc);
560 else
561 vlg_dbg1(base->io_dbg, " AR-RR(%u/%u): ", scan - (anc + nsc), arc);
562 pos = dns_app_name(base, base->io_dbg->out_vstr, pkt, pos, msg_len);
563 vlg_dbg1(base->io_dbg, " ");
564 pos = dns_app_class_type(base->io_dbg->out_vstr, pkt, pos, msg_len,
565 &dns_class, &dns_type);
566 pos = dns_app_ttl(base->io_dbg->out_vstr, pkt, pos, msg_len);
567 vlg_dbg1(base->io_dbg, "\n");
568 pos = dns_app_rr_data(base, base->io_dbg->out_vstr, pkt, pos, msg_len,
569 dns_class, dns_type);
570 vlg_dbg1(base->io_dbg, "\n");
571 }
572
573 vlg_prefix_set(base->io_dbg, prefix);
574 }
575
dns_app_recq_pkt(Dns_base * base,unsigned int qcount,...)576 void dns_app_recq_pkt(Dns_base *base, unsigned int qcount, ...)
577 {
578 Vstr_base *io_w = base->io_w_serv;
579 va_list ap;
580 size_t pos1 = 0;
581 size_t len1 = 0;
582 unsigned int id = 0;
583 Vstr_base *s1 = vstr_make_base(io_w->conf);
584 size_t srch_pos = 0;
585 size_t srch_len = 0;
586
587 if (!s1)
588 errno = ENOMEM, err(EXIT_FAILURE, __func__);
589
590 pos1 = io_w->len + 1;
591 app_b_uint16(io_w, 0); /* TCP length */
592
593 id = rand(); id &= 0xFFFF;
594 app_b_uint16(io_w, id);
595 app_b_uint16(io_w, DNS_HDR_OPC_QUERY | (base->opt_recur ? DNS_HDR_RD : 0));
596
597 app_b_uint16(io_w, qcount);
598 app_b_uint16(io_w, 0);
599 app_b_uint16(io_w, 0);
600 app_b_uint16(io_w, 0);
601
602 va_start(ap, qcount);
603 while (qcount--)
604 {
605 const char *name = va_arg(ap, const char *);
606 unsigned int dns_class = va_arg(ap, unsigned int);
607 unsigned int dns_type = va_arg(ap, unsigned int);
608
609 assert(name);
610
611 vstr_sub_cstr_ptr(s1, 1, s1->len, name);
612
613 if ((dns_class == DNS_CLASS_IN) && (dns_type == DNS_TYPE_IN_PTR))
614 { /* magic remapping for ptr */
615 unsigned char ipv4[4];
616 unsigned int ipv6[8];
617 unsigned int ern = 0;
618
619 if (0) { }
620 else if (vstr_parse_ipv4(s1, 1, s1->len, ipv4, NULL,
621 VSTR_FLAG_PARSE_IPV4_FULL |
622 VSTR_FLAG_PARSE_IPV4_ONLY, NULL, &ern) && !ern)
623 {
624 vstr_del(s1, 1, s1->len);
625 vstr_add_fmt(s1, s1->len, "%u.%u.%u.%u.in-addr.arpa",
626 ipv4[3], ipv4[2], ipv4[1], ipv4[0]);
627 }
628 else if (vstr_parse_ipv6(s1, 1, s1->len, ipv6, NULL,
629 VSTR_FLAG_PARSE_IPV6_ONLY, NULL, &ern) && !ern)
630 {
631 vstr_del(s1, 1, s1->len);
632 # define IP6_INT2BYTES(x) \
633 (ipv6[(x)] >> 0) & 0xF, \
634 (ipv6[(x)] >> 4) & 0xF, \
635 (ipv6[(x)] >> 8) & 0xF, \
636 (ipv6[(x)] >> 12) & 0xF
637 vstr_add_fmt(s1, s1->len,
638 "%x.%x.%x.%x." "%x.%x.%x.%x."
639 "%x.%x.%x.%x." "%x.%x.%x.%x."
640 "%x.%x.%x.%x." "%x.%x.%x.%x."
641 "%x.%x.%x.%x." "%x.%x.%x.%x."
642 "ip6.int",
643 IP6_INT2BYTES(7), IP6_INT2BYTES(6),
644 IP6_INT2BYTES(5), IP6_INT2BYTES(4),
645 IP6_INT2BYTES(3), IP6_INT2BYTES(2),
646 IP6_INT2BYTES(1), IP6_INT2BYTES(0));
647
648 # undef IP6_INT2BYTES
649 }
650
651 }
652
653 /* question */
654 srch_pos = vstr_csrch_cstr_chrs_fwd(s1, 1, s1->len, ".");
655 srch_len = vstr_sc_posdiff(srch_pos, s1->len);
656 while (srch_len)
657 {
658 size_t difflen = vstr_cspn_cstr_chrs_fwd(s1, srch_pos, srch_len, ".");
659
660 if (!difflen) /* ignore spurious '.' */
661 difflen = vstr_spn_cstr_chrs_fwd(s1, srch_pos, srch_len, ".");
662 else
663 {
664 app_b_uint8(io_w, difflen);
665 app_vstr(io_w, s1, srch_pos, difflen, VSTR_TYPE_ADD_ALL_BUF);
666
667 if (difflen != srch_len)
668 ++difflen;
669 }
670 assert(difflen <= srch_len);
671
672 srch_len -= difflen;
673 srch_pos += difflen;
674 }
675 app_b_uint8(io_w, 0); /* 0 length label is terminator */
676
677 app_b_uint16(io_w, dns_type);
678 app_b_uint16(io_w, dns_class);
679 }
680 va_end(ap);
681
682 if (io_w->conf->malloc_bad)
683 errno = ENOMEM, err(EXIT_FAILURE, __func__);
684
685 /* make the lengths correct */
686 len1 = io_w->len - (pos1 - 1);
687 sub_b_uint16(io_w, pos1, len1 - 2);
688
689 vlg_dbg1(base->io_dbg,
690 "\n${rep_chr:%c%zu} send ${BKMG.u:%u} ${rep_chr:%c%zu}\n",
691 '=', 33, len1 - 2, '=', 33);
692 if (base->io_dbg->out_dbg >= 1)
693 vstr_sub_vstr(s1, 1, s1->len,
694 io_w, pos1 + 2, len1 - 2, VSTR_TYPE_ADD_BUF_PTR);
695 dns_dbg_prnt_pkt(base, s1);
696 vlg_dbg1(base->io_dbg, "\n${rep_chr:%c%zu}\n", '-', 79);
697
698 vstr_free_base(s1);
699 io_w->conf->malloc_bad = FALSE;
700 }
701
dns_sc_ui_out(Dns_base * base,Vstr_base * pkt)702 void dns_sc_ui_out(Dns_base *base, Vstr_base *pkt)
703 {
704 Vstr_base *io_w = base->io_w_user;
705 size_t pos = 1;
706 unsigned int id = 0;
707 unsigned int flags = 0;
708 unsigned int qdc = 0;
709 unsigned int anc = 0;
710 unsigned int nsc = 0;
711 unsigned int arc = 0;
712 unsigned int scan = 0;
713 const size_t msg_len = pkt->len;
714
715 if (12 <= msg_len)
716 {
717 id = get_b_uint16(pkt, pos); pos += 2;
718 flags = get_b_uint16(pkt, pos); pos += 2;
719 qdc = get_b_uint16(pkt, pos); pos += 2;
720 anc = get_b_uint16(pkt, pos); pos += 2;
721 nsc = get_b_uint16(pkt, pos); pos += 2;
722 arc = get_b_uint16(pkt, pos); pos += 2;
723 }
724
725 /* can't check id atm. */
726 if (!(flags & DNS_HDR_QR))
727 return;
728
729 if (!anc)
730 {
731 scan = 0;
732 while ((scan++ < qdc) && (6 <= vstr_sc_posdiff(pos, msg_len)))
733 {
734 unsigned int hdr_r_code = ((flags & DNS_HDR_RMASK) >> DNS_HDR_ROFF);
735
736 pos = dns_app_label(base, io_w, pkt, pos, msg_len);
737 app_cstr_buf(io_w, " ");
738 pos = dns_app_class_type(io_w, pkt, pos, msg_len, NULL, NULL);
739 app_fmt(io_w, ":ret=%d#%s\n", hdr_r_code, dns_name_hdr_r(hdr_r_code));
740 }
741 return;
742 }
743
744 scan = 0;
745 while ((scan++ < qdc) && (6 <= vstr_sc_posdiff(pos, msg_len)))
746 {
747 pos = dns_app_label(base, NULL, pkt, pos, msg_len);
748 pos = dns_app_class_type(NULL, pkt, pos, msg_len, NULL, NULL);
749 }
750
751 scan = 0;
752 while ((scan++ < anc) && (12 <= vstr_sc_posdiff(pos, msg_len)))
753 {
754 unsigned int dns_class = 0;
755 unsigned int dns_type = 0;
756
757 pos = dns_app_name(base, io_w, pkt, pos, msg_len);
758 app_cstr_buf(io_w, " ");
759 pos = dns_app_class_type(io_w, pkt, pos, msg_len, &dns_class, &dns_type);
760 app_cstr_buf(io_w, " ");
761 pos = dns_app_ttl(NULL, pkt, pos, msg_len);
762 pos = dns_app_rr_data(base, io_w, pkt, pos, msg_len, dns_class, dns_type);
763 app_cstr_buf(io_w, "\n");
764 }
765 }
766
767