1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * References used throughout this code:
30 *
31 * [RFC1001] :	PROTOCOL STANDARD FOR A NetBIOS SERVICE
32 *			ON A TCP/UDP TRANSPORT:
33 *			CONCEPTS AND METHODS
34 *		NetBIOS Working Group, March 1987
35 *
36 * [RFC1002] :	PROTOCOL STANDARD FOR A NetBIOS SERVICE
37 *			ON A TCP/UDP TRANSPORT:
38 *			DETAILED SPECIFICATIONS
39 *		NetBIOS Working Group, March 1987
40 */
41
42#include <fcntl.h>
43#include "snoop.h"
44#include <stdio.h>
45#include <ctype.h>
46#include "snoop.h"
47
48extern char *dlc_header;
49char *show_type();
50
51/* See snoop_smb.c */
52extern void interpret_smb(int flags, uchar_t *data, int len);
53
54/*
55 * NBT Session Packet Header
56 * [RFC 1002, Sec. 4.3.1]
57 */
58struct nbt_ss {
59	uchar_t type;
60	uchar_t flags;
61	ushort_t length;
62};
63
64/*
65 * NBT Session Request Packet trailer
66 * [RFC 1002, Sec. 4.3.2]
67 */
68struct callnames {
69	uchar_t space;		/* padding */
70	uchar_t calledname[32];
71	uchar_t nullchar;		/* padding */
72	uchar_t space2;		/* padding */
73	uchar_t callingname[32];
74	uchar_t nullchar2;	/* padding */
75};
76
77
78static void interpret_netbios_names(int flags, uchar_t *data, int len,
79					char *xtra);
80static void netbiosname2ascii(char *asciiname, uchar_t *netbiosname);
81
82/*
83 * Helpers to read network-order values,
84 * with NO alignment assumed.
85 */
86static ushort_t
87getshort(uchar_t *p) {
88	return (p[1] + (p[0]<<8));
89}
90static uint_t
91getlong(uchar_t *p)
92{
93	return (p[3] + (p[2]<<8) + (p[1]<<16) + (p[0]<<24));
94}
95
96/*
97 * NM_FLAGS fields in the NetBIOS Name Service Packet header.
98 * [RFC 1002,  Sec. 4.2.1.1]
99 */
100static void
101print_flag_details(int headerflags)
102{
103	if (headerflags & 1<<4)
104		sprintf(get_line(0, 0), "   - Broadcast");
105	if (headerflags & 1<<7)
106		sprintf(get_line(0, 0), "   - Recursion Available");
107	if (headerflags & 1<<8)
108		sprintf(get_line(0, 0), "   - Recursion Desired");
109	if (headerflags & 1<<9)
110		sprintf(get_line(0, 0), "   - Truncation Flag");
111	if (headerflags & 1<<10)
112		sprintf(get_line(0, 0), "   - Authoritative Answer");
113}
114
115/*
116 * Possible errors in NetBIOS name service packets.
117 * [RFC 1002,  Sec. 4.2.6, 4.2.11, 4.2.14]
118 */
119static void
120getrcodeerr(int headerflags, char *errortype)
121{
122	int error = (headerflags & 0xf);
123
124	switch (error) {
125	case 0:
126		sprintf(errortype, "Success");
127		break;
128	case 1:
129		sprintf(errortype, "Format Error");
130		break;
131	case 2:
132		sprintf(errortype, "Server Failure");
133		break;
134	case 3:
135		sprintf(errortype, "Name Error");
136		break;
137	case 4:
138		sprintf(errortype, "Unsupported Request Error");
139		break;
140	case 5:
141		sprintf(errortype, "Refused Error");
142		break;
143	case 6:
144		sprintf(errortype, "Active Error");
145		break;
146	case 7:
147		sprintf(errortype, "Name in Conflict Error");
148		break;
149	default:
150		sprintf(errortype, "Unknown Error");
151		break;
152	}
153}
154
155/*
156 * OPCODE fields in the NetBIOS Name Service Packet header.
157 * [RFC 1002, Sec. 4.2.1.1]
158 */
159static void
160print_ns_type(int flags, int headerflags, char *xtra)
161{
162	int opcode = (headerflags & 0x7800)>>11;
163	int response = (headerflags & 1<<15);
164	char *resptype = response ? "Response" : "Request";
165	char *optype;
166
167	switch (opcode) {
168	case 0:
169		optype = "Query";
170		break;
171	case 5:
172		optype = "Registration";
173		break;
174	case 6:
175		optype = "Release";
176		break;
177	case 7:
178		optype = "WACK";
179		break;
180	case 8:
181		optype = "Refresh";
182		break;
183	default:
184		optype = "Unknown";
185		break;
186	}
187
188	if (flags & F_DTAIL)
189		sprintf(get_line(0, 0), "Type = %s %s", optype, resptype);
190	else
191		sprintf(xtra, "%s %s", optype, resptype);
192}
193
194
195/*
196 * Interpret Datagram Packets
197 * [RFC 1002, Sec. 4.4]
198 */
199void
200interpret_netbios_datagram(int flags, uchar_t *data, int len)
201{
202	char name[24];
203	int packettype = data[0];
204	int packetlen;
205	data++;
206
207	if (packettype < 0x10 || packettype > 0x11)
208		return;
209
210	if (flags & F_SUM) {
211		data += 14;
212		netbiosname2ascii(name, data);
213		sprintf(get_sum_line(),
214				"NBT Datagram Service Type=%d Source=%s",
215				packettype, name);
216	}
217
218	if (flags & F_DTAIL) {
219		show_header("NBT:  ", "Netbios Datagram Service Header", len);
220		show_space();
221		sprintf(get_line(0, 0), "Datagram Packet Type = 0x%.2x",
222					packettype);
223		sprintf(get_line(0, 0), "Datagram Flags = 0x%.2x",
224					data[0]);
225		data++;
226		sprintf(get_line(0, 0), "Datagram ID = 0x%.4x",
227					getshort(data));
228		data += 2;
229		sprintf(get_line(0, 0), "Source IP = %d.%d.%d.%d",
230					data[0], data[1], data[2], data[3]);
231		data += 4;
232		sprintf(get_line(0, 0), "Source Port = %d",
233					getshort(data));
234		data += 2;
235		packetlen = getshort(data);
236		sprintf(get_line(0, 0), "Datagram Length = 0x%.4x",
237					packetlen);
238		data += 2;
239		sprintf(get_line(0, 0), "Packet Offset = 0x%.4x",
240					getshort(data));
241		data += 3;
242		netbiosname2ascii(name, data);
243		sprintf(get_line(0, 0), "Source Name = %s", name);
244		data += 34;
245		netbiosname2ascii(name, data);
246		sprintf(get_line(0, 0), "Destination Name = %s", name);
247		sprintf(get_line(0, 0), "Number of data bytes remaining = %d",
248					packetlen - 68);
249		show_trailer();
250	}
251}
252
253/*
254 * Interpret NetBIOS Name Service packets.
255 * [RFC 1002, Sec. 4.2]
256 */
257void
258interpret_netbios_ns(int flags, uchar_t *data, int len)
259{
260	int headerflags, qcount, acount, nscount, arcount;
261	int transid;
262	char name[24];
263	char extra[256];
264	char errortype[50];
265	int rdatalen;
266	int rrflags;
267	int nameptr;
268	int nodecode;
269	char *nodetype;
270	uchar_t *data0 = data;
271
272	transid = getshort(data); data += 2;
273	headerflags = getshort(data); data += 2;
274	qcount = getshort(data); data += 2;
275	acount = getshort(data); data += 2;
276	nscount = getshort(data); data += 2;
277	arcount = getshort(data); data += 2;
278	getrcodeerr(headerflags, errortype);
279
280	if (flags & F_SUM) {
281		print_ns_type(flags, headerflags, extra);
282		data++;
283		netbiosname2ascii(name, data);
284		sprintf(get_sum_line(), "NBT NS %s for %s, %s",
285			extra, name, errortype);
286
287	}
288
289
290	if (flags & F_DTAIL) {
291		show_header("NBT:  ", "Netbios Name Service Header", len);
292		show_space();
293		print_ns_type(flags, headerflags, 0);
294		sprintf(get_line(0, 0), "Status = %s", errortype);
295		sprintf(get_line(0, 0), "Transaction ID = 0x%.4x", transid);
296		sprintf(get_line(0, 0), "Flags Summary = 0x%.4x",
297					headerflags);
298		print_flag_details(headerflags);
299		sprintf(get_line(0, 0), "Question count = %d", qcount);
300		sprintf(get_line(0, 0), "Answer Count = %d", acount);
301		sprintf(get_line(0, 0), "Name Service Count = %d", nscount);
302		sprintf(get_line(0, 0),
303				"Additional Record Count = %d", arcount);
304
305		/*
306		 * Question Section Packet Description from
307		 * [RFC 1002, Sec. 4.2.1.2]
308		 */
309
310		if (qcount) {
311			data++;
312			netbiosname2ascii(name, data);
313			sprintf(get_line(0, 0), "Question Name = %s", name);
314			data += 33;
315			sprintf(get_line(0, 0), "Question Type = 0x%.4x",
316						getshort(data));
317			data += 2;
318			sprintf(get_line(0, 0), "Question Class = 0x%.4x",
319						getshort(data));
320			data += 2;
321		}
322
323		/*
324		 * Resrouce Record Packet Description from
325		 * [RFC 1002, Sec. 4.2.1.3]
326		 */
327
328		if ((acount || nscount || arcount) ||
329		    (qcount+acount+nscount+arcount == 0)) {
330			/* Second level encoding from RFC883 (p.31, 32) */
331			if (data[0] & 0xc0) {
332				nameptr = getshort(data)&0x3fff;
333				netbiosname2ascii(name, (data0+nameptr+1));
334				sprintf(get_line(0, 0),
335					"Resource Record Name = %s", name);
336				data += 2;
337			} else {
338				data++;
339				netbiosname2ascii(name, data);
340				sprintf(get_line(0, 0),
341					"Resource Record Name = %s", name);
342				data += 33;
343			}
344			sprintf(get_line(0, 0),
345					"Resource Record Type = 0x%.4x",
346					getshort(data));
347			data += 2;
348			sprintf(get_line(0, 0),
349					"Resource Record Class = 0x%.4x",
350					getshort(data));
351			data += 2;
352			sprintf(get_line(0, 0),
353				"Time to Live (Milliseconds) = %d",
354				getlong(data));
355			data += 4;
356			rdatalen = getshort(data);
357			sprintf(get_line(0, 0), "RDATA Length = 0x%.4x",
358						rdatalen);
359			data += 2;
360			/* 15.4.2.1.3 */
361			if (rdatalen == 6) {
362				rrflags = getshort(data);
363				data += 2;
364				sprintf(get_line(0, 0),
365					"Resource Record Flags = 0x%.4x",
366					rrflags);
367				nodecode = (rrflags>>13)& 0x11;
368				if (nodecode == 0) nodetype = "B";
369				if (nodecode == 1) nodetype = "P";
370				if (nodecode == 2) nodetype = "M";
371				sprintf(get_line(0, 0), "   - %s, %s node",
372					(rrflags & 1<<15) ?
373					"Group NetBIOS Name":
374					"Unique NetBIOS Name", nodetype);
375				sprintf(get_line(0, 0),
376					"Owner IP Address = %d.%d.%d.%d",
377					data[0], data[1], data[2], data[3]);
378			}
379		}
380		show_trailer();
381
382	}
383}
384
385/*
386 * Interpret NetBIOS session packets.
387 * [RFC 1002, Sec. 4.3]
388 */
389void
390interpret_netbios_ses(int flags, uchar_t *data, int len)
391{
392	struct nbt_ss *ss;
393	uchar_t *trailer;
394	int length = len - 4;   /* NBT packet length without header */
395	char *type;
396	char extrainfo[300];
397
398	if (len < sizeof (struct nbt_ss))
399		return;
400
401	/*
402	 * Packets that are fragments of a large NetBIOS session
403	 * message will have no NetBIOS header.  (Only the first
404	 * TCP segment will have a NetBIOS header.)  It turns out
405	 * that very often, such fragments start with SMB data, so
406	 * we should try to recognize and decode them.
407	 */
408	if (data[0] == 0xff &&
409	    data[1] == 'S' &&
410	    data[2] == 'M' &&
411	    data[3] == 'B') {
412		interpret_smb(flags, data, len);
413		return;
414	}
415
416	/* LINTED PTRALIGN */
417	ss = (struct nbt_ss *)data;
418	trailer = data + sizeof (*ss);
419	extrainfo[0] = '\0';
420
421	if (flags & F_SUM) {
422		switch (ss->type) {
423		case 0x00:
424			type = "SESSION MESSAGE";
425			break;
426		case 0x81:
427			type = "SESSION REQUEST";
428			interpret_netbios_names(flags, trailer,
429						length, extrainfo);
430			break;
431		case 0x82:
432			type = "POSITIVE SESSION RESPONSE";
433			break;
434		case 0x83:
435			type = "NEGATIVE SESSION RESPONSE";
436			break;
437		case 0x84:
438			type = "RETARGET SESSION RESPONSE";
439			break;
440		case 0x85:
441			type = "SESSION KEEP ALIVE";
442			break;
443		default:
444			type = "Unknown";
445			break;
446		}
447		(void) sprintf(get_sum_line(),
448			"NBT Type=%s %sLength=%d", type, extrainfo, length);
449	}
450
451	if (flags & F_DTAIL) {
452		show_header("NBT:  ", "NBT Header", len);
453		show_space();
454
455		switch (ss->type) {
456		case 0x00:
457			(void) sprintf(get_line(0, 0),
458			"Type = SESSION MESSAGE");
459			break;
460		case 0x81:
461			(void) sprintf(get_line(0, 0),
462			"Type = SESSION REQUEST");
463			interpret_netbios_names(flags, trailer, length, 0);
464			break;
465		case 0x82:
466			(void) sprintf(get_line(0, 0),
467			"Type = POSITIVE SESSION RESPONSE");
468			break;
469		case 0x83:
470			(void) sprintf(get_line(0, 0),
471			"Type = NEGATIVE SESSION RESPONSE");
472			break;
473		case 0x84:
474			(void) sprintf(get_line(0, 0),
475			"Type = RETARGET SESSION RESPONSE");
476			break;
477		case 0x85:
478			(void) sprintf(get_line(0, 0),
479			"Type = SESSION KEEP ALIVE");
480			break;
481		default:
482			(void) sprintf(get_line(0, 0),
483			"Type = Unknown");
484			break;
485		}
486
487		(void) sprintf(get_line(0, 0), "Length = %d bytes", length);
488		show_trailer();
489	}
490
491	/*
492	 * SMB packets have { 0xff, 'S', 'M', 'B' }
493	 * in the first four bytes.  If we find that,
494	 * let snoop_smb.c have a look at it.
495	 */
496	if (ss->type == 0x00 &&
497	    length > 0 &&
498	    trailer[0] == 0xff &&
499	    trailer[1] == 'S' &&
500	    trailer[2] == 'M' &&
501	    trailer[3] == 'B')
502		interpret_smb(flags, trailer, length);
503}
504
505/*
506 * NetBIOS name encoding (First Level Encoding)
507 * [RFC 1001, Sec. 4.1]
508 */
509static void
510netbiosname2ascii(char *aname, uchar_t *nbname)
511{
512	int c, i, j;
513
514	i = j = 0;
515	for (;;) {
516		c = nbname[i++] - 'A';
517		c = (c << 4) +
518			nbname[i++] - 'A';
519		/* 16th char is the "type" */
520		if (i >= 32)
521			break;
522		if (iscntrl(c))
523			c = '.';
524		if (c != ' ')
525			aname[j++] = c;
526	}
527	sprintf(&aname[j], "[%x]", c);
528}
529
530/*
531 * Interpret the names in a Session Request packet.
532 * [RFC 1002, Sec. 4.3.2]
533 */
534static void
535interpret_netbios_names(int flags, uchar_t *data, int len, char *xtra)
536{
537	char  calledname[24];
538	char callingname[24];
539	struct callnames *names = (struct callnames *)data;
540
541	if (len < sizeof (*names))
542		return;
543
544	netbiosname2ascii(calledname, names->calledname);
545	netbiosname2ascii(callingname, names->callingname);
546
547	if (flags & F_SUM) {
548		sprintf(xtra, "Dest=%s Source=%s ", calledname, callingname);
549	}
550
551	if (flags & F_DTAIL) {
552		sprintf(get_line(0, 0), "Destination = %s", calledname);
553		sprintf(get_line(0, 0), "Source = %s", callingname);
554	}
555}
556