1 /*- 2 * Written by Atsushi Murai <amurai@spec.co.jp> 3 * Copyright (c) 1998, System Planning and Engineering Co. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * TODO: 27 * oClean up. 28 * oConsidering for word alignment for other platform. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 /* 35 alias_nbt.c performs special processing for NetBios over TCP/IP 36 sessions by UDP. 37 38 Initial version: May, 1998 (Atsushi Murai <amurai@spec.co.jp>) 39 40 See HISTORY file for record of revisions. 41 */ 42 43 /* Includes */ 44 #ifdef _KERNEL 45 #include <sys/param.h> 46 #include <sys/ctype.h> 47 #include <sys/libkern.h> 48 #else 49 #include <sys/types.h> 50 #include <ctype.h> 51 #include <stdio.h> 52 #include <string.h> 53 #include <arpa/inet.h> 54 #endif 55 56 #include <netinet/in_systm.h> 57 #include <netinet/in.h> 58 #include <netinet/ip.h> 59 #include <netinet/udp.h> 60 #include <netinet/tcp.h> 61 62 #ifdef _KERNEL 63 #include <netinet/libalias/alias.h> 64 #include <netinet/libalias/alias_local.h> 65 #else 66 #include "alias_local.h" 67 #endif 68 69 typedef struct { 70 struct in_addr oldaddr; 71 u_short oldport; 72 struct in_addr newaddr; 73 u_short newport; 74 u_short *uh_sum; 75 } NBTArguments; 76 77 typedef struct { 78 unsigned char type; 79 unsigned char flags; 80 u_short id; 81 struct in_addr source_ip; 82 u_short source_port; 83 u_short len; 84 u_short offset; 85 } NbtDataHeader; 86 87 #define OpQuery 0 88 #define OpUnknown 4 89 #define OpRegist 5 90 #define OpRelease 6 91 #define OpWACK 7 92 #define OpRefresh 8 93 typedef struct { 94 u_short nametrid; 95 u_short dir: 1, opcode:4, nmflags:7, rcode:4; 96 u_short qdcount; 97 u_short ancount; 98 u_short nscount; 99 u_short arcount; 100 } NbtNSHeader; 101 102 #define FMT_ERR 0x1 103 #define SRV_ERR 0x2 104 #define IMP_ERR 0x4 105 #define RFS_ERR 0x5 106 #define ACT_ERR 0x6 107 #define CFT_ERR 0x7 108 109 110 #ifdef LIBALIAS_DEBUG 111 static void 112 PrintRcode(u_char rcode) 113 { 114 115 switch (rcode) { 116 case FMT_ERR: 117 printf("\nFormat Error."); 118 case SRV_ERR: 119 printf("\nSever failure."); 120 case IMP_ERR: 121 printf("\nUnsupported request error.\n"); 122 case RFS_ERR: 123 printf("\nRefused error.\n"); 124 case ACT_ERR: 125 printf("\nActive error.\n"); 126 case CFT_ERR: 127 printf("\nName in conflict error.\n"); 128 default: 129 printf("\n?%c?=%0x\n", '?', rcode); 130 131 } 132 } 133 134 #endif 135 136 137 /* Handling Name field */ 138 static u_char * 139 AliasHandleName(u_char * p, char *pmax) 140 { 141 142 u_char *s; 143 u_char c; 144 int compress; 145 146 /* Following length field */ 147 148 if (p == NULL || (char *)p >= pmax) 149 return (NULL); 150 151 if (*p & 0xc0) { 152 p = p + 2; 153 if ((char *)p > pmax) 154 return (NULL); 155 return ((u_char *) p); 156 } 157 while ((*p & 0x3f) != 0x00) { 158 s = p + 1; 159 if (*p == 0x20) 160 compress = 1; 161 else 162 compress = 0; 163 164 /* Get next length field */ 165 p = (u_char *) (p + (*p & 0x3f) + 1); 166 if ((char *)p > pmax) { 167 p = NULL; 168 break; 169 } 170 #ifdef LIBALIAS_DEBUG 171 printf(":"); 172 #endif 173 while (s < p) { 174 if (compress == 1) { 175 c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11)); 176 #ifdef LIBALIAS_DEBUG 177 if (isprint(c)) 178 printf("%c", c); 179 else 180 printf("<0x%02x>", c); 181 #endif 182 s += 2; 183 } else { 184 #ifdef LIBALIAS_DEBUG 185 printf("%c", *s); 186 #endif 187 s++; 188 } 189 } 190 #ifdef LIBALIAS_DEBUG 191 printf(":"); 192 fflush(stdout); 193 #endif 194 } 195 196 /* Set up to out of Name field */ 197 if (p == NULL || (char *)p >= pmax) 198 p = NULL; 199 else 200 p++; 201 return ((u_char *) p); 202 } 203 204 /* 205 * NetBios Datagram Handler (IP/UDP) 206 */ 207 #define DGM_DIRECT_UNIQ 0x10 208 #define DGM_DIRECT_GROUP 0x11 209 #define DGM_BROADCAST 0x12 210 #define DGM_ERROR 0x13 211 #define DGM_QUERY 0x14 212 #define DGM_POSITIVE_RES 0x15 213 #define DGM_NEGATIVE_RES 0x16 214 215 int 216 AliasHandleUdpNbt( 217 struct libalias *la, 218 struct ip *pip, /* IP packet to examine/patch */ 219 struct alias_link *lnk, 220 struct in_addr *alias_address, 221 u_short alias_port 222 ) 223 { 224 struct udphdr *uh; 225 NbtDataHeader *ndh; 226 u_char *p = NULL; 227 char *pmax; 228 229 (void)la; 230 (void)lnk; 231 232 /* Calculate data length of UDP packet */ 233 uh = (struct udphdr *)ip_next(pip); 234 pmax = (char *)uh + ntohs(uh->uh_ulen); 235 236 ndh = (NbtDataHeader *)udp_next(uh); 237 if ((char *)(ndh + 1) > pmax) 238 return (-1); 239 #ifdef LIBALIAS_DEBUG 240 printf("\nType=%02x,", ndh->type); 241 #endif 242 switch (ndh->type) { 243 case DGM_DIRECT_UNIQ: 244 case DGM_DIRECT_GROUP: 245 case DGM_BROADCAST: 246 p = (u_char *) ndh + 14; 247 p = AliasHandleName(p, pmax); /* Source Name */ 248 p = AliasHandleName(p, pmax); /* Destination Name */ 249 break; 250 case DGM_ERROR: 251 p = (u_char *) ndh + 11; 252 break; 253 case DGM_QUERY: 254 case DGM_POSITIVE_RES: 255 case DGM_NEGATIVE_RES: 256 p = (u_char *) ndh + 10; 257 p = AliasHandleName(p, pmax); /* Destination Name */ 258 break; 259 } 260 if (p == NULL || (char *)p > pmax) 261 p = NULL; 262 #ifdef LIBALIAS_DEBUG 263 printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port)); 264 #endif 265 /* Doing an IP address and Port number Translation */ 266 if (uh->uh_sum != 0) { 267 int acc; 268 u_short *sptr; 269 270 acc = ndh->source_port; 271 acc -= alias_port; 272 sptr = (u_short *) & (ndh->source_ip); 273 acc += *sptr++; 274 acc += *sptr; 275 sptr = (u_short *) alias_address; 276 acc -= *sptr++; 277 acc -= *sptr; 278 ADJUST_CHECKSUM(acc, uh->uh_sum); 279 } 280 ndh->source_ip = *alias_address; 281 ndh->source_port = alias_port; 282 #ifdef LIBALIAS_DEBUG 283 printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port)); 284 fflush(stdout); 285 #endif 286 return ((p == NULL) ? -1 : 0); 287 } 288 289 /* Question Section */ 290 #define QS_TYPE_NB 0x0020 291 #define QS_TYPE_NBSTAT 0x0021 292 #define QS_CLAS_IN 0x0001 293 typedef struct { 294 u_short type; /* The type of Request */ 295 u_short class; /* The class of Request */ 296 } NBTNsQuestion; 297 298 static u_char * 299 AliasHandleQuestion( 300 u_short count, 301 NBTNsQuestion * q, 302 char *pmax, 303 NBTArguments * nbtarg) 304 { 305 306 (void)nbtarg; 307 308 while (count != 0) { 309 /* Name Filed */ 310 q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax); 311 312 if (q == NULL || (char *)(q + 1) > pmax) { 313 q = NULL; 314 break; 315 } 316 /* Type and Class filed */ 317 switch (ntohs(q->type)) { 318 case QS_TYPE_NB: 319 case QS_TYPE_NBSTAT: 320 q = q + 1; 321 break; 322 default: 323 #ifdef LIBALIAS_DEBUG 324 printf("\nUnknown Type on Question %0x\n", ntohs(q->type)); 325 #endif 326 break; 327 } 328 count--; 329 } 330 331 /* Set up to out of Question Section */ 332 return ((u_char *) q); 333 } 334 335 /* Resource Record */ 336 #define RR_TYPE_A 0x0001 337 #define RR_TYPE_NS 0x0002 338 #define RR_TYPE_NULL 0x000a 339 #define RR_TYPE_NB 0x0020 340 #define RR_TYPE_NBSTAT 0x0021 341 #define RR_CLAS_IN 0x0001 342 #define SizeOfNsResource 8 343 typedef struct { 344 u_short type; 345 u_short class; 346 unsigned int ttl; 347 u_short rdlen; 348 } NBTNsResource; 349 350 #define SizeOfNsRNB 6 351 typedef struct { 352 u_short g: 1 , ont:2, resv:13; 353 struct in_addr addr; 354 } NBTNsRNB; 355 356 static u_char * 357 AliasHandleResourceNB( 358 NBTNsResource * q, 359 char *pmax, 360 NBTArguments * nbtarg) 361 { 362 NBTNsRNB *nb; 363 u_short bcount; 364 365 if (q == NULL || (char *)(q + 1) > pmax) 366 return (NULL); 367 /* Check out a length */ 368 bcount = ntohs(q->rdlen); 369 370 /* Forward to Resource NB position */ 371 nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource); 372 373 /* Processing all in_addr array */ 374 #ifdef LIBALIAS_DEBUG 375 printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr)); 376 printf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount); 377 #endif 378 while (nb != NULL && bcount != 0) { 379 if ((char *)(nb + 1) > pmax) { 380 nb = NULL; 381 break; 382 } 383 #ifdef LIBALIAS_DEBUG 384 printf("<%s>", inet_ntoa(nb->addr)); 385 #endif 386 if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) { 387 if (*nbtarg->uh_sum != 0) { 388 int acc; 389 u_short *sptr; 390 391 sptr = (u_short *) & (nb->addr); 392 acc = *sptr++; 393 acc += *sptr; 394 sptr = (u_short *) & (nbtarg->newaddr); 395 acc -= *sptr++; 396 acc -= *sptr; 397 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); 398 } 399 nb->addr = nbtarg->newaddr; 400 #ifdef LIBALIAS_DEBUG 401 printf("O"); 402 #endif 403 } 404 #ifdef LIBALIAS_DEBUG 405 else { 406 printf("."); 407 } 408 #endif 409 nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB); 410 bcount -= SizeOfNsRNB; 411 } 412 if (nb == NULL || (char *)(nb + 1) > pmax) { 413 nb = NULL; 414 } 415 return ((u_char *) nb); 416 } 417 418 #define SizeOfResourceA 6 419 typedef struct { 420 struct in_addr addr; 421 } NBTNsResourceA; 422 423 static u_char * 424 AliasHandleResourceA( 425 NBTNsResource * q, 426 char *pmax, 427 NBTArguments * nbtarg) 428 { 429 NBTNsResourceA *a; 430 u_short bcount; 431 432 if (q == NULL || (char *)(q + 1) > pmax) 433 return (NULL); 434 435 /* Forward to Resource A position */ 436 a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource)); 437 438 /* Check out of length */ 439 bcount = ntohs(q->rdlen); 440 441 /* Processing all in_addr array */ 442 #ifdef LIBALIAS_DEBUG 443 printf("Arec [%s", inet_ntoa(nbtarg->oldaddr)); 444 printf("->%s]", inet_ntoa(nbtarg->newaddr)); 445 #endif 446 while (bcount != 0) { 447 if (a == NULL || (char *)(a + 1) > pmax) 448 return (NULL); 449 #ifdef LIBALIAS_DEBUG 450 printf("..%s", inet_ntoa(a->addr)); 451 #endif 452 if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) { 453 if (*nbtarg->uh_sum != 0) { 454 int acc; 455 u_short *sptr; 456 457 sptr = (u_short *) & (a->addr); /* Old */ 458 acc = *sptr++; 459 acc += *sptr; 460 sptr = (u_short *) & nbtarg->newaddr; /* New */ 461 acc -= *sptr++; 462 acc -= *sptr; 463 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); 464 } 465 a->addr = nbtarg->newaddr; 466 } 467 a++; /* XXXX */ 468 bcount -= SizeOfResourceA; 469 } 470 if (a == NULL || (char *)(a + 1) > pmax) 471 a = NULL; 472 return ((u_char *) a); 473 } 474 475 typedef struct { 476 u_short opcode:4, flags:8, resv:4; 477 } NBTNsResourceNULL; 478 479 static u_char * 480 AliasHandleResourceNULL( 481 NBTNsResource * q, 482 char *pmax, 483 NBTArguments * nbtarg) 484 { 485 NBTNsResourceNULL *n; 486 u_short bcount; 487 488 (void)nbtarg; 489 490 if (q == NULL || (char *)(q + 1) > pmax) 491 return (NULL); 492 493 /* Forward to Resource NULL position */ 494 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource)); 495 496 /* Check out of length */ 497 bcount = ntohs(q->rdlen); 498 499 /* Processing all in_addr array */ 500 while (bcount != 0) { 501 if ((char *)(n + 1) > pmax) { 502 n = NULL; 503 break; 504 } 505 n++; 506 bcount -= sizeof(NBTNsResourceNULL); 507 } 508 if ((char *)(n + 1) > pmax) 509 n = NULL; 510 511 return ((u_char *) n); 512 } 513 514 static u_char * 515 AliasHandleResourceNS( 516 NBTNsResource * q, 517 char *pmax, 518 NBTArguments * nbtarg) 519 { 520 NBTNsResourceNULL *n; 521 u_short bcount; 522 523 (void)nbtarg; 524 525 if (q == NULL || (char *)(q + 1) > pmax) 526 return (NULL); 527 528 /* Forward to Resource NULL position */ 529 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource)); 530 531 /* Check out of length */ 532 bcount = ntohs(q->rdlen); 533 534 /* Resource Record Name Filed */ 535 q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax); /* XXX */ 536 537 if (q == NULL || (char *)((u_char *) n + bcount) > pmax) 538 return (NULL); 539 else 540 return ((u_char *) n + bcount); 541 } 542 543 typedef struct { 544 u_short numnames; 545 } NBTNsResourceNBSTAT; 546 547 static u_char * 548 AliasHandleResourceNBSTAT( 549 NBTNsResource * q, 550 char *pmax, 551 NBTArguments * nbtarg) 552 { 553 NBTNsResourceNBSTAT *n; 554 u_short bcount; 555 556 (void)nbtarg; 557 558 if (q == NULL || (char *)(q + 1) > pmax) 559 return (NULL); 560 561 /* Forward to Resource NBSTAT position */ 562 n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource)); 563 564 /* Check out of length */ 565 bcount = ntohs(q->rdlen); 566 567 if (q == NULL || (char *)((u_char *) n + bcount) > pmax) 568 return (NULL); 569 else 570 return ((u_char *) n + bcount); 571 } 572 573 static u_char * 574 AliasHandleResource( 575 u_short count, 576 NBTNsResource * q, 577 char *pmax, 578 NBTArguments 579 * nbtarg) 580 { 581 while (count != 0) { 582 /* Resource Record Name Filed */ 583 q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax); 584 585 if (q == NULL || (char *)(q + 1) > pmax) 586 break; 587 #ifdef LIBALIAS_DEBUG 588 printf("type=%02x, count=%d\n", ntohs(q->type), count); 589 #endif 590 591 /* Type and Class filed */ 592 switch (ntohs(q->type)) { 593 case RR_TYPE_NB: 594 q = (NBTNsResource *) AliasHandleResourceNB( 595 q, 596 pmax, 597 nbtarg 598 ); 599 break; 600 case RR_TYPE_A: 601 q = (NBTNsResource *) AliasHandleResourceA( 602 q, 603 pmax, 604 nbtarg 605 ); 606 break; 607 case RR_TYPE_NS: 608 q = (NBTNsResource *) AliasHandleResourceNS( 609 q, 610 pmax, 611 nbtarg 612 ); 613 break; 614 case RR_TYPE_NULL: 615 q = (NBTNsResource *) AliasHandleResourceNULL( 616 q, 617 pmax, 618 nbtarg 619 ); 620 break; 621 case RR_TYPE_NBSTAT: 622 q = (NBTNsResource *) AliasHandleResourceNBSTAT( 623 q, 624 pmax, 625 nbtarg 626 ); 627 break; 628 default: 629 #ifdef LIBALIAS_DEBUG 630 printf( 631 "\nUnknown Type of Resource %0x\n", 632 ntohs(q->type) 633 ); 634 fflush(stdout); 635 #endif 636 break; 637 } 638 count--; 639 } 640 return ((u_char *) q); 641 } 642 643 int 644 AliasHandleUdpNbtNS( 645 struct libalias *la, 646 struct ip *pip, /* IP packet to examine/patch */ 647 struct alias_link *lnk, 648 struct in_addr *alias_address, 649 u_short * alias_port, 650 struct in_addr *original_address, 651 u_short * original_port) 652 { 653 struct udphdr *uh; 654 NbtNSHeader *nsh; 655 u_char *p; 656 char *pmax; 657 NBTArguments nbtarg; 658 659 (void)la; 660 (void)lnk; 661 662 /* Set up Common Parameter */ 663 nbtarg.oldaddr = *alias_address; 664 nbtarg.oldport = *alias_port; 665 nbtarg.newaddr = *original_address; 666 nbtarg.newport = *original_port; 667 668 /* Calculate data length of UDP packet */ 669 uh = (struct udphdr *)ip_next(pip); 670 nbtarg.uh_sum = &(uh->uh_sum); 671 nsh = (NbtNSHeader *)udp_next(uh); 672 p = (u_char *) (nsh + 1); 673 pmax = (char *)uh + ntohs(uh->uh_ulen); 674 675 if ((char *)(nsh + 1) > pmax) 676 return (-1); 677 678 #ifdef LIBALIAS_DEBUG 679 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x" 680 ", an=%04x, ns=%04x, ar=%04x, [%d]-->", 681 nsh->dir ? "Response" : "Request", 682 nsh->nametrid, 683 nsh->opcode, 684 nsh->nmflags, 685 nsh->rcode, 686 ntohs(nsh->qdcount), 687 ntohs(nsh->ancount), 688 ntohs(nsh->nscount), 689 ntohs(nsh->arcount), 690 (u_char *) p - (u_char *) nsh 691 ); 692 #endif 693 694 /* Question Entries */ 695 if (ntohs(nsh->qdcount) != 0) { 696 p = AliasHandleQuestion( 697 ntohs(nsh->qdcount), 698 (NBTNsQuestion *) p, 699 pmax, 700 &nbtarg 701 ); 702 } 703 /* Answer Resource Records */ 704 if (ntohs(nsh->ancount) != 0) { 705 p = AliasHandleResource( 706 ntohs(nsh->ancount), 707 (NBTNsResource *) p, 708 pmax, 709 &nbtarg 710 ); 711 } 712 /* Authority Resource Recodrs */ 713 if (ntohs(nsh->nscount) != 0) { 714 p = AliasHandleResource( 715 ntohs(nsh->nscount), 716 (NBTNsResource *) p, 717 pmax, 718 &nbtarg 719 ); 720 } 721 /* Additional Resource Recodrs */ 722 if (ntohs(nsh->arcount) != 0) { 723 p = AliasHandleResource( 724 ntohs(nsh->arcount), 725 (NBTNsResource *) p, 726 pmax, 727 &nbtarg 728 ); 729 } 730 #ifdef LIBALIAS_DEBUG 731 PrintRcode(nsh->rcode); 732 #endif 733 return ((p == NULL) ? -1 : 0); 734 } 735