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