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