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