]> git.saurik.com Git - apple/network_cmds.git/blame - alias/alias_nbt.c
network_cmds-245.8.tar.gz
[apple/network_cmds.git] / alias / alias_nbt.c
CommitLineData
b7080c8e 1/*
7ba0088d
A
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
a2c93a76
A
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.
7ba0088d 11 *
a2c93a76
A
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
7ba0088d
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
a2c93a76
A
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.
7ba0088d
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*-
b7080c8e 23 * Written by Atsushi Murai <amurai@spec.co.jp>
7ba0088d
A
24 * Copyright (c) 1998, System Planning and Engineering Co.
25 * All rights reserved.
b7080c8e 26 *
7ba0088d
A
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.
b7080c8e 35 *
7ba0088d
A
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.
b7080c8e 47 *
7ba0088d
A
48 * Based upon:
49 * $FreeBSD: src/lib/libalias/alias_nbt.c,v 1.4.2.3 2001/08/01 09:52:26 obrien Exp $
b7080c8e
A
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
b7080c8e
A
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("\nFormat Error.");
125 case SRV_ERR:
126 printf("\nSever failure.");
127 case IMP_ERR:
128 printf("\nUnsupported request error.\n");
129 case RFS_ERR:
130 printf("\nRefused error.\n");
131 case ACT_ERR:
132 printf("\nActive error.\n");
133 case CFT_ERR:
134 printf("\nName in conflict error.\n");
135 default:
136 printf("\n???=%0x\n", rcode );
137
138 }
139}
140#endif
141
142
143/* Handling Name field */
144static u_char *AliasHandleName ( u_char *p, char *pmax ) {
145
146 u_char *s;
147 u_char c;
148 int compress;
149
150 /* Following length field */
151
152 if (p == NULL || (char *)p >= pmax)
153 return(NULL);
154
155 if (*p & 0xc0 ) {
156 p = p + 2;
157 if ((char *)p > pmax)
158 return(NULL);
159 return ((u_char *)p);
160 }
161 while ( ( *p & 0x3f) != 0x00 ) {
162 s = p + 1;
163 if ( *p == 0x20 )
164 compress = 1;
165 else
166 compress = 0;
167
168 /* Get next length field */
169 p = (u_char *)(p + (*p & 0x3f) + 1);
170 if ((char *)p > pmax) {
171 p = NULL;
172 break;
173 }
174#ifdef DEBUG
175 printf(":");
176#endif
177 while (s < p) {
178 if ( compress == 1 ) {
179 c = (u_char )(((((*s & 0x0f) << 4) | (*(s+1) & 0x0f)) - 0x11));
180#ifdef DEBUG
181 if (isprint( c ) )
182 printf("%c", c );
183 else
184 printf("<0x%02x>", c );
185#endif
186 s +=2;
187 } else {
188#ifdef DEBUG
189 printf("%c", *s);
190#endif
191 s++;
192 }
193 }
194#ifdef DEBUG
195 printf(":");
196#endif
197 fflush(stdout);
198 }
199
200 /* Set up to out of Name field */
201 if (p == NULL || (char *)p >= pmax)
202 p = NULL;
203 else
204 p++;
205 return ((u_char *)p);
206}
207
208/*
209 * NetBios Datagram Handler (IP/UDP)
210 */
211#define DGM_DIRECT_UNIQ 0x10
212#define DGM_DIRECT_GROUP 0x11
213#define DGM_BROADCAST 0x12
214#define DGM_ERROR 0x13
215#define DGM_QUERY 0x14
216#define DGM_POSITIVE_RES 0x15
217#define DGM_NEGATIVE_RES 0x16
218
219int AliasHandleUdpNbt(
220 struct ip *pip, /* IP packet to examine/patch */
221 struct alias_link *link,
222 struct in_addr *alias_address,
223 u_short alias_port
224) {
225 struct udphdr * uh;
226 NbtDataHeader *ndh;
227 u_char *p = NULL;
228 char *pmax;
229
230 /* Calculate data length of UDP packet */
231 uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
232 pmax = (char *)uh + ntohs( uh->uh_ulen );
233
234 ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr)));
235 if ((char *)(ndh + 1) > pmax)
236 return(-1);
237#ifdef DEBUG
238 printf("\nType=%02x,", ndh->type );
239#endif
240 switch ( ndh->type ) {
241 case DGM_DIRECT_UNIQ:
242 case DGM_DIRECT_GROUP:
243 case DGM_BROADCAST:
244 p = (u_char *)ndh + 14;
245 p = AliasHandleName ( p, pmax ); /* Source Name */
246 p = AliasHandleName ( p, pmax ); /* Destination Name */
247 break;
248 case DGM_ERROR:
249 p = (u_char *)ndh + 11;
250 break;
251 case DGM_QUERY:
252 case DGM_POSITIVE_RES:
253 case DGM_NEGATIVE_RES:
254 p = (u_char *)ndh + 10;
255 p = AliasHandleName ( p, pmax ); /* Destination Name */
256 break;
257 }
258 if (p == NULL || (char *)p > pmax)
259 p = NULL;
260#ifdef DEBUG
261 printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
262#endif
263 /* Doing a IP address and Port number Translation */
264 if ( uh->uh_sum != 0 ) {
265 int acc;
266 u_short *sptr;
267 acc = ndh->source_port;
268 acc -= alias_port;
269 sptr = (u_short *) &(ndh->source_ip);
270 acc += *sptr++;
271 acc += *sptr;
272 sptr = (u_short *) alias_address;
273 acc -= *sptr++;
274 acc -= *sptr;
7ba0088d 275 ADJUST_CHECKSUM(acc, uh->uh_sum);
b7080c8e
A
276 }
277 ndh->source_ip = *alias_address;
278 ndh->source_port = alias_port;
279#ifdef DEBUG
280 printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
281 fflush(stdout);
282#endif
283 return((p == NULL) ? -1 : 0);
284}
285/* Question Section */
286#define QS_TYPE_NB 0x0020
287#define QS_TYPE_NBSTAT 0x0021
288#define QS_CLAS_IN 0x0001
289typedef struct {
290 u_short type; /* The type of Request */
291 u_short class; /* The class of Request */
292} NBTNsQuestion;
293
294static u_char *
295AliasHandleQuestion(
296 u_short count,
297 NBTNsQuestion *q,
298 char *pmax,
299 NBTArguments *nbtarg)
300{
301
302 while ( count != 0 ) {
303 /* Name Filed */
304 q = (NBTNsQuestion *)AliasHandleName((u_char *)q, pmax);
305
306 if (q == NULL || (char *)(q + 1) > pmax) {
307 q = NULL;
308 break;
309 }
310
311 /* Type and Class filed */
312 switch ( ntohs(q->type) ) {
313 case QS_TYPE_NB:
314 case QS_TYPE_NBSTAT:
315 q= q+1;
316 break;
317 default:
318#ifdef DEBUG
319 printf("\nUnknown Type on Question %0x\n", ntohs(q->type) );
320#endif
321 break;
322 }
323 count--;
324 }
325
326 /* Set up to out of Question Section */
327 return ((u_char *)q);
328}
329
330/* Resource Record */
331#define RR_TYPE_A 0x0001
332#define RR_TYPE_NS 0x0002
333#define RR_TYPE_NULL 0x000a
334#define RR_TYPE_NB 0x0020
335#define RR_TYPE_NBSTAT 0x0021
336#define RR_CLAS_IN 0x0001
337#define SizeOfNsResource 8
338typedef struct {
339 u_short type;
340 u_short class;
341 unsigned int ttl;
342 u_short rdlen;
343} NBTNsResource;
344
345#define SizeOfNsRNB 6
346typedef struct {
347 u_short g:1, ont:2, resv:13;
348 struct in_addr addr;
349} NBTNsRNB;
350
351static u_char *
352AliasHandleResourceNB(
353 NBTNsResource *q,
354 char *pmax,
355 NBTArguments *nbtarg)
356{
357 NBTNsRNB *nb;
358 u_short bcount;
359
360 if (q == NULL || (char *)(q + 1) > pmax)
361 return(NULL);
362 /* Check out a length */
363 bcount = ntohs(q->rdlen);
364
365 /* Forward to Resource NB position */
366 nb = (NBTNsRNB *)((u_char *)q + SizeOfNsResource);
367
368 /* Processing all in_addr array */
369#ifdef DEBUG
370 printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
371 printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount);
372#endif
373 while ( nb != NULL && bcount != 0 ) {
374 if ((char *)(nb + 1) > pmax) {
375 nb = NULL;
376 break;
377 }
378#ifdef DEBUG
379 printf("<%s>", inet_ntoa(nb->addr) );
380#endif
381 if (!bcmp(&nbtarg->oldaddr,&nb->addr, sizeof(struct in_addr) ) ) {
382 if ( *nbtarg->uh_sum != 0 ) {
383 int acc;
384 u_short *sptr;
385
386 sptr = (u_short *) &(nb->addr);
387 acc = *sptr++;
388 acc += *sptr;
389 sptr = (u_short *) &(nbtarg->newaddr);
390 acc -= *sptr++;
391 acc -= *sptr;
7ba0088d 392 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
b7080c8e
A
393 }
394
395 nb->addr = nbtarg->newaddr;
396#ifdef DEBUG
397 printf("O");
398#endif
399 }
400#ifdef DEBUG
401 else {
402 printf(".");
403 }
404#endif
405 nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB);
406 bcount -= SizeOfNsRNB;
407 }
408 if (nb == NULL || (char *)(nb + 1) > pmax) {
409 nb = NULL;
410 }
411
412 return ((u_char *)nb);
413}
414
415#define SizeOfResourceA 6
416typedef struct {
417 struct in_addr addr;
418} NBTNsResourceA;
419
420static u_char *
421AliasHandleResourceA(
422 NBTNsResource *q,
423 char *pmax,
424 NBTArguments *nbtarg)
425{
426 NBTNsResourceA *a;
427 u_short bcount;
428
429 if (q == NULL || (char *)(q + 1) > pmax)
430 return(NULL);
431
432 /* Forward to Resource A position */
433 a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) );
434
435 /* Check out of length */
436 bcount = ntohs(q->rdlen);
437
438 /* Processing all in_addr array */
439#ifdef DEBUG
440 printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
441 printf("->%s]",inet_ntoa(nbtarg->newaddr ));
442#endif
443 while ( bcount != 0 ) {
444 if (a == NULL || (char *)(a + 1) > pmax)
445 return(NULL);
446#ifdef DEBUG
447 printf("..%s", inet_ntoa(a->addr) );
448#endif
449 if ( !bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr) ) ) {
450 if ( *nbtarg->uh_sum != 0 ) {
451 int acc;
452 u_short *sptr;
453
454 sptr = (u_short *) &(a->addr); /* Old */
455 acc = *sptr++;
456 acc += *sptr;
457 sptr = (u_short *) &nbtarg->newaddr; /* New */
458 acc -= *sptr++;
459 acc -= *sptr;
7ba0088d 460 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
b7080c8e
A
461 }
462
463 a->addr = nbtarg->newaddr;
464 }
465 a++; /*XXXX*/
466 bcount -= SizeOfResourceA;
467 }
468 if (a == NULL || (char *)(a + 1) > pmax)
469 a = NULL;
470 return ((u_char *)a);
471}
472
473typedef struct {
474 u_short opcode:4, flags:8, resv:4;
475} NBTNsResourceNULL;
476
477static u_char *
478AliasHandleResourceNULL(
479 NBTNsResource *q,
480 char *pmax,
481 NBTArguments *nbtarg)
482{
483 NBTNsResourceNULL *n;
484 u_short bcount;
485
486 if (q == NULL || (char *)(q + 1) > pmax)
487 return(NULL);
488
489 /* Forward to Resource NULL position */
490 n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
491
492 /* Check out of length */
493 bcount = ntohs(q->rdlen);
494
495 /* Processing all in_addr array */
496 while ( bcount != 0 ) {
497 if ((char *)(n + 1) > pmax) {
498 n = NULL;
499 break;
500 }
501 n++;
502 bcount -= sizeof(NBTNsResourceNULL);
503 }
504 if ((char *)(n + 1) > pmax)
505 n = NULL;
506
507 return ((u_char *)n);
508}
509
510static u_char *
511AliasHandleResourceNS(
512 NBTNsResource *q,
513 char *pmax,
514 NBTArguments *nbtarg)
515{
516 NBTNsResourceNULL *n;
517 u_short bcount;
518
519 if (q == NULL || (char *)(q + 1) > pmax)
520 return(NULL);
521
522 /* Forward to Resource NULL position */
523 n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
524
525 /* Check out of length */
526 bcount = ntohs(q->rdlen);
527
528 /* Resource Record Name Filed */
529 q = (NBTNsResource *)AliasHandleName( (u_char *)n, pmax ); /* XXX */
530
531 if (q == NULL || (char *)((u_char *)n + bcount) > pmax)
532 return(NULL);
533 else
534 return ((u_char *)n + bcount);
535}
536
537typedef struct {
538 u_short numnames;
539} NBTNsResourceNBSTAT;
540
541static u_char *
542AliasHandleResourceNBSTAT(
543 NBTNsResource *q,
544 char *pmax,
545 NBTArguments *nbtarg)
546{
547 NBTNsResourceNBSTAT *n;
548 u_short bcount;
549
550 if (q == NULL || (char *)(q + 1) > pmax)
551 return(NULL);
552
553 /* Forward to Resource NBSTAT position */
554 n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) );
555
556 /* Check out of length */
557 bcount = ntohs(q->rdlen);
558
559 if (q == NULL || (char *)((u_char *)n + bcount) > pmax)
560 return(NULL);
561 else
562 return ((u_char *)n + bcount);
563}
564
565static u_char *
566AliasHandleResource(
567 u_short count,
568 NBTNsResource *q,
569 char *pmax,
570 NBTArguments
571 *nbtarg)
572{
573 while ( count != 0 ) {
574 /* Resource Record Name Filed */
575 q = (NBTNsResource *)AliasHandleName( (u_char *)q, pmax );
576
577 if (q == NULL || (char *)(q + 1) > pmax)
578 break;
579#ifdef DEBUG
580 printf("type=%02x, count=%d\n", ntohs(q->type), count );
581#endif
582
583 /* Type and Class filed */
584 switch ( ntohs(q->type) ) {
585 case RR_TYPE_NB:
586 q = (NBTNsResource *)AliasHandleResourceNB(
587 q,
588 pmax,
589 nbtarg
590 );
591 break;
592 case RR_TYPE_A:
593 q = (NBTNsResource *)AliasHandleResourceA(
594 q,
595 pmax,
596 nbtarg
597 );
598 break;
599 case RR_TYPE_NS:
600 q = (NBTNsResource *)AliasHandleResourceNS(
601 q,
602 pmax,
603 nbtarg
604 );
605 break;
606 case RR_TYPE_NULL:
607 q = (NBTNsResource *)AliasHandleResourceNULL(
608 q,
609 pmax,
610 nbtarg
611 );
612 break;
613 case RR_TYPE_NBSTAT:
614 q = (NBTNsResource *)AliasHandleResourceNBSTAT(
615 q,
616 pmax,
617 nbtarg
618 );
619 break;
620 default:
621#ifdef DEBUG
622 printf(
623 "\nUnknown Type of Resource %0x\n",
624 ntohs(q->type)
625 );
626#endif
627 break;
628 }
629 count--;
630 }
631 fflush(stdout);
632 return ((u_char *)q);
633}
634
635int AliasHandleUdpNbtNS(
636 struct ip *pip, /* IP packet to examine/patch */
637 struct alias_link *link,
638 struct in_addr *alias_address,
639 u_short *alias_port,
640 struct in_addr *original_address,
641 u_short *original_port )
642{
643 struct udphdr * uh;
644 NbtNSHeader * nsh;
645 u_char * p;
646 char *pmax;
647 NBTArguments nbtarg;
648
649 /* Set up Common Parameter */
650 nbtarg.oldaddr = *alias_address;
651 nbtarg.oldport = *alias_port;
652 nbtarg.newaddr = *original_address;
653 nbtarg.newport = *original_port;
654
655 /* Calculate data length of UDP packet */
656 uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
657 nbtarg.uh_sum = &(uh->uh_sum);
658 nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr)));
659 p = (u_char *)(nsh + 1);
660 pmax = (char *)uh + ntohs( uh->uh_ulen );
661
662 if ((char *)(nsh + 1) > pmax)
663 return(-1);
664
665#ifdef DEBUG
666 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
667 ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
668 nsh->dir ? "Response": "Request",
669 nsh->nametrid,
670 nsh->opcode,
671 nsh->nmflags,
672 nsh->rcode,
673 ntohs(nsh->qdcount),
674 ntohs(nsh->ancount),
675 ntohs(nsh->nscount),
676 ntohs(nsh->arcount),
677 (u_char *)p -(u_char *)nsh
678 );
679#endif
680
681 /* Question Entries */
682 if (ntohs(nsh->qdcount) !=0 ) {
683 p = AliasHandleQuestion(
684 ntohs(nsh->qdcount),
685 (NBTNsQuestion *)p,
686 pmax,
687 &nbtarg
688 );
689 }
690
691 /* Answer Resource Records */
692 if (ntohs(nsh->ancount) !=0 ) {
693 p = AliasHandleResource(
694 ntohs(nsh->ancount),
695 (NBTNsResource *)p,
696 pmax,
697 &nbtarg
698 );
699 }
700
701 /* Authority Resource Recodrs */
702 if (ntohs(nsh->nscount) !=0 ) {
703 p = AliasHandleResource(
704 ntohs(nsh->nscount),
705 (NBTNsResource *)p,
706 pmax,
707 &nbtarg
708 );
709 }
710
711 /* Additional Resource Recodrs */
712 if (ntohs(nsh->arcount) !=0 ) {
713 p = AliasHandleResource(
714 ntohs(nsh->arcount),
715 (NBTNsResource *)p,
716 pmax,
717 &nbtarg
718 );
719 }
720
721#ifdef DEBUG
722 PrintRcode(nsh->rcode);
723#endif
724 return ((p == NULL) ? -1 : 0);
725}