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