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 *link, 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 /* Calculate data length of UDP packet */ 218 uh = (struct udphdr *)((char *)pip + (pip->ip_hl << 2)); 219 pmax = (char *)uh + ntohs(uh->uh_ulen); 220 221 ndh = (NbtDataHeader *) ((char *)uh + (sizeof(struct udphdr))); 222 if ((char *)(ndh + 1) > pmax) 223 return (-1); 224 #ifdef DEBUG 225 printf("\nType=%02x,", ndh->type); 226 #endif 227 switch (ndh->type) { 228 case DGM_DIRECT_UNIQ: 229 case DGM_DIRECT_GROUP: 230 case DGM_BROADCAST: 231 p = (u_char *) ndh + 14; 232 p = AliasHandleName(p, pmax); /* Source Name */ 233 p = AliasHandleName(p, pmax); /* Destination Name */ 234 break; 235 case DGM_ERROR: 236 p = (u_char *) ndh + 11; 237 break; 238 case DGM_QUERY: 239 case DGM_POSITIVE_RES: 240 case DGM_NEGATIVE_RES: 241 p = (u_char *) ndh + 10; 242 p = AliasHandleName(p, pmax); /* Destination Name */ 243 break; 244 } 245 if (p == NULL || (char *)p > pmax) 246 p = NULL; 247 #ifdef DEBUG 248 printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port)); 249 #endif 250 /* Doing an IP address and Port number Translation */ 251 if (uh->uh_sum != 0) { 252 int acc; 253 u_short *sptr; 254 255 acc = ndh->source_port; 256 acc -= alias_port; 257 sptr = (u_short *) & (ndh->source_ip); 258 acc += *sptr++; 259 acc += *sptr; 260 sptr = (u_short *) alias_address; 261 acc -= *sptr++; 262 acc -= *sptr; 263 ADJUST_CHECKSUM(acc, uh->uh_sum); 264 } 265 ndh->source_ip = *alias_address; 266 ndh->source_port = alias_port; 267 #ifdef DEBUG 268 printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port)); 269 fflush(stdout); 270 #endif 271 return ((p == NULL) ? -1 : 0); 272 } 273 274 /* Question Section */ 275 #define QS_TYPE_NB 0x0020 276 #define QS_TYPE_NBSTAT 0x0021 277 #define QS_CLAS_IN 0x0001 278 typedef struct { 279 u_short type; /* The type of Request */ 280 u_short class; /* The class of Request */ 281 } NBTNsQuestion; 282 283 static u_char * 284 AliasHandleQuestion( 285 u_short count, 286 NBTNsQuestion * q, 287 char *pmax, 288 NBTArguments * nbtarg) 289 { 290 291 while (count != 0) { 292 /* Name Filed */ 293 q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax); 294 295 if (q == NULL || (char *)(q + 1) > pmax) { 296 q = NULL; 297 break; 298 } 299 /* Type and Class filed */ 300 switch (ntohs(q->type)) { 301 case QS_TYPE_NB: 302 case QS_TYPE_NBSTAT: 303 q = q + 1; 304 break; 305 default: 306 #ifdef DEBUG 307 printf("\nUnknown Type on Question %0x\n", ntohs(q->type)); 308 #endif 309 break; 310 } 311 count--; 312 } 313 314 /* Set up to out of Question Section */ 315 return ((u_char *) q); 316 } 317 318 /* Resource Record */ 319 #define RR_TYPE_A 0x0001 320 #define RR_TYPE_NS 0x0002 321 #define RR_TYPE_NULL 0x000a 322 #define RR_TYPE_NB 0x0020 323 #define RR_TYPE_NBSTAT 0x0021 324 #define RR_CLAS_IN 0x0001 325 #define SizeOfNsResource 8 326 typedef struct { 327 u_short type; 328 u_short class; 329 unsigned int ttl; 330 u_short rdlen; 331 } NBTNsResource; 332 333 #define SizeOfNsRNB 6 334 typedef struct { 335 u_short g: 1 , ont:2, resv:13; 336 struct in_addr addr; 337 } NBTNsRNB; 338 339 static u_char * 340 AliasHandleResourceNB( 341 NBTNsResource * q, 342 char *pmax, 343 NBTArguments * nbtarg) 344 { 345 NBTNsRNB *nb; 346 u_short bcount; 347 348 if (q == NULL || (char *)(q + 1) > pmax) 349 return (NULL); 350 /* Check out a length */ 351 bcount = ntohs(q->rdlen); 352 353 /* Forward to Resource NB position */ 354 nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource); 355 356 /* Processing all in_addr array */ 357 #ifdef DEBUG 358 printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr)); 359 printf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount); 360 #endif 361 while (nb != NULL && bcount != 0) { 362 if ((char *)(nb + 1) > pmax) { 363 nb = NULL; 364 break; 365 } 366 #ifdef DEBUG 367 printf("<%s>", inet_ntoa(nb->addr)); 368 #endif 369 if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) { 370 if (*nbtarg->uh_sum != 0) { 371 int acc; 372 u_short *sptr; 373 374 sptr = (u_short *) & (nb->addr); 375 acc = *sptr++; 376 acc += *sptr; 377 sptr = (u_short *) & (nbtarg->newaddr); 378 acc -= *sptr++; 379 acc -= *sptr; 380 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); 381 } 382 nb->addr = nbtarg->newaddr; 383 #ifdef DEBUG 384 printf("O"); 385 #endif 386 } 387 #ifdef DEBUG 388 else { 389 printf("."); 390 } 391 #endif 392 nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB); 393 bcount -= SizeOfNsRNB; 394 } 395 if (nb == NULL || (char *)(nb + 1) > pmax) { 396 nb = NULL; 397 } 398 return ((u_char *) nb); 399 } 400 401 #define SizeOfResourceA 6 402 typedef struct { 403 struct in_addr addr; 404 } NBTNsResourceA; 405 406 static u_char * 407 AliasHandleResourceA( 408 NBTNsResource * q, 409 char *pmax, 410 NBTArguments * nbtarg) 411 { 412 NBTNsResourceA *a; 413 u_short bcount; 414 415 if (q == NULL || (char *)(q + 1) > pmax) 416 return (NULL); 417 418 /* Forward to Resource A position */ 419 a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource)); 420 421 /* Check out of length */ 422 bcount = ntohs(q->rdlen); 423 424 /* Processing all in_addr array */ 425 #ifdef DEBUG 426 printf("Arec [%s", inet_ntoa(nbtarg->oldaddr)); 427 printf("->%s]", inet_ntoa(nbtarg->newaddr)); 428 #endif 429 while (bcount != 0) { 430 if (a == NULL || (char *)(a + 1) > pmax) 431 return (NULL); 432 #ifdef DEBUG 433 printf("..%s", inet_ntoa(a->addr)); 434 #endif 435 if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) { 436 if (*nbtarg->uh_sum != 0) { 437 int acc; 438 u_short *sptr; 439 440 sptr = (u_short *) & (a->addr); /* Old */ 441 acc = *sptr++; 442 acc += *sptr; 443 sptr = (u_short *) & nbtarg->newaddr; /* New */ 444 acc -= *sptr++; 445 acc -= *sptr; 446 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); 447 } 448 a->addr = nbtarg->newaddr; 449 } 450 a++; /* XXXX */ 451 bcount -= SizeOfResourceA; 452 } 453 if (a == NULL || (char *)(a + 1) > pmax) 454 a = NULL; 455 return ((u_char *) a); 456 } 457 458 typedef struct { 459 u_short opcode:4, flags:8, resv:4; 460 } NBTNsResourceNULL; 461 462 static u_char * 463 AliasHandleResourceNULL( 464 NBTNsResource * q, 465 char *pmax, 466 NBTArguments * nbtarg) 467 { 468 NBTNsResourceNULL *n; 469 u_short bcount; 470 471 if (q == NULL || (char *)(q + 1) > pmax) 472 return (NULL); 473 474 /* Forward to Resource NULL position */ 475 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource)); 476 477 /* Check out of length */ 478 bcount = ntohs(q->rdlen); 479 480 /* Processing all in_addr array */ 481 while (bcount != 0) { 482 if ((char *)(n + 1) > pmax) { 483 n = NULL; 484 break; 485 } 486 n++; 487 bcount -= sizeof(NBTNsResourceNULL); 488 } 489 if ((char *)(n + 1) > pmax) 490 n = NULL; 491 492 return ((u_char *) n); 493 } 494 495 static u_char * 496 AliasHandleResourceNS( 497 NBTNsResource * q, 498 char *pmax, 499 NBTArguments * nbtarg) 500 { 501 NBTNsResourceNULL *n; 502 u_short bcount; 503 504 if (q == NULL || (char *)(q + 1) > pmax) 505 return (NULL); 506 507 /* Forward to Resource NULL position */ 508 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource)); 509 510 /* Check out of length */ 511 bcount = ntohs(q->rdlen); 512 513 /* Resource Record Name Filed */ 514 q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax); /* XXX */ 515 516 if (q == NULL || (char *)((u_char *) n + bcount) > pmax) 517 return (NULL); 518 else 519 return ((u_char *) n + bcount); 520 } 521 522 typedef struct { 523 u_short numnames; 524 } NBTNsResourceNBSTAT; 525 526 static u_char * 527 AliasHandleResourceNBSTAT( 528 NBTNsResource * q, 529 char *pmax, 530 NBTArguments * nbtarg) 531 { 532 NBTNsResourceNBSTAT *n; 533 u_short bcount; 534 535 if (q == NULL || (char *)(q + 1) > pmax) 536 return (NULL); 537 538 /* Forward to Resource NBSTAT position */ 539 n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource)); 540 541 /* Check out of length */ 542 bcount = ntohs(q->rdlen); 543 544 if (q == NULL || (char *)((u_char *) n + bcount) > pmax) 545 return (NULL); 546 else 547 return ((u_char *) n + bcount); 548 } 549 550 static u_char * 551 AliasHandleResource( 552 u_short count, 553 NBTNsResource * q, 554 char *pmax, 555 NBTArguments 556 * nbtarg) 557 { 558 while (count != 0) { 559 /* Resource Record Name Filed */ 560 q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax); 561 562 if (q == NULL || (char *)(q + 1) > pmax) 563 break; 564 #ifdef DEBUG 565 printf("type=%02x, count=%d\n", ntohs(q->type), count); 566 #endif 567 568 /* Type and Class filed */ 569 switch (ntohs(q->type)) { 570 case RR_TYPE_NB: 571 q = (NBTNsResource *) AliasHandleResourceNB( 572 q, 573 pmax, 574 nbtarg 575 ); 576 break; 577 case RR_TYPE_A: 578 q = (NBTNsResource *) AliasHandleResourceA( 579 q, 580 pmax, 581 nbtarg 582 ); 583 break; 584 case RR_TYPE_NS: 585 q = (NBTNsResource *) AliasHandleResourceNS( 586 q, 587 pmax, 588 nbtarg 589 ); 590 break; 591 case RR_TYPE_NULL: 592 q = (NBTNsResource *) AliasHandleResourceNULL( 593 q, 594 pmax, 595 nbtarg 596 ); 597 break; 598 case RR_TYPE_NBSTAT: 599 q = (NBTNsResource *) AliasHandleResourceNBSTAT( 600 q, 601 pmax, 602 nbtarg 603 ); 604 break; 605 default: 606 #ifdef DEBUG 607 printf( 608 "\nUnknown Type of Resource %0x\n", 609 ntohs(q->type) 610 ); 611 #endif 612 break; 613 } 614 count--; 615 } 616 fflush(stdout); 617 return ((u_char *) q); 618 } 619 620 int 621 AliasHandleUdpNbtNS( 622 struct libalias *la, 623 struct ip *pip, /* IP packet to examine/patch */ 624 struct alias_link *link, 625 struct in_addr *alias_address, 626 u_short * alias_port, 627 struct in_addr *original_address, 628 u_short * original_port) 629 { 630 struct udphdr *uh; 631 NbtNSHeader *nsh; 632 u_char *p; 633 char *pmax; 634 NBTArguments nbtarg; 635 636 /* Set up Common Parameter */ 637 nbtarg.oldaddr = *alias_address; 638 nbtarg.oldport = *alias_port; 639 nbtarg.newaddr = *original_address; 640 nbtarg.newport = *original_port; 641 642 /* Calculate data length of UDP packet */ 643 uh = (struct udphdr *)((char *)pip + (pip->ip_hl << 2)); 644 nbtarg.uh_sum = &(uh->uh_sum); 645 nsh = (NbtNSHeader *) ((char *)uh + (sizeof(struct udphdr))); 646 p = (u_char *) (nsh + 1); 647 pmax = (char *)uh + ntohs(uh->uh_ulen); 648 649 if ((char *)(nsh + 1) > pmax) 650 return (-1); 651 652 #ifdef DEBUG 653 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x" 654 ", an=%04x, ns=%04x, ar=%04x, [%d]-->", 655 nsh->dir ? "Response" : "Request", 656 nsh->nametrid, 657 nsh->opcode, 658 nsh->nmflags, 659 nsh->rcode, 660 ntohs(nsh->qdcount), 661 ntohs(nsh->ancount), 662 ntohs(nsh->nscount), 663 ntohs(nsh->arcount), 664 (u_char *) p - (u_char *) nsh 665 ); 666 #endif 667 668 /* Question Entries */ 669 if (ntohs(nsh->qdcount) != 0) { 670 p = AliasHandleQuestion( 671 ntohs(nsh->qdcount), 672 (NBTNsQuestion *) p, 673 pmax, 674 &nbtarg 675 ); 676 } 677 /* Answer Resource Records */ 678 if (ntohs(nsh->ancount) != 0) { 679 p = AliasHandleResource( 680 ntohs(nsh->ancount), 681 (NBTNsResource *) p, 682 pmax, 683 &nbtarg 684 ); 685 } 686 /* Authority Resource Recodrs */ 687 if (ntohs(nsh->nscount) != 0) { 688 p = AliasHandleResource( 689 ntohs(nsh->nscount), 690 (NBTNsResource *) p, 691 pmax, 692 &nbtarg 693 ); 694 } 695 /* Additional Resource Recodrs */ 696 if (ntohs(nsh->arcount) != 0) { 697 p = AliasHandleResource( 698 ntohs(nsh->arcount), 699 (NBTNsResource *) p, 700 pmax, 701 &nbtarg 702 ); 703 } 704 #ifdef DEBUG 705 PrintRcode(nsh->rcode); 706 #endif 707 return ((p == NULL) ? -1 : 0); 708 } 709