dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.sbin / snoop / snoop_netbios.c
blob2e8f8a92ab442da06ebb602ade621c6409c06874
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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
42 #include <fcntl.h>
43 #include "snoop.h"
44 #include <stdio.h>
45 #include <ctype.h>
46 #include "snoop.h"
48 extern char *dlc_header;
49 char *show_type();
51 /* See snoop_smb.c */
52 extern void interpret_smb(int flags, uchar_t *data, int len);
55 * NBT Session Packet Header
56 * [RFC 1002, Sec. 4.3.1]
58 struct nbt_ss {
59 uchar_t type;
60 uchar_t flags;
61 ushort_t length;
65 * NBT Session Request Packet trailer
66 * [RFC 1002, Sec. 4.3.2]
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 */
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);
83 * Helpers to read network-order values,
84 * with NO alignment assumed.
86 static ushort_t
87 getshort(uchar_t *p) {
88 return (p[1] + (p[0]<<8));
90 static uint_t
91 getlong(uchar_t *p)
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]
100 static void
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]
119 static void
120 getrcodeerr(int headerflags, char *errortype)
122 int error = (headerflags & 0xf);
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;
156 * OPCODE fields in the NetBIOS Name Service Packet header.
157 * [RFC 1002, Sec. 4.2.1.1]
159 static void
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";
165 char *optype;
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;
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);
196 * Interpret Datagram Packets
197 * [RFC 1002, Sec. 4.4]
199 void
200 interpret_netbios_datagram(int flags, uchar_t *data, int len)
202 char name[24];
203 int packettype = data[0];
204 int packetlen;
205 data++;
207 if (packettype < 0x10 || packettype > 0x11)
208 return;
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);
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();
254 * Interpret NetBIOS Name Service packets.
255 * [RFC 1002, Sec. 4.2]
257 void
258 interpret_netbios_ns(int flags, uchar_t *data, int len)
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;
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);
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);
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);
306 * Question Section Packet Description from
307 * [RFC 1002, Sec. 4.2.1.2]
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;
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);
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;
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]);
380 show_trailer();
386 * Interpret NetBIOS session packets.
387 * [RFC 1002, Sec. 4.3]
389 void
390 interpret_netbios_ses(int flags, uchar_t *data, int len)
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];
398 if (len < sizeof (struct nbt_ss))
399 return;
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 &&
409 data[1] == 'S' &&
410 data[2] == 'M' &&
411 data[3] == 'B') {
412 interpret_smb(flags, data, len);
413 return;
416 /* LINTED PTRALIGN */
417 ss = (struct nbt_ss *)data;
418 trailer = data + sizeof (*ss);
419 extrainfo[0] = '\0';
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;
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);
453 show_space();
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;
487 (void) sprintf(get_line(0, 0), "Length = %d bytes", length);
488 show_trailer();
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 &&
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);
506 * NetBIOS name encoding (First Level Encoding)
507 * [RFC 1001, Sec. 4.1]
509 static void
510 netbiosname2ascii(char *aname, uchar_t *nbname)
512 int c, i, j;
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;
527 sprintf(&aname[j], "[%x]", c);
531 * Interpret the names in a Session Request packet.
532 * [RFC 1002, Sec. 4.3.2]
534 static void
535 interpret_netbios_names(int flags, uchar_t *data, int len, char *xtra)
537 char calledname[24];
538 char callingname[24];
539 struct callnames *names = (struct callnames *)data;
541 if (len < sizeof (*names))
542 return;
544 netbiosname2ascii(calledname, names->calledname);
545 netbiosname2ascii(callingname, names->callingname);
547 if (flags & F_SUM) {
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);