alias_nbt.c revision 77696
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: head/sys/netinet/libalias/alias_nbt.c 77696 2001-06-04 14:52:17Z brian $ 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 56typedef 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 64typedef 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 80typedef 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 98static 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 */ 122static 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 197int 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 267typedef struct { 268 u_short type; /* The type of Request */ 269 u_short class; /* The class of Request */ 270} NBTNsQuestion; 271 272static u_char * 273AliasHandleQuestion( 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 316typedef struct { 317 u_short type; 318 u_short class; 319 unsigned int ttl; 320 u_short rdlen; 321} NBTNsResource; 322 323#define SizeOfNsRNB 6 324typedef struct { 325 u_short g:1, ont:2, resv:13; 326 struct in_addr addr; 327} NBTNsRNB; 328 329static u_char * 330AliasHandleResourceNB( 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 394typedef struct { 395 struct in_addr addr; 396} NBTNsResourceA; 397 398static u_char * 399AliasHandleResourceA( 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 451typedef struct { 452 u_short opcode:4, flags:8, resv:4; 453} NBTNsResourceNULL; 454 455static u_char * 456AliasHandleResourceNULL( 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 488static u_char * 489AliasHandleResourceNS( 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 515typedef struct { 516 u_short numnames; 517} NBTNsResourceNBSTAT; 518 519static u_char * 520AliasHandleResourceNBSTAT( 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 543static u_char * 544AliasHandleResource( 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 613int 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