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
getshort(uchar_t * p)85 getshort(uchar_t *p)
86 {
87 return (p[1] + (p[0]<<8));
88 }
89 static uint_t
getlong(uchar_t * p)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
print_flag_details(int headerflags)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
getrcodeerr(int headerflags,char * errortype)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
print_ns_type(int flags,int headerflags,char * xtra)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
interpret_netbios_datagram(int flags,uchar_t * data,int len)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
interpret_netbios_ns(int flags,uchar_t * data,int len)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
interpret_netbios_ses(int flags,uchar_t * data,int len)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
netbiosname2ascii(char * aname,uchar_t * nbname)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
interpret_netbios_names(int flags,uchar_t * data,int len,char * xtra)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