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