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