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