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