4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <sys/types.h>
32 #include <sys/errno.h>
33 #include <sys/tiuser.h>
34 #include <arpa/nameser.h>
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
39 /* The string used to indent detail lines */
40 #define DNS_INDENT " "
42 * From RFC1035, the maximum size of a character-string is limited by the
43 * one octet length field. We add one character to that to make sure the
44 * result is terminated.
46 #define MAX_CHAR_STRING_SIZE UCHAR_MAX + 1
48 /* private functions */
49 static char *dns_opcode_string(uint_t opcode
);
50 static char *dns_rcode_string(uint_t rcode
);
51 static char *dns_type_string(uint_t type
, int detail
);
52 static char *dns_class_string(uint_t cls
, int detail
);
53 static size_t skip_question(const uchar_t
*header
, const uchar_t
*data
,
54 const uchar_t
*data_end
);
55 static size_t print_question(char *line
, const uchar_t
*header
,
56 const uchar_t
*data
, const uchar_t
*data_end
, int detail
);
57 static size_t print_answer(char *line
, const uchar_t
*header
,
58 const uchar_t
*data
, const uchar_t
*data_end
, int detail
);
59 static char *binary_string(char data
);
60 static void print_ip(int af
, char *line
, const uchar_t
*data
, uint16_t len
);
61 static const uchar_t
*get_char_string(const uchar_t
*data
, char *charbuf
,
63 static size_t print_char_string(char *line
, const uchar_t
*data
, uint16_t len
);
64 static const uchar_t
*get_domain_name(const uchar_t
*header
,
65 const uchar_t
*data
, const uchar_t
*data_end
, char *namebuf
, char *namend
);
66 static size_t print_domain_name(char *line
, const uchar_t
*header
,
67 const uchar_t
*data
, const uchar_t
*data_end
);
70 interpret_dns(int flags
, int proto
, const uchar_t
*data
, int len
, int port
)
72 typedef HEADER dns_header
;
75 ushort_t id
, qdcount
, ancount
, nscount
, arcount
;
77 const uchar_t
*rrp
; /* Resource Record Pointer. */
78 const uchar_t
*data_end
;
83 if (proto
== IPPROTO_TCP
) {
84 /* not supported now */
88 if (port
== IPPORT_DOMAIN
) {
90 protopfxstr
= "DNS: ";
91 protohdrstr
= "DNS Header";
94 protopfxstr
= "MDNS: ";
95 protohdrstr
= "MDNS Header";
98 /* We need at least the header in order to parse a packet. */
99 if (sizeof (dns_header
) > len
) {
102 data_end
= data
+ len
;
104 * Copy the header into a local structure for aligned access to
107 (void) memcpy(&header
, data
, sizeof (header
));
108 id
= ntohs(header
.id
);
109 qdcount
= ntohs(header
.qdcount
);
110 ancount
= ntohs(header
.ancount
);
111 nscount
= ntohs(header
.nscount
);
112 arcount
= ntohs(header
.arcount
);
115 line
= get_sum_line();
116 line
+= sprintf(line
, "%s %c ",
117 protostr
, header
.qr
? 'R' : 'C');
121 if (header
.rcode
== 0) {
123 rrp
= data
+ sizeof (dns_header
);
125 if (rrp
>= data_end
) {
128 rrp
+= skip_question(data
,
131 /* the answers follow the questions */
133 (void) print_answer(line
,
134 data
, rrp
, data_end
, FALSE
);
137 (void) sprintf(line
, " Error: %d(%s)",
139 dns_rcode_string(header
.rcode
));
143 rrp
= data
+ sizeof (dns_header
);
144 if (rrp
>= data_end
) {
147 (void) print_question(line
, data
, rrp
, data_end
,
151 if (flags
& F_DTAIL
) {
152 show_header(protopfxstr
, protohdrstr
, sizeof (dns_header
));
156 (void) snprintf(get_line(0, 0), get_line_remain(),
157 "Response ID = %d", id
);
158 (void) snprintf(get_line(0, 0), get_line_remain(),
160 header
.aa
? "AA (Authoritative Answer) " : "",
161 header
.tc
? "TC (TrunCation) " : "",
162 header
.ra
? "RA (Recursion Available) ": "");
163 (void) snprintf(get_line(0, 0), get_line_remain(),
164 "Response Code: %d (%s)",
165 header
.rcode
, dns_rcode_string(header
.rcode
));
166 (void) snprintf(get_line(0, 0), get_line_remain(),
167 "Reply to %d question(s)", qdcount
);
170 (void) snprintf(get_line(0, 0), get_line_remain(),
171 "Query ID = %d", id
);
172 (void) snprintf(get_line(0, 0), get_line_remain(),
173 "Opcode: %s", dns_opcode_string(header
.opcode
));
174 (void) snprintf(get_line(0, 0), get_line_remain(),
176 header
.tc
? "TC (TrunCation) " : "",
177 header
.rd
? "RD (Recursion Desired) " : "");
178 (void) snprintf(get_line(0, 0), get_line_remain(),
179 "%d question(s)", qdcount
);
181 rrp
= data
+ sizeof (dns_header
);
184 if (rrp
>= data_end
) {
188 rrp
+= print_question(get_line(0, 0),
189 data
, rrp
, data_end
, TRUE
);
192 /* Only answers should hold answers, but just in case */
193 if (header
.qr
|| ancount
> 0) {
194 (void) snprintf(get_line(0, 0), get_line_remain(),
195 "%d answer(s)", ancount
);
198 if (rrp
>= data_end
) {
202 rrp
+= print_answer(get_line(0, 0),
203 data
, rrp
, data_end
, TRUE
);
207 /* Likewise only answers should hold NS records */
208 if (header
.qr
|| nscount
> 0) {
209 (void) snprintf(get_line(0, 0), get_line_remain(),
210 "%d name server resource(s)", nscount
);
213 if (rrp
>= data_end
) {
217 rrp
+= print_answer(get_line(0, 0), data
,
218 rrp
, data_end
, TRUE
);
222 /* Additional section may hold an EDNS0 record. */
223 if (header
.qr
|| arcount
> 0) {
224 (void) snprintf(get_line(0, 0), get_line_remain(),
225 "%d additional record(s)", arcount
);
227 while (arcount
-- && rrp
< data_end
) {
229 rrp
+= print_answer(get_line(0, 0), data
,
230 rrp
, data_end
, TRUE
);
239 dns_opcode_string(uint_t opcode
)
241 static char buffer
[64];
243 case ns_o_query
: return ("Query");
244 case ns_o_iquery
: return ("Inverse Query");
245 case ns_o_status
: return ("Status");
247 (void) snprintf(buffer
, sizeof (buffer
), "Unknown (%u)",
254 dns_rcode_string(uint_t rcode
)
256 static char buffer
[64];
258 case ns_r_noerror
: return ("OK");
259 case ns_r_formerr
: return ("Format Error");
260 case ns_r_servfail
: return ("Server Fail");
261 case ns_r_nxdomain
: return ("Name Error");
262 case ns_r_notimpl
: return ("Unimplemented");
263 case ns_r_refused
: return ("Refused");
264 case ns_r_badvers
: return ("Bad Version"); /* EDNS rcode */
266 (void) snprintf(buffer
, sizeof (buffer
), "Unknown (%u)", rcode
);
272 dns_type_string(uint_t type
, int detail
)
274 static char buffer
[64];
276 case ns_t_a
: return (detail
? "Address" : "Addr");
277 case ns_t_ns
: return (detail
? "Authoritative Name Server" : "NS");
278 case ns_t_cname
: return (detail
? "Canonical Name" : "CNAME");
279 case ns_t_soa
: return (detail
? "Start Of a zone Authority" : "SOA");
280 case ns_t_mb
: return (detail
? "Mailbox domain name" : "MB");
281 case ns_t_mg
: return (detail
? "Mailbox Group member" : "MG");
282 case ns_t_mr
: return (detail
? "Mail Rename domain name" : "MR");
283 case ns_t_null
: return ("NULL");
284 case ns_t_wks
: return (detail
? "Well Known Service" : "WKS");
285 case ns_t_ptr
: return (detail
? "Domain Name Pointer" : "PTR");
286 case ns_t_hinfo
: return (detail
? "Host Information": "HINFO");
288 return (detail
? "Mailbox or maillist Info" : "MINFO");
289 case ns_t_mx
: return (detail
? "Mail Exchange" : "MX");
290 case ns_t_txt
: return (detail
? "Text strings" : "TXT");
291 case ns_t_aaaa
: return (detail
? "IPv6 Address" : "AAAA");
292 case ns_t_opt
: return (detail
? "EDNS0 option" : "OPT");
293 case ns_t_axfr
: return (detail
? "Transfer of entire zone" : "AXFR");
295 return (detail
? "Mailbox related records" : "MAILB");
296 case ns_t_maila
: return (detail
? "Mail agent RRs" : "MAILA");
297 case ns_t_any
: return (detail
? "All records" : "*");
299 (void) snprintf(buffer
, sizeof (buffer
), "Unknown (%u)", type
);
305 dns_class_string(uint_t cls
, int detail
)
307 static char buffer
[64];
309 case ns_c_in
: return (detail
? "Internet" : "Internet");
310 case ns_c_chaos
: return (detail
? "CHAOS" : "CH");
311 case ns_c_hs
: return (detail
? "Hesiod" : "HS");
312 case ns_c_any
: return (detail
? "* (Any class)" : "*");
314 (void) snprintf(buffer
, sizeof (buffer
), "Unknown (%u)", cls
);
320 skip_question(const uchar_t
*header
, const uchar_t
*data
,
321 const uchar_t
*data_end
)
323 const uchar_t
*data_bak
= data
;
324 char dummy_buffer
[NS_MAXDNAME
];
326 data
= get_domain_name(header
, data
, data_end
, dummy_buffer
,
327 dummy_buffer
+ sizeof (dummy_buffer
));
328 /* Skip the 32 bits of class and type that follow the domain name */
329 data
+= sizeof (uint32_t);
330 return (data
- data_bak
);
334 print_question(char *line
, const uchar_t
*header
, const uchar_t
*data
,
335 const uchar_t
*data_end
, int detail
)
337 const uchar_t
*data_bak
= data
;
342 line
+= snprintf(line
, get_line_remain(),
343 DNS_INDENT
"Domain Name: ");
345 data
+= print_domain_name(line
, header
, data
, data_end
);
348 * Make sure we don't run off the end of the packet by reading the
351 * The pointer subtraction on the left side of the following
352 * expression has a signed result of type ptrdiff_t, and the right
353 * side has an unsigned result of type size_t. We therefore need
354 * to cast the right side of the expression to be of the same
355 * signed type to keep the result of the pointer arithmetic to be
356 * automatically cast to an unsigned value. We do a similar cast
357 * in other similar expressions throughout this file.
359 if ((data_end
- data
) < (ptrdiff_t)(2 * sizeof (uint16_t)))
360 return (data_end
- data_bak
);
362 GETINT16(type
, data
);
366 * Multicast DNS re-uses the top bit of the class field
367 * in the question and answer sections. Unicast DNS only
368 * uses 1 (Internet), 3 and 4. Hence it is safe. The top
369 * order bit is always cleared here to display the rrclass in case
370 * of Multicast DNS packets.
375 (void) snprintf(get_line(0, 0), get_line_remain(),
376 DNS_INDENT
"Class: %u (%s)",
377 cls
, dns_class_string(cls
, detail
));
378 (void) snprintf(get_line(0, 0), get_line_remain(),
379 DNS_INDENT
"Type: %u (%s)", type
,
380 dns_type_string(type
, detail
));
382 (void) sprintf(line
+ strlen(line
), " %s %s \?",
383 dns_class_string(cls
, detail
),
384 dns_type_string(type
, detail
));
386 return (data
- data_bak
);
390 * print_answer() is used to display the contents of a single resource
391 * record (RR) from either the answer, name server or additional
392 * section of the DNS packet.
395 * *line: snoops output buffer.
396 * *header: start of the DNS packet, required for names and rcode.
397 * *data: location within header from where the RR starts.
398 * *data_end: where DNS data ends.
399 * detail: simple or verbose output.
402 * Pointer to next RR or data_end.
404 * Most RRs have the same top level format as defined in RFC 1035:
407 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
408 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
412 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
414 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
416 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
419 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
421 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
424 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
426 * However RFC 2671 introduced an exception to this rule
427 * with the "Extension Mechanisms for DNS" (EDNS0).
428 * When the type is 41 the remaining resource record format
432 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
433 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
435 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
436 * | Sender's UDP payload size |
437 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
438 * | Extended-rcode | Version |
439 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
441 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
443 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
446 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
450 print_answer(char *line
, const uchar_t
*header
, const uchar_t
*data
,
451 const uchar_t
*data_end
, int detail
)
453 const uchar_t
*data_bak
= data
;
454 const uchar_t
*data_next
;
459 uint32_t serial
, refresh
, retry
, expire
, minimum
;
463 /* declarations for EDNS follow */
464 uint16_t size
; /* Sender's UDP payload size */
465 uint8_t xrcode
; /* Extended-rcode */
466 uint8_t ver
; /* Version */
467 uint16_t rcode
; /* Extracted from the DNS header */
468 union { /* DNS header overlay used for extraction */
474 line
+= snprintf(line
, get_line_remain(),
475 DNS_INDENT
"Domain Name: ");
477 data
+= print_domain_name(line
, header
, data
, data_end
);
480 * Next, get the record type, being careful to make sure we
481 * don't run off the end of the packet.
483 if ((data_end
- data
) < (ptrdiff_t)(sizeof (type
))) {
484 return (data_end
- data_bak
);
487 GETINT16(type
, data
);
489 if (type
== ns_t_opt
) {
491 * Make sure we won't run off the end reading size,
492 * xrcode, version, zero and rdlen.
494 if ((data_end
- data
) <
495 ((ptrdiff_t)(sizeof (size
)
498 + sizeof (cls
) /* zero */
499 + sizeof (rdlen
)))) {
500 return (data_end
- data_bak
);
503 GETINT16(size
, data
);
504 GETINT8(xrcode
, data
);
506 * The extended rcode represents the top half of the
507 * rcode which must be added to the rcode in the header.
509 rcode
= 0xff & (xrcode
<< 4);
510 headptr
.raw
= header
; /* Overlay the header... */
511 rcode
+= headptr
.head
->rcode
; /* And pluck out the rcode. */
514 GETINT16(cls
, data
); /* zero */
515 GETINT16(rdlen
, data
);
518 (void) snprintf(get_line(0, 0), get_line_remain(),
519 DNS_INDENT
"Type: %u (%s)", type
,
520 dns_type_string(type
, detail
));
521 (void) snprintf(get_line(0, 0), get_line_remain(),
522 DNS_INDENT
"UDP payload size: %u (0x%.4x)",
524 (void) snprintf(get_line(0, 0), get_line_remain(),
525 DNS_INDENT
"Extended rcode: %u "
526 "(translates to %u (%s))",
527 xrcode
, rcode
, dns_rcode_string(rcode
));
528 (void) snprintf(get_line(0, 0), get_line_remain(),
529 DNS_INDENT
"EDNS0 Version: %u", ver
);
530 (void) snprintf(get_line(0, 0), get_line_remain(),
531 DNS_INDENT
"zero: %u", cls
);
532 (void) snprintf(get_line(0, 0), get_line_remain(),
533 DNS_INDENT
"Data length: %u", rdlen
);
535 line
+= strlen(line
);
536 line
+= sprintf(line
, " %s UDP %u rc %d ver %u len %u",
537 dns_type_string(type
, detail
), size
, rcode
, ver
,
542 * Make sure that rdlen is within data boundary.
544 if (rdlen
> data_end
- data
)
545 return (data_end
- data_bak
);
547 /* Future OPT decode code goes here. */
550 return (data
- data_bak
);
554 * Make sure we don't run off the end of the packet by reading the
555 * class, ttl, and length.
557 if ((data_end
- data
) <
558 ((ptrdiff_t)(sizeof (cls
)
560 + sizeof (rdlen
)))) {
561 return (data_end
- data_bak
);
567 * Multicast DNS re-uses the top bit of the class field
568 * in the question and answer sections. Unicast DNS only
569 * uses 1 (Internet), 3 and 4. Hence it is safe. The top
570 * order bit is always cleared here to display the rrclass in case
571 * of Multicast DNS packets.
576 (void) snprintf(get_line(0, 0), get_line_remain(),
577 DNS_INDENT
"Class: %d (%s)", cls
,
578 dns_class_string(cls
, detail
));
579 (void) snprintf(get_line(0, 0), get_line_remain(),
580 DNS_INDENT
"Type: %d (%s)", type
,
581 dns_type_string(type
, detail
));
583 line
+= strlen(line
);
584 line
+= sprintf(line
, " %s %s ",
585 dns_class_string(cls
, detail
),
586 dns_type_string(type
, detail
));
591 (void) snprintf(get_line(0, 0), get_line_remain(),
592 DNS_INDENT
"TTL (Time To Live): %d", ttl
);
595 GETINT16(rdlen
, data
);
597 line
= get_line(0, 0);
598 line
+= snprintf(line
, get_line_remain(), DNS_INDENT
"%s: ",
599 dns_type_string(type
, detail
));
602 if (rdlen
> data_end
- data
)
603 return (data_end
- data_bak
);
607 print_ip(AF_INET
, line
, data
, rdlen
);
610 print_ip(AF_INET6
, line
, data
, rdlen
);
613 line
+= sprintf(line
, "CPU: ");
614 data_next
= data
+ print_char_string(line
, data
, rdlen
);
615 if (data_next
>= data_end
)
617 line
+= strlen(line
);
618 line
+= sprintf(line
, "OS: ");
619 (void) print_char_string(line
, data_next
,
620 rdlen
- (data_next
- data
));
628 (void) print_domain_name(line
, header
, data
, data_end
);
632 if (rdlen
< sizeof (uint16_t))
634 GETINT16(preference
, data_next
);
636 (void) print_domain_name(line
, header
, data_next
,
638 (void) snprintf(get_line(0, 0), get_line_remain(),
639 DNS_INDENT
"Preference: %u", preference
);
641 (void) print_domain_name(line
, header
, data_next
,
648 line
= get_line(0, 0);
649 line
+= snprintf(line
, get_line_remain(),
650 DNS_INDENT
"MNAME (Server name): ");
651 data_next
= data
+ print_domain_name(line
, header
, data
,
653 if (data_next
>= data_end
)
655 line
= get_line(0, 0);
656 line
+= snprintf(line
, get_line_remain(),
657 DNS_INDENT
"RNAME (Resposible mailbox): ");
658 data_next
= data_next
+
659 print_domain_name(line
, header
, data_next
, data_end
);
660 if ((data_end
- data_next
) < (ptrdiff_t)(5 * sizeof (uint32_t)))
662 GETINT32(serial
, data_next
);
663 GETINT32(refresh
, data_next
);
664 GETINT32(retry
, data_next
);
665 GETINT32(expire
, data_next
);
666 GETINT32(minimum
, data_next
);
667 (void) snprintf(get_line(0, 0), get_line_remain(),
668 DNS_INDENT
"Serial: %u", serial
);
669 (void) snprintf(get_line(0, 0), get_line_remain(),
670 DNS_INDENT
"Refresh: %u Retry: %u "
671 "Expire: %u Minimum: %u",
672 refresh
, retry
, expire
, minimum
);
675 print_ip(AF_INET
, line
, data
, rdlen
);
678 data_next
= data
+ sizeof (in_addr_t
);
679 if (data_next
>= data_end
)
681 GETINT8(protocol
, data_next
);
682 line
= get_line(0, 0);
683 line
+= snprintf(line
, get_line_remain(),
684 DNS_INDENT
"Protocol: %u ", protocol
);
687 (void) snprintf(line
, get_line_remain(), "(UDP)");
690 (void) snprintf(line
, get_line_remain(), "(TCP)");
693 (void) snprintf(get_line(0, 0), get_line_remain(),
694 DNS_INDENT
"Service bitmap:");
695 (void) snprintf(line
, get_line_remain(),
696 DNS_INDENT
"0 8 16 24");
698 while (data_next
< data
+ rdlen
) {
700 line
= get_line(0, 0);
701 line
+= snprintf(line
, get_line_remain(),
705 line
+= snprintf(line
, get_line_remain(), "%s",
706 binary_string(*data_next
));
714 line
= get_line(0, 0);
715 line
+= snprintf(line
, get_line_remain(),
716 DNS_INDENT
"RMAILBX (Resposible mailbox): ");
717 data_next
= data
+ print_domain_name(line
, header
, data
,
719 line
= get_line(0, 0);
720 line
+= snprintf(line
, get_line_remain(),
721 DNS_INDENT
"EMAILBX (mailbox to receive err message): ");
722 data_next
= data_next
+ print_domain_name(line
, header
,
723 data_next
, data_end
);
727 return (data
- data_bak
);
731 binary_string(char data
)
733 static char bstring
[8 + 1];
737 for (i
= 0; i
< 8; i
++) {
738 *ptr
++ = (data
& 0x80) ? '1' : '0';
746 print_ip(int af
, char *line
, const uchar_t
*data
, uint16_t len
)
754 if (len
!= sizeof (in_addr_t
))
756 addr
= memcpy(&addr4
, data
, sizeof (addr4
));
759 if (len
!= sizeof (in6_addr_t
))
761 addr
= memcpy(&addr6
, data
, sizeof (addr6
));
765 (void) inet_ntop(af
, addr
, line
, INET6_ADDRSTRLEN
);
769 * charbuf is assumed to be of size MAX_CHAR_STRING_SIZE.
771 static const uchar_t
*
772 get_char_string(const uchar_t
*data
, char *charbuf
, uint16_t datalen
)
775 char *name
= charbuf
;
779 * From RFC1035, a character-string is a single length octet followed
780 * by that number of characters.
785 if (len
> 0 && len
< MAX_CHAR_STRING_SIZE
) {
786 for (i
= 0; i
< len
; i
++, data
++)
795 print_char_string(char *line
, const uchar_t
*data
, uint16_t len
)
797 char charbuf
[MAX_CHAR_STRING_SIZE
];
798 const uchar_t
*data_bak
= data
;
800 data
= get_char_string(data
, charbuf
, len
);
801 (void) sprintf(line
, "%s", charbuf
);
802 return (data
- data_bak
);
806 * header: the entire message header, this is where we start to
807 * count the offset of the compression scheme
808 * data: the start of the domain name
809 * namebuf: user supplied buffer
810 * return: the next byte after what we have parsed
812 static const uchar_t
*
813 get_domain_name(const uchar_t
*header
, const uchar_t
*data
,
814 const uchar_t
*data_end
, char *namebuf
, char *namend
)
817 char *name
= namebuf
;
820 * From RFC1035, a domain name is a sequence of labels, where each
821 * label consists of a length octet followed by that number of
822 * octets. The domain name terminates with the zero length octet
823 * for the null label of the root.
826 while (name
< (namend
- 1)) {
827 if ((data_end
- data
) < (ptrdiff_t)(sizeof (uint8_t))) {
828 /* The length octet is off the end of the packet. */
834 * Domain names end with a length byte of zero,
835 * which represents the null label of the root.
840 * test if we are using the compression scheme
842 if ((len
& 0xc0) == 0xc0) {
844 const uchar_t
*label_ptr
;
847 * From RFC1035, message compression allows a
848 * domain name or a list of labels at the end of a
849 * domain name to be replaced with a pointer to a
850 * prior occurance of the same name. In this
851 * scheme, the pointer is a two octet sequence
852 * where the most significant two bits are set, and
853 * the remaining 14 bits are the offset from the
854 * start of the message of the next label.
857 if ((data_end
- data
) <
858 (ptrdiff_t)(sizeof (uint16_t))) {
860 * The offset octets aren't entirely
861 * contained within this pakcet.
866 GETINT16(offset
, data
);
867 label_ptr
= header
+ (offset
& 0x3fff);
869 * We must verify that the offset is valid by
870 * checking that it is less than the current data
871 * pointer and that it isn't off the end of the
874 if (label_ptr
> data
|| label_ptr
>= data_end
)
876 (void) get_domain_name(header
, label_ptr
, data_end
,
880 if (len
> (data_end
- data
)) {
882 * The label isn't entirely contained
883 * within the packet. Don't read it. The
884 * caller checks that the data pointer is
885 * not beyond the end after we've
891 while (len
> 0 && name
< (namend
- 2)) {
906 print_domain_name(char *line
, const uchar_t
*header
, const uchar_t
*data
,
907 const uchar_t
*data_end
)
909 char name
[NS_MAXDNAME
];
910 const uchar_t
*new_data
;
912 new_data
= get_domain_name(header
, data
, data_end
, name
,
913 name
+ sizeof (name
));
915 (void) sprintf(line
, "%s", name
);
916 return (new_data
- data
);