drm: Bring back a KNOTE() call, unbreak vblank handling
[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.4 2006/03/18 19:43:18 swildner 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 #ifdef DEBUG
127         u_char c;
128 #endif
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 ) {
160 #ifdef DEBUG
161                                 c = (u_char )(((((*s & 0x0f) << 4) | (*(s+1) & 0x0f)) - 0x11));
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
200 int 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
270 typedef struct {
271         u_short type;   /* The type of Request */
272         u_short class;  /* The class of Request */
273 } NBTNsQuestion;
274
275 static u_char *
276 AliasHandleQuestion(
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
319 typedef struct {
320         u_short type;
321         u_short class;
322         unsigned int ttl;
323         u_short rdlen;
324 } NBTNsResource;
325
326 #define SizeOfNsRNB                     6
327 typedef struct {
328         u_short g:1, ont:2, resv:13;
329         struct  in_addr addr;
330 } NBTNsRNB;
331
332 static u_char *
333 AliasHandleResourceNB( 
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
397 typedef struct {
398         struct  in_addr addr;
399 } NBTNsResourceA;
400
401 static u_char *
402 AliasHandleResourceA( 
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
454 typedef struct {
455         u_short opcode:4, flags:8, resv:4;
456 } NBTNsResourceNULL;
457
458 static u_char *
459 AliasHandleResourceNULL( 
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
491 static u_char *
492 AliasHandleResourceNS( 
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
518 typedef struct {
519         u_short numnames;
520 } NBTNsResourceNBSTAT;
521
522 static u_char *
523 AliasHandleResourceNBSTAT(
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
546 static u_char *
547 AliasHandleResource(
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
616 int 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 }