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