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