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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * References used throughout this code:
31 * [RFC1001] : PROTOCOL STANDARD FOR A NetBIOS SERVICE
32 * ON A TCP/UDP TRANSPORT:
33 * CONCEPTS AND METHODS
34 * NetBIOS Working Group, March 1987
36 * [RFC1002] : PROTOCOL STANDARD FOR A NetBIOS SERVICE
37 * ON A TCP/UDP TRANSPORT:
38 * DETAILED SPECIFICATIONS
39 * NetBIOS Working Group, March 1987
48 extern char *dlc_header
;
52 extern void interpret_smb(int flags
, uchar_t
*data
, int len
);
55 * NBT Session Packet Header
56 * [RFC 1002, Sec. 4.3.1]
65 * NBT Session Request Packet trailer
66 * [RFC 1002, Sec. 4.3.2]
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 */
78 static void interpret_netbios_names(int flags
, uchar_t
*data
, int len
,
80 static void netbiosname2ascii(char *asciiname
, uchar_t
*netbiosname
);
83 * Helpers to read network-order values,
84 * with NO alignment assumed.
87 getshort(uchar_t
*p
) {
88 return (p
[1] + (p
[0]<<8));
93 return (p
[3] + (p
[2]<<8) + (p
[1]<<16) + (p
[0]<<24));
97 * NM_FLAGS fields in the NetBIOS Name Service Packet header.
98 * [RFC 1002, Sec. 4.2.1.1]
101 print_flag_details(int headerflags
)
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");
116 * Possible errors in NetBIOS name service packets.
117 * [RFC 1002, Sec. 4.2.6, 4.2.11, 4.2.14]
120 getrcodeerr(int headerflags
, char *errortype
)
122 int error
= (headerflags
& 0xf);
126 sprintf(errortype
, "Success");
129 sprintf(errortype
, "Format Error");
132 sprintf(errortype
, "Server Failure");
135 sprintf(errortype
, "Name Error");
138 sprintf(errortype
, "Unsupported Request Error");
141 sprintf(errortype
, "Refused Error");
144 sprintf(errortype
, "Active Error");
147 sprintf(errortype
, "Name in Conflict Error");
150 sprintf(errortype
, "Unknown Error");
156 * OPCODE fields in the NetBIOS Name Service Packet header.
157 * [RFC 1002, Sec. 4.2.1.1]
160 print_ns_type(int flags
, int headerflags
, char *xtra
)
162 int opcode
= (headerflags
& 0x7800)>>11;
163 int response
= (headerflags
& 1<<15);
164 char *resptype
= response
? "Response" : "Request";
172 optype
= "Registration";
189 sprintf(get_line(0, 0), "Type = %s %s", optype
, resptype
);
191 sprintf(xtra
, "%s %s", optype
, resptype
);
196 * Interpret Datagram Packets
197 * [RFC 1002, Sec. 4.4]
200 interpret_netbios_datagram(int flags
, uchar_t
*data
, int len
)
203 int packettype
= data
[0];
207 if (packettype
< 0x10 || packettype
> 0x11)
212 netbiosname2ascii(name
, data
);
213 sprintf(get_sum_line(),
214 "NBT Datagram Service Type=%d Source=%s",
218 if (flags
& F_DTAIL
) {
219 show_header("NBT: ", "Netbios Datagram Service Header", len
);
221 sprintf(get_line(0, 0), "Datagram Packet Type = 0x%.2x",
223 sprintf(get_line(0, 0), "Datagram Flags = 0x%.2x",
226 sprintf(get_line(0, 0), "Datagram ID = 0x%.4x",
229 sprintf(get_line(0, 0), "Source IP = %d.%d.%d.%d",
230 data
[0], data
[1], data
[2], data
[3]);
232 sprintf(get_line(0, 0), "Source Port = %d",
235 packetlen
= getshort(data
);
236 sprintf(get_line(0, 0), "Datagram Length = 0x%.4x",
239 sprintf(get_line(0, 0), "Packet Offset = 0x%.4x",
242 netbiosname2ascii(name
, data
);
243 sprintf(get_line(0, 0), "Source Name = %s", name
);
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",
254 * Interpret NetBIOS Name Service packets.
255 * [RFC 1002, Sec. 4.2]
258 interpret_netbios_ns(int flags
, uchar_t
*data
, int len
)
260 int headerflags
, qcount
, acount
, nscount
, arcount
;
270 uchar_t
*data0
= data
;
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
);
281 print_ns_type(flags
, headerflags
, extra
);
283 netbiosname2ascii(name
, data
);
284 sprintf(get_sum_line(), "NBT NS %s for %s, %s",
285 extra
, name
, errortype
);
290 if (flags
& F_DTAIL
) {
291 show_header("NBT: ", "Netbios Name Service Header", len
);
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",
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
);
306 * Question Section Packet Description from
307 * [RFC 1002, Sec. 4.2.1.2]
312 netbiosname2ascii(name
, data
);
313 sprintf(get_line(0, 0), "Question Name = %s", name
);
315 sprintf(get_line(0, 0), "Question Type = 0x%.4x",
318 sprintf(get_line(0, 0), "Question Class = 0x%.4x",
324 * Resrouce Record Packet Description from
325 * [RFC 1002, Sec. 4.2.1.3]
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
);
339 netbiosname2ascii(name
, data
);
340 sprintf(get_line(0, 0),
341 "Resource Record Name = %s", name
);
344 sprintf(get_line(0, 0),
345 "Resource Record Type = 0x%.4x",
348 sprintf(get_line(0, 0),
349 "Resource Record Class = 0x%.4x",
352 sprintf(get_line(0, 0),
353 "Time to Live (Milliseconds) = %d",
356 rdatalen
= getshort(data
);
357 sprintf(get_line(0, 0), "RDATA Length = 0x%.4x",
362 rrflags
= getshort(data
);
364 sprintf(get_line(0, 0),
365 "Resource Record Flags = 0x%.4x",
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",
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]);
386 * Interpret NetBIOS session packets.
387 * [RFC 1002, Sec. 4.3]
390 interpret_netbios_ses(int flags
, uchar_t
*data
, int len
)
394 int length
= len
- 4; /* NBT packet length without header */
398 if (len
< sizeof (struct nbt_ss
))
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.
408 if (data
[0] == 0xff &&
412 interpret_smb(flags
, data
, len
);
416 /* LINTED PTRALIGN */
417 ss
= (struct nbt_ss
*)data
;
418 trailer
= data
+ sizeof (*ss
);
424 type
= "SESSION MESSAGE";
427 type
= "SESSION REQUEST";
428 interpret_netbios_names(flags
, trailer
,
432 type
= "POSITIVE SESSION RESPONSE";
435 type
= "NEGATIVE SESSION RESPONSE";
438 type
= "RETARGET SESSION RESPONSE";
441 type
= "SESSION KEEP ALIVE";
447 (void) sprintf(get_sum_line(),
448 "NBT Type=%s %sLength=%d", type
, extrainfo
, length
);
451 if (flags
& F_DTAIL
) {
452 show_header("NBT: ", "NBT Header", len
);
457 (void) sprintf(get_line(0, 0),
458 "Type = SESSION MESSAGE");
461 (void) sprintf(get_line(0, 0),
462 "Type = SESSION REQUEST");
463 interpret_netbios_names(flags
, trailer
, length
, 0);
466 (void) sprintf(get_line(0, 0),
467 "Type = POSITIVE SESSION RESPONSE");
470 (void) sprintf(get_line(0, 0),
471 "Type = NEGATIVE SESSION RESPONSE");
474 (void) sprintf(get_line(0, 0),
475 "Type = RETARGET SESSION RESPONSE");
478 (void) sprintf(get_line(0, 0),
479 "Type = SESSION KEEP ALIVE");
482 (void) sprintf(get_line(0, 0),
487 (void) sprintf(get_line(0, 0), "Length = %d bytes", length
);
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.
496 if (ss
->type
== 0x00 &&
498 trailer
[0] == 0xff &&
502 interpret_smb(flags
, trailer
, length
);
506 * NetBIOS name encoding (First Level Encoding)
507 * [RFC 1001, Sec. 4.1]
510 netbiosname2ascii(char *aname
, uchar_t
*nbname
)
516 c
= nbname
[i
++] - 'A';
519 /* 16th char is the "type" */
527 sprintf(&aname
[j
], "[%x]", c
);
531 * Interpret the names in a Session Request packet.
532 * [RFC 1002, Sec. 4.3.2]
535 interpret_netbios_names(int flags
, uchar_t
*data
, int len
, char *xtra
)
538 char callingname
[24];
539 struct callnames
*names
= (struct callnames
*)data
;
541 if (len
< sizeof (*names
))
544 netbiosname2ascii(calledname
, names
->calledname
);
545 netbiosname2ascii(callingname
, names
->callingname
);
548 sprintf(xtra
, "Dest=%s Source=%s ", calledname
, callingname
);
551 if (flags
& F_DTAIL
) {
552 sprintf(get_line(0, 0), "Destination = %s", calledname
);
553 sprintf(get_line(0, 0), "Source = %s", callingname
);