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