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$ 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 typedef struct { 48 struct in_addr oldaddr; 49 u_short oldport; 50 struct in_addr newaddr; 51 u_short newport; 52 u_short *uh_sum; 53 } NBTArguments; 54 55 typedef struct { 56 unsigned char type; 57 unsigned char flags; 58 u_short id; 59 struct in_addr source_ip; 60 u_short source_port; 61 u_short len; 62 u_short offset; 63 } NbtDataHeader; 64 65 #define OpQuery 0 66 #define OpUnknown 4 67 #define OpRegist 5 68 #define OpRelease 6 69 #define OpWACK 7 70 #define OpRefresh 8 71 typedef struct { 72 u_short nametrid; 73 u_short dir:1, opcode:4, nmflags:7, rcode:4; 74 u_short qdcount; 75 u_short ancount; 76 u_short nscount; 77 u_short arcount; 78 } NbtNSHeader; 79 80 #define FMT_ERR 0x1 81 #define SRV_ERR 0x2 82 #define IMP_ERR 0x4 83 #define RFS_ERR 0x5 84 #define ACT_ERR 0x6 85 #define CFT_ERR 0x7 86 87 88 #ifdef DEBUG 89 static void PrintRcode( u_char rcode ) { 90 91 switch (rcode) { 92 case FMT_ERR: 93 printf("\nFormat Error."); 94 case SRV_ERR: 95 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 */ 113 static 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 188 int 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 258 typedef struct { 259 u_short type; /* The type of Request */ 260 u_short class; /* The class of Request */ 261 } NBTNsQuestion; 262 263 static u_char * 264 AliasHandleQuestion( 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 307 typedef struct { 308 u_short type; 309 u_short class; 310 unsigned int ttl; 311 u_short rdlen; 312 } NBTNsResource; 313 314 #define SizeOfNsRNB 6 315 typedef struct { 316 u_short g:1, ont:2, resv:13; 317 struct in_addr addr; 318 } NBTNsRNB; 319 320 static u_char * 321 AliasHandleResourceNB( 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 385 typedef struct { 386 struct in_addr addr; 387 } NBTNsResourceA; 388 389 static u_char * 390 AliasHandleResourceA( 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 442 typedef struct { 443 u_short opcode:4, flags:8, resv:4; 444 } NBTNsResourceNULL; 445 446 static u_char * 447 AliasHandleResourceNULL( 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 479 static u_char * 480 AliasHandleResourceNS( 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 506 typedef struct { 507 u_short numnames; 508 } NBTNsResourceNBSTAT; 509 510 static u_char * 511 AliasHandleResourceNBSTAT( 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 534 static u_char * 535 AliasHandleResource( 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 604 int 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