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