Merge from vendor branch BINUTILS:
[dragonfly.git] / lib / libalias / alias_nbt.c
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 $
28  * $DragonFly: src/lib/libalias/alias_nbt.c,v 1.3 2004/08/20 01:21:36 joerg Exp $
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 */
44 #include <sys/param.h>
45 #include <ctype.h>
46 #include <stdio.h> 
47 #include <string.h>
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
57 typedef 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
65 typedef 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
81 typedef 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
99 static 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:
115                         printf("\n???=%0x\n", rcode );
116
117         }       
118 }
119 #endif
120
121
122 /* Handling Name field */
123 static 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
198 int 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
268 typedef struct {
269         u_short type;   /* The type of Request */
270         u_short class;  /* The class of Request */
271 } NBTNsQuestion;
272
273 static u_char *
274 AliasHandleQuestion(
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
317 typedef struct {
318         u_short type;
319         u_short class;
320         unsigned int ttl;
321         u_short rdlen;
322 } NBTNsResource;
323
324 #define SizeOfNsRNB                     6
325 typedef struct {
326         u_short g:1, ont:2, resv:13;
327         struct  in_addr addr;
328 } NBTNsRNB;
329
330 static u_char *
331 AliasHandleResourceNB( 
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
395 typedef struct {
396         struct  in_addr addr;
397 } NBTNsResourceA;
398
399 static u_char *
400 AliasHandleResourceA( 
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
452 typedef struct {
453         u_short opcode:4, flags:8, resv:4;
454 } NBTNsResourceNULL;
455
456 static u_char *
457 AliasHandleResourceNULL( 
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
489 static u_char *
490 AliasHandleResourceNS( 
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
516 typedef struct {
517         u_short numnames;
518 } NBTNsResourceNBSTAT;
519
520 static u_char *
521 AliasHandleResourceNBSTAT(
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
544 static u_char *
545 AliasHandleResource(
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
614 int 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 }