alias_nbt.c revision 74778
1109998Smarkm/* 2109998Smarkm * Written by Atsushi Murai <amurai@spec.co.jp> 3109998Smarkm * 4109998Smarkm * Copyright (C) 1998, System Planning and Engineering Co. All rights reserverd. 5109998Smarkm * 6109998Smarkm * Redistribution and use in source and binary forms are permitted 7109998Smarkm * provided that the above copyright notice and this paragraph are 8109998Smarkm * duplicated in all such forms and that any documentation, 9109998Smarkm * advertising materials, and other materials related to such 10109998Smarkm * distribution and use acknowledge that the software was developed 11109998Smarkm * by the System Planning and Engineering Co. The name of the 12109998Smarkm * SPEC may not be used to endorse or promote products derived 13109998Smarkm * from this software without specific prior written permission. 14109998Smarkm * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15109998Smarkm * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16109998Smarkm * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 17109998Smarkm * 18109998Smarkm * $FreeBSD: head/sys/netinet/libalias/alias_nbt.c 74778 2001-03-25 12:05:10Z brian $ 19109998Smarkm * 20109998Smarkm * TODO: 21109998Smarkm * oClean up. 22109998Smarkm * oConsidering for word alignment for other platform. 23109998Smarkm */ 24109998Smarkm/* 25109998Smarkm alias_nbt.c performs special processing for NetBios over TCP/IP 26109998Smarkm sessions by UDP. 27109998Smarkm 28109998Smarkm Initial version: May, 1998 (Atsushi Murai <amurai@spec.co.jp>) 29109998Smarkm 30109998Smarkm See HISTORY file for record of revisions. 31109998Smarkm*/ 32109998Smarkm 33109998Smarkm/* Includes */ 34109998Smarkm#include <ctype.h> 35109998Smarkm#include <stdio.h> 36109998Smarkm#include <string.h> 37109998Smarkm#include <sys/types.h> 38109998Smarkm#include <netinet/in_systm.h> 39109998Smarkm#include <netinet/in.h> 40109998Smarkm#include <arpa/inet.h> 41109998Smarkm#include <netinet/ip.h> 42109998Smarkm#include <netinet/udp.h> 43109998Smarkm#include <netinet/tcp.h> 44109998Smarkm 45109998Smarkm#include "alias_local.h" 46109998Smarkm 47109998Smarkmtypedef struct { 48109998Smarkm struct in_addr oldaddr; 49109998Smarkm u_short oldport; 50109998Smarkm struct in_addr newaddr; 51109998Smarkm u_short newport; 52109998Smarkm u_short *uh_sum; 53109998Smarkm} NBTArguments; 54109998Smarkm 55109998Smarkmtypedef struct { 56109998Smarkm unsigned char type; 57109998Smarkm unsigned char flags; 58109998Smarkm u_short id; 59109998Smarkm struct in_addr source_ip; 60109998Smarkm u_short source_port; 61109998Smarkm u_short len; 62109998Smarkm u_short offset; 63109998Smarkm} NbtDataHeader; 64109998Smarkm 65109998Smarkm#define OpQuery 0 66109998Smarkm#define OpUnknown 4 67109998Smarkm#define OpRegist 5 68109998Smarkm#define OpRelease 6 69109998Smarkm#define OpWACK 7 70109998Smarkm#define OpRefresh 8 71109998Smarkmtypedef struct { 72109998Smarkm u_short nametrid; 73109998Smarkm u_short dir:1, opcode:4, nmflags:7, rcode:4; 74109998Smarkm u_short qdcount; 75109998Smarkm u_short ancount; 76109998Smarkm u_short nscount; 77109998Smarkm u_short arcount; 78109998Smarkm} NbtNSHeader; 79109998Smarkm 80109998Smarkm#define FMT_ERR 0x1 81109998Smarkm#define SRV_ERR 0x2 82109998Smarkm#define IMP_ERR 0x4 83109998Smarkm#define RFS_ERR 0x5 84109998Smarkm#define ACT_ERR 0x6 85109998Smarkm#define CFT_ERR 0x7 86109998Smarkm 87109998Smarkm 88109998Smarkm#ifdef DEBUG 89109998Smarkmstatic void PrintRcode( u_char rcode ) { 90109998Smarkm 91109998Smarkm switch (rcode) { 92109998Smarkm case FMT_ERR: 93109998Smarkm printf("\nFormat Error."); 94109998Smarkm case SRV_ERR: 95109998Smarkm printf("\nSever failure."); 96 case IMP_ERR: 97 printf("\nUnsupported request error.\n"); 98 case RFS_ERR: 99 printf("\nRefused error.\n"); 100 case ACT_ERR: 101 printf("\nActive error.\n"); 102 case CFT_ERR: 103 printf("\nName in conflict error.\n"); 104 default: 105 printf("\n???=%0x\n", rcode ); 106 107 } 108} 109#endif 110 111 112/* Handling Name field */ 113static u_char *AliasHandleName ( u_char *p, char *pmax ) { 114 115 u_char *s; 116 u_char c; 117 int compress; 118 119 /* Following length field */ 120 121 if (p == NULL || (char *)p >= pmax) 122 return(NULL); 123 124 if (*p & 0xc0 ) { 125 p = p + 2; 126 if ((char *)p > pmax) 127 return(NULL); 128 return ((u_char *)p); 129 } 130 while ( ( *p & 0x3f) != 0x00 ) { 131 s = p + 1; 132 if ( *p == 0x20 ) 133 compress = 1; 134 else 135 compress = 0; 136 137 /* Get next length field */ 138 p = (u_char *)(p + (*p & 0x3f) + 1); 139 if ((char *)p > pmax) { 140 p = NULL; 141 break; 142 } 143#ifdef DEBUG 144 printf(":"); 145#endif 146 while (s < p) { 147 if ( compress == 1 ) { 148 c = (u_char )(((((*s & 0x0f) << 4) | (*(s+1) & 0x0f)) - 0x11)); 149#ifdef DEBUG 150 if (isprint( c ) ) 151 printf("%c", c ); 152 else 153 printf("<0x%02x>", c ); 154#endif 155 s +=2; 156 } else { 157#ifdef DEBUG 158 printf("%c", *s); 159#endif 160 s++; 161 } 162 } 163#ifdef DEBUG 164 printf(":"); 165#endif 166 fflush(stdout); 167 } 168 169 /* Set up to out of Name field */ 170 if (p == NULL || (char *)p >= pmax) 171 p = NULL; 172 else 173 p++; 174 return ((u_char *)p); 175} 176 177/* 178 * NetBios Datagram Handler (IP/UDP) 179 */ 180#define DGM_DIRECT_UNIQ 0x10 181#define DGM_DIRECT_GROUP 0x11 182#define DGM_BROADCAST 0x12 183#define DGM_ERROR 0x13 184#define DGM_QUERY 0x14 185#define DGM_POSITIVE_RES 0x15 186#define DGM_NEGATIVE_RES 0x16 187 188int AliasHandleUdpNbt( 189 struct ip *pip, /* IP packet to examine/patch */ 190 struct alias_link *link, 191 struct in_addr *alias_address, 192 u_short alias_port 193) { 194 struct udphdr * uh; 195 NbtDataHeader *ndh; 196 u_char *p = NULL; 197 char *pmax; 198 199 /* Calculate data length of UDP packet */ 200 uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); 201 pmax = (char *)uh + ntohs( uh->uh_ulen ); 202 203 ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr))); 204 if ((char *)(ndh + 1) > pmax) 205 return(-1); 206#ifdef DEBUG 207 printf("\nType=%02x,", ndh->type ); 208#endif 209 switch ( ndh->type ) { 210 case DGM_DIRECT_UNIQ: 211 case DGM_DIRECT_GROUP: 212 case DGM_BROADCAST: 213 p = (u_char *)ndh + 14; 214 p = AliasHandleName ( p, pmax ); /* Source Name */ 215 p = AliasHandleName ( p, pmax ); /* Destination Name */ 216 break; 217 case DGM_ERROR: 218 p = (u_char *)ndh + 11; 219 break; 220 case DGM_QUERY: 221 case DGM_POSITIVE_RES: 222 case DGM_NEGATIVE_RES: 223 p = (u_char *)ndh + 10; 224 p = AliasHandleName ( p, pmax ); /* Destination Name */ 225 break; 226 } 227 if (p == NULL || (char *)p > pmax) 228 p = NULL; 229#ifdef DEBUG 230 printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) ); 231#endif 232 /* Doing a IP address and Port number Translation */ 233 if ( uh->uh_sum != 0 ) { 234 int acc; 235 u_short *sptr; 236 acc = ndh->source_port; 237 acc -= alias_port; 238 sptr = (u_short *) &(ndh->source_ip); 239 acc += *sptr++; 240 acc += *sptr; 241 sptr = (u_short *) alias_address; 242 acc -= *sptr++; 243 acc -= *sptr; 244 ADJUST_CHECKSUM(acc, uh->uh_sum); 245 } 246 ndh->source_ip = *alias_address; 247 ndh->source_port = alias_port; 248#ifdef DEBUG 249 printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) ); 250 fflush(stdout); 251#endif 252 return((p == NULL) ? -1 : 0); 253} 254/* Question Section */ 255#define QS_TYPE_NB 0x0020 256#define QS_TYPE_NBSTAT 0x0021 257#define QS_CLAS_IN 0x0001 258typedef struct { 259 u_short type; /* The type of Request */ 260 u_short class; /* The class of Request */ 261} NBTNsQuestion; 262 263static u_char * 264AliasHandleQuestion( 265 u_short count, 266 NBTNsQuestion *q, 267 char *pmax, 268 NBTArguments *nbtarg) 269{ 270 271 while ( count != 0 ) { 272 /* Name Filed */ 273 q = (NBTNsQuestion *)AliasHandleName((u_char *)q, pmax); 274 275 if (q == NULL || (char *)(q + 1) > pmax) { 276 q = NULL; 277 break; 278 } 279 280 /* Type and Class filed */ 281 switch ( ntohs(q->type) ) { 282 case QS_TYPE_NB: 283 case QS_TYPE_NBSTAT: 284 q= q+1; 285 break; 286 default: 287#ifdef DEBUG 288 printf("\nUnknown Type on Question %0x\n", ntohs(q->type) ); 289#endif 290 break; 291 } 292 count--; 293 } 294 295 /* Set up to out of Question Section */ 296 return ((u_char *)q); 297} 298 299/* Resource Record */ 300#define RR_TYPE_A 0x0001 301#define RR_TYPE_NS 0x0002 302#define RR_TYPE_NULL 0x000a 303#define RR_TYPE_NB 0x0020 304#define RR_TYPE_NBSTAT 0x0021 305#define RR_CLAS_IN 0x0001 306#define SizeOfNsResource 8 307typedef struct { 308 u_short type; 309 u_short class; 310 unsigned int ttl; 311 u_short rdlen; 312} NBTNsResource; 313 314#define SizeOfNsRNB 6 315typedef struct { 316 u_short g:1, ont:2, resv:13; 317 struct in_addr addr; 318} NBTNsRNB; 319 320static u_char * 321AliasHandleResourceNB( 322 NBTNsResource *q, 323 char *pmax, 324 NBTArguments *nbtarg) 325{ 326 NBTNsRNB *nb; 327 u_short bcount; 328 329 if (q == NULL || (char *)(q + 1) > pmax) 330 return(NULL); 331 /* Check out a length */ 332 bcount = ntohs(q->rdlen); 333 334 /* Forward to Resource NB position */ 335 nb = (NBTNsRNB *)((u_char *)q + SizeOfNsResource); 336 337 /* Processing all in_addr array */ 338#ifdef DEBUG 339 printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr)); 340 printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount); 341#endif 342 while ( nb != NULL && bcount != 0 ) { 343 if ((char *)(nb + 1) > pmax) { 344 nb = NULL; 345 break; 346 } 347#ifdef DEBUG 348 printf("<%s>", inet_ntoa(nb->addr) ); 349#endif 350 if (!bcmp(&nbtarg->oldaddr,&nb->addr, sizeof(struct in_addr) ) ) { 351 if ( *nbtarg->uh_sum != 0 ) { 352 int acc; 353 u_short *sptr; 354 355 sptr = (u_short *) &(nb->addr); 356 acc = *sptr++; 357 acc += *sptr; 358 sptr = (u_short *) &(nbtarg->newaddr); 359 acc -= *sptr++; 360 acc -= *sptr; 361 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); 362 } 363 364 nb->addr = nbtarg->newaddr; 365#ifdef DEBUG 366 printf("O"); 367#endif 368 } 369#ifdef DEBUG 370 else { 371 printf("."); 372 } 373#endif 374 nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB); 375 bcount -= SizeOfNsRNB; 376 } 377 if (nb == NULL || (char *)(nb + 1) > pmax) { 378 nb = NULL; 379 } 380 381 return ((u_char *)nb); 382} 383 384#define SizeOfResourceA 6 385typedef struct { 386 struct in_addr addr; 387} NBTNsResourceA; 388 389static u_char * 390AliasHandleResourceA( 391 NBTNsResource *q, 392 char *pmax, 393 NBTArguments *nbtarg) 394{ 395 NBTNsResourceA *a; 396 u_short bcount; 397 398 if (q == NULL || (char *)(q + 1) > pmax) 399 return(NULL); 400 401 /* Forward to Resource A position */ 402 a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) ); 403 404 /* Check out of length */ 405 bcount = ntohs(q->rdlen); 406 407 /* Processing all in_addr array */ 408#ifdef DEBUG 409 printf("Arec [%s", inet_ntoa(nbtarg->oldaddr)); 410 printf("->%s]",inet_ntoa(nbtarg->newaddr )); 411#endif 412 while ( bcount != 0 ) { 413 if (a == NULL || (char *)(a + 1) > pmax) 414 return(NULL); 415#ifdef DEBUG 416 printf("..%s", inet_ntoa(a->addr) ); 417#endif 418 if ( !bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr) ) ) { 419 if ( *nbtarg->uh_sum != 0 ) { 420 int acc; 421 u_short *sptr; 422 423 sptr = (u_short *) &(a->addr); /* Old */ 424 acc = *sptr++; 425 acc += *sptr; 426 sptr = (u_short *) &nbtarg->newaddr; /* New */ 427 acc -= *sptr++; 428 acc -= *sptr; 429 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); 430 } 431 432 a->addr = nbtarg->newaddr; 433 } 434 a++; /*XXXX*/ 435 bcount -= SizeOfResourceA; 436 } 437 if (a == NULL || (char *)(a + 1) > pmax) 438 a = NULL; 439 return ((u_char *)a); 440} 441 442typedef struct { 443 u_short opcode:4, flags:8, resv:4; 444} NBTNsResourceNULL; 445 446static u_char * 447AliasHandleResourceNULL( 448 NBTNsResource *q, 449 char *pmax, 450 NBTArguments *nbtarg) 451{ 452 NBTNsResourceNULL *n; 453 u_short bcount; 454 455 if (q == NULL || (char *)(q + 1) > pmax) 456 return(NULL); 457 458 /* Forward to Resource NULL position */ 459 n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) ); 460 461 /* Check out of length */ 462 bcount = ntohs(q->rdlen); 463 464 /* Processing all in_addr array */ 465 while ( bcount != 0 ) { 466 if ((char *)(n + 1) > pmax) { 467 n = NULL; 468 break; 469 } 470 n++; 471 bcount -= sizeof(NBTNsResourceNULL); 472 } 473 if ((char *)(n + 1) > pmax) 474 n = NULL; 475 476 return ((u_char *)n); 477} 478 479static u_char * 480AliasHandleResourceNS( 481 NBTNsResource *q, 482 char *pmax, 483 NBTArguments *nbtarg) 484{ 485 NBTNsResourceNULL *n; 486 u_short bcount; 487 488 if (q == NULL || (char *)(q + 1) > pmax) 489 return(NULL); 490 491 /* Forward to Resource NULL position */ 492 n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) ); 493 494 /* Check out of length */ 495 bcount = ntohs(q->rdlen); 496 497 /* Resource Record Name Filed */ 498 q = (NBTNsResource *)AliasHandleName( (u_char *)n, pmax ); /* XXX */ 499 500 if (q == NULL || (char *)((u_char *)n + bcount) > pmax) 501 return(NULL); 502 else 503 return ((u_char *)n + bcount); 504} 505 506typedef struct { 507 u_short numnames; 508} NBTNsResourceNBSTAT; 509 510static u_char * 511AliasHandleResourceNBSTAT( 512 NBTNsResource *q, 513 char *pmax, 514 NBTArguments *nbtarg) 515{ 516 NBTNsResourceNBSTAT *n; 517 u_short bcount; 518 519 if (q == NULL || (char *)(q + 1) > pmax) 520 return(NULL); 521 522 /* Forward to Resource NBSTAT position */ 523 n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) ); 524 525 /* Check out of length */ 526 bcount = ntohs(q->rdlen); 527 528 if (q == NULL || (char *)((u_char *)n + bcount) > pmax) 529 return(NULL); 530 else 531 return ((u_char *)n + bcount); 532} 533 534static u_char * 535AliasHandleResource( 536 u_short count, 537 NBTNsResource *q, 538 char *pmax, 539 NBTArguments 540 *nbtarg) 541{ 542 while ( count != 0 ) { 543 /* Resource Record Name Filed */ 544 q = (NBTNsResource *)AliasHandleName( (u_char *)q, pmax ); 545 546 if (q == NULL || (char *)(q + 1) > pmax) 547 break; 548#ifdef DEBUG 549 printf("type=%02x, count=%d\n", ntohs(q->type), count ); 550#endif 551 552 /* Type and Class filed */ 553 switch ( ntohs(q->type) ) { 554 case RR_TYPE_NB: 555 q = (NBTNsResource *)AliasHandleResourceNB( 556 q, 557 pmax, 558 nbtarg 559 ); 560 break; 561 case RR_TYPE_A: 562 q = (NBTNsResource *)AliasHandleResourceA( 563 q, 564 pmax, 565 nbtarg 566 ); 567 break; 568 case RR_TYPE_NS: 569 q = (NBTNsResource *)AliasHandleResourceNS( 570 q, 571 pmax, 572 nbtarg 573 ); 574 break; 575 case RR_TYPE_NULL: 576 q = (NBTNsResource *)AliasHandleResourceNULL( 577 q, 578 pmax, 579 nbtarg 580 ); 581 break; 582 case RR_TYPE_NBSTAT: 583 q = (NBTNsResource *)AliasHandleResourceNBSTAT( 584 q, 585 pmax, 586 nbtarg 587 ); 588 break; 589 default: 590#ifdef DEBUG 591 printf( 592 "\nUnknown Type of Resource %0x\n", 593 ntohs(q->type) 594 ); 595#endif 596 break; 597 } 598 count--; 599 } 600 fflush(stdout); 601 return ((u_char *)q); 602} 603 604int AliasHandleUdpNbtNS( 605 struct ip *pip, /* IP packet to examine/patch */ 606 struct alias_link *link, 607 struct in_addr *alias_address, 608 u_short *alias_port, 609 struct in_addr *original_address, 610 u_short *original_port ) 611{ 612 struct udphdr * uh; 613 NbtNSHeader * nsh; 614 u_char * p; 615 char *pmax; 616 NBTArguments nbtarg; 617 618 /* Set up Common Parameter */ 619 nbtarg.oldaddr = *alias_address; 620 nbtarg.oldport = *alias_port; 621 nbtarg.newaddr = *original_address; 622 nbtarg.newport = *original_port; 623 624 /* Calculate data length of UDP packet */ 625 uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); 626 nbtarg.uh_sum = &(uh->uh_sum); 627 nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr))); 628 p = (u_char *)(nsh + 1); 629 pmax = (char *)uh + ntohs( uh->uh_ulen ); 630 631 if ((char *)(nsh + 1) > pmax) 632 return(-1); 633 634#ifdef DEBUG 635 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x" 636 ", an=%04x, ns=%04x, ar=%04x, [%d]-->", 637 nsh->dir ? "Response": "Request", 638 nsh->nametrid, 639 nsh->opcode, 640 nsh->nmflags, 641 nsh->rcode, 642 ntohs(nsh->qdcount), 643 ntohs(nsh->ancount), 644 ntohs(nsh->nscount), 645 ntohs(nsh->arcount), 646 (u_char *)p -(u_char *)nsh 647 ); 648#endif 649 650 /* Question Entries */ 651 if (ntohs(nsh->qdcount) !=0 ) { 652 p = AliasHandleQuestion( 653 ntohs(nsh->qdcount), 654 (NBTNsQuestion *)p, 655 pmax, 656 &nbtarg 657 ); 658 } 659 660 /* Answer Resource Records */ 661 if (ntohs(nsh->ancount) !=0 ) { 662 p = AliasHandleResource( 663 ntohs(nsh->ancount), 664 (NBTNsResource *)p, 665 pmax, 666 &nbtarg 667 ); 668 } 669 670 /* Authority Resource Recodrs */ 671 if (ntohs(nsh->nscount) !=0 ) { 672 p = AliasHandleResource( 673 ntohs(nsh->nscount), 674 (NBTNsResource *)p, 675 pmax, 676 &nbtarg 677 ); 678 } 679 680 /* Additional Resource Recodrs */ 681 if (ntohs(nsh->arcount) !=0 ) { 682 p = AliasHandleResource( 683 ntohs(nsh->arcount), 684 (NBTNsResource *)p, 685 pmax, 686 &nbtarg 687 ); 688 } 689 690#ifdef DEBUG 691 PrintRcode(nsh->rcode); 692#endif 693 return ((p == NULL) ? -1 : 0); 694} 695