xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_netbios.c (revision a38ddfee9c8c6b6c5a2947ff52fd2338362a4444)
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 
48 extern char *dlc_header;
49 char *show_type();
50 
51 /* See snoop_smb.c */
52 extern 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  */
58 struct 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  */
68 struct 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 
78 static void interpret_netbios_names(int flags, uchar_t *data, int len,
79 					char *xtra);
80 static void netbiosname2ascii(char *asciiname, uchar_t *netbiosname);
81 
82 /*
83  * Helpers to read network-order values,
84  * with NO alignment assumed.
85  */
86 static ushort_t
87 getshort(uchar_t *p) {
88 	return (p[1] + (p[0]<<8));
89 }
90 static uint_t
91 getlong(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  */
100 static void
101 print_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  */
119 static void
120 getrcodeerr(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  */
159 static void
160 print_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  */
199 void
200 interpret_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  */
257 void
258 interpret_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  */
389 void
390 interpret_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  */
509 static void
510 netbiosname2ascii(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  */
534 static void
535 interpret_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