1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 7280 blu * Common Development and Distribution License (the "License"). 6 7280 blu * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 7280 blu * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 7280 blu * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 27 0 stevel 28 0 stevel /* 29 0 stevel * References used throughout this code: 30 0 stevel * 31 0 stevel * [RFC1001] : PROTOCOL STANDARD FOR A NetBIOS SERVICE 32 0 stevel * ON A TCP/UDP TRANSPORT: 33 0 stevel * CONCEPTS AND METHODS 34 0 stevel * NetBIOS Working Group, March 1987 35 0 stevel * 36 0 stevel * [RFC1002] : PROTOCOL STANDARD FOR A NetBIOS SERVICE 37 0 stevel * ON A TCP/UDP TRANSPORT: 38 0 stevel * DETAILED SPECIFICATIONS 39 0 stevel * NetBIOS Working Group, March 1987 40 0 stevel */ 41 0 stevel 42 0 stevel #include <fcntl.h> 43 0 stevel #include "snoop.h" 44 0 stevel #include <stdio.h> 45 0 stevel #include <ctype.h> 46 0 stevel #include "snoop.h" 47 0 stevel 48 0 stevel extern char *dlc_header; 49 0 stevel char *show_type(); 50 0 stevel 51 0 stevel /* See snoop_smb.c */ 52 0 stevel extern void interpret_smb(int flags, uchar_t *data, int len); 53 0 stevel 54 0 stevel /* 55 0 stevel * NBT Session Packet Header 56 0 stevel * [RFC 1002, Sec. 4.3.1] 57 0 stevel */ 58 0 stevel struct nbt_ss { 59 0 stevel uchar_t type; 60 0 stevel uchar_t flags; 61 0 stevel ushort_t length; 62 0 stevel }; 63 0 stevel 64 0 stevel /* 65 0 stevel * NBT Session Request Packet trailer 66 0 stevel * [RFC 1002, Sec. 4.3.2] 67 0 stevel */ 68 0 stevel struct callnames { 69 0 stevel uchar_t space; /* padding */ 70 0 stevel uchar_t calledname[32]; 71 0 stevel uchar_t nullchar; /* padding */ 72 0 stevel uchar_t space2; /* padding */ 73 0 stevel uchar_t callingname[32]; 74 0 stevel uchar_t nullchar2; /* padding */ 75 0 stevel }; 76 0 stevel 77 0 stevel 78 0 stevel static void interpret_netbios_names(int flags, uchar_t *data, int len, 79 0 stevel char *xtra); 80 0 stevel static void netbiosname2ascii(char *asciiname, uchar_t *netbiosname); 81 0 stevel 82 0 stevel /* 83 0 stevel * Helpers to read network-order values, 84 0 stevel * with NO alignment assumed. 85 0 stevel */ 86 0 stevel static ushort_t 87 0 stevel getshort(uchar_t *p) { 88 0 stevel return (p[1] + (p[0]<<8)); 89 0 stevel } 90 0 stevel static uint_t 91 0 stevel getlong(uchar_t *p) 92 0 stevel { 93 0 stevel return (p[3] + (p[2]<<8) + (p[1]<<16) + (p[0]<<24)); 94 0 stevel } 95 0 stevel 96 0 stevel /* 97 0 stevel * NM_FLAGS fields in the NetBIOS Name Service Packet header. 98 0 stevel * [RFC 1002, Sec. 4.2.1.1] 99 0 stevel */ 100 0 stevel static void 101 0 stevel print_flag_details(int headerflags) 102 0 stevel { 103 0 stevel if (headerflags & 1<<4) 104 0 stevel sprintf(get_line(0, 0), " - Broadcast"); 105 0 stevel if (headerflags & 1<<7) 106 0 stevel sprintf(get_line(0, 0), " - Recursion Available"); 107 0 stevel if (headerflags & 1<<8) 108 0 stevel sprintf(get_line(0, 0), " - Recursion Desired"); 109 0 stevel if (headerflags & 1<<9) 110 0 stevel sprintf(get_line(0, 0), " - Truncation Flag"); 111 0 stevel if (headerflags & 1<<10) 112 0 stevel sprintf(get_line(0, 0), " - Authoritative Answer"); 113 0 stevel } 114 0 stevel 115 0 stevel /* 116 0 stevel * Possible errors in NetBIOS name service packets. 117 0 stevel * [RFC 1002, Sec. 4.2.6, 4.2.11, 4.2.14] 118 0 stevel */ 119 0 stevel static void 120 0 stevel getrcodeerr(int headerflags, char *errortype) 121 0 stevel { 122 0 stevel int error = (headerflags & 0xf); 123 0 stevel 124 0 stevel switch (error) { 125 0 stevel case 0: 126 0 stevel sprintf(errortype, "Success"); 127 0 stevel break; 128 0 stevel case 1: 129 0 stevel sprintf(errortype, "Format Error"); 130 0 stevel break; 131 0 stevel case 2: 132 0 stevel sprintf(errortype, "Server Failure"); 133 0 stevel break; 134 0 stevel case 3: 135 0 stevel sprintf(errortype, "Name Error"); 136 0 stevel break; 137 0 stevel case 4: 138 0 stevel sprintf(errortype, "Unsupported Request Error"); 139 0 stevel break; 140 0 stevel case 5: 141 0 stevel sprintf(errortype, "Refused Error"); 142 0 stevel break; 143 0 stevel case 6: 144 0 stevel sprintf(errortype, "Active Error"); 145 0 stevel break; 146 0 stevel case 7: 147 0 stevel sprintf(errortype, "Name in Conflict Error"); 148 0 stevel break; 149 0 stevel default: 150 0 stevel sprintf(errortype, "Unknown Error"); 151 0 stevel break; 152 0 stevel } 153 0 stevel } 154 0 stevel 155 0 stevel /* 156 0 stevel * OPCODE fields in the NetBIOS Name Service Packet header. 157 0 stevel * [RFC 1002, Sec. 4.2.1.1] 158 0 stevel */ 159 0 stevel static void 160 0 stevel print_ns_type(int flags, int headerflags, char *xtra) 161 0 stevel { 162 0 stevel int opcode = (headerflags & 0x7800)>>11; 163 0 stevel int response = (headerflags & 1<<15); 164 0 stevel char *resptype = response ? "Response" : "Request"; 165 0 stevel char *optype; 166 0 stevel 167 0 stevel switch (opcode) { 168 0 stevel case 0: 169 0 stevel optype = "Query"; 170 0 stevel break; 171 0 stevel case 5: 172 0 stevel optype = "Registration"; 173 0 stevel break; 174 0 stevel case 6: 175 0 stevel optype = "Release"; 176 0 stevel break; 177 0 stevel case 7: 178 0 stevel optype = "WACK"; 179 0 stevel break; 180 0 stevel case 8: 181 0 stevel optype = "Refresh"; 182 0 stevel break; 183 0 stevel default: 184 0 stevel optype = "Unknown"; 185 0 stevel break; 186 0 stevel } 187 0 stevel 188 0 stevel if (flags & F_DTAIL) 189 0 stevel sprintf(get_line(0, 0), "Type = %s %s", optype, resptype); 190 0 stevel else 191 0 stevel sprintf(xtra, "%s %s", optype, resptype); 192 0 stevel } 193 0 stevel 194 0 stevel 195 0 stevel /* 196 0 stevel * Interpret Datagram Packets 197 0 stevel * [RFC 1002, Sec. 4.4] 198 0 stevel */ 199 0 stevel void 200 0 stevel interpret_netbios_datagram(int flags, uchar_t *data, int len) 201 0 stevel { 202 0 stevel char name[24]; 203 0 stevel int packettype = data[0]; 204 0 stevel int packetlen; 205 0 stevel data++; 206 0 stevel 207 0 stevel if (packettype < 0x10 || packettype > 0x11) 208 0 stevel return; 209 0 stevel 210 0 stevel if (flags & F_SUM) { 211 0 stevel data += 14; 212 0 stevel netbiosname2ascii(name, data); 213 0 stevel sprintf(get_sum_line(), 214 0 stevel "NBT Datagram Service Type=%d Source=%s", 215 0 stevel packettype, name); 216 0 stevel } 217 0 stevel 218 0 stevel if (flags & F_DTAIL) { 219 0 stevel show_header("NBT: ", "Netbios Datagram Service Header", len); 220 0 stevel show_space(); 221 0 stevel sprintf(get_line(0, 0), "Datagram Packet Type = 0x%.2x", 222 0 stevel packettype); 223 0 stevel sprintf(get_line(0, 0), "Datagram Flags = 0x%.2x", 224 0 stevel data[0]); 225 0 stevel data++; 226 0 stevel sprintf(get_line(0, 0), "Datagram ID = 0x%.4x", 227 0 stevel getshort(data)); 228 0 stevel data += 2; 229 0 stevel sprintf(get_line(0, 0), "Source IP = %d.%d.%d.%d", 230 0 stevel data[0], data[1], data[2], data[3]); 231 0 stevel data += 4; 232 0 stevel sprintf(get_line(0, 0), "Source Port = %d", 233 0 stevel getshort(data)); 234 0 stevel data += 2; 235 0 stevel packetlen = getshort(data); 236 0 stevel sprintf(get_line(0, 0), "Datagram Length = 0x%.4x", 237 0 stevel packetlen); 238 0 stevel data += 2; 239 0 stevel sprintf(get_line(0, 0), "Packet Offset = 0x%.4x", 240 0 stevel getshort(data)); 241 0 stevel data += 3; 242 0 stevel netbiosname2ascii(name, data); 243 0 stevel sprintf(get_line(0, 0), "Source Name = %s", name); 244 0 stevel data += 34; 245 0 stevel netbiosname2ascii(name, data); 246 0 stevel sprintf(get_line(0, 0), "Destination Name = %s", name); 247 0 stevel sprintf(get_line(0, 0), "Number of data bytes remaining = %d", 248 0 stevel packetlen - 68); 249 0 stevel show_trailer(); 250 0 stevel } 251 0 stevel } 252 0 stevel 253 0 stevel /* 254 0 stevel * Interpret NetBIOS Name Service packets. 255 0 stevel * [RFC 1002, Sec. 4.2] 256 0 stevel */ 257 0 stevel void 258 0 stevel interpret_netbios_ns(int flags, uchar_t *data, int len) 259 0 stevel { 260 0 stevel int headerflags, qcount, acount, nscount, arcount; 261 0 stevel int transid; 262 0 stevel char name[24]; 263 0 stevel char extra[256]; 264 0 stevel char errortype[50]; 265 0 stevel int rdatalen; 266 0 stevel int rrflags; 267 0 stevel int nameptr; 268 0 stevel int nodecode; 269 0 stevel char *nodetype; 270 0 stevel uchar_t *data0 = data; 271 0 stevel 272 0 stevel transid = getshort(data); data += 2; 273 0 stevel headerflags = getshort(data); data += 2; 274 0 stevel qcount = getshort(data); data += 2; 275 0 stevel acount = getshort(data); data += 2; 276 0 stevel nscount = getshort(data); data += 2; 277 0 stevel arcount = getshort(data); data += 2; 278 0 stevel getrcodeerr(headerflags, errortype); 279 0 stevel 280 0 stevel if (flags & F_SUM) { 281 0 stevel print_ns_type(flags, headerflags, extra); 282 0 stevel data++; 283 0 stevel netbiosname2ascii(name, data); 284 0 stevel sprintf(get_sum_line(), "NBT NS %s for %s, %s", 285 0 stevel extra, name, errortype); 286 0 stevel 287 0 stevel } 288 0 stevel 289 0 stevel 290 0 stevel if (flags & F_DTAIL) { 291 0 stevel show_header("NBT: ", "Netbios Name Service Header", len); 292 0 stevel show_space(); 293 0 stevel print_ns_type(flags, headerflags, 0); 294 0 stevel sprintf(get_line(0, 0), "Status = %s", errortype); 295 0 stevel sprintf(get_line(0, 0), "Transaction ID = 0x%.4x", transid); 296 0 stevel sprintf(get_line(0, 0), "Flags Summary = 0x%.4x", 297 0 stevel headerflags); 298 0 stevel print_flag_details(headerflags); 299 0 stevel sprintf(get_line(0, 0), "Question count = %d", qcount); 300 0 stevel sprintf(get_line(0, 0), "Answer Count = %d", acount); 301 0 stevel sprintf(get_line(0, 0), "Name Service Count = %d", nscount); 302 0 stevel sprintf(get_line(0, 0), 303 0 stevel "Additional Record Count = %d", arcount); 304 0 stevel 305 0 stevel /* 306 0 stevel * Question Section Packet Description from 307 0 stevel * [RFC 1002, Sec. 4.2.1.2] 308 0 stevel */ 309 0 stevel 310 0 stevel if (qcount) { 311 0 stevel data++; 312 0 stevel netbiosname2ascii(name, data); 313 0 stevel sprintf(get_line(0, 0), "Question Name = %s", name); 314 0 stevel data += 33; 315 0 stevel sprintf(get_line(0, 0), "Question Type = 0x%.4x", 316 0 stevel getshort(data)); 317 0 stevel data += 2; 318 0 stevel sprintf(get_line(0, 0), "Question Class = 0x%.4x", 319 0 stevel getshort(data)); 320 0 stevel data += 2; 321 0 stevel } 322 0 stevel 323 0 stevel /* 324 0 stevel * Resrouce Record Packet Description from 325 0 stevel * [RFC 1002, Sec. 4.2.1.3] 326 0 stevel */ 327 0 stevel 328 0 stevel if ((acount || nscount || arcount) || 329 0 stevel (qcount+acount+nscount+arcount == 0)) { 330 0 stevel /* Second level encoding from RFC883 (p.31, 32) */ 331 0 stevel if (data[0] & 0xc0) { 332 0 stevel nameptr = getshort(data)&0x3fff; 333 0 stevel netbiosname2ascii(name, (data0+nameptr+1)); 334 0 stevel sprintf(get_line(0, 0), 335 0 stevel "Resource Record Name = %s", name); 336 0 stevel data += 2; 337 0 stevel } else { 338 0 stevel data++; 339 0 stevel netbiosname2ascii(name, data); 340 0 stevel sprintf(get_line(0, 0), 341 0 stevel "Resource Record Name = %s", name); 342 0 stevel data += 33; 343 0 stevel } 344 0 stevel sprintf(get_line(0, 0), 345 0 stevel "Resource Record Type = 0x%.4x", 346 0 stevel getshort(data)); 347 0 stevel data += 2; 348 0 stevel sprintf(get_line(0, 0), 349 0 stevel "Resource Record Class = 0x%.4x", 350 0 stevel getshort(data)); 351 0 stevel data += 2; 352 0 stevel sprintf(get_line(0, 0), 353 0 stevel "Time to Live (Milliseconds) = %d", 354 0 stevel getlong(data)); 355 0 stevel data += 4; 356 0 stevel rdatalen = getshort(data); 357 0 stevel sprintf(get_line(0, 0), "RDATA Length = 0x%.4x", 358 0 stevel rdatalen); 359 0 stevel data += 2; 360 0 stevel /* 15.4.2.1.3 */ 361 0 stevel if (rdatalen == 6) { 362 0 stevel rrflags = getshort(data); 363 0 stevel data += 2; 364 0 stevel sprintf(get_line(0, 0), 365 0 stevel "Resource Record Flags = 0x%.4x", 366 0 stevel rrflags); 367 0 stevel nodecode = (rrflags>>13)& 0x11; 368 0 stevel if (nodecode == 0) nodetype = "B"; 369 0 stevel if (nodecode == 1) nodetype = "P"; 370 0 stevel if (nodecode == 2) nodetype = "M"; 371 0 stevel sprintf(get_line(0, 0), " - %s, %s node", 372 0 stevel (rrflags & 1<<15) ? 373 0 stevel "Group NetBIOS Name": 374 0 stevel "Unique NetBIOS Name", nodetype); 375 0 stevel sprintf(get_line(0, 0), 376 0 stevel "Owner IP Address = %d.%d.%d.%d", 377 0 stevel data[0], data[1], data[2], data[3]); 378 0 stevel } 379 0 stevel } 380 0 stevel show_trailer(); 381 0 stevel 382 0 stevel } 383 0 stevel } 384 0 stevel 385 0 stevel /* 386 0 stevel * Interpret NetBIOS session packets. 387 0 stevel * [RFC 1002, Sec. 4.3] 388 0 stevel */ 389 0 stevel void 390 0 stevel interpret_netbios_ses(int flags, uchar_t *data, int len) 391 0 stevel { 392 0 stevel struct nbt_ss *ss; 393 0 stevel uchar_t *trailer; 394 0 stevel int length = len - 4; /* NBT packet length without header */ 395 0 stevel char *type; 396 0 stevel char extrainfo[300]; 397 0 stevel 398 0 stevel if (len < sizeof (struct nbt_ss)) 399 0 stevel return; 400 0 stevel 401 0 stevel /* 402 0 stevel * Packets that are fragments of a large NetBIOS session 403 0 stevel * message will have no NetBIOS header. (Only the first 404 0 stevel * TCP segment will have a NetBIOS header.) It turns out 405 0 stevel * that very often, such fragments start with SMB data, so 406 0 stevel * we should try to recognize and decode them. 407 0 stevel */ 408 0 stevel if (data[0] == 0xff && 409 0 stevel data[1] == 'S' && 410 0 stevel data[2] == 'M' && 411 0 stevel data[3] == 'B') { 412 0 stevel interpret_smb(flags, data, len); 413 0 stevel return; 414 0 stevel } 415 0 stevel 416 0 stevel /* LINTED PTRALIGN */ 417 0 stevel ss = (struct nbt_ss *)data; 418 0 stevel trailer = data + sizeof (*ss); 419 0 stevel extrainfo[0] = '\0'; 420 0 stevel 421 0 stevel if (flags & F_SUM) { 422 0 stevel switch (ss->type) { 423 0 stevel case 0x00: 424 0 stevel type = "SESSION MESSAGE"; 425 0 stevel break; 426 0 stevel case 0x81: 427 0 stevel type = "SESSION REQUEST"; 428 0 stevel interpret_netbios_names(flags, trailer, 429 0 stevel length, extrainfo); 430 0 stevel break; 431 0 stevel case 0x82: 432 0 stevel type = "POSITIVE SESSION RESPONSE"; 433 0 stevel break; 434 0 stevel case 0x83: 435 0 stevel type = "NEGATIVE SESSION RESPONSE"; 436 0 stevel break; 437 0 stevel case 0x84: 438 0 stevel type = "RETARGET SESSION RESPONSE"; 439 0 stevel break; 440 0 stevel case 0x85: 441 0 stevel type = "SESSION KEEP ALIVE"; 442 0 stevel break; 443 0 stevel default: 444 0 stevel type = "Unknown"; 445 0 stevel break; 446 0 stevel } 447 0 stevel (void) sprintf(get_sum_line(), 448 0 stevel "NBT Type=%s %sLength=%d", type, extrainfo, length); 449 0 stevel } 450 0 stevel 451 0 stevel if (flags & F_DTAIL) { 452 0 stevel show_header("NBT: ", "NBT Header", len); 453 0 stevel show_space(); 454 0 stevel 455 0 stevel switch (ss->type) { 456 0 stevel case 0x00: 457 0 stevel (void) sprintf(get_line(0, 0), 458 0 stevel "Type = SESSION MESSAGE"); 459 0 stevel break; 460 0 stevel case 0x81: 461 0 stevel (void) sprintf(get_line(0, 0), 462 0 stevel "Type = SESSION REQUEST"); 463 0 stevel interpret_netbios_names(flags, trailer, length, 0); 464 0 stevel break; 465 0 stevel case 0x82: 466 0 stevel (void) sprintf(get_line(0, 0), 467 0 stevel "Type = POSITIVE SESSION RESPONSE"); 468 0 stevel break; 469 0 stevel case 0x83: 470 0 stevel (void) sprintf(get_line(0, 0), 471 0 stevel "Type = NEGATIVE SESSION RESPONSE"); 472 0 stevel break; 473 0 stevel case 0x84: 474 0 stevel (void) sprintf(get_line(0, 0), 475 0 stevel "Type = RETARGET SESSION RESPONSE"); 476 0 stevel break; 477 0 stevel case 0x85: 478 0 stevel (void) sprintf(get_line(0, 0), 479 0 stevel "Type = SESSION KEEP ALIVE"); 480 0 stevel break; 481 0 stevel default: 482 0 stevel (void) sprintf(get_line(0, 0), 483 0 stevel "Type = Unknown"); 484 0 stevel break; 485 0 stevel } 486 0 stevel 487 0 stevel (void) sprintf(get_line(0, 0), "Length = %d bytes", length); 488 0 stevel show_trailer(); 489 0 stevel } 490 0 stevel 491 0 stevel /* 492 0 stevel * SMB packets have { 0xff, 'S', 'M', 'B' } 493 0 stevel * in the first four bytes. If we find that, 494 0 stevel * let snoop_smb.c have a look at it. 495 0 stevel */ 496 0 stevel if (ss->type == 0x00 && 497 0 stevel length > 0 && 498 0 stevel trailer[0] == 0xff && 499 0 stevel trailer[1] == 'S' && 500 0 stevel trailer[2] == 'M' && 501 0 stevel trailer[3] == 'B') 502 7280 blu interpret_smb(flags, trailer, length); 503 0 stevel } 504 0 stevel 505 0 stevel /* 506 0 stevel * NetBIOS name encoding (First Level Encoding) 507 0 stevel * [RFC 1001, Sec. 4.1] 508 0 stevel */ 509 0 stevel static void 510 0 stevel netbiosname2ascii(char *aname, uchar_t *nbname) 511 0 stevel { 512 0 stevel int c, i, j; 513 0 stevel 514 0 stevel i = j = 0; 515 0 stevel for (;;) { 516 0 stevel c = nbname[i++] - 'A'; 517 0 stevel c = (c << 4) + 518 0 stevel nbname[i++] - 'A'; 519 0 stevel /* 16th char is the "type" */ 520 0 stevel if (i >= 32) 521 0 stevel break; 522 0 stevel if (iscntrl(c)) 523 0 stevel c = '.'; 524 0 stevel if (c != ' ') 525 0 stevel aname[j++] = c; 526 0 stevel } 527 0 stevel sprintf(&aname[j], "[%x]", c); 528 0 stevel } 529 0 stevel 530 0 stevel /* 531 0 stevel * Interpret the names in a Session Request packet. 532 0 stevel * [RFC 1002, Sec. 4.3.2] 533 0 stevel */ 534 0 stevel static void 535 0 stevel interpret_netbios_names(int flags, uchar_t *data, int len, char *xtra) 536 0 stevel { 537 0 stevel char calledname[24]; 538 0 stevel char callingname[24]; 539 0 stevel struct callnames *names = (struct callnames *)data; 540 0 stevel 541 0 stevel if (len < sizeof (*names)) 542 0 stevel return; 543 0 stevel 544 0 stevel netbiosname2ascii(calledname, names->calledname); 545 0 stevel netbiosname2ascii(callingname, names->callingname); 546 0 stevel 547 0 stevel if (flags & F_SUM) { 548 0 stevel sprintf(xtra, "Dest=%s Source=%s ", calledname, callingname); 549 0 stevel } 550 0 stevel 551 0 stevel if (flags & F_DTAIL) { 552 0 stevel sprintf(get_line(0, 0), "Destination = %s", calledname); 553 0 stevel sprintf(get_line(0, 0), "Source = %s", callingname); 554 0 stevel } 555 0 stevel } 556