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