Home | History | Annotate | Download | only in snoop
      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