17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5f7a9f694Ssm26363 * Common Development and Distribution License (the "License").
6f7a9f694Ssm26363 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22f7a9f694Ssm26363 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate #include <stdio.h>
277c478bd9Sstevel@tonic-gate #include <string.h>
287c478bd9Sstevel@tonic-gate #include <limits.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/errno.h>
317c478bd9Sstevel@tonic-gate #include <sys/tiuser.h>
327c478bd9Sstevel@tonic-gate #include <arpa/nameser.h>
337c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
347c478bd9Sstevel@tonic-gate #include <netinet/in.h>
357c478bd9Sstevel@tonic-gate #include "snoop.h"
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate /* The string used to indent detail lines */
387c478bd9Sstevel@tonic-gate #define DNS_INDENT " "
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate * From RFC1035, the maximum size of a character-string is limited by the
417c478bd9Sstevel@tonic-gate * one octet length field. We add one character to that to make sure the
427c478bd9Sstevel@tonic-gate * result is terminated.
437c478bd9Sstevel@tonic-gate */
447c478bd9Sstevel@tonic-gate #define MAX_CHAR_STRING_SIZE UCHAR_MAX + 1
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate /* private functions */
477c478bd9Sstevel@tonic-gate static char *dns_opcode_string(uint_t opcode);
487c478bd9Sstevel@tonic-gate static char *dns_rcode_string(uint_t rcode);
497c478bd9Sstevel@tonic-gate static char *dns_type_string(uint_t type, int detail);
507c478bd9Sstevel@tonic-gate static char *dns_class_string(uint_t cls, int detail);
517c478bd9Sstevel@tonic-gate static size_t skip_question(const uchar_t *header, const uchar_t *data,
527c478bd9Sstevel@tonic-gate const uchar_t *data_end);
537c478bd9Sstevel@tonic-gate static size_t print_question(char *line, const uchar_t *header,
547c478bd9Sstevel@tonic-gate const uchar_t *data, const uchar_t *data_end, int detail);
557c478bd9Sstevel@tonic-gate static size_t print_answer(char *line, const uchar_t *header,
567c478bd9Sstevel@tonic-gate const uchar_t *data, const uchar_t *data_end, int detail);
577c478bd9Sstevel@tonic-gate static char *binary_string(char data);
587c478bd9Sstevel@tonic-gate static void print_ip(int af, char *line, const uchar_t *data, uint16_t len);
597c478bd9Sstevel@tonic-gate static const uchar_t *get_char_string(const uchar_t *data, char *charbuf,
607c478bd9Sstevel@tonic-gate uint16_t datalen);
617c478bd9Sstevel@tonic-gate static size_t print_char_string(char *line, const uchar_t *data, uint16_t len);
627c478bd9Sstevel@tonic-gate static const uchar_t *get_domain_name(const uchar_t *header,
637c478bd9Sstevel@tonic-gate const uchar_t *data, const uchar_t *data_end, char *namebuf, char *namend);
647c478bd9Sstevel@tonic-gate static size_t print_domain_name(char *line, const uchar_t *header,
657c478bd9Sstevel@tonic-gate const uchar_t *data, const uchar_t *data_end);
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate void
interpret_dns(int flags,int proto,const uchar_t * data,int len,int port)684b22b933Srs200217 interpret_dns(int flags, int proto, const uchar_t *data, int len, int port)
697c478bd9Sstevel@tonic-gate {
707c478bd9Sstevel@tonic-gate typedef HEADER dns_header;
717c478bd9Sstevel@tonic-gate dns_header header;
727c478bd9Sstevel@tonic-gate char *line;
737c478bd9Sstevel@tonic-gate ushort_t id, qdcount, ancount, nscount, arcount;
747c478bd9Sstevel@tonic-gate ushort_t count;
75f7a9f694Ssm26363 const uchar_t *rrp; /* Resource Record Pointer. */
767c478bd9Sstevel@tonic-gate const uchar_t *data_end;
774b22b933Srs200217 const char *protostr;
784b22b933Srs200217 char *protopfxstr;
794b22b933Srs200217 char *protohdrstr;
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate if (proto == IPPROTO_TCP) {
827c478bd9Sstevel@tonic-gate /* not supported now */
837c478bd9Sstevel@tonic-gate return;
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate
864b22b933Srs200217 if (port == IPPORT_DOMAIN) {
874b22b933Srs200217 protostr = "DNS";
884b22b933Srs200217 protopfxstr = "DNS: ";
894b22b933Srs200217 protohdrstr = "DNS Header";
904b22b933Srs200217 } else {
914b22b933Srs200217 protostr = "MDNS";
924b22b933Srs200217 protopfxstr = "MDNS: ";
934b22b933Srs200217 protohdrstr = "MDNS Header";
944b22b933Srs200217 }
954b22b933Srs200217
967c478bd9Sstevel@tonic-gate /* We need at least the header in order to parse a packet. */
977c478bd9Sstevel@tonic-gate if (sizeof (dns_header) > len) {
987c478bd9Sstevel@tonic-gate return;
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate data_end = data + len;
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate * Copy the header into a local structure for aligned access to
1037c478bd9Sstevel@tonic-gate * each field.
1047c478bd9Sstevel@tonic-gate */
1057c478bd9Sstevel@tonic-gate (void) memcpy(&header, data, sizeof (header));
1067c478bd9Sstevel@tonic-gate id = ntohs(header.id);
1077c478bd9Sstevel@tonic-gate qdcount = ntohs(header.qdcount);
1087c478bd9Sstevel@tonic-gate ancount = ntohs(header.ancount);
1097c478bd9Sstevel@tonic-gate nscount = ntohs(header.nscount);
1107c478bd9Sstevel@tonic-gate arcount = ntohs(header.arcount);
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate if (flags & F_SUM) {
1137c478bd9Sstevel@tonic-gate line = get_sum_line();
1144b22b933Srs200217 line += sprintf(line, "%s %c ",
1154b22b933Srs200217 protostr, header.qr ? 'R' : 'C');
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate if (header.qr) {
1187c478bd9Sstevel@tonic-gate /* answer */
1197c478bd9Sstevel@tonic-gate if (header.rcode == 0) {
1207c478bd9Sstevel@tonic-gate /* reply is OK */
121f7a9f694Ssm26363 rrp = data + sizeof (dns_header);
1227c478bd9Sstevel@tonic-gate while (qdcount--) {
123f7a9f694Ssm26363 if (rrp >= data_end) {
1247c478bd9Sstevel@tonic-gate return;
1257c478bd9Sstevel@tonic-gate }
126f7a9f694Ssm26363 rrp += skip_question(data,
127f7a9f694Ssm26363 rrp, data_end);
1287c478bd9Sstevel@tonic-gate }
129f7a9f694Ssm26363 /* the answers follow the questions */
1307c478bd9Sstevel@tonic-gate if (ancount > 0) {
1317c478bd9Sstevel@tonic-gate (void) print_answer(line,
132f7a9f694Ssm26363 data, rrp, data_end, FALSE);
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate } else {
1357c478bd9Sstevel@tonic-gate (void) sprintf(line, " Error: %d(%s)",
1367c478bd9Sstevel@tonic-gate header.rcode,
1377c478bd9Sstevel@tonic-gate dns_rcode_string(header.rcode));
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate } else {
1407c478bd9Sstevel@tonic-gate /* question */
141f7a9f694Ssm26363 rrp = data + sizeof (dns_header);
142f7a9f694Ssm26363 if (rrp >= data_end) {
1437c478bd9Sstevel@tonic-gate return;
1447c478bd9Sstevel@tonic-gate }
145f7a9f694Ssm26363 (void) print_question(line, data, rrp, data_end,
1467c478bd9Sstevel@tonic-gate FALSE);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate if (flags & F_DTAIL) {
1504b22b933Srs200217 show_header(protopfxstr, protohdrstr, sizeof (dns_header));
1517c478bd9Sstevel@tonic-gate show_space();
1527c478bd9Sstevel@tonic-gate if (header.qr) {
1537c478bd9Sstevel@tonic-gate /* answer */
1547c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
1557c478bd9Sstevel@tonic-gate "Response ID = %d", id);
1567c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
1577c478bd9Sstevel@tonic-gate "%s%s%s",
1587c478bd9Sstevel@tonic-gate header.aa ? "AA (Authoritative Answer) " : "",
1597c478bd9Sstevel@tonic-gate header.tc ? "TC (TrunCation) " : "",
1607c478bd9Sstevel@tonic-gate header.ra ? "RA (Recursion Available) ": "");
1617c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
1627c478bd9Sstevel@tonic-gate "Response Code: %d (%s)",
1637c478bd9Sstevel@tonic-gate header.rcode, dns_rcode_string(header.rcode));
1647c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
1657c478bd9Sstevel@tonic-gate "Reply to %d question(s)", qdcount);
1667c478bd9Sstevel@tonic-gate } else {
1677c478bd9Sstevel@tonic-gate /* question */
1687c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
1697c478bd9Sstevel@tonic-gate "Query ID = %d", id);
1707c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
1717c478bd9Sstevel@tonic-gate "Opcode: %s", dns_opcode_string(header.opcode));
1727c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
1737c478bd9Sstevel@tonic-gate "%s%s",
1747c478bd9Sstevel@tonic-gate header.tc ? "TC (TrunCation) " : "",
1757c478bd9Sstevel@tonic-gate header.rd ? "RD (Recursion Desired) " : "");
1767c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
1777c478bd9Sstevel@tonic-gate "%d question(s)", qdcount);
178f7a9f694Ssm26363 }
179f7a9f694Ssm26363 rrp = data + sizeof (dns_header);
1807c478bd9Sstevel@tonic-gate count = 0;
181f7a9f694Ssm26363 while (qdcount--) {
182f7a9f694Ssm26363 if (rrp >= data_end) {
183f7a9f694Ssm26363 return;
184f7a9f694Ssm26363 }
1857c478bd9Sstevel@tonic-gate count++;
186f7a9f694Ssm26363 rrp += print_question(get_line(0, 0),
187f7a9f694Ssm26363 data, rrp, data_end, TRUE);
188f7a9f694Ssm26363 show_space();
189f7a9f694Ssm26363 }
190f7a9f694Ssm26363 /* Only answers should hold answers, but just in case */
191f7a9f694Ssm26363 if (header.qr || ancount > 0) {
192f7a9f694Ssm26363 (void) snprintf(get_line(0, 0), get_line_remain(),
193f7a9f694Ssm26363 "%d answer(s)", ancount);
194f7a9f694Ssm26363 count = 0;
195f7a9f694Ssm26363 while (ancount--) {
196f7a9f694Ssm26363 if (rrp >= data_end) {
197f7a9f694Ssm26363 return;
198f7a9f694Ssm26363 }
199f7a9f694Ssm26363 count++;
200f7a9f694Ssm26363 rrp += print_answer(get_line(0, 0),
201f7a9f694Ssm26363 data, rrp, data_end, TRUE);
202f7a9f694Ssm26363 show_space();
203f7a9f694Ssm26363 }
204f7a9f694Ssm26363 }
205f7a9f694Ssm26363 /* Likewise only answers should hold NS records */
206f7a9f694Ssm26363 if (header.qr || nscount > 0) {
207f7a9f694Ssm26363 (void) snprintf(get_line(0, 0), get_line_remain(),
208f7a9f694Ssm26363 "%d name server resource(s)", nscount);
209f7a9f694Ssm26363 count = 0;
210f7a9f694Ssm26363 while (nscount--) {
211f7a9f694Ssm26363 if (rrp >= data_end) {
212f7a9f694Ssm26363 return;
213f7a9f694Ssm26363 }
214f7a9f694Ssm26363 count++;
215f7a9f694Ssm26363 rrp += print_answer(get_line(0, 0), data,
216f7a9f694Ssm26363 rrp, data_end, TRUE);
217f7a9f694Ssm26363 show_space();
218f7a9f694Ssm26363 }
219f7a9f694Ssm26363 }
220f7a9f694Ssm26363 /* Additional section may hold an EDNS0 record. */
221f7a9f694Ssm26363 if (header.qr || arcount > 0) {
222f7a9f694Ssm26363 (void) snprintf(get_line(0, 0), get_line_remain(),
223f7a9f694Ssm26363 "%d additional record(s)", arcount);
224f7a9f694Ssm26363 count = 0;
225f7a9f694Ssm26363 while (arcount-- && rrp < data_end) {
226f7a9f694Ssm26363 count++;
227f7a9f694Ssm26363 rrp += print_answer(get_line(0, 0), data,
228f7a9f694Ssm26363 rrp, data_end, TRUE);
2297c478bd9Sstevel@tonic-gate show_space();
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate
2367c478bd9Sstevel@tonic-gate static char *
dns_opcode_string(uint_t opcode)2377c478bd9Sstevel@tonic-gate dns_opcode_string(uint_t opcode)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate static char buffer[64];
2407c478bd9Sstevel@tonic-gate switch (opcode) {
2417c478bd9Sstevel@tonic-gate case ns_o_query: return ("Query");
2427c478bd9Sstevel@tonic-gate case ns_o_iquery: return ("Inverse Query");
2437c478bd9Sstevel@tonic-gate case ns_o_status: return ("Status");
2447c478bd9Sstevel@tonic-gate default:
2457c478bd9Sstevel@tonic-gate (void) snprintf(buffer, sizeof (buffer), "Unknown (%u)",
2467c478bd9Sstevel@tonic-gate opcode);
2477c478bd9Sstevel@tonic-gate return (buffer);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate static char *
dns_rcode_string(uint_t rcode)2527c478bd9Sstevel@tonic-gate dns_rcode_string(uint_t rcode)
2537c478bd9Sstevel@tonic-gate {
2547c478bd9Sstevel@tonic-gate static char buffer[64];
2557c478bd9Sstevel@tonic-gate switch (rcode) {
2567c478bd9Sstevel@tonic-gate case ns_r_noerror: return ("OK");
2577c478bd9Sstevel@tonic-gate case ns_r_formerr: return ("Format Error");
2587c478bd9Sstevel@tonic-gate case ns_r_servfail: return ("Server Fail");
2597c478bd9Sstevel@tonic-gate case ns_r_nxdomain: return ("Name Error");
2607c478bd9Sstevel@tonic-gate case ns_r_notimpl: return ("Unimplemented");
2617c478bd9Sstevel@tonic-gate case ns_r_refused: return ("Refused");
262f7a9f694Ssm26363 case ns_r_badvers: return ("Bad Version"); /* EDNS rcode */
2637c478bd9Sstevel@tonic-gate default:
2647c478bd9Sstevel@tonic-gate (void) snprintf(buffer, sizeof (buffer), "Unknown (%u)", rcode);
2657c478bd9Sstevel@tonic-gate return (buffer);
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate static char *
dns_type_string(uint_t type,int detail)2707c478bd9Sstevel@tonic-gate dns_type_string(uint_t type, int detail)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate static char buffer[64];
2737c478bd9Sstevel@tonic-gate switch (type) {
274*ffe0b5faSSebastian Wiedenroth case ns_t_a: return (detail ? "Address" : "A");
2757c478bd9Sstevel@tonic-gate case ns_t_ns: return (detail ? "Authoritative Name Server" : "NS");
2767c478bd9Sstevel@tonic-gate case ns_t_cname: return (detail ? "Canonical Name" : "CNAME");
2777c478bd9Sstevel@tonic-gate case ns_t_soa: return (detail ? "Start Of a zone Authority" : "SOA");
2787c478bd9Sstevel@tonic-gate case ns_t_mb: return (detail ? "Mailbox domain name" : "MB");
2797c478bd9Sstevel@tonic-gate case ns_t_mg: return (detail ? "Mailbox Group member" : "MG");
2807c478bd9Sstevel@tonic-gate case ns_t_mr: return (detail ? "Mail Rename domain name" : "MR");
2817c478bd9Sstevel@tonic-gate case ns_t_null: return ("NULL");
2827c478bd9Sstevel@tonic-gate case ns_t_wks: return (detail ? "Well Known Service" : "WKS");
2837c478bd9Sstevel@tonic-gate case ns_t_ptr: return (detail ? "Domain Name Pointer" : "PTR");
2847c478bd9Sstevel@tonic-gate case ns_t_hinfo: return (detail ? "Host Information": "HINFO");
2857c478bd9Sstevel@tonic-gate case ns_t_minfo:
2867c478bd9Sstevel@tonic-gate return (detail ? "Mailbox or maillist Info" : "MINFO");
2877c478bd9Sstevel@tonic-gate case ns_t_mx: return (detail ? "Mail Exchange" : "MX");
2887c478bd9Sstevel@tonic-gate case ns_t_txt: return (detail ? "Text strings" : "TXT");
2897c478bd9Sstevel@tonic-gate case ns_t_aaaa: return (detail ? "IPv6 Address" : "AAAA");
290*ffe0b5faSSebastian Wiedenroth case ns_t_loc: return (detail ? "Location Information" : "LOC");
291*ffe0b5faSSebastian Wiedenroth case ns_t_srv: return (detail ? "Server Selection" : "SRV");
292*ffe0b5faSSebastian Wiedenroth case ns_t_naptr:
293*ffe0b5faSSebastian Wiedenroth return (detail ? "Naming Authority Pointer" : "NAPTR");
294f7a9f694Ssm26363 case ns_t_opt: return (detail ? "EDNS0 option" : "OPT");
295*ffe0b5faSSebastian Wiedenroth case ns_t_cert: return (detail ? "Certificate record" : "CERT");
296*ffe0b5faSSebastian Wiedenroth case ns_t_sshfp:
297*ffe0b5faSSebastian Wiedenroth return (detail ? "SSH Fingerprint" : "SSHFP");
298*ffe0b5faSSebastian Wiedenroth case ns_t_ipseckey:
299*ffe0b5faSSebastian Wiedenroth return (detail ? "IPsec Key" : "IPSECKEY");
300*ffe0b5faSSebastian Wiedenroth case ns_t_rrsig:
301*ffe0b5faSSebastian Wiedenroth return (detail ? "DNSSEC signature" : "RRSIG");
302*ffe0b5faSSebastian Wiedenroth case ns_t_nsec: return (detail ? "Next Secure record" : "NSEC");
303*ffe0b5faSSebastian Wiedenroth case ns_t_dnskey:
304*ffe0b5faSSebastian Wiedenroth return (detail ? "DNS Key record" : "DNSKEY");
305*ffe0b5faSSebastian Wiedenroth case ns_t_dhcid:
306*ffe0b5faSSebastian Wiedenroth return (detail ? "DHCP identifier" : "DHCID");
307*ffe0b5faSSebastian Wiedenroth case ns_t_nsec3:
308*ffe0b5faSSebastian Wiedenroth return (detail ? "NSEC3 record" : "NSEC3");
309*ffe0b5faSSebastian Wiedenroth case ns_t_nsec3param:
310*ffe0b5faSSebastian Wiedenroth return (detail ? "NSEC3 parameter" : "NSEC3PARAM");
311*ffe0b5faSSebastian Wiedenroth case ns_t_tlsa:
312*ffe0b5faSSebastian Wiedenroth return (detail ? "TLSA certificate association" : "TLSA");
313*ffe0b5faSSebastian Wiedenroth case ns_t_smimea:
314*ffe0b5faSSebastian Wiedenroth return (detail ? "S/MIME cert association" : "SMIMEA");
315*ffe0b5faSSebastian Wiedenroth case ns_t_hip: return (detail ? "Host Identity record" : "HIP");
316*ffe0b5faSSebastian Wiedenroth case ns_t_cds: return (detail ? "Child DS" : "CDS");
317*ffe0b5faSSebastian Wiedenroth case ns_t_cdnskey:
318*ffe0b5faSSebastian Wiedenroth return (detail ? "Child copy of DNSKEY record" : "CDNSKEY");
319*ffe0b5faSSebastian Wiedenroth case ns_t_openpgpkey:
320*ffe0b5faSSebastian Wiedenroth return (detail ? "OpenPGP public key record" : "OPENPGPKEY");
321*ffe0b5faSSebastian Wiedenroth case ns_t_csync:
322*ffe0b5faSSebastian Wiedenroth return (detail ? "Child-to-Parent Synchronization" : "CSYNC");
323*ffe0b5faSSebastian Wiedenroth case ns_t_caa:
324*ffe0b5faSSebastian Wiedenroth return (detail ? "Certification Authority Restriction" : "CAA");
3257c478bd9Sstevel@tonic-gate case ns_t_axfr: return (detail ? "Transfer of entire zone" : "AXFR");
3267c478bd9Sstevel@tonic-gate case ns_t_mailb:
3277c478bd9Sstevel@tonic-gate return (detail ? "Mailbox related records" : "MAILB");
3287c478bd9Sstevel@tonic-gate case ns_t_maila: return (detail ? "Mail agent RRs" : "MAILA");
3297c478bd9Sstevel@tonic-gate case ns_t_any: return (detail ? "All records" : "*");
3307c478bd9Sstevel@tonic-gate default:
3317c478bd9Sstevel@tonic-gate (void) snprintf(buffer, sizeof (buffer), "Unknown (%u)", type);
3327c478bd9Sstevel@tonic-gate return (buffer);
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate static char *
dns_class_string(uint_t cls,int detail)3377c478bd9Sstevel@tonic-gate dns_class_string(uint_t cls, int detail)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate static char buffer[64];
3407c478bd9Sstevel@tonic-gate switch (cls) {
341*ffe0b5faSSebastian Wiedenroth case ns_c_in: return (detail ? "Internet" : "IN");
3427c478bd9Sstevel@tonic-gate case ns_c_chaos: return (detail ? "CHAOS" : "CH");
3437c478bd9Sstevel@tonic-gate case ns_c_hs: return (detail ? "Hesiod" : "HS");
3447c478bd9Sstevel@tonic-gate case ns_c_any: return (detail ? "* (Any class)" : "*");
3457c478bd9Sstevel@tonic-gate default:
3467c478bd9Sstevel@tonic-gate (void) snprintf(buffer, sizeof (buffer), "Unknown (%u)", cls);
3477c478bd9Sstevel@tonic-gate return (buffer);
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate static size_t
skip_question(const uchar_t * header,const uchar_t * data,const uchar_t * data_end)3527c478bd9Sstevel@tonic-gate skip_question(const uchar_t *header, const uchar_t *data,
3537c478bd9Sstevel@tonic-gate const uchar_t *data_end)
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate const uchar_t *data_bak = data;
3567c478bd9Sstevel@tonic-gate char dummy_buffer[NS_MAXDNAME];
3577c478bd9Sstevel@tonic-gate
3587c478bd9Sstevel@tonic-gate data = get_domain_name(header, data, data_end, dummy_buffer,
3597c478bd9Sstevel@tonic-gate dummy_buffer + sizeof (dummy_buffer));
3607c478bd9Sstevel@tonic-gate /* Skip the 32 bits of class and type that follow the domain name */
3617c478bd9Sstevel@tonic-gate data += sizeof (uint32_t);
3627c478bd9Sstevel@tonic-gate return (data - data_bak);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate static size_t
print_question(char * line,const uchar_t * header,const uchar_t * data,const uchar_t * data_end,int detail)3667c478bd9Sstevel@tonic-gate print_question(char *line, const uchar_t *header, const uchar_t *data,
3677c478bd9Sstevel@tonic-gate const uchar_t *data_end, int detail)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate const uchar_t *data_bak = data;
3707c478bd9Sstevel@tonic-gate uint16_t type;
3717c478bd9Sstevel@tonic-gate uint16_t cls;
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate if (detail) {
3747c478bd9Sstevel@tonic-gate line += snprintf(line, get_line_remain(),
3757c478bd9Sstevel@tonic-gate DNS_INDENT "Domain Name: ");
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate data += print_domain_name(line, header, data, data_end);
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate * Make sure we don't run off the end of the packet by reading the
3817c478bd9Sstevel@tonic-gate * type and class.
3827c478bd9Sstevel@tonic-gate *
3837c478bd9Sstevel@tonic-gate * The pointer subtraction on the left side of the following
3847c478bd9Sstevel@tonic-gate * expression has a signed result of type ptrdiff_t, and the right
3857c478bd9Sstevel@tonic-gate * side has an unsigned result of type size_t. We therefore need
3867c478bd9Sstevel@tonic-gate * to cast the right side of the expression to be of the same
3877c478bd9Sstevel@tonic-gate * signed type to keep the result of the pointer arithmetic to be
3887c478bd9Sstevel@tonic-gate * automatically cast to an unsigned value. We do a similar cast
3897c478bd9Sstevel@tonic-gate * in other similar expressions throughout this file.
3907c478bd9Sstevel@tonic-gate */
3917c478bd9Sstevel@tonic-gate if ((data_end - data) < (ptrdiff_t)(2 * sizeof (uint16_t)))
3927c478bd9Sstevel@tonic-gate return (data_end - data_bak);
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate GETINT16(type, data);
3957c478bd9Sstevel@tonic-gate GETINT16(cls, data);
3967c478bd9Sstevel@tonic-gate
3974b22b933Srs200217 /*
3984b22b933Srs200217 * Multicast DNS re-uses the top bit of the class field
3994b22b933Srs200217 * in the question and answer sections. Unicast DNS only
4004b22b933Srs200217 * uses 1 (Internet), 3 and 4. Hence it is safe. The top
4014b22b933Srs200217 * order bit is always cleared here to display the rrclass in case
4024b22b933Srs200217 * of Multicast DNS packets.
4034b22b933Srs200217 */
4044b22b933Srs200217 cls = cls & 0x7fff;
4054b22b933Srs200217
4067c478bd9Sstevel@tonic-gate if (detail) {
4077c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4087c478bd9Sstevel@tonic-gate DNS_INDENT "Class: %u (%s)",
4097c478bd9Sstevel@tonic-gate cls, dns_class_string(cls, detail));
4107c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
4117c478bd9Sstevel@tonic-gate DNS_INDENT "Type: %u (%s)", type,
4127c478bd9Sstevel@tonic-gate dns_type_string(type, detail));
4137c478bd9Sstevel@tonic-gate } else {
4147c478bd9Sstevel@tonic-gate (void) sprintf(line + strlen(line), " %s %s \?",
4157c478bd9Sstevel@tonic-gate dns_class_string(cls, detail),
4167c478bd9Sstevel@tonic-gate dns_type_string(type, detail));
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate return (data - data_bak);
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate
421f7a9f694Ssm26363 /*
422f7a9f694Ssm26363 * print_answer() is used to display the contents of a single resource
423f7a9f694Ssm26363 * record (RR) from either the answer, name server or additional
424f7a9f694Ssm26363 * section of the DNS packet.
425f7a9f694Ssm26363 *
426f7a9f694Ssm26363 * Input:
427f7a9f694Ssm26363 * *line: snoops output buffer.
428f7a9f694Ssm26363 * *header: start of the DNS packet, required for names and rcode.
429f7a9f694Ssm26363 * *data: location within header from where the RR starts.
430f7a9f694Ssm26363 * *data_end: where DNS data ends.
431f7a9f694Ssm26363 * detail: simple or verbose output.
432f7a9f694Ssm26363 *
433f7a9f694Ssm26363 * Returns:
434f7a9f694Ssm26363 * Pointer to next RR or data_end.
435f7a9f694Ssm26363 *
436f7a9f694Ssm26363 * Most RRs have the same top level format as defined in RFC 1035:
437f7a9f694Ssm26363 *
438f7a9f694Ssm26363 * 1 1 1 1 1 1
439f7a9f694Ssm26363 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
440f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
441f7a9f694Ssm26363 * | |
442f7a9f694Ssm26363 * / NAME /
443f7a9f694Ssm26363 * | |
444f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
445f7a9f694Ssm26363 * | TYPE |
446f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
447f7a9f694Ssm26363 * | CLASS |
448f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
449f7a9f694Ssm26363 * | TTL |
450f7a9f694Ssm26363 * | |
451f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
452f7a9f694Ssm26363 * | RDLENGTH |
453f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
454f7a9f694Ssm26363 * / RDATA /
455f7a9f694Ssm26363 * / /
456f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
457f7a9f694Ssm26363 *
458f7a9f694Ssm26363 * However RFC 2671 introduced an exception to this rule
459f7a9f694Ssm26363 * with the "Extension Mechanisms for DNS" (EDNS0).
460f7a9f694Ssm26363 * When the type is 41 the remaining resource record format
461f7a9f694Ssm26363 * is:
462f7a9f694Ssm26363 *
463f7a9f694Ssm26363 * 1 1 1 1 1 1
464f7a9f694Ssm26363 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
465f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
466f7a9f694Ssm26363 * | TYPE = 41 |
467f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
468f7a9f694Ssm26363 * | Sender's UDP payload size |
469f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
470f7a9f694Ssm26363 * | Extended-rcode | Version |
471f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
472f7a9f694Ssm26363 * | Zero |
473f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
474f7a9f694Ssm26363 * | RDLENGTH |
475f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
476f7a9f694Ssm26363 * / RDATA /
477f7a9f694Ssm26363 * / /
478f7a9f694Ssm26363 * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
479f7a9f694Ssm26363 *
480f7a9f694Ssm26363 */
4817c478bd9Sstevel@tonic-gate static size_t
print_answer(char * line,const uchar_t * header,const uchar_t * data,const uchar_t * data_end,int detail)4827c478bd9Sstevel@tonic-gate print_answer(char *line, const uchar_t *header, const uchar_t *data,
4837c478bd9Sstevel@tonic-gate const uchar_t *data_end, int detail)
4847c478bd9Sstevel@tonic-gate {
4857c478bd9Sstevel@tonic-gate const uchar_t *data_bak = data;
4867c478bd9Sstevel@tonic-gate const uchar_t *data_next;
4877c478bd9Sstevel@tonic-gate uint16_t type;
4887c478bd9Sstevel@tonic-gate uint16_t cls;
4897c478bd9Sstevel@tonic-gate int32_t ttl;
4907c478bd9Sstevel@tonic-gate uint16_t rdlen;
4917c478bd9Sstevel@tonic-gate uint32_t serial, refresh, retry, expire, minimum;
4927c478bd9Sstevel@tonic-gate uint8_t protocol;
4937c478bd9Sstevel@tonic-gate int linepos;
4947c478bd9Sstevel@tonic-gate uint16_t preference;
495f7a9f694Ssm26363 /* declarations for EDNS follow */
496f7a9f694Ssm26363 uint16_t size; /* Sender's UDP payload size */
497f7a9f694Ssm26363 uint8_t xrcode; /* Extended-rcode */
498f7a9f694Ssm26363 uint8_t ver; /* Version */
499f7a9f694Ssm26363 uint16_t rcode; /* Extracted from the DNS header */
500f7a9f694Ssm26363 union { /* DNS header overlay used for extraction */
501f7a9f694Ssm26363 HEADER *head;
502f7a9f694Ssm26363 const uchar_t *raw;
503f7a9f694Ssm26363 } headptr;
5047c478bd9Sstevel@tonic-gate
5057c478bd9Sstevel@tonic-gate if (detail) {
5067c478bd9Sstevel@tonic-gate line += snprintf(line, get_line_remain(),
5077c478bd9Sstevel@tonic-gate DNS_INDENT "Domain Name: ");
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate data += print_domain_name(line, header, data, data_end);
5107c478bd9Sstevel@tonic-gate
5117c478bd9Sstevel@tonic-gate /*
512f7a9f694Ssm26363 * Next, get the record type, being careful to make sure we
513f7a9f694Ssm26363 * don't run off the end of the packet.
5147c478bd9Sstevel@tonic-gate */
515f7a9f694Ssm26363 if ((data_end - data) < (ptrdiff_t)(sizeof (type))) {
5167c478bd9Sstevel@tonic-gate return (data_end - data_bak);
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate
5197c478bd9Sstevel@tonic-gate GETINT16(type, data);
520f7a9f694Ssm26363
521f7a9f694Ssm26363 if (type == ns_t_opt) {
522f7a9f694Ssm26363 /*
523f7a9f694Ssm26363 * Make sure we won't run off the end reading size,
524f7a9f694Ssm26363 * xrcode, version, zero and rdlen.
525f7a9f694Ssm26363 */
526f7a9f694Ssm26363 if ((data_end - data) <
527f7a9f694Ssm26363 ((ptrdiff_t)(sizeof (size)
528f7a9f694Ssm26363 + sizeof (xrcode)
529f7a9f694Ssm26363 + sizeof (ver)
530f7a9f694Ssm26363 + sizeof (cls) /* zero */
531f7a9f694Ssm26363 + sizeof (rdlen)))) {
532f7a9f694Ssm26363 return (data_end - data_bak);
533f7a9f694Ssm26363 }
534f7a9f694Ssm26363
535f7a9f694Ssm26363 GETINT16(size, data);
536f7a9f694Ssm26363 GETINT8(xrcode, data);
537f7a9f694Ssm26363 /*
538f7a9f694Ssm26363 * The extended rcode represents the top half of the
539f7a9f694Ssm26363 * rcode which must be added to the rcode in the header.
540f7a9f694Ssm26363 */
541f7a9f694Ssm26363 rcode = 0xff & (xrcode << 4);
542f7a9f694Ssm26363 headptr.raw = header; /* Overlay the header... */
543f7a9f694Ssm26363 rcode += headptr.head->rcode; /* And pluck out the rcode. */
544f7a9f694Ssm26363
545f7a9f694Ssm26363 GETINT8(ver, data);
546f7a9f694Ssm26363 GETINT16(cls, data); /* zero */
547f7a9f694Ssm26363 GETINT16(rdlen, data);
548f7a9f694Ssm26363
549f7a9f694Ssm26363 if (detail) {
550f7a9f694Ssm26363 (void) snprintf(get_line(0, 0), get_line_remain(),
551f7a9f694Ssm26363 DNS_INDENT "Type: %u (%s)", type,
552f7a9f694Ssm26363 dns_type_string(type, detail));
553f7a9f694Ssm26363 (void) snprintf(get_line(0, 0), get_line_remain(),
554f7a9f694Ssm26363 DNS_INDENT "UDP payload size: %u (0x%.4x)",
555f7a9f694Ssm26363 size, size);
556f7a9f694Ssm26363 (void) snprintf(get_line(0, 0), get_line_remain(),
557f7a9f694Ssm26363 DNS_INDENT "Extended rcode: %u "
558f7a9f694Ssm26363 "(translates to %u (%s))",
559f7a9f694Ssm26363 xrcode, rcode, dns_rcode_string(rcode));
560f7a9f694Ssm26363 (void) snprintf(get_line(0, 0), get_line_remain(),
561f7a9f694Ssm26363 DNS_INDENT "EDNS0 Version: %u", ver);
562f7a9f694Ssm26363 (void) snprintf(get_line(0, 0), get_line_remain(),
563f7a9f694Ssm26363 DNS_INDENT "zero: %u", cls);
564f7a9f694Ssm26363 (void) snprintf(get_line(0, 0), get_line_remain(),
565f7a9f694Ssm26363 DNS_INDENT "Data length: %u", rdlen);
566f7a9f694Ssm26363 } else {
567f7a9f694Ssm26363 line += strlen(line);
568f7a9f694Ssm26363 line += sprintf(line, " %s UDP %u rc %d ver %u len %u",
569f7a9f694Ssm26363 dns_type_string(type, detail), size, rcode, ver,
570f7a9f694Ssm26363 rdlen);
571f7a9f694Ssm26363 }
572f7a9f694Ssm26363
573f7a9f694Ssm26363 /*
574f7a9f694Ssm26363 * Make sure that rdlen is within data boundary.
575f7a9f694Ssm26363 */
576f7a9f694Ssm26363 if (rdlen > data_end - data)
577f7a9f694Ssm26363 return (data_end - data_bak);
578f7a9f694Ssm26363
579f7a9f694Ssm26363 /* Future OPT decode code goes here. */
580f7a9f694Ssm26363
581f7a9f694Ssm26363 data += rdlen;
582f7a9f694Ssm26363 return (data - data_bak);
583f7a9f694Ssm26363 }
584f7a9f694Ssm26363
585f7a9f694Ssm26363 /*
586f7a9f694Ssm26363 * Make sure we don't run off the end of the packet by reading the
587f7a9f694Ssm26363 * class, ttl, and length.
588f7a9f694Ssm26363 */
589f7a9f694Ssm26363 if ((data_end - data) <
590f7a9f694Ssm26363 ((ptrdiff_t)(sizeof (cls)
591f7a9f694Ssm26363 + sizeof (ttl)
592f7a9f694Ssm26363 + sizeof (rdlen)))) {
593f7a9f694Ssm26363 return (data_end - data_bak);
594f7a9f694Ssm26363 }
595f7a9f694Ssm26363
5967c478bd9Sstevel@tonic-gate GETINT16(cls, data);
5977c478bd9Sstevel@tonic-gate
5984b22b933Srs200217 /*
5994b22b933Srs200217 * Multicast DNS re-uses the top bit of the class field
6004b22b933Srs200217 * in the question and answer sections. Unicast DNS only
6014b22b933Srs200217 * uses 1 (Internet), 3 and 4. Hence it is safe. The top
6024b22b933Srs200217 * order bit is always cleared here to display the rrclass in case
6034b22b933Srs200217 * of Multicast DNS packets.
6044b22b933Srs200217 */
6054b22b933Srs200217 cls = cls & 0x7fff;
6064b22b933Srs200217
6077c478bd9Sstevel@tonic-gate if (detail) {
6087c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
6097c478bd9Sstevel@tonic-gate DNS_INDENT "Class: %d (%s)", cls,
6107c478bd9Sstevel@tonic-gate dns_class_string(cls, detail));
6117c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
6127c478bd9Sstevel@tonic-gate DNS_INDENT "Type: %d (%s)", type,
6137c478bd9Sstevel@tonic-gate dns_type_string(type, detail));
6147c478bd9Sstevel@tonic-gate } else {
6157c478bd9Sstevel@tonic-gate line += strlen(line);
6167c478bd9Sstevel@tonic-gate line += sprintf(line, " %s %s ",
6177c478bd9Sstevel@tonic-gate dns_class_string(cls, detail),
6187c478bd9Sstevel@tonic-gate dns_type_string(type, detail));
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate
6217c478bd9Sstevel@tonic-gate GETINT32(ttl, data);
6227c478bd9Sstevel@tonic-gate if (detail) {
6237c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
6247c478bd9Sstevel@tonic-gate DNS_INDENT "TTL (Time To Live): %d", ttl);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate GETINT16(rdlen, data);
6287c478bd9Sstevel@tonic-gate if (detail) {
6297c478bd9Sstevel@tonic-gate line = get_line(0, 0);
6307c478bd9Sstevel@tonic-gate line += snprintf(line, get_line_remain(), DNS_INDENT "%s: ",
6317c478bd9Sstevel@tonic-gate dns_type_string(type, detail));
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate if (rdlen > data_end - data)
6357c478bd9Sstevel@tonic-gate return (data_end - data_bak);
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate switch (type) {
6387c478bd9Sstevel@tonic-gate case ns_t_a:
6397c478bd9Sstevel@tonic-gate print_ip(AF_INET, line, data, rdlen);
6407c478bd9Sstevel@tonic-gate break;
6417c478bd9Sstevel@tonic-gate case ns_t_aaaa:
6427c478bd9Sstevel@tonic-gate print_ip(AF_INET6, line, data, rdlen);
6437c478bd9Sstevel@tonic-gate break;
6447c478bd9Sstevel@tonic-gate case ns_t_hinfo:
6457c478bd9Sstevel@tonic-gate line += sprintf(line, "CPU: ");
6467c478bd9Sstevel@tonic-gate data_next = data + print_char_string(line, data, rdlen);
6477c478bd9Sstevel@tonic-gate if (data_next >= data_end)
6487c478bd9Sstevel@tonic-gate break;
6497c478bd9Sstevel@tonic-gate line += strlen(line);
6507c478bd9Sstevel@tonic-gate line += sprintf(line, "OS: ");
6517c478bd9Sstevel@tonic-gate (void) print_char_string(line, data_next,
6527c478bd9Sstevel@tonic-gate rdlen - (data_next - data));
6537c478bd9Sstevel@tonic-gate break;
6547c478bd9Sstevel@tonic-gate case ns_t_ns:
6557c478bd9Sstevel@tonic-gate case ns_t_cname:
6567c478bd9Sstevel@tonic-gate case ns_t_mb:
6577c478bd9Sstevel@tonic-gate case ns_t_mg:
6587c478bd9Sstevel@tonic-gate case ns_t_mr:
6597c478bd9Sstevel@tonic-gate case ns_t_ptr:
6607c478bd9Sstevel@tonic-gate (void) print_domain_name(line, header, data, data_end);
6617c478bd9Sstevel@tonic-gate break;
6627c478bd9Sstevel@tonic-gate case ns_t_mx:
6637c478bd9Sstevel@tonic-gate data_next = data;
6647c478bd9Sstevel@tonic-gate if (rdlen < sizeof (uint16_t))
6657c478bd9Sstevel@tonic-gate break;
6667c478bd9Sstevel@tonic-gate GETINT16(preference, data_next);
6677c478bd9Sstevel@tonic-gate if (detail) {
6687c478bd9Sstevel@tonic-gate (void) print_domain_name(line, header, data_next,
6697c478bd9Sstevel@tonic-gate data_end);
6707c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
6717c478bd9Sstevel@tonic-gate DNS_INDENT "Preference: %u", preference);
6727c478bd9Sstevel@tonic-gate } else {
6737c478bd9Sstevel@tonic-gate (void) print_domain_name(line, header, data_next,
6747c478bd9Sstevel@tonic-gate data_end);
6757c478bd9Sstevel@tonic-gate }
6767c478bd9Sstevel@tonic-gate break;
6777c478bd9Sstevel@tonic-gate case ns_t_soa:
6787c478bd9Sstevel@tonic-gate if (!detail)
6797c478bd9Sstevel@tonic-gate break;
6807c478bd9Sstevel@tonic-gate line = get_line(0, 0);
6817c478bd9Sstevel@tonic-gate line += snprintf(line, get_line_remain(),
6827c478bd9Sstevel@tonic-gate DNS_INDENT "MNAME (Server name): ");
6837c478bd9Sstevel@tonic-gate data_next = data + print_domain_name(line, header, data,
6847c478bd9Sstevel@tonic-gate data_end);
6857c478bd9Sstevel@tonic-gate if (data_next >= data_end)
6867c478bd9Sstevel@tonic-gate break;
6877c478bd9Sstevel@tonic-gate line = get_line(0, 0);
6887c478bd9Sstevel@tonic-gate line += snprintf(line, get_line_remain(),
6897c478bd9Sstevel@tonic-gate DNS_INDENT "RNAME (Resposible mailbox): ");
6907c478bd9Sstevel@tonic-gate data_next = data_next +
6917c478bd9Sstevel@tonic-gate print_domain_name(line, header, data_next, data_end);
6927c478bd9Sstevel@tonic-gate if ((data_end - data_next) < (ptrdiff_t)(5 * sizeof (uint32_t)))
6937c478bd9Sstevel@tonic-gate break;
6947c478bd9Sstevel@tonic-gate GETINT32(serial, data_next);
6957c478bd9Sstevel@tonic-gate GETINT32(refresh, data_next);
6967c478bd9Sstevel@tonic-gate GETINT32(retry, data_next);
6977c478bd9Sstevel@tonic-gate GETINT32(expire, data_next);
6987c478bd9Sstevel@tonic-gate GETINT32(minimum, data_next);
6997c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7007c478bd9Sstevel@tonic-gate DNS_INDENT "Serial: %u", serial);
7017c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7027c478bd9Sstevel@tonic-gate DNS_INDENT "Refresh: %u Retry: %u "
7037c478bd9Sstevel@tonic-gate "Expire: %u Minimum: %u",
7047c478bd9Sstevel@tonic-gate refresh, retry, expire, minimum);
7057c478bd9Sstevel@tonic-gate break;
7067c478bd9Sstevel@tonic-gate case ns_t_wks:
7077c478bd9Sstevel@tonic-gate print_ip(AF_INET, line, data, rdlen);
7087c478bd9Sstevel@tonic-gate if (!detail)
7097c478bd9Sstevel@tonic-gate break;
7107c478bd9Sstevel@tonic-gate data_next = data + sizeof (in_addr_t);
7117c478bd9Sstevel@tonic-gate if (data_next >= data_end)
7127c478bd9Sstevel@tonic-gate break;
7137c478bd9Sstevel@tonic-gate GETINT8(protocol, data_next);
7147c478bd9Sstevel@tonic-gate line = get_line(0, 0);
7157c478bd9Sstevel@tonic-gate line += snprintf(line, get_line_remain(),
7167c478bd9Sstevel@tonic-gate DNS_INDENT "Protocol: %u ", protocol);
7177c478bd9Sstevel@tonic-gate switch (protocol) {
7187c478bd9Sstevel@tonic-gate case IPPROTO_UDP:
7197c478bd9Sstevel@tonic-gate (void) snprintf(line, get_line_remain(), "(UDP)");
7207c478bd9Sstevel@tonic-gate break;
7217c478bd9Sstevel@tonic-gate case IPPROTO_TCP:
7227c478bd9Sstevel@tonic-gate (void) snprintf(line, get_line_remain(), "(TCP)");
7237c478bd9Sstevel@tonic-gate break;
7247c478bd9Sstevel@tonic-gate }
7257c478bd9Sstevel@tonic-gate (void) snprintf(get_line(0, 0), get_line_remain(),
7267c478bd9Sstevel@tonic-gate DNS_INDENT "Service bitmap:");
7277c478bd9Sstevel@tonic-gate (void) snprintf(line, get_line_remain(),
7287c478bd9Sstevel@tonic-gate DNS_INDENT "0 8 16 24");
7297c478bd9Sstevel@tonic-gate linepos = 4;
7307c478bd9Sstevel@tonic-gate while (data_next < data + rdlen) {
7317c478bd9Sstevel@tonic-gate if (linepos == 4) {
7327c478bd9Sstevel@tonic-gate line = get_line(0, 0);
7337c478bd9Sstevel@tonic-gate line += snprintf(line, get_line_remain(),
7347c478bd9Sstevel@tonic-gate DNS_INDENT);
7357c478bd9Sstevel@tonic-gate linepos = 0;
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate line += snprintf(line, get_line_remain(), "%s",
7387c478bd9Sstevel@tonic-gate binary_string(*data_next));
7397c478bd9Sstevel@tonic-gate linepos++;
7407c478bd9Sstevel@tonic-gate data_next++;
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate break;
7437c478bd9Sstevel@tonic-gate case ns_t_minfo:
7447c478bd9Sstevel@tonic-gate if (!detail)
7457c478bd9Sstevel@tonic-gate break;
7467c478bd9Sstevel@tonic-gate line = get_line(0, 0);
7477c478bd9Sstevel@tonic-gate line += snprintf(line, get_line_remain(),
7487c478bd9Sstevel@tonic-gate DNS_INDENT "RMAILBX (Resposible mailbox): ");
7497c478bd9Sstevel@tonic-gate data_next = data + print_domain_name(line, header, data,
7507c478bd9Sstevel@tonic-gate data_end);
7517c478bd9Sstevel@tonic-gate line = get_line(0, 0);
7527c478bd9Sstevel@tonic-gate line += snprintf(line, get_line_remain(),
7537c478bd9Sstevel@tonic-gate DNS_INDENT "EMAILBX (mailbox to receive err message): ");
7547c478bd9Sstevel@tonic-gate data_next = data_next + print_domain_name(line, header,
7557c478bd9Sstevel@tonic-gate data_next, data_end);
7567c478bd9Sstevel@tonic-gate break;
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate data += rdlen;
7597c478bd9Sstevel@tonic-gate return (data - data_bak);
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate
7627c478bd9Sstevel@tonic-gate static char *
binary_string(char data)7637c478bd9Sstevel@tonic-gate binary_string(char data)
7647c478bd9Sstevel@tonic-gate {
7657c478bd9Sstevel@tonic-gate static char bstring[8 + 1];
7667c478bd9Sstevel@tonic-gate char *ptr;
7677c478bd9Sstevel@tonic-gate int i;
7687c478bd9Sstevel@tonic-gate ptr = bstring;
7697c478bd9Sstevel@tonic-gate for (i = 0; i < 8; i++) {
7707c478bd9Sstevel@tonic-gate *ptr++ = (data & 0x80) ? '1' : '0';
7717c478bd9Sstevel@tonic-gate data = data << 1;
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate *ptr = (char)0;
7747c478bd9Sstevel@tonic-gate return (bstring);
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate static void
print_ip(int af,char * line,const uchar_t * data,uint16_t len)7787c478bd9Sstevel@tonic-gate print_ip(int af, char *line, const uchar_t *data, uint16_t len)
7797c478bd9Sstevel@tonic-gate {
7807c478bd9Sstevel@tonic-gate in6_addr_t addr6;
7817c478bd9Sstevel@tonic-gate in_addr_t addr4;
7827c478bd9Sstevel@tonic-gate void *addr;
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate switch (af) {
7857c478bd9Sstevel@tonic-gate case AF_INET:
7867c478bd9Sstevel@tonic-gate if (len != sizeof (in_addr_t))
7877c478bd9Sstevel@tonic-gate return;
7887c478bd9Sstevel@tonic-gate addr = memcpy(&addr4, data, sizeof (addr4));
7897c478bd9Sstevel@tonic-gate break;
7907c478bd9Sstevel@tonic-gate case AF_INET6:
7917c478bd9Sstevel@tonic-gate if (len != sizeof (in6_addr_t))
7927c478bd9Sstevel@tonic-gate return;
7937c478bd9Sstevel@tonic-gate addr = memcpy(&addr6, data, sizeof (addr6));
7947c478bd9Sstevel@tonic-gate break;
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate (void) inet_ntop(af, addr, line, INET6_ADDRSTRLEN);
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate
8007c478bd9Sstevel@tonic-gate /*
8017c478bd9Sstevel@tonic-gate * charbuf is assumed to be of size MAX_CHAR_STRING_SIZE.
8027c478bd9Sstevel@tonic-gate */
8037c478bd9Sstevel@tonic-gate static const uchar_t *
get_char_string(const uchar_t * data,char * charbuf,uint16_t datalen)8047c478bd9Sstevel@tonic-gate get_char_string(const uchar_t *data, char *charbuf, uint16_t datalen)
8057c478bd9Sstevel@tonic-gate {
8062e3b6467Skcpoon int len;
8077c478bd9Sstevel@tonic-gate char *name = charbuf;
8087c478bd9Sstevel@tonic-gate int i = 0;
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate /*
8117c478bd9Sstevel@tonic-gate * From RFC1035, a character-string is a single length octet followed
8127c478bd9Sstevel@tonic-gate * by that number of characters.
8137c478bd9Sstevel@tonic-gate */
8147c478bd9Sstevel@tonic-gate if (datalen > 1) {
8157c478bd9Sstevel@tonic-gate len = *data;
8167c478bd9Sstevel@tonic-gate data++;
8177c478bd9Sstevel@tonic-gate if (len > 0 && len < MAX_CHAR_STRING_SIZE) {
8187c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++, data++)
8197c478bd9Sstevel@tonic-gate name[i] = *data;
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate name[i] = '\0';
8237c478bd9Sstevel@tonic-gate return (data);
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate static size_t
print_char_string(char * line,const uchar_t * data,uint16_t len)8277c478bd9Sstevel@tonic-gate print_char_string(char *line, const uchar_t *data, uint16_t len)
8287c478bd9Sstevel@tonic-gate {
8297c478bd9Sstevel@tonic-gate char charbuf[MAX_CHAR_STRING_SIZE];
8307c478bd9Sstevel@tonic-gate const uchar_t *data_bak = data;
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate data = get_char_string(data, charbuf, len);
8337c478bd9Sstevel@tonic-gate (void) sprintf(line, "%s", charbuf);
8347c478bd9Sstevel@tonic-gate return (data - data_bak);
8357c478bd9Sstevel@tonic-gate }
8367c478bd9Sstevel@tonic-gate
8377c478bd9Sstevel@tonic-gate /*
8387c478bd9Sstevel@tonic-gate * header: the entire message header, this is where we start to
8397c478bd9Sstevel@tonic-gate * count the offset of the compression scheme
8407c478bd9Sstevel@tonic-gate * data: the start of the domain name
8417c478bd9Sstevel@tonic-gate * namebuf: user supplied buffer
8427c478bd9Sstevel@tonic-gate * return: the next byte after what we have parsed
8437c478bd9Sstevel@tonic-gate */
8447c478bd9Sstevel@tonic-gate static const uchar_t *
get_domain_name(const uchar_t * header,const uchar_t * data,const uchar_t * data_end,char * namebuf,char * namend)8457c478bd9Sstevel@tonic-gate get_domain_name(const uchar_t *header, const uchar_t *data,
8467c478bd9Sstevel@tonic-gate const uchar_t *data_end, char *namebuf, char *namend)
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate uint8_t len;
8497c478bd9Sstevel@tonic-gate char *name = namebuf;
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate /*
8527c478bd9Sstevel@tonic-gate * From RFC1035, a domain name is a sequence of labels, where each
8537c478bd9Sstevel@tonic-gate * label consists of a length octet followed by that number of
8547c478bd9Sstevel@tonic-gate * octets. The domain name terminates with the zero length octet
8557c478bd9Sstevel@tonic-gate * for the null label of the root.
8567c478bd9Sstevel@tonic-gate */
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate while (name < (namend - 1)) {
8597c478bd9Sstevel@tonic-gate if ((data_end - data) < (ptrdiff_t)(sizeof (uint8_t))) {
8607c478bd9Sstevel@tonic-gate /* The length octet is off the end of the packet. */
8617c478bd9Sstevel@tonic-gate break;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate GETINT8(len, data);
8647c478bd9Sstevel@tonic-gate if (len == 0) {
8657c478bd9Sstevel@tonic-gate /*
8667c478bd9Sstevel@tonic-gate * Domain names end with a length byte of zero,
8677c478bd9Sstevel@tonic-gate * which represents the null label of the root.
8687c478bd9Sstevel@tonic-gate */
8697c478bd9Sstevel@tonic-gate break;
8707c478bd9Sstevel@tonic-gate }
8717c478bd9Sstevel@tonic-gate /*
8727c478bd9Sstevel@tonic-gate * test if we are using the compression scheme
8737c478bd9Sstevel@tonic-gate */
8747c478bd9Sstevel@tonic-gate if ((len & 0xc0) == 0xc0) {
8757c478bd9Sstevel@tonic-gate uint16_t offset;
8767c478bd9Sstevel@tonic-gate const uchar_t *label_ptr;
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate /*
8797c478bd9Sstevel@tonic-gate * From RFC1035, message compression allows a
8807c478bd9Sstevel@tonic-gate * domain name or a list of labels at the end of a
8817c478bd9Sstevel@tonic-gate * domain name to be replaced with a pointer to a
8827c478bd9Sstevel@tonic-gate * prior occurance of the same name. In this
8837c478bd9Sstevel@tonic-gate * scheme, the pointer is a two octet sequence
8847c478bd9Sstevel@tonic-gate * where the most significant two bits are set, and
8857c478bd9Sstevel@tonic-gate * the remaining 14 bits are the offset from the
8867c478bd9Sstevel@tonic-gate * start of the message of the next label.
8877c478bd9Sstevel@tonic-gate */
8887c478bd9Sstevel@tonic-gate data--;
8897c478bd9Sstevel@tonic-gate if ((data_end - data) <
8907c478bd9Sstevel@tonic-gate (ptrdiff_t)(sizeof (uint16_t))) {
8917c478bd9Sstevel@tonic-gate /*
8927c478bd9Sstevel@tonic-gate * The offset octets aren't entirely
8937c478bd9Sstevel@tonic-gate * contained within this pakcet.
8947c478bd9Sstevel@tonic-gate */
8957c478bd9Sstevel@tonic-gate data = data_end;
8967c478bd9Sstevel@tonic-gate break;
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate GETINT16(offset, data);
8997c478bd9Sstevel@tonic-gate label_ptr = header + (offset & 0x3fff);
9007c478bd9Sstevel@tonic-gate /*
9017c478bd9Sstevel@tonic-gate * We must verify that the offset is valid by
9027c478bd9Sstevel@tonic-gate * checking that it is less than the current data
9037c478bd9Sstevel@tonic-gate * pointer and that it isn't off the end of the
9047c478bd9Sstevel@tonic-gate * packet.
9057c478bd9Sstevel@tonic-gate */
9067c478bd9Sstevel@tonic-gate if (label_ptr > data || label_ptr >= data_end)
9077c478bd9Sstevel@tonic-gate break;
9087c478bd9Sstevel@tonic-gate (void) get_domain_name(header, label_ptr, data_end,
9097c478bd9Sstevel@tonic-gate name, namend);
9107c478bd9Sstevel@tonic-gate return (data);
9117c478bd9Sstevel@tonic-gate } else {
9127c478bd9Sstevel@tonic-gate if (len > (data_end - data)) {
9137c478bd9Sstevel@tonic-gate /*
9147c478bd9Sstevel@tonic-gate * The label isn't entirely contained
9157c478bd9Sstevel@tonic-gate * within the packet. Don't read it. The
9167c478bd9Sstevel@tonic-gate * caller checks that the data pointer is
9177c478bd9Sstevel@tonic-gate * not beyond the end after we've
9187c478bd9Sstevel@tonic-gate * incremented it.
9197c478bd9Sstevel@tonic-gate */
9207c478bd9Sstevel@tonic-gate data = data_end;
9217c478bd9Sstevel@tonic-gate break;
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate while (len > 0 && name < (namend - 2)) {
9247c478bd9Sstevel@tonic-gate *name = *data;
9257c478bd9Sstevel@tonic-gate name++;
9267c478bd9Sstevel@tonic-gate data++;
9277c478bd9Sstevel@tonic-gate len--;
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate *name = '.';
9307c478bd9Sstevel@tonic-gate name++;
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate *name = '\0';
9347c478bd9Sstevel@tonic-gate return (data);
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate
9377c478bd9Sstevel@tonic-gate static size_t
print_domain_name(char * line,const uchar_t * header,const uchar_t * data,const uchar_t * data_end)9387c478bd9Sstevel@tonic-gate print_domain_name(char *line, const uchar_t *header, const uchar_t *data,
9397c478bd9Sstevel@tonic-gate const uchar_t *data_end)
9407c478bd9Sstevel@tonic-gate {
9417c478bd9Sstevel@tonic-gate char name[NS_MAXDNAME];
9427c478bd9Sstevel@tonic-gate const uchar_t *new_data;
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate new_data = get_domain_name(header, data, data_end, name,
9457c478bd9Sstevel@tonic-gate name + sizeof (name));
9467c478bd9Sstevel@tonic-gate
9477c478bd9Sstevel@tonic-gate (void) sprintf(line, "%s", name);
9487c478bd9Sstevel@tonic-gate return (new_data - data);
9497c478bd9Sstevel@tonic-gate }
950