]> git.saurik.com Git - apple/network_cmds.git/blob - alias/alias_nbt.c
network_cmds-245.12.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("\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 */
144 static 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
219 int 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;
275 ADJUST_CHECKSUM(acc, uh->uh_sum);
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
289 typedef struct {
290 u_short type; /* The type of Request */
291 u_short class; /* The class of Request */
292 } NBTNsQuestion;
293
294 static u_char *
295 AliasHandleQuestion(
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
338 typedef struct {
339 u_short type;
340 u_short class;
341 unsigned int ttl;
342 u_short rdlen;
343 } NBTNsResource;
344
345 #define SizeOfNsRNB 6
346 typedef struct {
347 u_short g:1, ont:2, resv:13;
348 struct in_addr addr;
349 } NBTNsRNB;
350
351 static u_char *
352 AliasHandleResourceNB(
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;
392 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
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
416 typedef struct {
417 struct in_addr addr;
418 } NBTNsResourceA;
419
420 static u_char *
421 AliasHandleResourceA(
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;
460 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
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
473 typedef struct {
474 u_short opcode:4, flags:8, resv:4;
475 } NBTNsResourceNULL;
476
477 static u_char *
478 AliasHandleResourceNULL(
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
510 static u_char *
511 AliasHandleResourceNS(
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
537 typedef struct {
538 u_short numnames;
539 } NBTNsResourceNBSTAT;
540
541 static u_char *
542 AliasHandleResourceNBSTAT(
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
565 static u_char *
566 AliasHandleResource(
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
635 int 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 }