network_cmds-511.tar.gz
[apple/network_cmds.git] / alias / alias_nbt.c
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
78 typedef 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
86 typedef 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
102 typedef 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
120 static 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 */
150 static 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
225 int 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
295 typedef struct {
296 u_short type; /* The type of Request */
297 u_short class; /* The class of Request */
298 } NBTNsQuestion;
299
300 static u_char *
301 AliasHandleQuestion(
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
344 typedef struct {
345 u_short type;
346 u_short class;
347 unsigned int ttl;
348 u_short rdlen;
349 } NBTNsResource;
350
351 #define SizeOfNsRNB 6
352 typedef struct {
353 u_short g:1, ont:2, resv:13;
354 struct in_addr addr;
355 } NBTNsRNB;
356
357 static u_char *
358 AliasHandleResourceNB(
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
422 typedef struct {
423 struct in_addr addr;
424 } NBTNsResourceA;
425
426 static u_char *
427 AliasHandleResourceA(
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
479 typedef struct {
480 u_short opcode:4, flags:8, resv:4;
481 } NBTNsResourceNULL;
482
483 static u_char *
484 AliasHandleResourceNULL(
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
516 static u_char *
517 AliasHandleResourceNS(
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
543 typedef struct {
544 u_short numnames;
545 } NBTNsResourceNBSTAT;
546
547 static u_char *
548 AliasHandleResourceNBSTAT(
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
571 static u_char *
572 AliasHandleResource(
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
641 int 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 }