alias_nbt.c revision 36321
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:$ 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 64typedef 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 72typedef 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 88typedef 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 *******************************************************************/ 107void putip(void *dest,void *src) 108{ 109 memcpy(dest,src,4); 110} 111 112void 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 */ 135u_char *AliasHandleName ( u_char *p ) { 136 137 u_char *s; 138 u_char c; 139 int compress; 140 141 /* Following length field */ 142 if (*p & 0xc0 ) { 143 p = p + 2; 144 return ((u_char *)p); 145 } 146 while ( ( *p & 0x3f) != 0x00 ) { 147 s = p + 1; 148 if ( *p == 0x20 ) 149 compress = 1; 150 else 151 compress = 0; 152 153 /* Get next length field */ 154 p = (u_char *)(p + (*p & 0x3f) + 1); 155#ifdef DEBUG 156 printf(":"); 157#endif 158 while (s < p) { 159 if ( compress == 1 ) { 160 c = (u_char )(((((*s & 0x0f) << 4) | (*(s+1) & 0x0f)) - 0x11)); 161#ifdef DEBUG 162 if (isprint( c ) ) 163 printf("%c", c ); 164 else 165 printf("<0x%02x>", c ); 166#endif 167 s +=2; 168 } else { 169#ifdef DEBUG 170 printf("%c", *s); 171#endif 172 s++; 173 } 174 } 175#ifdef DEBUG 176 printf(":"); 177#endif 178 fflush(stdout); 179 } 180 181 /* Set up to out of Name field */ 182 p++; 183 return ((u_char *)p); 184} 185 186/* 187 * NetBios Datagram Handler (IP/UDP) 188 */ 189#define DGM_DIRECT_UNIQ 0x10 190#define DGM_DIRECT_GROUP 0x11 191#define DGM_BROADCAST 0x12 192#define DGM_ERROR 0x13 193#define DGM_QUERY 0x14 194#define DGM_POSITIVE_RES 0x15 195#define DGM_NEGATIVE_RES 0x16 196 197void AliasHandleUdpNbt( 198 struct ip *pip, /* IP packet to examine/patch */ 199 struct alias_link *link, 200 struct in_addr *alias_address, 201 u_short alias_port ) 202{ 203 struct udphdr * uh; 204 NbtDataHeader *ndh; 205 u_char *p; 206 207 /* Calculate data length of UDP packet */ 208 uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); 209 ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr))); 210#ifdef DEBUG 211 printf("\nType=%02x,", ndh->type ); 212#endif 213 switch ( ndh->type ) { 214 case DGM_DIRECT_UNIQ: 215 case DGM_DIRECT_GROUP: 216 case DGM_BROADCAST: 217 p = (u_char *)ndh + 14; 218 p = AliasHandleName ( p ); /* Source Name */ 219 p = AliasHandleName ( p ); /* Destination Name */ 220 break; 221 case DGM_ERROR: 222 p = (u_char *)ndh + 11; 223 break; 224 case DGM_QUERY: 225 case DGM_POSITIVE_RES: 226 case DGM_NEGATIVE_RES: 227 p = (u_char *)ndh + 10; 228 p = AliasHandleName ( p ); /* Destination Name */ 229 break; 230 } 231#ifdef DEBUG 232 printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) ); 233#endif 234 /* Doing a IP address and Port number Translation */ 235 if ( uh->uh_sum != 0 ) { 236 int acc; 237 u_short *sptr; 238 acc = ndh->source_port; 239 acc -= alias_port; 240 sptr = (u_short *) &(ndh->source_ip); 241 acc += *sptr++; 242 acc += *sptr; 243 sptr = (u_short *) alias_address; 244 acc -= *sptr++; 245 acc -= *sptr; 246 ADJUST_CHECKSUM(acc, uh->uh_sum) 247 } 248 ndh->source_ip = *alias_address; 249 ndh->source_port = alias_port; 250#ifdef DEBUG 251 printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) ); 252 fflush(stdout); 253#endif 254} 255/* Question Section */ 256#define QS_TYPE_NB 0x0020 257#define QS_TYPE_NBSTAT 0x0021 258#define QS_CLAS_IN 0x0001 259typedef struct { 260 u_short type; /* The type of Request */ 261 u_short class; /* The class of Request */ 262} NBTNsQuestion; 263 264u_char *AliasHandleQuestion(u_short count, 265 NBTNsQuestion *q, 266 NBTArguments *nbtarg) 267{ 268 269 while ( count != 0 ) { 270 /* Name Filed */ 271 q = (NBTNsQuestion *)AliasHandleName((u_char *)q ); 272 273 /* Type and Class filed */ 274 switch ( ntohs(q->type) ) { 275 case QS_TYPE_NB: 276 case QS_TYPE_NBSTAT: 277 q= q+1; 278 break; 279 default: 280 printf("\nUnknown Type on Question %0x\n", ntohs(q->type) ); 281 break; 282 } 283 count--; 284 } 285 286 /* Set up to out of Question Section */ 287 return ((u_char *)q); 288} 289 290/* Resource Record */ 291#define RR_TYPE_A 0x0001 292#define RR_TYPE_NS 0x0002 293#define RR_TYPE_NULL 0x000a 294#define RR_TYPE_NB 0x0020 295#define RR_TYPE_NBSTAT 0x0021 296#define RR_CLAS_IN 0x0001 297#define SizeOfNsResource 8 298typedef struct { 299 u_short type; 300 u_short class; 301 unsigned int ttl; 302 u_short rdlen; 303} NBTNsResource; 304 305#define SizeOfNsRNB 6 306typedef struct { 307 u_short g:1, ont:2, resv:13; 308 struct in_addr addr; 309} NBTNsRNB; 310 311u_char *AliasHandleResourceNB( NBTNsResource *q, 312 NBTArguments *nbtarg) 313{ 314 NBTNsRNB *nb; 315 u_short bcount; 316 317 /* Check out a length */ 318 bcount = ntohs(q->rdlen); 319 320 /* Forward to Resource NB position */ 321 nb = (NBTNsRNB *)((u_char *)q + SizeOfNsResource); 322 323 /* Processing all in_addr array */ 324#ifdef DEBUG 325 printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr)); 326 printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount); 327#endif 328 while ( bcount != 0 ) { 329#ifdef DEBUG 330 printf("<%s>", inet_ntoa(nb->addr) ); 331#endif 332 if (!bcmp(&nbtarg->oldaddr,&nb->addr, sizeof(struct in_addr) ) ) { 333 if ( *nbtarg->uh_sum != 0 ) { 334 int acc; 335 u_short *sptr; 336 337 sptr = (u_short *) &(nb->addr); 338 acc = *sptr++; 339 acc += *sptr; 340 sptr = (u_short *) &(nbtarg->newaddr); 341 acc -= *sptr++; 342 acc -= *sptr; 343 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum) 344 } 345 346 nb->addr = nbtarg->newaddr; 347#ifdef DEBUG 348 printf("O"); 349#endif 350 } 351#ifdef DEBUG 352 else { 353 printf("."); 354 } 355#endif 356 nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB); 357 bcount -= SizeOfNsRNB; 358 } 359 360 return ((u_char *)nb); 361} 362 363#define SizeOfResourceA 6 364typedef struct { 365 struct in_addr addr; 366} NBTNsResourceA; 367 368u_char *AliasHandleResourceA( NBTNsResource *q, 369 NBTArguments *nbtarg) 370{ 371 NBTNsResourceA *a; 372 u_short bcount; 373 374 /* Forward to Resource A position */ 375 a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) ); 376 377 /* Check out of length */ 378 bcount = ntohs(q->rdlen); 379 380 /* Processing all in_addr array */ 381#ifdef DEBUG 382 printf("Arec [%s", inet_ntoa(nbtarg->oldaddr)); 383 printf("->%s]",inet_ntoa(nbtarg->newaddr )); 384#endif 385 while ( bcount != 0 ) { 386#ifdef DEBUG 387 printf("..%s", inet_ntoa(a->addr) ); 388#endif 389 if ( !bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr) ) ) { 390 if ( *nbtarg->uh_sum != 0 ) { 391 int acc; 392 u_short *sptr; 393 394 sptr = (u_short *) &(a->addr); /* Old */ 395 acc = *sptr++; 396 acc += *sptr; 397 sptr = (u_short *) &nbtarg->newaddr; /* New */ 398 acc -= *sptr++; 399 acc -= *sptr; 400 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum) 401 } 402 403 a->addr = nbtarg->newaddr; 404 } 405 a++; /*XXXX*/ 406 bcount -= SizeOfResourceA; 407 } 408 return ((u_char *)a); 409} 410 411typedef struct { 412 u_short opcode:4, flags:8, resv:4; 413} NBTNsResourceNULL; 414 415u_char *AliasHandleResourceNULL( NBTNsResource *q, 416 NBTArguments *nbtarg) 417{ 418 NBTNsResourceNULL *n; 419 u_short bcount; 420 421 /* Forward to Resource NULL position */ 422 n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) ); 423 424 /* Check out of length */ 425 bcount = ntohs(q->rdlen); 426 427 /* Processing all in_addr array */ 428 while ( bcount != 0 ) { 429 n++; 430 bcount -= sizeof(NBTNsResourceNULL); 431 } 432 433 return ((u_char *)n); 434} 435 436u_char *AliasHandleResourceNS( NBTNsResource *q, 437 NBTArguments *nbtarg) 438{ 439 NBTNsResourceNULL *n; 440 u_short bcount; 441 442 /* Forward to Resource NULL position */ 443 n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) ); 444 445 /* Check out of length */ 446 bcount = ntohs(q->rdlen); 447 448 /* Resource Record Name Filed */ 449 q = (NBTNsResource *)AliasHandleName( (u_char *)n ); /* XXX */ 450 451 return ((u_char *)n + bcount); 452} 453 454typedef struct { 455 u_short numnames; 456} NBTNsResourceNBSTAT; 457 458u_char *AliasHandleResourceNBSTAT( NBTNsResource *q, 459 NBTArguments *nbtarg) 460{ 461 NBTNsResourceNBSTAT *n; 462 u_short bcount; 463 464 /* Forward to Resource NBSTAT position */ 465 n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) ); 466 467 /* Check out of length */ 468 bcount = ntohs(q->rdlen); 469 470 return ((u_char *)n + bcount); 471} 472 473u_char *AliasHandleResource(u_short count, 474 NBTNsResource *q, 475 NBTArguments *nbtarg) 476{ 477 while ( count != 0 ) { 478 /* Resource Record Name Filed */ 479 q = (NBTNsResource *)AliasHandleName( (u_char *)q ); 480#ifdef DEBUG 481 printf("type=%02x, count=%d\n", ntohs(q->type), count ); 482#endif 483 484 /* Type and Class filed */ 485 switch ( ntohs(q->type) ) { 486 case RR_TYPE_NB: 487 q = (NBTNsResource *)AliasHandleResourceNB( q, nbtarg ); 488 break; 489 case RR_TYPE_A: 490 q = (NBTNsResource *)AliasHandleResourceA( q, nbtarg ); 491 break; 492 case RR_TYPE_NS: 493 q = (NBTNsResource *)AliasHandleResourceNS( q, nbtarg ); 494 break; 495 case RR_TYPE_NULL: 496 q = (NBTNsResource *)AliasHandleResourceNULL( q, nbtarg ); 497 break; 498 case RR_TYPE_NBSTAT: 499 q = (NBTNsResource *)AliasHandleResourceNBSTAT( q, nbtarg ); 500 break; 501 default: printf("\nUnknown Type of Resource %0x\n", 502 ntohs(q->type) ); 503 break; 504 } 505 count--; 506 } 507 fflush(stdout); 508 return ((u_char *)q); 509} 510 511void AliasHandleUdpNbtNS( 512 struct ip *pip, /* IP packet to examine/patch */ 513 struct alias_link *link, 514 struct in_addr *alias_address, 515 u_short *alias_port, 516 struct in_addr *original_address, 517 u_short *original_port ) 518{ 519 struct udphdr * uh; 520 NbtNSHeader * nsh; 521 u_short dlen; 522 u_char * p; 523 NBTArguments nbtarg; 524 525 /* Set up Common Parameter */ 526 nbtarg.oldaddr = *alias_address; 527 nbtarg.oldport = *alias_port; 528 nbtarg.newaddr = *original_address; 529 nbtarg.newport = *original_port; 530 531 /* Calculate data length of UDP packet */ 532 uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2)); 533 nbtarg.uh_sum = &(uh->uh_sum); 534 dlen = ntohs( uh->uh_ulen ); 535 nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr))); 536 p = (u_char *)(nsh + 1); 537 538#ifdef DEBUG 539 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x, an=%04x, ns=%04x, ar=%04x, [%d]-->", 540 nsh->dir ? "Response": "Request", 541 nsh->nametrid, 542 nsh->opcode, 543 nsh->nmflags, 544 nsh->rcode, 545 ntohs(nsh->qdcount), 546 ntohs(nsh->ancount), 547 ntohs(nsh->nscount), 548 ntohs(nsh->arcount), 549 (u_char *)p -(u_char *)nsh); 550#endif 551 552 /* Question Entries */ 553 if (ntohs(nsh->qdcount) !=0 ) { 554 p = AliasHandleQuestion(ntohs(nsh->qdcount), (NBTNsQuestion *)p, &nbtarg ); 555 } 556 557 /* Answer Resource Records */ 558 if (ntohs(nsh->ancount) !=0 ) { 559 p = AliasHandleResource(ntohs(nsh->ancount), (NBTNsResource *)p, &nbtarg ); 560 } 561 562 /* Authority Resource Recodrs */ 563 if (ntohs(nsh->nscount) !=0 ) { 564 p = AliasHandleResource(ntohs(nsh->nscount), (NBTNsResource *)p, &nbtarg ); 565 } 566 567 /* Additional Resource Recodrs */ 568 if (ntohs(nsh->arcount) !=0 ) { 569 p = AliasHandleResource(ntohs(nsh->arcount), (NBTNsResource *)p, &nbtarg ); 570 } 571 572#ifdef DEBUG 573 PrintRcode(nsh->rcode); 574#endif 575 return; 576} 577