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