]> git.saurik.com Git - apple/network_cmds.git/blob - alias/alias_nbt.c
d2199f68834de4a136bfd23767fcea599d8d72d5
[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 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*-
24 * Written by Atsushi Murai <amurai@spec.co.jp>
25 * Copyright (c) 1998, System Planning and Engineering Co.
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 *
49 * Based upon:
50 * $FreeBSD: src/lib/libalias/alias_nbt.c,v 1.4.2.3 2001/08/01 09:52:26 obrien Exp $
51 *
52 * TODO:
53 * oClean up.
54 * oConsidering for word alignment for other platform.
55 */
56 /*
57 alias_nbt.c performs special processing for NetBios over TCP/IP
58 sessions by UDP.
59
60 Initial version: May, 1998 (Atsushi Murai <amurai@spec.co.jp>)
61
62 See HISTORY file for record of revisions.
63 */
64
65 /* Includes */
66 #include <ctype.h>
67 #include <stdio.h>
68 #include <string.h>
69 #include <sys/types.h>
70 #include <netinet/in_systm.h>
71 #include <netinet/in.h>
72 #include <arpa/inet.h>
73 #include <netinet/ip.h>
74 #include <netinet/udp.h>
75 #include <netinet/tcp.h>
76
77 #include "alias_local.h"
78
79 typedef struct {
80 struct in_addr oldaddr;
81 u_short oldport;
82 struct in_addr newaddr;
83 u_short newport;
84 u_short *uh_sum;
85 } NBTArguments;
86
87 typedef struct {
88 unsigned char type;
89 unsigned char flags;
90 u_short id;
91 struct in_addr source_ip;
92 u_short source_port;
93 u_short len;
94 u_short offset;
95 } NbtDataHeader;
96
97 #define OpQuery 0
98 #define OpUnknown 4
99 #define OpRegist 5
100 #define OpRelease 6
101 #define OpWACK 7
102 #define OpRefresh 8
103 typedef struct {
104 u_short nametrid;
105 u_short dir:1, opcode:4, nmflags:7, rcode:4;
106 u_short qdcount;
107 u_short ancount;
108 u_short nscount;
109 u_short arcount;
110 } NbtNSHeader;
111
112 #define FMT_ERR 0x1
113 #define SRV_ERR 0x2
114 #define IMP_ERR 0x4
115 #define RFS_ERR 0x5
116 #define ACT_ERR 0x6
117 #define CFT_ERR 0x7
118
119
120 #ifdef DEBUG
121 static void PrintRcode( u_char rcode ) {
122
123 switch (rcode) {
124 case FMT_ERR:
125 printf("\nFormat Error.");
126 case SRV_ERR:
127 printf("\nSever failure.");
128 case IMP_ERR:
129 printf("\nUnsupported request error.\n");
130 case RFS_ERR:
131 printf("\nRefused error.\n");
132 case ACT_ERR:
133 printf("\nActive error.\n");
134 case CFT_ERR:
135 printf("\nName in conflict error.\n");
136 default:
137 printf("\n???=%0x\n", rcode );
138
139 }
140 }
141 #endif
142
143
144 /* Handling Name field */
145 static u_char *AliasHandleName ( u_char *p, char *pmax ) {
146
147 u_char *s;
148 u_char c;
149 int compress;
150
151 /* Following length field */
152
153 if (p == NULL || (char *)p >= pmax)
154 return(NULL);
155
156 if (*p & 0xc0 ) {
157 p = p + 2;
158 if ((char *)p > pmax)
159 return(NULL);
160 return ((u_char *)p);
161 }
162 while ( ( *p & 0x3f) != 0x00 ) {
163 s = p + 1;
164 if ( *p == 0x20 )
165 compress = 1;
166 else
167 compress = 0;
168
169 /* Get next length field */
170 p = (u_char *)(p + (*p & 0x3f) + 1);
171 if ((char *)p > pmax) {
172 p = NULL;
173 break;
174 }
175 #ifdef DEBUG
176 printf(":");
177 #endif
178 while (s < p) {
179 if ( compress == 1 ) {
180 c = (u_char )(((((*s & 0x0f) << 4) | (*(s+1) & 0x0f)) - 0x11));
181 #ifdef DEBUG
182 if (isprint( c ) )
183 printf("%c", c );
184 else
185 printf("<0x%02x>", c );
186 #endif
187 s +=2;
188 } else {
189 #ifdef DEBUG
190 printf("%c", *s);
191 #endif
192 s++;
193 }
194 }
195 #ifdef DEBUG
196 printf(":");
197 #endif
198 fflush(stdout);
199 }
200
201 /* Set up to out of Name field */
202 if (p == NULL || (char *)p >= pmax)
203 p = NULL;
204 else
205 p++;
206 return ((u_char *)p);
207 }
208
209 /*
210 * NetBios Datagram Handler (IP/UDP)
211 */
212 #define DGM_DIRECT_UNIQ 0x10
213 #define DGM_DIRECT_GROUP 0x11
214 #define DGM_BROADCAST 0x12
215 #define DGM_ERROR 0x13
216 #define DGM_QUERY 0x14
217 #define DGM_POSITIVE_RES 0x15
218 #define DGM_NEGATIVE_RES 0x16
219
220 int AliasHandleUdpNbt(
221 struct ip *pip, /* IP packet to examine/patch */
222 struct alias_link *link,
223 struct in_addr *alias_address,
224 u_short alias_port
225 ) {
226 struct udphdr * uh;
227 NbtDataHeader *ndh;
228 u_char *p = NULL;
229 char *pmax;
230
231 /* Calculate data length of UDP packet */
232 uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
233 pmax = (char *)uh + ntohs( uh->uh_ulen );
234
235 ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr)));
236 if ((char *)(ndh + 1) > pmax)
237 return(-1);
238 #ifdef DEBUG
239 printf("\nType=%02x,", ndh->type );
240 #endif
241 switch ( ndh->type ) {
242 case DGM_DIRECT_UNIQ:
243 case DGM_DIRECT_GROUP:
244 case DGM_BROADCAST:
245 p = (u_char *)ndh + 14;
246 p = AliasHandleName ( p, pmax ); /* Source Name */
247 p = AliasHandleName ( p, pmax ); /* Destination Name */
248 break;
249 case DGM_ERROR:
250 p = (u_char *)ndh + 11;
251 break;
252 case DGM_QUERY:
253 case DGM_POSITIVE_RES:
254 case DGM_NEGATIVE_RES:
255 p = (u_char *)ndh + 10;
256 p = AliasHandleName ( p, pmax ); /* Destination Name */
257 break;
258 }
259 if (p == NULL || (char *)p > pmax)
260 p = NULL;
261 #ifdef DEBUG
262 printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
263 #endif
264 /* Doing a IP address and Port number Translation */
265 if ( uh->uh_sum != 0 ) {
266 int acc;
267 u_short *sptr;
268 acc = ndh->source_port;
269 acc -= alias_port;
270 sptr = (u_short *) &(ndh->source_ip);
271 acc += *sptr++;
272 acc += *sptr;
273 sptr = (u_short *) alias_address;
274 acc -= *sptr++;
275 acc -= *sptr;
276 ADJUST_CHECKSUM(acc, uh->uh_sum);
277 }
278 ndh->source_ip = *alias_address;
279 ndh->source_port = alias_port;
280 #ifdef DEBUG
281 printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
282 fflush(stdout);
283 #endif
284 return((p == NULL) ? -1 : 0);
285 }
286 /* Question Section */
287 #define QS_TYPE_NB 0x0020
288 #define QS_TYPE_NBSTAT 0x0021
289 #define QS_CLAS_IN 0x0001
290 typedef struct {
291 u_short type; /* The type of Request */
292 u_short class; /* The class of Request */
293 } NBTNsQuestion;
294
295 static u_char *
296 AliasHandleQuestion(
297 u_short count,
298 NBTNsQuestion *q,
299 char *pmax,
300 NBTArguments *nbtarg)
301 {
302
303 while ( count != 0 ) {
304 /* Name Filed */
305 q = (NBTNsQuestion *)AliasHandleName((u_char *)q, pmax);
306
307 if (q == NULL || (char *)(q + 1) > pmax) {
308 q = NULL;
309 break;
310 }
311
312 /* Type and Class filed */
313 switch ( ntohs(q->type) ) {
314 case QS_TYPE_NB:
315 case QS_TYPE_NBSTAT:
316 q= q+1;
317 break;
318 default:
319 #ifdef DEBUG
320 printf("\nUnknown Type on Question %0x\n", ntohs(q->type) );
321 #endif
322 break;
323 }
324 count--;
325 }
326
327 /* Set up to out of Question Section */
328 return ((u_char *)q);
329 }
330
331 /* Resource Record */
332 #define RR_TYPE_A 0x0001
333 #define RR_TYPE_NS 0x0002
334 #define RR_TYPE_NULL 0x000a
335 #define RR_TYPE_NB 0x0020
336 #define RR_TYPE_NBSTAT 0x0021
337 #define RR_CLAS_IN 0x0001
338 #define SizeOfNsResource 8
339 typedef struct {
340 u_short type;
341 u_short class;
342 unsigned int ttl;
343 u_short rdlen;
344 } NBTNsResource;
345
346 #define SizeOfNsRNB 6
347 typedef struct {
348 u_short g:1, ont:2, resv:13;
349 struct in_addr addr;
350 } NBTNsRNB;
351
352 static u_char *
353 AliasHandleResourceNB(
354 NBTNsResource *q,
355 char *pmax,
356 NBTArguments *nbtarg)
357 {
358 NBTNsRNB *nb;
359 u_short bcount;
360
361 if (q == NULL || (char *)(q + 1) > pmax)
362 return(NULL);
363 /* Check out a length */
364 bcount = ntohs(q->rdlen);
365
366 /* Forward to Resource NB position */
367 nb = (NBTNsRNB *)((u_char *)q + SizeOfNsResource);
368
369 /* Processing all in_addr array */
370 #ifdef DEBUG
371 printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
372 printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount);
373 #endif
374 while ( nb != NULL && bcount != 0 ) {
375 if ((char *)(nb + 1) > pmax) {
376 nb = NULL;
377 break;
378 }
379 #ifdef DEBUG
380 printf("<%s>", inet_ntoa(nb->addr) );
381 #endif
382 if (!bcmp(&nbtarg->oldaddr,&nb->addr, sizeof(struct in_addr) ) ) {
383 if ( *nbtarg->uh_sum != 0 ) {
384 int acc;
385 u_short *sptr;
386
387 sptr = (u_short *) &(nb->addr);
388 acc = *sptr++;
389 acc += *sptr;
390 sptr = (u_short *) &(nbtarg->newaddr);
391 acc -= *sptr++;
392 acc -= *sptr;
393 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
394 }
395
396 nb->addr = nbtarg->newaddr;
397 #ifdef DEBUG
398 printf("O");
399 #endif
400 }
401 #ifdef DEBUG
402 else {
403 printf(".");
404 }
405 #endif
406 nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB);
407 bcount -= SizeOfNsRNB;
408 }
409 if (nb == NULL || (char *)(nb + 1) > pmax) {
410 nb = NULL;
411 }
412
413 return ((u_char *)nb);
414 }
415
416 #define SizeOfResourceA 6
417 typedef struct {
418 struct in_addr addr;
419 } NBTNsResourceA;
420
421 static u_char *
422 AliasHandleResourceA(
423 NBTNsResource *q,
424 char *pmax,
425 NBTArguments *nbtarg)
426 {
427 NBTNsResourceA *a;
428 u_short bcount;
429
430 if (q == NULL || (char *)(q + 1) > pmax)
431 return(NULL);
432
433 /* Forward to Resource A position */
434 a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) );
435
436 /* Check out of length */
437 bcount = ntohs(q->rdlen);
438
439 /* Processing all in_addr array */
440 #ifdef DEBUG
441 printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
442 printf("->%s]",inet_ntoa(nbtarg->newaddr ));
443 #endif
444 while ( bcount != 0 ) {
445 if (a == NULL || (char *)(a + 1) > pmax)
446 return(NULL);
447 #ifdef DEBUG
448 printf("..%s", inet_ntoa(a->addr) );
449 #endif
450 if ( !bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr) ) ) {
451 if ( *nbtarg->uh_sum != 0 ) {
452 int acc;
453 u_short *sptr;
454
455 sptr = (u_short *) &(a->addr); /* Old */
456 acc = *sptr++;
457 acc += *sptr;
458 sptr = (u_short *) &nbtarg->newaddr; /* New */
459 acc -= *sptr++;
460 acc -= *sptr;
461 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
462 }
463
464 a->addr = nbtarg->newaddr;
465 }
466 a++; /*XXXX*/
467 bcount -= SizeOfResourceA;
468 }
469 if (a == NULL || (char *)(a + 1) > pmax)
470 a = NULL;
471 return ((u_char *)a);
472 }
473
474 typedef struct {
475 u_short opcode:4, flags:8, resv:4;
476 } NBTNsResourceNULL;
477
478 static u_char *
479 AliasHandleResourceNULL(
480 NBTNsResource *q,
481 char *pmax,
482 NBTArguments *nbtarg)
483 {
484 NBTNsResourceNULL *n;
485 u_short bcount;
486
487 if (q == NULL || (char *)(q + 1) > pmax)
488 return(NULL);
489
490 /* Forward to Resource NULL position */
491 n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
492
493 /* Check out of length */
494 bcount = ntohs(q->rdlen);
495
496 /* Processing all in_addr array */
497 while ( bcount != 0 ) {
498 if ((char *)(n + 1) > pmax) {
499 n = NULL;
500 break;
501 }
502 n++;
503 bcount -= sizeof(NBTNsResourceNULL);
504 }
505 if ((char *)(n + 1) > pmax)
506 n = NULL;
507
508 return ((u_char *)n);
509 }
510
511 static u_char *
512 AliasHandleResourceNS(
513 NBTNsResource *q,
514 char *pmax,
515 NBTArguments *nbtarg)
516 {
517 NBTNsResourceNULL *n;
518 u_short bcount;
519
520 if (q == NULL || (char *)(q + 1) > pmax)
521 return(NULL);
522
523 /* Forward to Resource NULL position */
524 n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
525
526 /* Check out of length */
527 bcount = ntohs(q->rdlen);
528
529 /* Resource Record Name Filed */
530 q = (NBTNsResource *)AliasHandleName( (u_char *)n, pmax ); /* XXX */
531
532 if (q == NULL || (char *)((u_char *)n + bcount) > pmax)
533 return(NULL);
534 else
535 return ((u_char *)n + bcount);
536 }
537
538 typedef struct {
539 u_short numnames;
540 } NBTNsResourceNBSTAT;
541
542 static u_char *
543 AliasHandleResourceNBSTAT(
544 NBTNsResource *q,
545 char *pmax,
546 NBTArguments *nbtarg)
547 {
548 NBTNsResourceNBSTAT *n;
549 u_short bcount;
550
551 if (q == NULL || (char *)(q + 1) > pmax)
552 return(NULL);
553
554 /* Forward to Resource NBSTAT position */
555 n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) );
556
557 /* Check out of length */
558 bcount = ntohs(q->rdlen);
559
560 if (q == NULL || (char *)((u_char *)n + bcount) > pmax)
561 return(NULL);
562 else
563 return ((u_char *)n + bcount);
564 }
565
566 static u_char *
567 AliasHandleResource(
568 u_short count,
569 NBTNsResource *q,
570 char *pmax,
571 NBTArguments
572 *nbtarg)
573 {
574 while ( count != 0 ) {
575 /* Resource Record Name Filed */
576 q = (NBTNsResource *)AliasHandleName( (u_char *)q, pmax );
577
578 if (q == NULL || (char *)(q + 1) > pmax)
579 break;
580 #ifdef DEBUG
581 printf("type=%02x, count=%d\n", ntohs(q->type), count );
582 #endif
583
584 /* Type and Class filed */
585 switch ( ntohs(q->type) ) {
586 case RR_TYPE_NB:
587 q = (NBTNsResource *)AliasHandleResourceNB(
588 q,
589 pmax,
590 nbtarg
591 );
592 break;
593 case RR_TYPE_A:
594 q = (NBTNsResource *)AliasHandleResourceA(
595 q,
596 pmax,
597 nbtarg
598 );
599 break;
600 case RR_TYPE_NS:
601 q = (NBTNsResource *)AliasHandleResourceNS(
602 q,
603 pmax,
604 nbtarg
605 );
606 break;
607 case RR_TYPE_NULL:
608 q = (NBTNsResource *)AliasHandleResourceNULL(
609 q,
610 pmax,
611 nbtarg
612 );
613 break;
614 case RR_TYPE_NBSTAT:
615 q = (NBTNsResource *)AliasHandleResourceNBSTAT(
616 q,
617 pmax,
618 nbtarg
619 );
620 break;
621 default:
622 #ifdef DEBUG
623 printf(
624 "\nUnknown Type of Resource %0x\n",
625 ntohs(q->type)
626 );
627 #endif
628 break;
629 }
630 count--;
631 }
632 fflush(stdout);
633 return ((u_char *)q);
634 }
635
636 int AliasHandleUdpNbtNS(
637 struct ip *pip, /* IP packet to examine/patch */
638 struct alias_link *link,
639 struct in_addr *alias_address,
640 u_short *alias_port,
641 struct in_addr *original_address,
642 u_short *original_port )
643 {
644 struct udphdr * uh;
645 NbtNSHeader * nsh;
646 u_char * p;
647 char *pmax;
648 NBTArguments nbtarg;
649
650 /* Set up Common Parameter */
651 nbtarg.oldaddr = *alias_address;
652 nbtarg.oldport = *alias_port;
653 nbtarg.newaddr = *original_address;
654 nbtarg.newport = *original_port;
655
656 /* Calculate data length of UDP packet */
657 uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
658 nbtarg.uh_sum = &(uh->uh_sum);
659 nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr)));
660 p = (u_char *)(nsh + 1);
661 pmax = (char *)uh + ntohs( uh->uh_ulen );
662
663 if ((char *)(nsh + 1) > pmax)
664 return(-1);
665
666 #ifdef DEBUG
667 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
668 ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
669 nsh->dir ? "Response": "Request",
670 nsh->nametrid,
671 nsh->opcode,
672 nsh->nmflags,
673 nsh->rcode,
674 ntohs(nsh->qdcount),
675 ntohs(nsh->ancount),
676 ntohs(nsh->nscount),
677 ntohs(nsh->arcount),
678 (u_char *)p -(u_char *)nsh
679 );
680 #endif
681
682 /* Question Entries */
683 if (ntohs(nsh->qdcount) !=0 ) {
684 p = AliasHandleQuestion(
685 ntohs(nsh->qdcount),
686 (NBTNsQuestion *)p,
687 pmax,
688 &nbtarg
689 );
690 }
691
692 /* Answer Resource Records */
693 if (ntohs(nsh->ancount) !=0 ) {
694 p = AliasHandleResource(
695 ntohs(nsh->ancount),
696 (NBTNsResource *)p,
697 pmax,
698 &nbtarg
699 );
700 }
701
702 /* Authority Resource Recodrs */
703 if (ntohs(nsh->nscount) !=0 ) {
704 p = AliasHandleResource(
705 ntohs(nsh->nscount),
706 (NBTNsResource *)p,
707 pmax,
708 &nbtarg
709 );
710 }
711
712 /* Additional Resource Recodrs */
713 if (ntohs(nsh->arcount) !=0 ) {
714 p = AliasHandleResource(
715 ntohs(nsh->arcount),
716 (NBTNsResource *)p,
717 pmax,
718 &nbtarg
719 );
720 }
721
722 #ifdef DEBUG
723 PrintRcode(nsh->rcode);
724 #endif
725 return ((p == NULL) ? -1 : 0);
726 }