/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include "snoop.h"
/* The string used to indent detail lines */
/*
* From RFC1035, the maximum size of a character-string is limited by the
* one octet length field. We add one character to that to make sure the
* result is terminated.
*/
/* private functions */
static char *binary_string(char data);
void
{
char *line;
const char *protostr;
char *protopfxstr;
char *protohdrstr;
if (proto == IPPROTO_TCP) {
/* not supported now */
return;
}
if (port == IPPORT_DOMAIN) {
protostr = "DNS";
protopfxstr = "DNS: ";
protohdrstr = "DNS Header";
} else {
protostr = "MDNS";
protopfxstr = "MDNS: ";
protohdrstr = "MDNS Header";
}
/* We need at least the header in order to parse a packet. */
if (sizeof (dns_header) > len) {
return;
}
/*
* Copy the header into a local structure for aligned access to
* each field.
*/
line = get_sum_line();
/* answer */
/* reply is OK */
while (qdcount--) {
return;
}
}
/* the answers follow the questions */
if (ancount > 0) {
(void) print_answer(line,
}
} else {
}
} else {
/* question */
return;
}
FALSE);
}
}
show_space();
/* answer */
"Response ID = %d", id);
"%s%s%s",
"Response Code: %d (%s)",
"Reply to %d question(s)", qdcount);
} else {
/* question */
"Query ID = %d", id);
"%s%s",
"%d question(s)", qdcount);
}
count = 0;
while (qdcount--) {
return;
}
count++;
show_space();
}
/* Only answers should hold answers, but just in case */
"%d answer(s)", ancount);
count = 0;
while (ancount--) {
return;
}
count++;
show_space();
}
}
/* Likewise only answers should hold NS records */
"%d name server resource(s)", nscount);
count = 0;
while (nscount--) {
return;
}
count++;
show_space();
}
}
/* Additional section may hold an EDNS0 record. */
"%d additional record(s)", arcount);
count = 0;
count++;
show_space();
}
}
}
}
static char *
{
switch (opcode) {
case ns_o_query: return ("Query");
case ns_o_iquery: return ("Inverse Query");
case ns_o_status: return ("Status");
default:
opcode);
return (buffer);
}
}
static char *
{
switch (rcode) {
case ns_r_noerror: return ("OK");
case ns_r_formerr: return ("Format Error");
case ns_r_servfail: return ("Server Fail");
case ns_r_nxdomain: return ("Name Error");
case ns_r_notimpl: return ("Unimplemented");
case ns_r_refused: return ("Refused");
default:
return (buffer);
}
}
static char *
{
switch (type) {
case ns_t_null: return ("NULL");
case ns_t_minfo:
case ns_t_mailb:
default:
return (buffer);
}
}
static char *
{
switch (cls) {
default:
return (buffer);
}
}
static size_t
{
dummy_buffer + sizeof (dummy_buffer));
/* Skip the 32 bits of class and type that follow the domain name */
}
static size_t
{
if (detail) {
DNS_INDENT "Domain Name: ");
}
/*
* Make sure we don't run off the end of the packet by reading the
* type and class.
*
* The pointer subtraction on the left side of the following
* expression has a signed result of type ptrdiff_t, and the right
* side has an unsigned result of type size_t. We therefore need
* to cast the right side of the expression to be of the same
* signed type to keep the result of the pointer arithmetic to be
* automatically cast to an unsigned value. We do a similar cast
* in other similar expressions throughout this file.
*/
/*
* Multicast DNS re-uses the top bit of the class field
* in the question and answer sections. Unicast DNS only
* uses 1 (Internet), 3 and 4. Hence it is safe. The top
* order bit is always cleared here to display the rrclass in case
* of Multicast DNS packets.
*/
if (detail) {
DNS_INDENT "Class: %u (%s)",
} else {
}
}
/*
* print_answer() is used to display the contents of a single resource
* record (RR) from either the answer, name server or additional
* section of the DNS packet.
*
* Input:
* *line: snoops output buffer.
* *header: start of the DNS packet, required for names and rcode.
* *data: location within header from where the RR starts.
* *data_end: where DNS data ends.
* detail: simple or verbose output.
*
* Returns:
* Pointer to next RR or data_end.
*
* Most RRs have the same top level format as defined in RFC 1035:
*
* 1 1 1 1 1 1
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | |
* / NAME /
* | |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | TYPE |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | CLASS |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | TTL |
* | |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | RDLENGTH |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
* / RDATA /
* / /
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*
* However RFC 2671 introduced an exception to this rule
* with the "Extension Mechanisms for DNS" (EDNS0).
* When the type is 41 the remaining resource record format
* is:
*
* 1 1 1 1 1 1
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | TYPE = 41 |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | Sender's UDP payload size |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | Extended-rcode | Version |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | Zero |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | RDLENGTH |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
* / RDATA /
* / /
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*
*/
static size_t
{
int linepos;
/* declarations for EDNS follow */
union { /* DNS header overlay used for extraction */
} headptr;
if (detail) {
DNS_INDENT "Domain Name: ");
}
/*
* Next, get the record type, being careful to make sure we
* don't run off the end of the packet.
*/
}
/*
* Make sure we won't run off the end reading size,
* xrcode, version, zero and rdlen.
*/
+ sizeof (xrcode)
+ sizeof (ver)
+ sizeof (cls) /* zero */
+ sizeof (rdlen)))) {
}
/*
* The extended rcode represents the top half of the
* rcode which must be added to the rcode in the header.
*/
if (detail) {
DNS_INDENT "UDP payload size: %u (0x%.4x)",
DNS_INDENT "Extended rcode: %u "
"(translates to %u (%s))",
} else {
rdlen);
}
/*
* Make sure that rdlen is within data boundary.
*/
/* Future OPT decode code goes here. */
}
/*
* Make sure we don't run off the end of the packet by reading the
* class, ttl, and length.
*/
+ sizeof (ttl)
+ sizeof (rdlen)))) {
}
/*
* Multicast DNS re-uses the top bit of the class field
* in the question and answer sections. Unicast DNS only
* uses 1 (Internet), 3 and 4. Hence it is safe. The top
* order bit is always cleared here to display the rrclass in case
* of Multicast DNS packets.
*/
if (detail) {
} else {
}
if (detail) {
}
if (detail) {
}
switch (type) {
case ns_t_a:
break;
case ns_t_aaaa:
break;
case ns_t_hinfo:
break;
break;
case ns_t_ns:
case ns_t_cname:
case ns_t_mb:
case ns_t_mg:
case ns_t_mr:
case ns_t_ptr:
break;
case ns_t_mx:
break;
if (detail) {
data_end);
} else {
data_end);
}
break;
case ns_t_soa:
if (!detail)
break;
DNS_INDENT "MNAME (Server name): ");
data_end);
break;
DNS_INDENT "RNAME (Resposible mailbox): ");
break;
DNS_INDENT "Refresh: %u Retry: %u "
"Expire: %u Minimum: %u",
break;
case ns_t_wks:
if (!detail)
break;
break;
switch (protocol) {
case IPPROTO_UDP:
break;
case IPPROTO_TCP:
break;
}
DNS_INDENT "Service bitmap:");
DNS_INDENT "0 8 16 24");
linepos = 4;
if (linepos == 4) {
linepos = 0;
}
linepos++;
data_next++;
}
break;
case ns_t_minfo:
if (!detail)
break;
DNS_INDENT "RMAILBX (Resposible mailbox): ");
data_end);
DNS_INDENT "EMAILBX (mailbox to receive err message): ");
break;
}
}
static char *
{
char *ptr;
int i;
for (i = 0; i < 8; i++) {
}
*ptr = (char)0;
return (bstring);
}
static void
{
void *addr;
switch (af) {
case AF_INET:
return;
break;
case AF_INET6:
if (len != sizeof (in6_addr_t))
return;
break;
}
}
/*
* charbuf is assumed to be of size MAX_CHAR_STRING_SIZE.
*/
static const uchar_t *
{
int len;
int i = 0;
/*
* From RFC1035, a character-string is a single length octet followed
* by that number of characters.
*/
if (datalen > 1) {
data++;
}
}
name[i] = '\0';
return (data);
}
static size_t
{
}
/*
* header: the entire message header, this is where we start to
* count the offset of the compression scheme
* data: the start of the domain name
* namebuf: user supplied buffer
* return: the next byte after what we have parsed
*/
static const uchar_t *
{
/*
* From RFC1035, a domain name is a sequence of labels, where each
* label consists of a length octet followed by that number of
* octets. The domain name terminates with the zero length octet
* for the null label of the root.
*/
/* The length octet is off the end of the packet. */
break;
}
if (len == 0) {
/*
* Domain names end with a length byte of zero,
* which represents the null label of the root.
*/
break;
}
/*
* test if we are using the compression scheme
*/
/*
* From RFC1035, message compression allows a
* domain name or a list of labels at the end of a
* domain name to be replaced with a pointer to a
* prior occurance of the same name. In this
* scheme, the pointer is a two octet sequence
* where the most significant two bits are set, and
* the remaining 14 bits are the offset from the
* start of the message of the next label.
*/
data--;
/*
* The offset octets aren't entirely
* contained within this pakcet.
*/
break;
}
/*
* We must verify that the offset is valid by
* checking that it is less than the current data
* pointer and that it isn't off the end of the
* packet.
*/
break;
return (data);
} else {
/*
* The label isn't entirely contained
* within the packet. Don't read it. The
* caller checks that the data pointer is
* not beyond the end after we've
* incremented it.
*/
break;
}
name++;
data++;
len--;
}
*name = '.';
name++;
}
}
*name = '\0';
return (data);
}
static size_t
{
}