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