1/* 2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22/*- 23 * Written by Atsushi Murai <amurai@spec.co.jp> 24 * Copyright (c) 1998, System Planning and Engineering Co. 25 * All rights reserved. 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 1. Redistributions of source code must retain the above copyright 31 * notice, this list of conditions and the following disclaimer. 32 * 2. Redistributions in binary form must reproduce the above copyright 33 * notice, this list of conditions and the following disclaimer in the 34 * documentation and/or other materials provided with the distribution. 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 37 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 39 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 40 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 42 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 44 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 45 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * 48 * Based upon: 49 * $FreeBSD: src/lib/libalias/alias_nbt.c,v 1.4.2.3 2001/08/01 09:52:26 obrien Exp $ 50 * 51 * TODO: 52 * oClean up. 53 * oConsidering for word alignment for other platform. 54 */ 55/* 56 alias_nbt.c performs special processing for NetBios over TCP/IP 57 sessions by UDP. 58 59 Initial version: May, 1998 (Atsushi Murai <amurai@spec.co.jp>) 60 61 See HISTORY file for record of revisions. 62*/ 63 64/* Includes */ 65#include <ctype.h> 66#include <stdio.h> 67#include <string.h> 68#include <sys/types.h> 69#include <netinet/in_systm.h> 70#include <netinet/in.h> 71#include <arpa/inet.h> 72#include <netinet/ip.h> 73#include <netinet/udp.h> 74#include <netinet/tcp.h> 75 76#include "alias_local.h" 77 78typedef struct { 79 struct in_addr oldaddr; 80 u_short oldport; 81 struct in_addr newaddr; 82 u_short newport; 83 u_short *uh_sum; 84} NBTArguments; 85 86typedef struct { 87 unsigned char type; 88 unsigned char flags; 89 u_short id; 90 struct in_addr source_ip; 91 u_short source_port; 92 u_short len; 93 u_short offset; 94} NbtDataHeader; 95 96#define OpQuery 0 97#define OpUnknown 4 98#define OpRegist 5 99#define OpRelease 6 100#define OpWACK 7 101#define OpRefresh 8 102typedef struct { 103 u_short nametrid; 104 u_short dir:1, opcode:4, nmflags:7, rcode:4; 105 u_short qdcount; 106 u_short ancount; 107 u_short nscount; 108 u_short arcount; 109} NbtNSHeader; 110 111#define FMT_ERR 0x1 112#define SRV_ERR 0x2 113#define IMP_ERR 0x4 114#define RFS_ERR 0x5 115#define ACT_ERR 0x6 116#define CFT_ERR 0x7 117 118 119#ifdef DEBUG 120static void PrintRcode( u_char rcode ) { 121 122 switch (rcode) { 123 case FMT_ERR: 124 printf("\n Format Error.\n"); 125 break; 126 case SRV_ERR: 127 printf("\n Server failure.\n"); 128 break; 129 case IMP_ERR: 130 printf("\n Unsupported request error.\n"); 131 break; 132 case RFS_ERR: 133 printf("\n Refused error.\n"); 134 break; 135 case ACT_ERR: 136 printf("\n Active error.\n"); 137 break; 138 case CFT_ERR: 139 printf("\n Name in conflict error.\n"); 140 break; 141 default: 142 printf("\n \?\?\?=%0x\n", rcode ); 143 break; 144 } 145} 146#endif 147 148 149/* Handling Name field */ 150static u_char *AliasHandleName ( u_char *p, char *pmax ) { 151 152 u_char *s; 153 u_char c; 154 int compress; 155 156 /* Following length field */ 157 158 if (p == NULL || (char *)p >= pmax) 159 return(NULL); 160 161 if (*p & 0xc0 ) { 162 p = p + 2; 163 if ((char *)p > pmax) 164 return(NULL); 165 return ((u_char *)p); 166 } 167 while ( ( *p & 0x3f) != 0x00 ) { 168 s = p + 1; 169 if ( *p == 0x20 ) 170 compress = 1; 171 else 172 compress = 0; 173 174 /* Get next length field */ 175 p = (u_char *)(p + (*p & 0x3f) + 1); 176 if ((char *)p > pmax) { 177 p = NULL; 178 break; 179 } 180#ifdef DEBUG 181 printf(":"); 182#endif 183 while (s < p) { 184 if ( compress == 1 ) { 185 c = (u_char )(((((*s & 0x0f) << 4) | (*(s+1) & 0x0f)) - 0x11)); 186#ifdef DEBUG 187 if (isprint( c ) ) 188 printf("%c", c ); 189 else 190 printf("<0x%02x>", c ); 191#endif 192 s +=2; 193 } else { 194#ifdef DEBUG 195 printf("%c", *s); 196#endif 197 s++; 198 } 199 } 200#ifdef DEBUG 201 printf(":"); 202#endif 203 fflush(stdout); 204 } 205 206 /* Set up to out of Name field */ 207 if (p == NULL || (char *)p >= pmax) 208 p = NULL; 209 else 210 p++; 211 return ((u_char *)p); 212} 213 214/* 215 * NetBios Datagram Handler (IP/UDP) 216 */ 217#define DGM_DIRECT_UNIQ 0x10 218#define DGM_DIRECT_GROUP 0x11 219#define DGM_BROADCAST 0x12 220#define DGM_ERROR 0x13 221#define DGM_QUERY 0x14 222#define DGM_POSITIVE_RES 0x15 223#define DGM_NEGATIVE_RES 0x16 224 225int AliasHandleUdpNbt( 226 struct ip *pip, /* IP packet to examine/patch */ 227 struct alias_link *link, 228 struct in_addr *alias_address, 229 u_short alias_port 230) { 231 struct udphdr * uh; 232 NbtDataHeader *ndh; 233 u_char *p = NULL; 234 char *pmax; 235 236 /* Calculate data length of UDP packet */ 237 uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); 238 pmax = (char *)uh + ntohs( uh->uh_ulen ); 239 240 ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr))); 241 if ((char *)(ndh + 1) > pmax) 242 return(-1); 243#ifdef DEBUG 244 printf("Type=%02x,", ndh->type ); 245#endif 246 switch ( ndh->type ) { 247 case DGM_DIRECT_UNIQ: 248 case DGM_DIRECT_GROUP: 249 case DGM_BROADCAST: 250 p = (u_char *)ndh + 14; 251 p = AliasHandleName ( p, pmax ); /* Source Name */ 252 p = AliasHandleName ( p, pmax ); /* Destination Name */ 253 break; 254 case DGM_ERROR: 255 p = (u_char *)ndh + 11; 256 break; 257 case DGM_QUERY: 258 case DGM_POSITIVE_RES: 259 case DGM_NEGATIVE_RES: 260 p = (u_char *)ndh + 10; 261 p = AliasHandleName ( p, pmax ); /* Destination Name */ 262 break; 263 } 264 if (p == NULL || (char *)p > pmax) 265 p = NULL; 266#ifdef DEBUG 267 printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) ); 268#endif 269 /* Doing a IP address and Port number Translation */ 270 if ( uh->uh_sum != 0 ) { 271 int acc; 272 u_short *sptr; 273 acc = ndh->source_port; 274 acc -= alias_port; 275 sptr = (u_short *) &(ndh->source_ip); 276 acc += *sptr++; 277 acc += *sptr; 278 sptr = (u_short *) alias_address; 279 acc -= *sptr++; 280 acc -= *sptr; 281 ADJUST_CHECKSUM(acc, uh->uh_sum); 282 } 283 ndh->source_ip = *alias_address; 284 ndh->source_port = alias_port; 285#ifdef DEBUG 286 printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) ); 287 fflush(stdout); 288#endif 289 return((p == NULL) ? -1 : 0); 290} 291/* Question Section */ 292#define QS_TYPE_NB 0x0020 293#define QS_TYPE_NBSTAT 0x0021 294#define QS_CLAS_IN 0x0001 295typedef struct { 296 u_short type; /* The type of Request */ 297 u_short class; /* The class of Request */ 298} NBTNsQuestion; 299 300static u_char * 301AliasHandleQuestion( 302 u_short count, 303 NBTNsQuestion *q, 304 char *pmax, 305 NBTArguments *nbtarg) 306{ 307 308 while ( count != 0 ) { 309 /* Name Filed */ 310 q = (NBTNsQuestion *)AliasHandleName((u_char *)q, pmax); 311 312 if (q == NULL || (char *)(q + 1) > pmax) { 313 q = NULL; 314 break; 315 } 316 317 /* Type and Class filed */ 318 switch ( ntohs(q->type) ) { 319 case QS_TYPE_NB: 320 case QS_TYPE_NBSTAT: 321 q= q+1; 322 break; 323 default: 324#ifdef DEBUG 325 printf("\nUnknown Type on Question %0x\n", ntohs(q->type) ); 326#endif 327 break; 328 } 329 count--; 330 } 331 332 /* Set up to out of Question Section */ 333 return ((u_char *)q); 334} 335 336/* Resource Record */ 337#define RR_TYPE_A 0x0001 338#define RR_TYPE_NS 0x0002 339#define RR_TYPE_NULL 0x000a 340#define RR_TYPE_NB 0x0020 341#define RR_TYPE_NBSTAT 0x0021 342#define RR_CLAS_IN 0x0001 343#define SizeOfNsResource 8 344typedef struct { 345 u_short type; 346 u_short class; 347 unsigned int ttl; 348 u_short rdlen; 349} NBTNsResource; 350 351#define SizeOfNsRNB 6 352typedef struct { 353 u_short g:1, ont:2, resv:13; 354 struct in_addr addr; 355} NBTNsRNB; 356 357static u_char * 358AliasHandleResourceNB( 359 NBTNsResource *q, 360 char *pmax, 361 NBTArguments *nbtarg) 362{ 363 NBTNsRNB *nb; 364 u_short bcount; 365 366 if (q == NULL || (char *)(q + 1) > pmax) 367 return(NULL); 368 /* Check out a length */ 369 bcount = ntohs(q->rdlen); 370 371 /* Forward to Resource NB position */ 372 nb = (NBTNsRNB *)((u_char *)q + SizeOfNsResource); 373 374 /* Processing all in_addr array */ 375#ifdef DEBUG 376 printf(" NB rec[%s", inet_ntoa(nbtarg->oldaddr)); 377 printf("->%s, %d bytes] ",inet_ntoa(nbtarg->newaddr ), bcount); 378#endif 379 while ( nb != NULL && bcount != 0 ) { 380 if ((char *)(nb + 1) > pmax) { 381 nb = NULL; 382 break; 383 } 384#ifdef DEBUG 385 printf("<%s>", inet_ntoa(nb->addr) ); 386#endif 387 if (!bcmp(&nbtarg->oldaddr,&nb->addr, sizeof(struct in_addr) ) ) { 388 if ( *nbtarg->uh_sum != 0 ) { 389 int acc; 390 u_short *sptr; 391 392 sptr = (u_short *) &(nb->addr); 393 acc = *sptr++; 394 acc += *sptr; 395 sptr = (u_short *) &(nbtarg->newaddr); 396 acc -= *sptr++; 397 acc -= *sptr; 398 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); 399 } 400 401 nb->addr = nbtarg->newaddr; 402#ifdef DEBUG 403 printf("O"); 404#endif 405 } 406#ifdef DEBUG 407 else { 408 printf("."); 409 } 410#endif 411 nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB); 412 bcount -= SizeOfNsRNB; 413 } 414 if (nb == NULL || (char *)(nb + 1) > pmax) { 415 nb = NULL; 416 } 417 418 return ((u_char *)nb); 419} 420 421#define SizeOfResourceA 6 422typedef struct { 423 struct in_addr addr; 424} NBTNsResourceA; 425 426static u_char * 427AliasHandleResourceA( 428 NBTNsResource *q, 429 char *pmax, 430 NBTArguments *nbtarg) 431{ 432 NBTNsResourceA *a; 433 u_short bcount; 434 435 if (q == NULL || (char *)(q + 1) > pmax) 436 return(NULL); 437 438 /* Forward to Resource A position */ 439 a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) ); 440 441 /* Check out of length */ 442 bcount = ntohs(q->rdlen); 443 444 /* Processing all in_addr array */ 445#ifdef DEBUG 446 printf("Arec [%s", inet_ntoa(nbtarg->oldaddr)); 447 printf("->%s]",inet_ntoa(nbtarg->newaddr )); 448#endif 449 while ( bcount != 0 ) { 450 if (a == NULL || (char *)(a + 1) > pmax) 451 return(NULL); 452#ifdef DEBUG 453 printf("..%s", inet_ntoa(a->addr) ); 454#endif 455 if ( !bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr) ) ) { 456 if ( *nbtarg->uh_sum != 0 ) { 457 int acc; 458 u_short *sptr; 459 460 sptr = (u_short *) &(a->addr); /* Old */ 461 acc = *sptr++; 462 acc += *sptr; 463 sptr = (u_short *) &nbtarg->newaddr; /* New */ 464 acc -= *sptr++; 465 acc -= *sptr; 466 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); 467 } 468 469 a->addr = nbtarg->newaddr; 470 } 471 a++; /*XXXX*/ 472 bcount -= SizeOfResourceA; 473 } 474 if (a == NULL || (char *)(a + 1) > pmax) 475 a = NULL; 476 return ((u_char *)a); 477} 478 479typedef struct { 480 u_short opcode:4, flags:8, resv:4; 481} NBTNsResourceNULL; 482 483static u_char * 484AliasHandleResourceNULL( 485 NBTNsResource *q, 486 char *pmax, 487 NBTArguments *nbtarg) 488{ 489 NBTNsResourceNULL *n; 490 u_short bcount; 491 492 if (q == NULL || (char *)(q + 1) > pmax) 493 return(NULL); 494 495 /* Forward to Resource NULL position */ 496 n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) ); 497 498 /* Check out of length */ 499 bcount = ntohs(q->rdlen); 500 501 /* Processing all in_addr array */ 502 while ( bcount != 0 ) { 503 if ((char *)(n + 1) > pmax) { 504 n = NULL; 505 break; 506 } 507 n++; 508 bcount -= sizeof(NBTNsResourceNULL); 509 } 510 if ((char *)(n + 1) > pmax) 511 n = NULL; 512 513 return ((u_char *)n); 514} 515 516static u_char * 517AliasHandleResourceNS( 518 NBTNsResource *q, 519 char *pmax, 520 NBTArguments *nbtarg) 521{ 522 NBTNsResourceNULL *n; 523 u_short bcount; 524 525 if (q == NULL || (char *)(q + 1) > pmax) 526 return(NULL); 527 528 /* Forward to Resource NULL position */ 529 n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) ); 530 531 /* Check out of length */ 532 bcount = ntohs(q->rdlen); 533 534 /* Resource Record Name Filed */ 535 q = (NBTNsResource *)AliasHandleName( (u_char *)n, pmax ); /* XXX */ 536 537 if (q == NULL || (char *)((u_char *)n + bcount) > pmax) 538 return(NULL); 539 else 540 return ((u_char *)n + bcount); 541} 542 543typedef struct { 544 u_short numnames; 545} NBTNsResourceNBSTAT; 546 547static u_char * 548AliasHandleResourceNBSTAT( 549 NBTNsResource *q, 550 char *pmax, 551 NBTArguments *nbtarg) 552{ 553 NBTNsResourceNBSTAT *n; 554 u_short bcount; 555 556 if (q == NULL || (char *)(q + 1) > pmax) 557 return(NULL); 558 559 /* Forward to Resource NBSTAT position */ 560 n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) ); 561 562 /* Check out of length */ 563 bcount = ntohs(q->rdlen); 564 565 if (q == NULL || (char *)((u_char *)n + bcount) > pmax) 566 return(NULL); 567 else 568 return ((u_char *)n + bcount); 569} 570 571static u_char * 572AliasHandleResource( 573 u_short count, 574 NBTNsResource *q, 575 char *pmax, 576 NBTArguments 577 *nbtarg) 578{ 579 while ( count != 0 ) { 580 /* Resource Record Name Filed */ 581 q = (NBTNsResource *)AliasHandleName( (u_char *)q, pmax ); 582 583 if (q == NULL || (char *)(q + 1) > pmax) 584 break; 585#ifdef DEBUG 586 printf("\n type=%02x, count=%d\n", ntohs(q->type), count ); 587#endif 588 589 /* Type and Class filed */ 590 switch ( ntohs(q->type) ) { 591 case RR_TYPE_NB: 592 q = (NBTNsResource *)AliasHandleResourceNB( 593 q, 594 pmax, 595 nbtarg 596 ); 597 break; 598 case RR_TYPE_A: 599 q = (NBTNsResource *)AliasHandleResourceA( 600 q, 601 pmax, 602 nbtarg 603 ); 604 break; 605 case RR_TYPE_NS: 606 q = (NBTNsResource *)AliasHandleResourceNS( 607 q, 608 pmax, 609 nbtarg 610 ); 611 break; 612 case RR_TYPE_NULL: 613 q = (NBTNsResource *)AliasHandleResourceNULL( 614 q, 615 pmax, 616 nbtarg 617 ); 618 break; 619 case RR_TYPE_NBSTAT: 620 q = (NBTNsResource *)AliasHandleResourceNBSTAT( 621 q, 622 pmax, 623 nbtarg 624 ); 625 break; 626 default: 627#ifdef DEBUG 628 printf( 629 "\nUnknown Type of Resource %0x\n", 630 ntohs(q->type) 631 ); 632#endif 633 break; 634 } 635 count--; 636 } 637 fflush(stdout); 638 return ((u_char *)q); 639} 640 641int AliasHandleUdpNbtNS( 642 struct ip *pip, /* IP packet to examine/patch */ 643 struct alias_link *link, 644 struct in_addr *alias_address, 645 u_short *alias_port, 646 struct in_addr *original_address, 647 u_short *original_port ) 648{ 649 struct udphdr * uh; 650 NbtNSHeader * nsh; 651 u_char * p; 652 char *pmax; 653 NBTArguments nbtarg; 654 655 /* Set up Common Parameter */ 656 nbtarg.oldaddr = *alias_address; 657 nbtarg.oldport = *alias_port; 658 nbtarg.newaddr = *original_address; 659 nbtarg.newport = *original_port; 660 661 /* Calculate data length of UDP packet */ 662 uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); 663 nbtarg.uh_sum = &(uh->uh_sum); 664 nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr))); 665 p = (u_char *)(nsh + 1); 666 pmax = (char *)uh + ntohs( uh->uh_ulen ); 667 668 if ((char *)(nsh + 1) > pmax) 669 return(-1); 670 671#ifdef DEBUG 672 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x" 673 ", an=%04x, ns=%04x, ar=%04x, [%d]-->", 674 nsh->dir ? "Response": "Request", 675 nsh->nametrid, 676 nsh->opcode, 677 nsh->nmflags, 678 nsh->rcode, 679 ntohs(nsh->qdcount), 680 ntohs(nsh->ancount), 681 ntohs(nsh->nscount), 682 ntohs(nsh->arcount), 683 (int)((u_char *)p -(u_char *)nsh) 684 ); 685#endif 686 687 /* Question Entries */ 688 if (ntohs(nsh->qdcount) !=0 ) { 689 p = AliasHandleQuestion( 690 ntohs(nsh->qdcount), 691 (NBTNsQuestion *)p, 692 pmax, 693 &nbtarg 694 ); 695 } 696 697 /* Answer Resource Records */ 698 if (ntohs(nsh->ancount) !=0 ) { 699 p = AliasHandleResource( 700 ntohs(nsh->ancount), 701 (NBTNsResource *)p, 702 pmax, 703 &nbtarg 704 ); 705 } 706 707 /* Authority Resource Recodrs */ 708 if (ntohs(nsh->nscount) !=0 ) { 709 p = AliasHandleResource( 710 ntohs(nsh->nscount), 711 (NBTNsResource *)p, 712 pmax, 713 &nbtarg 714 ); 715 } 716 717 /* Additional Resource Recodrs */ 718 if (ntohs(nsh->arcount) !=0 ) { 719 p = AliasHandleResource( 720 ntohs(nsh->arcount), 721 (NBTNsResource *)p, 722 pmax, 723 &nbtarg 724 ); 725 } 726 727#ifdef DEBUG 728 if (nsh->rcode) 729 PrintRcode(nsh->rcode); 730#endif 731 return ((p == NULL) ? -1 : 0); 732} 733