xref: /titanic_52/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_netbios.c (revision 4bb0471c90a1b41593e55b18e3045fd3666c6841)
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
5*4bb0471cSblu  * Common Development and Distribution License (the "License").
6*4bb0471cSblu  * 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 /*
22*4bb0471cSblu  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*4bb0471cSblu  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * References used throughout this code:
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * [RFC1001] :	PROTOCOL STANDARD FOR A NetBIOS SERVICE
327c478bd9Sstevel@tonic-gate  *			ON A TCP/UDP TRANSPORT:
337c478bd9Sstevel@tonic-gate  *			CONCEPTS AND METHODS
347c478bd9Sstevel@tonic-gate  *		NetBIOS Working Group, March 1987
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * [RFC1002] :	PROTOCOL STANDARD FOR A NetBIOS SERVICE
377c478bd9Sstevel@tonic-gate  *			ON A TCP/UDP TRANSPORT:
387c478bd9Sstevel@tonic-gate  *			DETAILED SPECIFICATIONS
397c478bd9Sstevel@tonic-gate  *		NetBIOS Working Group, March 1987
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #include <fcntl.h>
437c478bd9Sstevel@tonic-gate #include "snoop.h"
447c478bd9Sstevel@tonic-gate #include <stdio.h>
457c478bd9Sstevel@tonic-gate #include <ctype.h>
467c478bd9Sstevel@tonic-gate #include "snoop.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate extern char *dlc_header;
497c478bd9Sstevel@tonic-gate char *show_type();
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /* See snoop_smb.c */
527c478bd9Sstevel@tonic-gate extern void interpret_smb(int flags, uchar_t *data, int len);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * NBT Session Packet Header
567c478bd9Sstevel@tonic-gate  * [RFC 1002, Sec. 4.3.1]
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate struct nbt_ss {
597c478bd9Sstevel@tonic-gate 	uchar_t type;
607c478bd9Sstevel@tonic-gate 	uchar_t flags;
617c478bd9Sstevel@tonic-gate 	ushort_t length;
627c478bd9Sstevel@tonic-gate };
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * NBT Session Request Packet trailer
667c478bd9Sstevel@tonic-gate  * [RFC 1002, Sec. 4.3.2]
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate struct callnames {
697c478bd9Sstevel@tonic-gate 	uchar_t space;		/* padding */
707c478bd9Sstevel@tonic-gate 	uchar_t calledname[32];
717c478bd9Sstevel@tonic-gate 	uchar_t nullchar;		/* padding */
727c478bd9Sstevel@tonic-gate 	uchar_t space2;		/* padding */
737c478bd9Sstevel@tonic-gate 	uchar_t callingname[32];
747c478bd9Sstevel@tonic-gate 	uchar_t nullchar2;	/* padding */
757c478bd9Sstevel@tonic-gate };
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate static void interpret_netbios_names(int flags, uchar_t *data, int len,
797c478bd9Sstevel@tonic-gate 					char *xtra);
807c478bd9Sstevel@tonic-gate static void netbiosname2ascii(char *asciiname, uchar_t *netbiosname);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate  * Helpers to read network-order values,
847c478bd9Sstevel@tonic-gate  * with NO alignment assumed.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate static ushort_t
877c478bd9Sstevel@tonic-gate getshort(uchar_t *p) {
887c478bd9Sstevel@tonic-gate 	return (p[1] + (p[0]<<8));
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate static uint_t
917c478bd9Sstevel@tonic-gate getlong(uchar_t *p)
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate 	return (p[3] + (p[2]<<8) + (p[1]<<16) + (p[0]<<24));
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * NM_FLAGS fields in the NetBIOS Name Service Packet header.
987c478bd9Sstevel@tonic-gate  * [RFC 1002,  Sec. 4.2.1.1]
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate static void
1017c478bd9Sstevel@tonic-gate print_flag_details(int headerflags)
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate 	if (headerflags & 1<<4)
1047c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "   - Broadcast");
1057c478bd9Sstevel@tonic-gate 	if (headerflags & 1<<7)
1067c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "   - Recursion Available");
1077c478bd9Sstevel@tonic-gate 	if (headerflags & 1<<8)
1087c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "   - Recursion Desired");
1097c478bd9Sstevel@tonic-gate 	if (headerflags & 1<<9)
1107c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "   - Truncation Flag");
1117c478bd9Sstevel@tonic-gate 	if (headerflags & 1<<10)
1127c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "   - Authoritative Answer");
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /*
1167c478bd9Sstevel@tonic-gate  * Possible errors in NetBIOS name service packets.
1177c478bd9Sstevel@tonic-gate  * [RFC 1002,  Sec. 4.2.6, 4.2.11, 4.2.14]
1187c478bd9Sstevel@tonic-gate  */
1197c478bd9Sstevel@tonic-gate static void
1207c478bd9Sstevel@tonic-gate getrcodeerr(int headerflags, char *errortype)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate 	int error = (headerflags & 0xf);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	switch (error) {
1257c478bd9Sstevel@tonic-gate 	case 0:
1267c478bd9Sstevel@tonic-gate 		sprintf(errortype, "Success");
1277c478bd9Sstevel@tonic-gate 		break;
1287c478bd9Sstevel@tonic-gate 	case 1:
1297c478bd9Sstevel@tonic-gate 		sprintf(errortype, "Format Error");
1307c478bd9Sstevel@tonic-gate 		break;
1317c478bd9Sstevel@tonic-gate 	case 2:
1327c478bd9Sstevel@tonic-gate 		sprintf(errortype, "Server Failure");
1337c478bd9Sstevel@tonic-gate 		break;
1347c478bd9Sstevel@tonic-gate 	case 3:
1357c478bd9Sstevel@tonic-gate 		sprintf(errortype, "Name Error");
1367c478bd9Sstevel@tonic-gate 		break;
1377c478bd9Sstevel@tonic-gate 	case 4:
1387c478bd9Sstevel@tonic-gate 		sprintf(errortype, "Unsupported Request Error");
1397c478bd9Sstevel@tonic-gate 		break;
1407c478bd9Sstevel@tonic-gate 	case 5:
1417c478bd9Sstevel@tonic-gate 		sprintf(errortype, "Refused Error");
1427c478bd9Sstevel@tonic-gate 		break;
1437c478bd9Sstevel@tonic-gate 	case 6:
1447c478bd9Sstevel@tonic-gate 		sprintf(errortype, "Active Error");
1457c478bd9Sstevel@tonic-gate 		break;
1467c478bd9Sstevel@tonic-gate 	case 7:
1477c478bd9Sstevel@tonic-gate 		sprintf(errortype, "Name in Conflict Error");
1487c478bd9Sstevel@tonic-gate 		break;
1497c478bd9Sstevel@tonic-gate 	default:
1507c478bd9Sstevel@tonic-gate 		sprintf(errortype, "Unknown Error");
1517c478bd9Sstevel@tonic-gate 		break;
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  * OPCODE fields in the NetBIOS Name Service Packet header.
1577c478bd9Sstevel@tonic-gate  * [RFC 1002, Sec. 4.2.1.1]
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate static void
1607c478bd9Sstevel@tonic-gate print_ns_type(int flags, int headerflags, char *xtra)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	int opcode = (headerflags & 0x7800)>>11;
1637c478bd9Sstevel@tonic-gate 	int response = (headerflags & 1<<15);
1647c478bd9Sstevel@tonic-gate 	char *resptype = response ? "Response" : "Request";
1657c478bd9Sstevel@tonic-gate 	char *optype;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	switch (opcode) {
1687c478bd9Sstevel@tonic-gate 	case 0:
1697c478bd9Sstevel@tonic-gate 		optype = "Query";
1707c478bd9Sstevel@tonic-gate 		break;
1717c478bd9Sstevel@tonic-gate 	case 5:
1727c478bd9Sstevel@tonic-gate 		optype = "Registration";
1737c478bd9Sstevel@tonic-gate 		break;
1747c478bd9Sstevel@tonic-gate 	case 6:
1757c478bd9Sstevel@tonic-gate 		optype = "Release";
1767c478bd9Sstevel@tonic-gate 		break;
1777c478bd9Sstevel@tonic-gate 	case 7:
1787c478bd9Sstevel@tonic-gate 		optype = "WACK";
1797c478bd9Sstevel@tonic-gate 		break;
1807c478bd9Sstevel@tonic-gate 	case 8:
1817c478bd9Sstevel@tonic-gate 		optype = "Refresh";
1827c478bd9Sstevel@tonic-gate 		break;
1837c478bd9Sstevel@tonic-gate 	default:
1847c478bd9Sstevel@tonic-gate 		optype = "Unknown";
1857c478bd9Sstevel@tonic-gate 		break;
1867c478bd9Sstevel@tonic-gate 	}
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL)
1897c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Type = %s %s", optype, resptype);
1907c478bd9Sstevel@tonic-gate 	else
1917c478bd9Sstevel@tonic-gate 		sprintf(xtra, "%s %s", optype, resptype);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate /*
1967c478bd9Sstevel@tonic-gate  * Interpret Datagram Packets
1977c478bd9Sstevel@tonic-gate  * [RFC 1002, Sec. 4.4]
1987c478bd9Sstevel@tonic-gate  */
1997c478bd9Sstevel@tonic-gate void
2007c478bd9Sstevel@tonic-gate interpret_netbios_datagram(int flags, uchar_t *data, int len)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	char name[24];
2037c478bd9Sstevel@tonic-gate 	int packettype = data[0];
2047c478bd9Sstevel@tonic-gate 	int packetlen;
2057c478bd9Sstevel@tonic-gate 	data++;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	if (packettype < 0x10 || packettype > 0x11)
2087c478bd9Sstevel@tonic-gate 		return;
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
2117c478bd9Sstevel@tonic-gate 		data += 14;
2127c478bd9Sstevel@tonic-gate 		netbiosname2ascii(name, data);
2137c478bd9Sstevel@tonic-gate 		sprintf(get_sum_line(),
2147c478bd9Sstevel@tonic-gate 				"NBT Datagram Service Type=%d Source=%s",
2157c478bd9Sstevel@tonic-gate 				packettype, name);
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
2197c478bd9Sstevel@tonic-gate 		show_header("NBT:  ", "Netbios Datagram Service Header", len);
2207c478bd9Sstevel@tonic-gate 		show_space();
2217c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Datagram Packet Type = 0x%.2x",
2227c478bd9Sstevel@tonic-gate 					packettype);
2237c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Datagram Flags = 0x%.2x",
2247c478bd9Sstevel@tonic-gate 					data[0]);
2257c478bd9Sstevel@tonic-gate 		data++;
2267c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Datagram ID = 0x%.4x",
2277c478bd9Sstevel@tonic-gate 					getshort(data));
2287c478bd9Sstevel@tonic-gate 		data += 2;
2297c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Source IP = %d.%d.%d.%d",
2307c478bd9Sstevel@tonic-gate 					data[0], data[1], data[2], data[3]);
2317c478bd9Sstevel@tonic-gate 		data += 4;
2327c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Source Port = %d",
2337c478bd9Sstevel@tonic-gate 					getshort(data));
2347c478bd9Sstevel@tonic-gate 		data += 2;
2357c478bd9Sstevel@tonic-gate 		packetlen = getshort(data);
2367c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Datagram Length = 0x%.4x",
2377c478bd9Sstevel@tonic-gate 					packetlen);
2387c478bd9Sstevel@tonic-gate 		data += 2;
2397c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Packet Offset = 0x%.4x",
2407c478bd9Sstevel@tonic-gate 					getshort(data));
2417c478bd9Sstevel@tonic-gate 		data += 3;
2427c478bd9Sstevel@tonic-gate 		netbiosname2ascii(name, data);
2437c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Source Name = %s", name);
2447c478bd9Sstevel@tonic-gate 		data += 34;
2457c478bd9Sstevel@tonic-gate 		netbiosname2ascii(name, data);
2467c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Destination Name = %s", name);
2477c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Number of data bytes remaining = %d",
2487c478bd9Sstevel@tonic-gate 					packetlen - 68);
2497c478bd9Sstevel@tonic-gate 		show_trailer();
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * Interpret NetBIOS Name Service packets.
2557c478bd9Sstevel@tonic-gate  * [RFC 1002, Sec. 4.2]
2567c478bd9Sstevel@tonic-gate  */
2577c478bd9Sstevel@tonic-gate void
2587c478bd9Sstevel@tonic-gate interpret_netbios_ns(int flags, uchar_t *data, int len)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	int headerflags, qcount, acount, nscount, arcount;
2617c478bd9Sstevel@tonic-gate 	int transid;
2627c478bd9Sstevel@tonic-gate 	char name[24];
2637c478bd9Sstevel@tonic-gate 	char extra[256];
2647c478bd9Sstevel@tonic-gate 	char errortype[50];
2657c478bd9Sstevel@tonic-gate 	int rdatalen;
2667c478bd9Sstevel@tonic-gate 	int rrflags;
2677c478bd9Sstevel@tonic-gate 	int nameptr;
2687c478bd9Sstevel@tonic-gate 	int nodecode;
2697c478bd9Sstevel@tonic-gate 	char *nodetype;
2707c478bd9Sstevel@tonic-gate 	uchar_t *data0 = data;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	transid = getshort(data); data += 2;
2737c478bd9Sstevel@tonic-gate 	headerflags = getshort(data); data += 2;
2747c478bd9Sstevel@tonic-gate 	qcount = getshort(data); data += 2;
2757c478bd9Sstevel@tonic-gate 	acount = getshort(data); data += 2;
2767c478bd9Sstevel@tonic-gate 	nscount = getshort(data); data += 2;
2777c478bd9Sstevel@tonic-gate 	arcount = getshort(data); data += 2;
2787c478bd9Sstevel@tonic-gate 	getrcodeerr(headerflags, errortype);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
2817c478bd9Sstevel@tonic-gate 		print_ns_type(flags, headerflags, extra);
2827c478bd9Sstevel@tonic-gate 		data++;
2837c478bd9Sstevel@tonic-gate 		netbiosname2ascii(name, data);
2847c478bd9Sstevel@tonic-gate 		sprintf(get_sum_line(), "NBT NS %s for %s, %s",
2857c478bd9Sstevel@tonic-gate 			extra, name, errortype);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
2917c478bd9Sstevel@tonic-gate 		show_header("NBT:  ", "Netbios Name Service Header", len);
2927c478bd9Sstevel@tonic-gate 		show_space();
2937c478bd9Sstevel@tonic-gate 		print_ns_type(flags, headerflags, 0);
2947c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Status = %s", errortype);
2957c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Transaction ID = 0x%.4x", transid);
2967c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Flags Summary = 0x%.4x",
2977c478bd9Sstevel@tonic-gate 					headerflags);
2987c478bd9Sstevel@tonic-gate 		print_flag_details(headerflags);
2997c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Question count = %d", qcount);
3007c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Answer Count = %d", acount);
3017c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Name Service Count = %d", nscount);
3027c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0),
3037c478bd9Sstevel@tonic-gate 				"Additional Record Count = %d", arcount);
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 		/*
3067c478bd9Sstevel@tonic-gate 		 * Question Section Packet Description from
3077c478bd9Sstevel@tonic-gate 		 * [RFC 1002, Sec. 4.2.1.2]
3087c478bd9Sstevel@tonic-gate 		 */
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 		if (qcount) {
3117c478bd9Sstevel@tonic-gate 			data++;
3127c478bd9Sstevel@tonic-gate 			netbiosname2ascii(name, data);
3137c478bd9Sstevel@tonic-gate 			sprintf(get_line(0, 0), "Question Name = %s", name);
3147c478bd9Sstevel@tonic-gate 			data += 33;
3157c478bd9Sstevel@tonic-gate 			sprintf(get_line(0, 0), "Question Type = 0x%.4x",
3167c478bd9Sstevel@tonic-gate 						getshort(data));
3177c478bd9Sstevel@tonic-gate 			data += 2;
3187c478bd9Sstevel@tonic-gate 			sprintf(get_line(0, 0), "Question Class = 0x%.4x",
3197c478bd9Sstevel@tonic-gate 						getshort(data));
3207c478bd9Sstevel@tonic-gate 			data += 2;
3217c478bd9Sstevel@tonic-gate 		}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 		/*
3247c478bd9Sstevel@tonic-gate 		 * Resrouce Record Packet Description from
3257c478bd9Sstevel@tonic-gate 		 * [RFC 1002, Sec. 4.2.1.3]
3267c478bd9Sstevel@tonic-gate 		 */
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 		if ((acount || nscount || arcount) ||
3297c478bd9Sstevel@tonic-gate 		    (qcount+acount+nscount+arcount == 0)) {
3307c478bd9Sstevel@tonic-gate 			/* Second level encoding from RFC883 (p.31, 32) */
3317c478bd9Sstevel@tonic-gate 			if (data[0] & 0xc0) {
3327c478bd9Sstevel@tonic-gate 				nameptr = getshort(data)&0x3fff;
3337c478bd9Sstevel@tonic-gate 				netbiosname2ascii(name, (data0+nameptr+1));
3347c478bd9Sstevel@tonic-gate 				sprintf(get_line(0, 0),
3357c478bd9Sstevel@tonic-gate 					"Resource Record Name = %s", name);
3367c478bd9Sstevel@tonic-gate 				data += 2;
3377c478bd9Sstevel@tonic-gate 			} else {
3387c478bd9Sstevel@tonic-gate 				data++;
3397c478bd9Sstevel@tonic-gate 				netbiosname2ascii(name, data);
3407c478bd9Sstevel@tonic-gate 				sprintf(get_line(0, 0),
3417c478bd9Sstevel@tonic-gate 					"Resource Record Name = %s", name);
3427c478bd9Sstevel@tonic-gate 				data += 33;
3437c478bd9Sstevel@tonic-gate 			}
3447c478bd9Sstevel@tonic-gate 			sprintf(get_line(0, 0),
3457c478bd9Sstevel@tonic-gate 					"Resource Record Type = 0x%.4x",
3467c478bd9Sstevel@tonic-gate 					getshort(data));
3477c478bd9Sstevel@tonic-gate 			data += 2;
3487c478bd9Sstevel@tonic-gate 			sprintf(get_line(0, 0),
3497c478bd9Sstevel@tonic-gate 					"Resource Record Class = 0x%.4x",
3507c478bd9Sstevel@tonic-gate 					getshort(data));
3517c478bd9Sstevel@tonic-gate 			data += 2;
3527c478bd9Sstevel@tonic-gate 			sprintf(get_line(0, 0),
3537c478bd9Sstevel@tonic-gate 				"Time to Live (Milliseconds) = %d",
3547c478bd9Sstevel@tonic-gate 				getlong(data));
3557c478bd9Sstevel@tonic-gate 			data += 4;
3567c478bd9Sstevel@tonic-gate 			rdatalen = getshort(data);
3577c478bd9Sstevel@tonic-gate 			sprintf(get_line(0, 0), "RDATA Length = 0x%.4x",
3587c478bd9Sstevel@tonic-gate 						rdatalen);
3597c478bd9Sstevel@tonic-gate 			data += 2;
3607c478bd9Sstevel@tonic-gate 			/* 15.4.2.1.3 */
3617c478bd9Sstevel@tonic-gate 			if (rdatalen == 6) {
3627c478bd9Sstevel@tonic-gate 				rrflags = getshort(data);
3637c478bd9Sstevel@tonic-gate 				data += 2;
3647c478bd9Sstevel@tonic-gate 				sprintf(get_line(0, 0),
3657c478bd9Sstevel@tonic-gate 					"Resource Record Flags = 0x%.4x",
3667c478bd9Sstevel@tonic-gate 					rrflags);
3677c478bd9Sstevel@tonic-gate 				nodecode = (rrflags>>13)& 0x11;
3687c478bd9Sstevel@tonic-gate 				if (nodecode == 0) nodetype = "B";
3697c478bd9Sstevel@tonic-gate 				if (nodecode == 1) nodetype = "P";
3707c478bd9Sstevel@tonic-gate 				if (nodecode == 2) nodetype = "M";
3717c478bd9Sstevel@tonic-gate 				sprintf(get_line(0, 0), "   - %s, %s node",
3727c478bd9Sstevel@tonic-gate 					(rrflags & 1<<15) ?
3737c478bd9Sstevel@tonic-gate 					"Group NetBIOS Name":
3747c478bd9Sstevel@tonic-gate 					"Unique NetBIOS Name", nodetype);
3757c478bd9Sstevel@tonic-gate 				sprintf(get_line(0, 0),
3767c478bd9Sstevel@tonic-gate 					"Owner IP Address = %d.%d.%d.%d",
3777c478bd9Sstevel@tonic-gate 					data[0], data[1], data[2], data[3]);
3787c478bd9Sstevel@tonic-gate 			}
3797c478bd9Sstevel@tonic-gate 		}
3807c478bd9Sstevel@tonic-gate 		show_trailer();
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * Interpret NetBIOS session packets.
3877c478bd9Sstevel@tonic-gate  * [RFC 1002, Sec. 4.3]
3887c478bd9Sstevel@tonic-gate  */
3897c478bd9Sstevel@tonic-gate void
3907c478bd9Sstevel@tonic-gate interpret_netbios_ses(int flags, uchar_t *data, int len)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	struct nbt_ss *ss;
3937c478bd9Sstevel@tonic-gate 	uchar_t *trailer;
3947c478bd9Sstevel@tonic-gate 	int length = len - 4;   /* NBT packet length without header */
3957c478bd9Sstevel@tonic-gate 	char *type;
3967c478bd9Sstevel@tonic-gate 	char extrainfo[300];
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	if (len < sizeof (struct nbt_ss))
3997c478bd9Sstevel@tonic-gate 		return;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	/*
4027c478bd9Sstevel@tonic-gate 	 * Packets that are fragments of a large NetBIOS session
4037c478bd9Sstevel@tonic-gate 	 * message will have no NetBIOS header.  (Only the first
4047c478bd9Sstevel@tonic-gate 	 * TCP segment will have a NetBIOS header.)  It turns out
4057c478bd9Sstevel@tonic-gate 	 * that very often, such fragments start with SMB data, so
4067c478bd9Sstevel@tonic-gate 	 * we should try to recognize and decode them.
4077c478bd9Sstevel@tonic-gate 	 */
4087c478bd9Sstevel@tonic-gate 	if (data[0] == 0xff &&
4097c478bd9Sstevel@tonic-gate 	    data[1] == 'S' &&
4107c478bd9Sstevel@tonic-gate 	    data[2] == 'M' &&
4117c478bd9Sstevel@tonic-gate 	    data[3] == 'B') {
4127c478bd9Sstevel@tonic-gate 		interpret_smb(flags, data, len);
4137c478bd9Sstevel@tonic-gate 		return;
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	/* LINTED PTRALIGN */
4177c478bd9Sstevel@tonic-gate 	ss = (struct nbt_ss *)data;
4187c478bd9Sstevel@tonic-gate 	trailer = data + sizeof (*ss);
4197c478bd9Sstevel@tonic-gate 	extrainfo[0] = '\0';
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
4227c478bd9Sstevel@tonic-gate 		switch (ss->type) {
4237c478bd9Sstevel@tonic-gate 		case 0x00:
4247c478bd9Sstevel@tonic-gate 			type = "SESSION MESSAGE";
4257c478bd9Sstevel@tonic-gate 			break;
4267c478bd9Sstevel@tonic-gate 		case 0x81:
4277c478bd9Sstevel@tonic-gate 			type = "SESSION REQUEST";
4287c478bd9Sstevel@tonic-gate 			interpret_netbios_names(flags, trailer,
4297c478bd9Sstevel@tonic-gate 						length, extrainfo);
4307c478bd9Sstevel@tonic-gate 			break;
4317c478bd9Sstevel@tonic-gate 		case 0x82:
4327c478bd9Sstevel@tonic-gate 			type = "POSITIVE SESSION RESPONSE";
4337c478bd9Sstevel@tonic-gate 			break;
4347c478bd9Sstevel@tonic-gate 		case 0x83:
4357c478bd9Sstevel@tonic-gate 			type = "NEGATIVE SESSION RESPONSE";
4367c478bd9Sstevel@tonic-gate 			break;
4377c478bd9Sstevel@tonic-gate 		case 0x84:
4387c478bd9Sstevel@tonic-gate 			type = "RETARGET SESSION RESPONSE";
4397c478bd9Sstevel@tonic-gate 			break;
4407c478bd9Sstevel@tonic-gate 		case 0x85:
4417c478bd9Sstevel@tonic-gate 			type = "SESSION KEEP ALIVE";
4427c478bd9Sstevel@tonic-gate 			break;
4437c478bd9Sstevel@tonic-gate 		default:
4447c478bd9Sstevel@tonic-gate 			type = "Unknown";
4457c478bd9Sstevel@tonic-gate 			break;
4467c478bd9Sstevel@tonic-gate 		}
4477c478bd9Sstevel@tonic-gate 		(void) sprintf(get_sum_line(),
4487c478bd9Sstevel@tonic-gate 			"NBT Type=%s %sLength=%d", type, extrainfo, length);
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
4527c478bd9Sstevel@tonic-gate 		show_header("NBT:  ", "NBT Header", len);
4537c478bd9Sstevel@tonic-gate 		show_space();
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 		switch (ss->type) {
4567c478bd9Sstevel@tonic-gate 		case 0x00:
4577c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
4587c478bd9Sstevel@tonic-gate 			"Type = SESSION MESSAGE");
4597c478bd9Sstevel@tonic-gate 			break;
4607c478bd9Sstevel@tonic-gate 		case 0x81:
4617c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
4627c478bd9Sstevel@tonic-gate 			"Type = SESSION REQUEST");
4637c478bd9Sstevel@tonic-gate 			interpret_netbios_names(flags, trailer, length, 0);
4647c478bd9Sstevel@tonic-gate 			break;
4657c478bd9Sstevel@tonic-gate 		case 0x82:
4667c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
4677c478bd9Sstevel@tonic-gate 			"Type = POSITIVE SESSION RESPONSE");
4687c478bd9Sstevel@tonic-gate 			break;
4697c478bd9Sstevel@tonic-gate 		case 0x83:
4707c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
4717c478bd9Sstevel@tonic-gate 			"Type = NEGATIVE SESSION RESPONSE");
4727c478bd9Sstevel@tonic-gate 			break;
4737c478bd9Sstevel@tonic-gate 		case 0x84:
4747c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
4757c478bd9Sstevel@tonic-gate 			"Type = RETARGET SESSION RESPONSE");
4767c478bd9Sstevel@tonic-gate 			break;
4777c478bd9Sstevel@tonic-gate 		case 0x85:
4787c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
4797c478bd9Sstevel@tonic-gate 			"Type = SESSION KEEP ALIVE");
4807c478bd9Sstevel@tonic-gate 			break;
4817c478bd9Sstevel@tonic-gate 		default:
4827c478bd9Sstevel@tonic-gate 			(void) sprintf(get_line(0, 0),
4837c478bd9Sstevel@tonic-gate 			"Type = Unknown");
4847c478bd9Sstevel@tonic-gate 			break;
4857c478bd9Sstevel@tonic-gate 		}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		(void) sprintf(get_line(0, 0), "Length = %d bytes", length);
4887c478bd9Sstevel@tonic-gate 		show_trailer();
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	/*
4927c478bd9Sstevel@tonic-gate 	 * SMB packets have { 0xff, 'S', 'M', 'B' }
4937c478bd9Sstevel@tonic-gate 	 * in the first four bytes.  If we find that,
4947c478bd9Sstevel@tonic-gate 	 * let snoop_smb.c have a look at it.
4957c478bd9Sstevel@tonic-gate 	 */
4967c478bd9Sstevel@tonic-gate 	if (ss->type == 0x00 &&
4977c478bd9Sstevel@tonic-gate 	    length > 0 &&
4987c478bd9Sstevel@tonic-gate 	    trailer[0] == 0xff &&
4997c478bd9Sstevel@tonic-gate 	    trailer[1] == 'S' &&
5007c478bd9Sstevel@tonic-gate 	    trailer[2] == 'M' &&
5017c478bd9Sstevel@tonic-gate 	    trailer[3] == 'B')
502*4bb0471cSblu 		interpret_smb(flags, trailer, length);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate /*
5067c478bd9Sstevel@tonic-gate  * NetBIOS name encoding (First Level Encoding)
5077c478bd9Sstevel@tonic-gate  * [RFC 1001, Sec. 4.1]
5087c478bd9Sstevel@tonic-gate  */
5097c478bd9Sstevel@tonic-gate static void
5107c478bd9Sstevel@tonic-gate netbiosname2ascii(char *aname, uchar_t *nbname)
5117c478bd9Sstevel@tonic-gate {
5127c478bd9Sstevel@tonic-gate 	int c, i, j;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	i = j = 0;
5157c478bd9Sstevel@tonic-gate 	for (;;) {
5167c478bd9Sstevel@tonic-gate 		c = nbname[i++] - 'A';
5177c478bd9Sstevel@tonic-gate 		c = (c << 4) +
5187c478bd9Sstevel@tonic-gate 			nbname[i++] - 'A';
5197c478bd9Sstevel@tonic-gate 		/* 16th char is the "type" */
5207c478bd9Sstevel@tonic-gate 		if (i >= 32)
5217c478bd9Sstevel@tonic-gate 			break;
5227c478bd9Sstevel@tonic-gate 		if (iscntrl(c))
5237c478bd9Sstevel@tonic-gate 			c = '.';
5247c478bd9Sstevel@tonic-gate 		if (c != ' ')
5257c478bd9Sstevel@tonic-gate 			aname[j++] = c;
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 	sprintf(&aname[j], "[%x]", c);
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate /*
5317c478bd9Sstevel@tonic-gate  * Interpret the names in a Session Request packet.
5327c478bd9Sstevel@tonic-gate  * [RFC 1002, Sec. 4.3.2]
5337c478bd9Sstevel@tonic-gate  */
5347c478bd9Sstevel@tonic-gate static void
5357c478bd9Sstevel@tonic-gate interpret_netbios_names(int flags, uchar_t *data, int len, char *xtra)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	char  calledname[24];
5387c478bd9Sstevel@tonic-gate 	char callingname[24];
5397c478bd9Sstevel@tonic-gate 	struct callnames *names = (struct callnames *)data;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	if (len < sizeof (*names))
5427c478bd9Sstevel@tonic-gate 		return;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	netbiosname2ascii(calledname, names->calledname);
5457c478bd9Sstevel@tonic-gate 	netbiosname2ascii(callingname, names->callingname);
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
5487c478bd9Sstevel@tonic-gate 		sprintf(xtra, "Dest=%s Source=%s ", calledname, callingname);
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
5527c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Destination = %s", calledname);
5537c478bd9Sstevel@tonic-gate 		sprintf(get_line(0, 0), "Source = %s", callingname);
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate }
556