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