xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_dns.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <stdio.h>
30*0Sstevel@tonic-gate #include <string.h>
31*0Sstevel@tonic-gate #include <limits.h>
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/errno.h>
34*0Sstevel@tonic-gate #include <sys/tiuser.h>
35*0Sstevel@tonic-gate #include <arpa/nameser.h>
36*0Sstevel@tonic-gate #include <arpa/inet.h>
37*0Sstevel@tonic-gate #include <netinet/in.h>
38*0Sstevel@tonic-gate #include "snoop.h"
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate /* The string used to indent detail lines */
41*0Sstevel@tonic-gate #define	DNS_INDENT	"    "
42*0Sstevel@tonic-gate /*
43*0Sstevel@tonic-gate  * From RFC1035, the maximum size of a character-string is limited by the
44*0Sstevel@tonic-gate  * one octet length field.  We add one character to that to make sure the
45*0Sstevel@tonic-gate  * result is terminated.
46*0Sstevel@tonic-gate  */
47*0Sstevel@tonic-gate #define	MAX_CHAR_STRING_SIZE	UCHAR_MAX + 1
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate /* private functions */
50*0Sstevel@tonic-gate static char *dns_opcode_string(uint_t opcode);
51*0Sstevel@tonic-gate static char *dns_rcode_string(uint_t rcode);
52*0Sstevel@tonic-gate static char *dns_type_string(uint_t type, int detail);
53*0Sstevel@tonic-gate static char *dns_class_string(uint_t cls, int detail);
54*0Sstevel@tonic-gate static size_t skip_question(const uchar_t *header, const uchar_t *data,
55*0Sstevel@tonic-gate     const uchar_t *data_end);
56*0Sstevel@tonic-gate static size_t print_question(char *line, const uchar_t *header,
57*0Sstevel@tonic-gate     const uchar_t *data, const uchar_t *data_end, int detail);
58*0Sstevel@tonic-gate static size_t print_answer(char *line, const uchar_t *header,
59*0Sstevel@tonic-gate     const uchar_t *data, const uchar_t *data_end, int detail);
60*0Sstevel@tonic-gate static char *binary_string(char data);
61*0Sstevel@tonic-gate static void print_ip(int af, char *line, const uchar_t *data, uint16_t len);
62*0Sstevel@tonic-gate static const uchar_t *get_char_string(const uchar_t *data, char *charbuf,
63*0Sstevel@tonic-gate     uint16_t datalen);
64*0Sstevel@tonic-gate static size_t print_char_string(char *line, const uchar_t *data, uint16_t len);
65*0Sstevel@tonic-gate static const uchar_t *get_domain_name(const uchar_t *header,
66*0Sstevel@tonic-gate     const uchar_t *data, const uchar_t *data_end, char *namebuf, char *namend);
67*0Sstevel@tonic-gate static size_t print_domain_name(char *line, const uchar_t *header,
68*0Sstevel@tonic-gate     const uchar_t *data, const uchar_t *data_end);
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate void
71*0Sstevel@tonic-gate interpret_dns(int flags, int proto, const uchar_t *data, int len)
72*0Sstevel@tonic-gate {
73*0Sstevel@tonic-gate 	typedef HEADER dns_header;
74*0Sstevel@tonic-gate 	dns_header header;
75*0Sstevel@tonic-gate 	char *line;
76*0Sstevel@tonic-gate 	ushort_t id, qdcount, ancount, nscount, arcount;
77*0Sstevel@tonic-gate 	ushort_t count;
78*0Sstevel@tonic-gate 	const uchar_t *questions;
79*0Sstevel@tonic-gate 	const uchar_t *answers;
80*0Sstevel@tonic-gate 	const uchar_t *nservers;
81*0Sstevel@tonic-gate 	const uchar_t *additions;
82*0Sstevel@tonic-gate 	const uchar_t *data_end;
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate 	if (proto == IPPROTO_TCP) {
85*0Sstevel@tonic-gate 		/* not supported now */
86*0Sstevel@tonic-gate 		return;
87*0Sstevel@tonic-gate 	}
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate 	/* We need at least the header in order to parse a packet. */
90*0Sstevel@tonic-gate 	if (sizeof (dns_header) > len) {
91*0Sstevel@tonic-gate 		return;
92*0Sstevel@tonic-gate 	}
93*0Sstevel@tonic-gate 	data_end = data + len;
94*0Sstevel@tonic-gate 	/*
95*0Sstevel@tonic-gate 	 * Copy the header into a local structure for aligned access to
96*0Sstevel@tonic-gate 	 * each field.
97*0Sstevel@tonic-gate 	 */
98*0Sstevel@tonic-gate 	(void) memcpy(&header, data, sizeof (header));
99*0Sstevel@tonic-gate 	id = ntohs(header.id);
100*0Sstevel@tonic-gate 	qdcount = ntohs(header.qdcount);
101*0Sstevel@tonic-gate 	ancount = ntohs(header.ancount);
102*0Sstevel@tonic-gate 	nscount = ntohs(header.nscount);
103*0Sstevel@tonic-gate 	arcount = ntohs(header.arcount);
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	if (flags & F_SUM) {
106*0Sstevel@tonic-gate 		line = get_sum_line();
107*0Sstevel@tonic-gate 		line += sprintf(line, "DNS %c ", header.qr ? 'R' : 'C');
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 		if (header.qr) {
110*0Sstevel@tonic-gate 			/* answer */
111*0Sstevel@tonic-gate 			if (header.rcode == 0) {
112*0Sstevel@tonic-gate 				/* reply is OK */
113*0Sstevel@tonic-gate 				questions = data + sizeof (dns_header);
114*0Sstevel@tonic-gate 				while (qdcount--) {
115*0Sstevel@tonic-gate 					if (questions >= data_end) {
116*0Sstevel@tonic-gate 						return;
117*0Sstevel@tonic-gate 					}
118*0Sstevel@tonic-gate 					questions += skip_question(data,
119*0Sstevel@tonic-gate 					    questions, data_end);
120*0Sstevel@tonic-gate 				}
121*0Sstevel@tonic-gate 				/* the answers are following the questions */
122*0Sstevel@tonic-gate 				answers = questions;
123*0Sstevel@tonic-gate 				if (ancount > 0) {
124*0Sstevel@tonic-gate 					(void) print_answer(line,
125*0Sstevel@tonic-gate 					    data, answers, data_end, FALSE);
126*0Sstevel@tonic-gate 				}
127*0Sstevel@tonic-gate 			} else {
128*0Sstevel@tonic-gate 				(void) sprintf(line, " Error: %d(%s)",
129*0Sstevel@tonic-gate 				    header.rcode,
130*0Sstevel@tonic-gate 				    dns_rcode_string(header.rcode));
131*0Sstevel@tonic-gate 			}
132*0Sstevel@tonic-gate 		} else {
133*0Sstevel@tonic-gate 			/* question */
134*0Sstevel@tonic-gate 			questions = data + sizeof (dns_header);
135*0Sstevel@tonic-gate 			if (questions >= data_end) {
136*0Sstevel@tonic-gate 				return;
137*0Sstevel@tonic-gate 			}
138*0Sstevel@tonic-gate 			(void) print_question(line, data, questions, data_end,
139*0Sstevel@tonic-gate 			    FALSE);
140*0Sstevel@tonic-gate 		}
141*0Sstevel@tonic-gate 	}
142*0Sstevel@tonic-gate 	if (flags & F_DTAIL) {
143*0Sstevel@tonic-gate 		show_header("DNS:  ", "DNS Header", sizeof (dns_header));
144*0Sstevel@tonic-gate 		show_space();
145*0Sstevel@tonic-gate 		if (header.qr) {
146*0Sstevel@tonic-gate 			/* answer */
147*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
148*0Sstevel@tonic-gate 			    "Response ID = %d", id);
149*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
150*0Sstevel@tonic-gate 			    "%s%s%s",
151*0Sstevel@tonic-gate 			    header.aa ? "AA (Authoritative Answer) " : "",
152*0Sstevel@tonic-gate 			    header.tc ? "TC (TrunCation) " : "",
153*0Sstevel@tonic-gate 			    header.ra ? "RA (Recursion Available) ": "");
154*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
155*0Sstevel@tonic-gate 			    "Response Code: %d (%s)",
156*0Sstevel@tonic-gate 			    header.rcode, dns_rcode_string(header.rcode));
157*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
158*0Sstevel@tonic-gate 			    "Reply to %d question(s)", qdcount);
159*0Sstevel@tonic-gate 			questions = data + sizeof (dns_header);
160*0Sstevel@tonic-gate 			count = 0;
161*0Sstevel@tonic-gate 			while (qdcount--) {
162*0Sstevel@tonic-gate 				if (questions >= data_end) {
163*0Sstevel@tonic-gate 					return;
164*0Sstevel@tonic-gate 				}
165*0Sstevel@tonic-gate 				count++;
166*0Sstevel@tonic-gate 				questions += print_question(get_line(0, 0),
167*0Sstevel@tonic-gate 				    data, questions, data_end, TRUE);
168*0Sstevel@tonic-gate 				show_space();
169*0Sstevel@tonic-gate 			}
170*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
171*0Sstevel@tonic-gate 			    "%d answer(s)", ancount);
172*0Sstevel@tonic-gate 			answers = questions;
173*0Sstevel@tonic-gate 			count = 0;
174*0Sstevel@tonic-gate 			while (ancount--) {
175*0Sstevel@tonic-gate 				if (answers >= data_end) {
176*0Sstevel@tonic-gate 					return;
177*0Sstevel@tonic-gate 				}
178*0Sstevel@tonic-gate 				count++;
179*0Sstevel@tonic-gate 				answers += print_answer(get_line(0, 0),
180*0Sstevel@tonic-gate 				    data, answers, data_end, TRUE);
181*0Sstevel@tonic-gate 				show_space();
182*0Sstevel@tonic-gate 			}
183*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
184*0Sstevel@tonic-gate 			    "%d name server resource(s)", nscount);
185*0Sstevel@tonic-gate 			nservers = answers;
186*0Sstevel@tonic-gate 			count = 0;
187*0Sstevel@tonic-gate 			while (nscount--) {
188*0Sstevel@tonic-gate 				if (nservers >= data_end) {
189*0Sstevel@tonic-gate 					return;
190*0Sstevel@tonic-gate 				}
191*0Sstevel@tonic-gate 				count++;
192*0Sstevel@tonic-gate 				nservers += print_answer(get_line(0, 0), data,
193*0Sstevel@tonic-gate 				    nservers, data_end, TRUE);
194*0Sstevel@tonic-gate 				show_space();
195*0Sstevel@tonic-gate 			}
196*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
197*0Sstevel@tonic-gate 			    "%d additional record(s)", arcount);
198*0Sstevel@tonic-gate 			additions = nservers;
199*0Sstevel@tonic-gate 			count = 0;
200*0Sstevel@tonic-gate 			while (arcount-- && additions < data_end) {
201*0Sstevel@tonic-gate 				count++;
202*0Sstevel@tonic-gate 				additions += print_answer(get_line(0, 0), data,
203*0Sstevel@tonic-gate 				    additions, data_end, TRUE);
204*0Sstevel@tonic-gate 				show_space();
205*0Sstevel@tonic-gate 			}
206*0Sstevel@tonic-gate 		} else {
207*0Sstevel@tonic-gate 			/* question */
208*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
209*0Sstevel@tonic-gate 			    "Query ID = %d", id);
210*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
211*0Sstevel@tonic-gate 			    "Opcode: %s", dns_opcode_string(header.opcode));
212*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
213*0Sstevel@tonic-gate 			    "%s%s",
214*0Sstevel@tonic-gate 			    header.tc ? "TC (TrunCation) " : "",
215*0Sstevel@tonic-gate 			    header.rd ? "RD (Recursion Desired) " : "");
216*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
217*0Sstevel@tonic-gate 			    "%d question(s)", qdcount);
218*0Sstevel@tonic-gate 			questions = data + sizeof (dns_header);
219*0Sstevel@tonic-gate 			count = 0;
220*0Sstevel@tonic-gate 			while (qdcount-- && questions < data_end) {
221*0Sstevel@tonic-gate 				count++;
222*0Sstevel@tonic-gate 				questions += print_question(get_line(0, 0),
223*0Sstevel@tonic-gate 				    data, questions, data_end, TRUE);
224*0Sstevel@tonic-gate 				show_space();
225*0Sstevel@tonic-gate 			}
226*0Sstevel@tonic-gate 		}
227*0Sstevel@tonic-gate 	}
228*0Sstevel@tonic-gate }
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate static char *
232*0Sstevel@tonic-gate dns_opcode_string(uint_t opcode)
233*0Sstevel@tonic-gate {
234*0Sstevel@tonic-gate 	static char buffer[64];
235*0Sstevel@tonic-gate 	switch (opcode) {
236*0Sstevel@tonic-gate 	case ns_o_query:	return ("Query");
237*0Sstevel@tonic-gate 	case ns_o_iquery:	return ("Inverse Query");
238*0Sstevel@tonic-gate 	case ns_o_status:	return ("Status");
239*0Sstevel@tonic-gate 	default:
240*0Sstevel@tonic-gate 		(void) snprintf(buffer, sizeof (buffer), "Unknown (%u)",
241*0Sstevel@tonic-gate 		    opcode);
242*0Sstevel@tonic-gate 		return (buffer);
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate }
245*0Sstevel@tonic-gate 
246*0Sstevel@tonic-gate static char *
247*0Sstevel@tonic-gate dns_rcode_string(uint_t rcode)
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate 	static char buffer[64];
250*0Sstevel@tonic-gate 	switch (rcode) {
251*0Sstevel@tonic-gate 	case ns_r_noerror:	return ("OK");
252*0Sstevel@tonic-gate 	case ns_r_formerr:	return ("Format Error");
253*0Sstevel@tonic-gate 	case ns_r_servfail:	return ("Server Fail");
254*0Sstevel@tonic-gate 	case ns_r_nxdomain:	return ("Name Error");
255*0Sstevel@tonic-gate 	case ns_r_notimpl:	return ("Unimplemented");
256*0Sstevel@tonic-gate 	case ns_r_refused:	return ("Refused");
257*0Sstevel@tonic-gate 	default:
258*0Sstevel@tonic-gate 		(void) snprintf(buffer, sizeof (buffer), "Unknown (%u)", rcode);
259*0Sstevel@tonic-gate 		return (buffer);
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate }
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate static char *
264*0Sstevel@tonic-gate dns_type_string(uint_t type, int detail)
265*0Sstevel@tonic-gate {
266*0Sstevel@tonic-gate 	static char buffer[64];
267*0Sstevel@tonic-gate 	switch (type) {
268*0Sstevel@tonic-gate 	case ns_t_a:	return (detail ? "Address" : "Addr");
269*0Sstevel@tonic-gate 	case ns_t_ns:	return (detail ? "Authoritative Name Server" : "NS");
270*0Sstevel@tonic-gate 	case ns_t_cname:	return (detail ? "Canonical Name" : "CNAME");
271*0Sstevel@tonic-gate 	case ns_t_soa:	return (detail ? "Start Of a zone Authority" : "SOA");
272*0Sstevel@tonic-gate 	case ns_t_mb:	return (detail ? "Mailbox domain name" : "MB");
273*0Sstevel@tonic-gate 	case ns_t_mg:	return (detail ? "Mailbox Group member" : "MG");
274*0Sstevel@tonic-gate 	case ns_t_mr:	return (detail ? "Mail Rename domain name" : "MR");
275*0Sstevel@tonic-gate 	case ns_t_null:	return ("NULL");
276*0Sstevel@tonic-gate 	case ns_t_wks:	return (detail ? "Well Known Service" : "WKS");
277*0Sstevel@tonic-gate 	case ns_t_ptr:	return (detail ? "Domain Name Pointer" : "PTR");
278*0Sstevel@tonic-gate 	case ns_t_hinfo:	return (detail ? "Host Information": "HINFO");
279*0Sstevel@tonic-gate 	case ns_t_minfo:
280*0Sstevel@tonic-gate 		return (detail ? "Mailbox or maillist Info" : "MINFO");
281*0Sstevel@tonic-gate 	case ns_t_mx:	return (detail ? "Mail Exchange" : "MX");
282*0Sstevel@tonic-gate 	case ns_t_txt:	return (detail ? "Text strings" : "TXT");
283*0Sstevel@tonic-gate 	case ns_t_aaaa:	return (detail ? "IPv6 Address" : "AAAA");
284*0Sstevel@tonic-gate 	case ns_t_axfr:	return (detail ? "Transfer of entire zone" : "AXFR");
285*0Sstevel@tonic-gate 	case ns_t_mailb:
286*0Sstevel@tonic-gate 		return (detail ? "Mailbox related records" : "MAILB");
287*0Sstevel@tonic-gate 	case ns_t_maila:	return (detail ? "Mail agent RRs" : "MAILA");
288*0Sstevel@tonic-gate 	case ns_t_any:	return (detail ? "All records" : "*");
289*0Sstevel@tonic-gate 	default:
290*0Sstevel@tonic-gate 		(void) snprintf(buffer, sizeof (buffer), "Unknown (%u)", type);
291*0Sstevel@tonic-gate 		return (buffer);
292*0Sstevel@tonic-gate 	}
293*0Sstevel@tonic-gate }
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate static char *
296*0Sstevel@tonic-gate dns_class_string(uint_t cls, int detail)
297*0Sstevel@tonic-gate {
298*0Sstevel@tonic-gate 	static char buffer[64];
299*0Sstevel@tonic-gate 	switch (cls) {
300*0Sstevel@tonic-gate 	case ns_c_in:		return (detail ? "Internet" : "Internet");
301*0Sstevel@tonic-gate 	case ns_c_chaos: 	return (detail ? "CHAOS" : "CH");
302*0Sstevel@tonic-gate 	case ns_c_hs:		return (detail ? "Hesiod" : "HS");
303*0Sstevel@tonic-gate 	case ns_c_any:		return (detail ? "* (Any class)" : "*");
304*0Sstevel@tonic-gate 	default:
305*0Sstevel@tonic-gate 		(void) snprintf(buffer, sizeof (buffer), "Unknown (%u)", cls);
306*0Sstevel@tonic-gate 		return (buffer);
307*0Sstevel@tonic-gate 	}
308*0Sstevel@tonic-gate }
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate static size_t
311*0Sstevel@tonic-gate skip_question(const uchar_t *header, const uchar_t *data,
312*0Sstevel@tonic-gate     const uchar_t *data_end)
313*0Sstevel@tonic-gate {
314*0Sstevel@tonic-gate 	const uchar_t *data_bak = data;
315*0Sstevel@tonic-gate 	char dummy_buffer[NS_MAXDNAME];
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	data = get_domain_name(header, data, data_end, dummy_buffer,
318*0Sstevel@tonic-gate 	    dummy_buffer + sizeof (dummy_buffer));
319*0Sstevel@tonic-gate 	/* Skip the 32 bits of class and type that follow the domain name */
320*0Sstevel@tonic-gate 	data += sizeof (uint32_t);
321*0Sstevel@tonic-gate 	return (data - data_bak);
322*0Sstevel@tonic-gate }
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate static size_t
325*0Sstevel@tonic-gate print_question(char *line, const uchar_t *header, const uchar_t *data,
326*0Sstevel@tonic-gate     const uchar_t *data_end, int detail)
327*0Sstevel@tonic-gate {
328*0Sstevel@tonic-gate 	const uchar_t *data_bak = data;
329*0Sstevel@tonic-gate 	uint16_t type;
330*0Sstevel@tonic-gate 	uint16_t cls;
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	if (detail) {
333*0Sstevel@tonic-gate 		line += snprintf(line, get_line_remain(),
334*0Sstevel@tonic-gate 		    DNS_INDENT "Domain Name: ");
335*0Sstevel@tonic-gate 	}
336*0Sstevel@tonic-gate 	data += print_domain_name(line, header, data, data_end);
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	/*
339*0Sstevel@tonic-gate 	 * Make sure we don't run off the end of the packet by reading the
340*0Sstevel@tonic-gate 	 * type and class.
341*0Sstevel@tonic-gate 	 *
342*0Sstevel@tonic-gate 	 * The pointer subtraction on the left side of the following
343*0Sstevel@tonic-gate 	 * expression has a signed result of type ptrdiff_t, and the right
344*0Sstevel@tonic-gate 	 * side has an unsigned result of type size_t.  We therefore need
345*0Sstevel@tonic-gate 	 * to cast the right side of the expression to be of the same
346*0Sstevel@tonic-gate 	 * signed type to keep the result of the pointer arithmetic to be
347*0Sstevel@tonic-gate 	 * automatically cast to an unsigned value.  We do a similar cast
348*0Sstevel@tonic-gate 	 * in other similar expressions throughout this file.
349*0Sstevel@tonic-gate 	 */
350*0Sstevel@tonic-gate 	if ((data_end - data) < (ptrdiff_t)(2 * sizeof (uint16_t)))
351*0Sstevel@tonic-gate 		return (data_end - data_bak);
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate 	GETINT16(type, data);
354*0Sstevel@tonic-gate 	GETINT16(cls, data);
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	if (detail) {
357*0Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
358*0Sstevel@tonic-gate 		    DNS_INDENT "Class: %u (%s)",
359*0Sstevel@tonic-gate 		    cls, dns_class_string(cls, detail));
360*0Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
361*0Sstevel@tonic-gate 		    DNS_INDENT "Type:  %u (%s)", type,
362*0Sstevel@tonic-gate 		    dns_type_string(type, detail));
363*0Sstevel@tonic-gate 	} else {
364*0Sstevel@tonic-gate 		(void) sprintf(line + strlen(line), " %s %s \?",
365*0Sstevel@tonic-gate 		    dns_class_string(cls, detail),
366*0Sstevel@tonic-gate 		    dns_type_string(type, detail));
367*0Sstevel@tonic-gate 	}
368*0Sstevel@tonic-gate 	return (data - data_bak);
369*0Sstevel@tonic-gate }
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate static size_t
372*0Sstevel@tonic-gate print_answer(char *line, const uchar_t *header, const uchar_t *data,
373*0Sstevel@tonic-gate     const uchar_t *data_end, int detail)
374*0Sstevel@tonic-gate {
375*0Sstevel@tonic-gate 	const uchar_t *data_bak = data;
376*0Sstevel@tonic-gate 	const uchar_t *data_next;
377*0Sstevel@tonic-gate 	uint16_t type;
378*0Sstevel@tonic-gate 	uint16_t cls;
379*0Sstevel@tonic-gate 	int32_t ttl;
380*0Sstevel@tonic-gate 	uint16_t rdlen;
381*0Sstevel@tonic-gate 	uint32_t serial, refresh, retry, expire, minimum;
382*0Sstevel@tonic-gate 	uint8_t protocol;
383*0Sstevel@tonic-gate 	int linepos;
384*0Sstevel@tonic-gate 	uint16_t preference;
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	if (detail) {
387*0Sstevel@tonic-gate 		line += snprintf(line, get_line_remain(),
388*0Sstevel@tonic-gate 		    DNS_INDENT "Domain Name: ");
389*0Sstevel@tonic-gate 	}
390*0Sstevel@tonic-gate 	data += print_domain_name(line, header, data, data_end);
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	/*
393*0Sstevel@tonic-gate 	 * Make sure we don't run off the end of the packet by reading the
394*0Sstevel@tonic-gate 	 * type, class, ttl, and length.
395*0Sstevel@tonic-gate 	 */
396*0Sstevel@tonic-gate 	if ((data_end - data) <
397*0Sstevel@tonic-gate 	    (ptrdiff_t)(3 * sizeof (uint16_t) + sizeof (uint32_t))) {
398*0Sstevel@tonic-gate 		return (data_end - data_bak);
399*0Sstevel@tonic-gate 	}
400*0Sstevel@tonic-gate 
401*0Sstevel@tonic-gate 	GETINT16(type, data);
402*0Sstevel@tonic-gate 	GETINT16(cls, data);
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	if (detail) {
405*0Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
406*0Sstevel@tonic-gate 		    DNS_INDENT "Class: %d (%s)", cls,
407*0Sstevel@tonic-gate 		    dns_class_string(cls, detail));
408*0Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
409*0Sstevel@tonic-gate 		    DNS_INDENT "Type:  %d (%s)", type,
410*0Sstevel@tonic-gate 		    dns_type_string(type, detail));
411*0Sstevel@tonic-gate 	} else {
412*0Sstevel@tonic-gate 		line += strlen(line);
413*0Sstevel@tonic-gate 		line += sprintf(line, " %s %s ",
414*0Sstevel@tonic-gate 		    dns_class_string(cls, detail),
415*0Sstevel@tonic-gate 		    dns_type_string(type, detail));
416*0Sstevel@tonic-gate 	}
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	GETINT32(ttl, data);
419*0Sstevel@tonic-gate 	if (detail) {
420*0Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
421*0Sstevel@tonic-gate 		    DNS_INDENT "TTL (Time To Live): %d", ttl);
422*0Sstevel@tonic-gate 	}
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	GETINT16(rdlen, data);
425*0Sstevel@tonic-gate 	if (detail) {
426*0Sstevel@tonic-gate 		line = get_line(0, 0);
427*0Sstevel@tonic-gate 		line += snprintf(line, get_line_remain(), DNS_INDENT "%s: ",
428*0Sstevel@tonic-gate 		    dns_type_string(type, detail));
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	if (rdlen > data_end - data)
432*0Sstevel@tonic-gate 		return (data_end - data_bak);
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	switch (type) {
435*0Sstevel@tonic-gate 	case ns_t_a:
436*0Sstevel@tonic-gate 		print_ip(AF_INET, line, data, rdlen);
437*0Sstevel@tonic-gate 		break;
438*0Sstevel@tonic-gate 	case ns_t_aaaa:
439*0Sstevel@tonic-gate 		print_ip(AF_INET6, line, data, rdlen);
440*0Sstevel@tonic-gate 		break;
441*0Sstevel@tonic-gate 	case ns_t_hinfo:
442*0Sstevel@tonic-gate 		line += sprintf(line, "CPU: ");
443*0Sstevel@tonic-gate 		data_next = data + print_char_string(line, data, rdlen);
444*0Sstevel@tonic-gate 		if (data_next >= data_end)
445*0Sstevel@tonic-gate 			break;
446*0Sstevel@tonic-gate 		line += strlen(line);
447*0Sstevel@tonic-gate 		line += sprintf(line, "OS: ");
448*0Sstevel@tonic-gate 		(void) print_char_string(line, data_next,
449*0Sstevel@tonic-gate 		    rdlen - (data_next - data));
450*0Sstevel@tonic-gate 		break;
451*0Sstevel@tonic-gate 	case ns_t_ns:
452*0Sstevel@tonic-gate 	case ns_t_cname:
453*0Sstevel@tonic-gate 	case ns_t_mb:
454*0Sstevel@tonic-gate 	case ns_t_mg:
455*0Sstevel@tonic-gate 	case ns_t_mr:
456*0Sstevel@tonic-gate 	case ns_t_ptr:
457*0Sstevel@tonic-gate 		(void) print_domain_name(line, header, data, data_end);
458*0Sstevel@tonic-gate 		break;
459*0Sstevel@tonic-gate 	case ns_t_mx:
460*0Sstevel@tonic-gate 		data_next = data;
461*0Sstevel@tonic-gate 		if (rdlen < sizeof (uint16_t))
462*0Sstevel@tonic-gate 			break;
463*0Sstevel@tonic-gate 		GETINT16(preference, data_next);
464*0Sstevel@tonic-gate 		if (detail) {
465*0Sstevel@tonic-gate 			(void) print_domain_name(line, header, data_next,
466*0Sstevel@tonic-gate 			    data_end);
467*0Sstevel@tonic-gate 			(void) snprintf(get_line(0, 0), get_line_remain(),
468*0Sstevel@tonic-gate 			    DNS_INDENT "Preference: %u", preference);
469*0Sstevel@tonic-gate 		} else {
470*0Sstevel@tonic-gate 			(void) print_domain_name(line, header, data_next,
471*0Sstevel@tonic-gate 			    data_end);
472*0Sstevel@tonic-gate 		}
473*0Sstevel@tonic-gate 		break;
474*0Sstevel@tonic-gate 	case ns_t_soa:
475*0Sstevel@tonic-gate 		if (!detail)
476*0Sstevel@tonic-gate 			break;
477*0Sstevel@tonic-gate 		line = get_line(0, 0);
478*0Sstevel@tonic-gate 		line += snprintf(line, get_line_remain(),
479*0Sstevel@tonic-gate 		    DNS_INDENT "MNAME (Server name): ");
480*0Sstevel@tonic-gate 		data_next = data + print_domain_name(line, header, data,
481*0Sstevel@tonic-gate 		    data_end);
482*0Sstevel@tonic-gate 		if (data_next >= data_end)
483*0Sstevel@tonic-gate 			break;
484*0Sstevel@tonic-gate 		line = get_line(0, 0);
485*0Sstevel@tonic-gate 		line += snprintf(line, get_line_remain(),
486*0Sstevel@tonic-gate 		    DNS_INDENT "RNAME (Resposible mailbox): ");
487*0Sstevel@tonic-gate 		data_next = data_next +
488*0Sstevel@tonic-gate 		    print_domain_name(line, header, data_next, data_end);
489*0Sstevel@tonic-gate 		if ((data_end - data_next) < (ptrdiff_t)(5 * sizeof (uint32_t)))
490*0Sstevel@tonic-gate 			break;
491*0Sstevel@tonic-gate 		GETINT32(serial, data_next);
492*0Sstevel@tonic-gate 		GETINT32(refresh, data_next);
493*0Sstevel@tonic-gate 		GETINT32(retry, data_next);
494*0Sstevel@tonic-gate 		GETINT32(expire, data_next);
495*0Sstevel@tonic-gate 		GETINT32(minimum, data_next);
496*0Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
497*0Sstevel@tonic-gate 		    DNS_INDENT "Serial: %u", serial);
498*0Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
499*0Sstevel@tonic-gate 		    DNS_INDENT "Refresh: %u  Retry: %u  "
500*0Sstevel@tonic-gate 		    "Expire: %u Minimum: %u",
501*0Sstevel@tonic-gate 		    refresh, retry, expire, minimum);
502*0Sstevel@tonic-gate 		break;
503*0Sstevel@tonic-gate 	case ns_t_wks:
504*0Sstevel@tonic-gate 		print_ip(AF_INET, line, data, rdlen);
505*0Sstevel@tonic-gate 		if (!detail)
506*0Sstevel@tonic-gate 			break;
507*0Sstevel@tonic-gate 		data_next = data + sizeof (in_addr_t);
508*0Sstevel@tonic-gate 		if (data_next >= data_end)
509*0Sstevel@tonic-gate 			break;
510*0Sstevel@tonic-gate 		GETINT8(protocol, data_next);
511*0Sstevel@tonic-gate 		line = get_line(0, 0);
512*0Sstevel@tonic-gate 		line += snprintf(line, get_line_remain(),
513*0Sstevel@tonic-gate 		    DNS_INDENT "Protocol: %u ", protocol);
514*0Sstevel@tonic-gate 		switch (protocol) {
515*0Sstevel@tonic-gate 		case IPPROTO_UDP:
516*0Sstevel@tonic-gate 			(void) snprintf(line, get_line_remain(), "(UDP)");
517*0Sstevel@tonic-gate 			break;
518*0Sstevel@tonic-gate 		case IPPROTO_TCP:
519*0Sstevel@tonic-gate 			(void) snprintf(line, get_line_remain(), "(TCP)");
520*0Sstevel@tonic-gate 			break;
521*0Sstevel@tonic-gate 		}
522*0Sstevel@tonic-gate 		(void) snprintf(get_line(0, 0), get_line_remain(),
523*0Sstevel@tonic-gate 		    DNS_INDENT "Service bitmap:");
524*0Sstevel@tonic-gate 		(void) snprintf(line, get_line_remain(),
525*0Sstevel@tonic-gate 		    DNS_INDENT "0       8       16      24");
526*0Sstevel@tonic-gate 		linepos = 4;
527*0Sstevel@tonic-gate 		while (data_next < data + rdlen) {
528*0Sstevel@tonic-gate 			if (linepos == 4) {
529*0Sstevel@tonic-gate 				line = get_line(0, 0);
530*0Sstevel@tonic-gate 				line += snprintf(line, get_line_remain(),
531*0Sstevel@tonic-gate 				    DNS_INDENT);
532*0Sstevel@tonic-gate 				linepos = 0;
533*0Sstevel@tonic-gate 			}
534*0Sstevel@tonic-gate 			line += snprintf(line, get_line_remain(), "%s",
535*0Sstevel@tonic-gate 			    binary_string(*data_next));
536*0Sstevel@tonic-gate 			linepos++;
537*0Sstevel@tonic-gate 			data_next++;
538*0Sstevel@tonic-gate 		}
539*0Sstevel@tonic-gate 		break;
540*0Sstevel@tonic-gate 	case ns_t_minfo:
541*0Sstevel@tonic-gate 		if (!detail)
542*0Sstevel@tonic-gate 			break;
543*0Sstevel@tonic-gate 		line = get_line(0, 0);
544*0Sstevel@tonic-gate 		line += snprintf(line, get_line_remain(),
545*0Sstevel@tonic-gate 		    DNS_INDENT "RMAILBX (Resposible mailbox): ");
546*0Sstevel@tonic-gate 		data_next = data + print_domain_name(line, header, data,
547*0Sstevel@tonic-gate 		    data_end);
548*0Sstevel@tonic-gate 		line = get_line(0, 0);
549*0Sstevel@tonic-gate 		line += snprintf(line, get_line_remain(),
550*0Sstevel@tonic-gate 		    DNS_INDENT "EMAILBX (mailbox to receive err message): ");
551*0Sstevel@tonic-gate 		data_next = data_next + print_domain_name(line, header,
552*0Sstevel@tonic-gate 		    data_next, data_end);
553*0Sstevel@tonic-gate 		break;
554*0Sstevel@tonic-gate 	}
555*0Sstevel@tonic-gate 	data += rdlen;
556*0Sstevel@tonic-gate 	return (data - data_bak);
557*0Sstevel@tonic-gate }
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate static char *
560*0Sstevel@tonic-gate binary_string(char data)
561*0Sstevel@tonic-gate {
562*0Sstevel@tonic-gate 	static char bstring[8 + 1];
563*0Sstevel@tonic-gate 	char *ptr;
564*0Sstevel@tonic-gate 	int i;
565*0Sstevel@tonic-gate 	ptr = bstring;
566*0Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
567*0Sstevel@tonic-gate 		*ptr++ = (data & 0x80) ? '1' : '0';
568*0Sstevel@tonic-gate 		data = data << 1;
569*0Sstevel@tonic-gate 	}
570*0Sstevel@tonic-gate 	*ptr = (char)0;
571*0Sstevel@tonic-gate 	return (bstring);
572*0Sstevel@tonic-gate }
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate static void
575*0Sstevel@tonic-gate print_ip(int af, char *line, const uchar_t *data, uint16_t len)
576*0Sstevel@tonic-gate {
577*0Sstevel@tonic-gate 	in6_addr_t	addr6;
578*0Sstevel@tonic-gate 	in_addr_t	addr4;
579*0Sstevel@tonic-gate 	void		*addr;
580*0Sstevel@tonic-gate 
581*0Sstevel@tonic-gate 	switch (af) {
582*0Sstevel@tonic-gate 	case AF_INET:
583*0Sstevel@tonic-gate 		if (len != sizeof (in_addr_t))
584*0Sstevel@tonic-gate 			return;
585*0Sstevel@tonic-gate 		addr = memcpy(&addr4, data, sizeof (addr4));
586*0Sstevel@tonic-gate 		break;
587*0Sstevel@tonic-gate 	case AF_INET6:
588*0Sstevel@tonic-gate 		if (len != sizeof (in6_addr_t))
589*0Sstevel@tonic-gate 			return;
590*0Sstevel@tonic-gate 		addr = memcpy(&addr6, data, sizeof (addr6));
591*0Sstevel@tonic-gate 		break;
592*0Sstevel@tonic-gate 	}
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 	(void) inet_ntop(af, addr, line, INET6_ADDRSTRLEN);
595*0Sstevel@tonic-gate }
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate /*
598*0Sstevel@tonic-gate  * charbuf is assumed to be of size MAX_CHAR_STRING_SIZE.
599*0Sstevel@tonic-gate  */
600*0Sstevel@tonic-gate static const uchar_t *
601*0Sstevel@tonic-gate get_char_string(const uchar_t *data, char *charbuf, uint16_t datalen)
602*0Sstevel@tonic-gate {
603*0Sstevel@tonic-gate 	uint8_t len;
604*0Sstevel@tonic-gate 	char *name = charbuf;
605*0Sstevel@tonic-gate 	int i = 0;
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	/*
608*0Sstevel@tonic-gate 	 * From RFC1035, a character-string is a single length octet followed
609*0Sstevel@tonic-gate 	 * by that number of characters.
610*0Sstevel@tonic-gate 	 */
611*0Sstevel@tonic-gate 	if (datalen > 1) {
612*0Sstevel@tonic-gate 		len = *data;
613*0Sstevel@tonic-gate 		data++;
614*0Sstevel@tonic-gate 		if (len > 0 && len < MAX_CHAR_STRING_SIZE) {
615*0Sstevel@tonic-gate 			for (i = 0; i < len; i++, data++)
616*0Sstevel@tonic-gate 				name[i] = *data;
617*0Sstevel@tonic-gate 		}
618*0Sstevel@tonic-gate 	}
619*0Sstevel@tonic-gate 	name[i] = '\0';
620*0Sstevel@tonic-gate 	return (data);
621*0Sstevel@tonic-gate }
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate static size_t
624*0Sstevel@tonic-gate print_char_string(char *line, const uchar_t *data, uint16_t len)
625*0Sstevel@tonic-gate {
626*0Sstevel@tonic-gate 	char charbuf[MAX_CHAR_STRING_SIZE];
627*0Sstevel@tonic-gate 	const uchar_t *data_bak = data;
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	data = get_char_string(data, charbuf, len);
630*0Sstevel@tonic-gate 	(void) sprintf(line, "%s", charbuf);
631*0Sstevel@tonic-gate 	return (data - data_bak);
632*0Sstevel@tonic-gate }
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate /*
635*0Sstevel@tonic-gate  * header: the entire message header, this is where we start to
636*0Sstevel@tonic-gate  *	   count the offset of the compression scheme
637*0Sstevel@tonic-gate  * data:   the start of the domain name
638*0Sstevel@tonic-gate  * namebuf: user supplied buffer
639*0Sstevel@tonic-gate  * return: the next byte after what we have parsed
640*0Sstevel@tonic-gate  */
641*0Sstevel@tonic-gate static const uchar_t *
642*0Sstevel@tonic-gate get_domain_name(const uchar_t *header, const uchar_t *data,
643*0Sstevel@tonic-gate     const uchar_t *data_end, char *namebuf, char *namend)
644*0Sstevel@tonic-gate {
645*0Sstevel@tonic-gate 	uint8_t len;
646*0Sstevel@tonic-gate 	char *name = namebuf;
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 	/*
649*0Sstevel@tonic-gate 	 * From RFC1035, a domain name is a sequence of labels, where each
650*0Sstevel@tonic-gate 	 * label consists of a length octet followed by that number of
651*0Sstevel@tonic-gate 	 * octets.  The domain name terminates with the zero length octet
652*0Sstevel@tonic-gate 	 * for the null label of the root.
653*0Sstevel@tonic-gate 	 */
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 	while (name < (namend - 1)) {
656*0Sstevel@tonic-gate 		if ((data_end - data) < (ptrdiff_t)(sizeof (uint8_t))) {
657*0Sstevel@tonic-gate 			/* The length octet is off the end of the packet. */
658*0Sstevel@tonic-gate 			break;
659*0Sstevel@tonic-gate 		}
660*0Sstevel@tonic-gate 		GETINT8(len, data);
661*0Sstevel@tonic-gate 		if (len == 0) {
662*0Sstevel@tonic-gate 			/*
663*0Sstevel@tonic-gate 			 * Domain names end with a length byte of zero,
664*0Sstevel@tonic-gate 			 * which represents the null label of the root.
665*0Sstevel@tonic-gate 			 */
666*0Sstevel@tonic-gate 			break;
667*0Sstevel@tonic-gate 		}
668*0Sstevel@tonic-gate 		/*
669*0Sstevel@tonic-gate 		 * test if we are using the compression scheme
670*0Sstevel@tonic-gate 		 */
671*0Sstevel@tonic-gate 		if ((len & 0xc0) == 0xc0) {
672*0Sstevel@tonic-gate 			uint16_t offset;
673*0Sstevel@tonic-gate 			const uchar_t *label_ptr;
674*0Sstevel@tonic-gate 
675*0Sstevel@tonic-gate 			/*
676*0Sstevel@tonic-gate 			 * From RFC1035, message compression allows a
677*0Sstevel@tonic-gate 			 * domain name or a list of labels at the end of a
678*0Sstevel@tonic-gate 			 * domain name to be replaced with a pointer to a
679*0Sstevel@tonic-gate 			 * prior occurance of the same name.  In this
680*0Sstevel@tonic-gate 			 * scheme, the pointer is a two octet sequence
681*0Sstevel@tonic-gate 			 * where the most significant two bits are set, and
682*0Sstevel@tonic-gate 			 * the remaining 14 bits are the offset from the
683*0Sstevel@tonic-gate 			 * start of the message of the next label.
684*0Sstevel@tonic-gate 			 */
685*0Sstevel@tonic-gate 			data--;
686*0Sstevel@tonic-gate 			if ((data_end - data) <
687*0Sstevel@tonic-gate 			    (ptrdiff_t)(sizeof (uint16_t))) {
688*0Sstevel@tonic-gate 				/*
689*0Sstevel@tonic-gate 				 * The offset octets aren't entirely
690*0Sstevel@tonic-gate 				 * contained within this pakcet.
691*0Sstevel@tonic-gate 				 */
692*0Sstevel@tonic-gate 				data = data_end;
693*0Sstevel@tonic-gate 				break;
694*0Sstevel@tonic-gate 			}
695*0Sstevel@tonic-gate 			GETINT16(offset, data);
696*0Sstevel@tonic-gate 			label_ptr = header + (offset & 0x3fff);
697*0Sstevel@tonic-gate 			/*
698*0Sstevel@tonic-gate 			 * We must verify that the offset is valid by
699*0Sstevel@tonic-gate 			 * checking that it is less than the current data
700*0Sstevel@tonic-gate 			 * pointer and that it isn't off the end of the
701*0Sstevel@tonic-gate 			 * packet.
702*0Sstevel@tonic-gate 			 */
703*0Sstevel@tonic-gate 			if (label_ptr > data || label_ptr >= data_end)
704*0Sstevel@tonic-gate 				break;
705*0Sstevel@tonic-gate 			(void) get_domain_name(header, label_ptr, data_end,
706*0Sstevel@tonic-gate 			    name, namend);
707*0Sstevel@tonic-gate 			return (data);
708*0Sstevel@tonic-gate 		} else {
709*0Sstevel@tonic-gate 			if (len > (data_end - data)) {
710*0Sstevel@tonic-gate 				/*
711*0Sstevel@tonic-gate 				 * The label isn't entirely contained
712*0Sstevel@tonic-gate 				 * within the packet.  Don't read it.  The
713*0Sstevel@tonic-gate 				 * caller checks that the data pointer is
714*0Sstevel@tonic-gate 				 * not beyond the end after we've
715*0Sstevel@tonic-gate 				 * incremented it.
716*0Sstevel@tonic-gate 				 */
717*0Sstevel@tonic-gate 				data = data_end;
718*0Sstevel@tonic-gate 				break;
719*0Sstevel@tonic-gate 			}
720*0Sstevel@tonic-gate 			while (len > 0 && name < (namend - 2)) {
721*0Sstevel@tonic-gate 				*name = *data;
722*0Sstevel@tonic-gate 				name++;
723*0Sstevel@tonic-gate 				data++;
724*0Sstevel@tonic-gate 				len--;
725*0Sstevel@tonic-gate 			}
726*0Sstevel@tonic-gate 			*name = '.';
727*0Sstevel@tonic-gate 			name++;
728*0Sstevel@tonic-gate 		}
729*0Sstevel@tonic-gate 	}
730*0Sstevel@tonic-gate 	*name = '\0';
731*0Sstevel@tonic-gate 	return (data);
732*0Sstevel@tonic-gate }
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate static size_t
735*0Sstevel@tonic-gate print_domain_name(char *line, const uchar_t *header, const uchar_t *data,
736*0Sstevel@tonic-gate     const uchar_t *data_end)
737*0Sstevel@tonic-gate {
738*0Sstevel@tonic-gate 	char name[NS_MAXDNAME];
739*0Sstevel@tonic-gate 	const uchar_t *new_data;
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	new_data = get_domain_name(header, data, data_end, name,
742*0Sstevel@tonic-gate 	    name + sizeof (name));
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 	(void) sprintf(line, "%s", name);
745*0Sstevel@tonic-gate 	return (new_data - data);
746*0Sstevel@tonic-gate }
747