2 * Written by Atsushi Murai <amurai@spec.co.jp>
3 * Copyright (c) 1998, System Planning and Engineering Co.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
28 * oConsidering for word alignment for other platform.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
35 alias_nbt.c performs special processing for NetBios over TCP/IP
38 Initial version: May, 1998 (Atsushi Murai <amurai@spec.co.jp>)
40 See HISTORY file for record of revisions.
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/module.h>
51 #include <sys/types.h>
56 #include <netinet/in_systm.h>
57 #include <netinet/in.h>
58 #include <netinet/ip.h>
59 #include <netinet/udp.h>
62 #include <netinet/libalias/alias_local.h>
63 #include <netinet/libalias/alias_mod.h>
65 #include "alias_local.h"
66 #include "alias_mod.h"
69 #define NETBIOS_NS_PORT_NUMBER 137
70 #define NETBIOS_DGM_PORT_NUMBER 138
73 AliasHandleUdpNbt(struct libalias *, struct ip *, struct alias_link *,
74 struct in_addr *, u_short);
77 AliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
78 struct in_addr *, u_short *, struct in_addr *, u_short *);
80 fingerprint1(struct libalias *la, struct alias_data *ah)
83 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
84 ah->aaddr == NULL || ah->aport == NULL)
86 if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
87 || ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
93 protohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
96 return (AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport));
100 fingerprint2(struct libalias *la, struct alias_data *ah)
103 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
104 ah->aaddr == NULL || ah->aport == NULL)
106 if (ntohs(*ah->dport) == NETBIOS_NS_PORT_NUMBER
107 || ntohs(*ah->sport) == NETBIOS_NS_PORT_NUMBER)
113 protohandler2in(struct libalias *la, struct ip *pip, struct alias_data *ah)
116 AliasHandleUdpNbtNS(la, pip, ah->lnk, ah->aaddr, ah->aport,
117 ah->oaddr, ah->dport);
122 protohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
125 return (AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
126 ah->aaddr, ah->aport));
129 /* Kernel module definition. */
130 struct proto_handler handlers[] = {
135 .fingerprint = &fingerprint1,
136 .protohandler = &protohandler1
142 .fingerprint = &fingerprint2,
143 .protohandler = &protohandler2in
149 .fingerprint = &fingerprint2,
150 .protohandler = &protohandler2out
156 mod_handler(module_t mod, int type, void *data)
163 LibAliasAttachHandlers(handlers);
167 LibAliasDetachHandlers(handlers);
178 moduledata_t alias_mod = {
179 "alias_nbt", mod_handler, NULL
183 DECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
184 MODULE_VERSION(alias_nbt, 1);
185 MODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
189 struct in_addr oldaddr;
191 struct in_addr newaddr;
200 struct in_addr source_ip;
214 u_short dir: 1, opcode:4, nmflags:7, rcode:4;
229 #ifdef LIBALIAS_DEBUG
231 PrintRcode(u_char rcode)
236 printf("\nFormat Error.");
238 printf("\nSever failure.");
240 printf("\nUnsupported request error.\n");
242 printf("\nRefused error.\n");
244 printf("\nActive error.\n");
246 printf("\nName in conflict error.\n");
248 printf("\n?%c?=%0x\n", '?', rcode);
256 /* Handling Name field */
258 AliasHandleName(u_char * p, char *pmax)
265 /* Following length field */
267 if (p == NULL || (char *)p >= pmax)
272 if ((char *)p > pmax)
274 return ((u_char *) p);
276 while ((*p & 0x3f) != 0x00) {
283 /* Get next length field */
284 p = (u_char *) (p + (*p & 0x3f) + 1);
285 if ((char *)p > pmax) {
289 #ifdef LIBALIAS_DEBUG
294 c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
295 #ifdef LIBALIAS_DEBUG
299 printf("<0x%02x>", c);
303 #ifdef LIBALIAS_DEBUG
309 #ifdef LIBALIAS_DEBUG
315 /* Set up to out of Name field */
316 if (p == NULL || (char *)p >= pmax)
320 return ((u_char *) p);
324 * NetBios Datagram Handler (IP/UDP)
326 #define DGM_DIRECT_UNIQ 0x10
327 #define DGM_DIRECT_GROUP 0x11
328 #define DGM_BROADCAST 0x12
329 #define DGM_ERROR 0x13
330 #define DGM_QUERY 0x14
331 #define DGM_POSITIVE_RES 0x15
332 #define DGM_NEGATIVE_RES 0x16
337 struct ip *pip, /* IP packet to examine/patch */
338 struct alias_link *lnk,
339 struct in_addr *alias_address,
347 #ifdef LIBALIAS_DEBUG
348 char addrbuf[INET_ADDRSTRLEN];
354 /* Calculate data length of UDP packet */
355 uh = (struct udphdr *)ip_next(pip);
356 pmax = (char *)uh + ntohs(uh->uh_ulen);
358 ndh = (NbtDataHeader *)udp_next(uh);
359 if ((char *)(ndh + 1) > pmax)
361 #ifdef LIBALIAS_DEBUG
362 printf("\nType=%02x,", ndh->type);
365 case DGM_DIRECT_UNIQ:
366 case DGM_DIRECT_GROUP:
368 p = (u_char *) ndh + 14;
369 p = AliasHandleName(p, pmax); /* Source Name */
370 p = AliasHandleName(p, pmax); /* Destination Name */
373 p = (u_char *) ndh + 11;
376 case DGM_POSITIVE_RES:
377 case DGM_NEGATIVE_RES:
378 p = (u_char *) ndh + 10;
379 p = AliasHandleName(p, pmax); /* Destination Name */
382 if (p == NULL || (char *)p > pmax)
384 #ifdef LIBALIAS_DEBUG
385 printf("%s:%d-->", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
386 ntohs(ndh->source_port));
388 /* Doing an IP address and Port number Translation */
389 if (uh->uh_sum != 0) {
393 acc = ndh->source_port;
395 sptr = (u_short *) & (ndh->source_ip);
398 sptr = (u_short *) alias_address;
401 ADJUST_CHECKSUM(acc, uh->uh_sum);
403 ndh->source_ip = *alias_address;
404 ndh->source_port = alias_port;
405 #ifdef LIBALIAS_DEBUG
406 printf("%s:%d\n", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
407 ntohs(ndh->source_port));
410 return ((p == NULL) ? -1 : 0);
413 /* Question Section */
414 #define QS_TYPE_NB 0x0020
415 #define QS_TYPE_NBSTAT 0x0021
416 #define QS_CLAS_IN 0x0001
418 u_short type; /* The type of Request */
419 u_short class; /* The class of Request */
427 NBTArguments * nbtarg)
434 q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
436 if (q == NULL || (char *)(q + 1) > pmax) {
440 /* Type and Class filed */
441 switch (ntohs(q->type)) {
447 #ifdef LIBALIAS_DEBUG
448 printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
455 /* Set up to out of Question Section */
456 return ((u_char *) q);
459 /* Resource Record */
460 #define RR_TYPE_A 0x0001
461 #define RR_TYPE_NS 0x0002
462 #define RR_TYPE_NULL 0x000a
463 #define RR_TYPE_NB 0x0020
464 #define RR_TYPE_NBSTAT 0x0021
465 #define RR_CLAS_IN 0x0001
466 #define SizeOfNsResource 8
474 #define SizeOfNsRNB 6
476 u_short g: 1 , ont:2, resv:13;
481 AliasHandleResourceNB(
484 NBTArguments * nbtarg)
488 #ifdef LIBALIAS_DEBUG
489 char oldbuf[INET_ADDRSTRLEN];
490 char newbuf[INET_ADDRSTRLEN];
493 if (q == NULL || (char *)(q + 1) > pmax)
495 /* Check out a length */
496 bcount = ntohs(q->rdlen);
498 /* Forward to Resource NB position */
499 nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
501 /* Processing all in_addr array */
502 #ifdef LIBALIAS_DEBUG
503 printf("NB rec[%s->%s, %dbytes] ",
504 inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
505 inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)),
508 while (nb != NULL && bcount != 0) {
509 if ((char *)(nb + 1) > pmax) {
513 #ifdef LIBALIAS_DEBUG
514 printf("<%s>", inet_ntoa_r(nb->addr, INET_NTOA_BUF(newbuf)));
516 if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
517 if (*nbtarg->uh_sum != 0) {
521 sptr = (u_short *) & (nb->addr);
524 sptr = (u_short *) & (nbtarg->newaddr);
527 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
529 nb->addr = nbtarg->newaddr;
530 #ifdef LIBALIAS_DEBUG
534 #ifdef LIBALIAS_DEBUG
539 nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
540 bcount -= SizeOfNsRNB;
542 if (nb == NULL || (char *)(nb + 1) > pmax) {
545 return ((u_char *) nb);
548 #define SizeOfResourceA 6
554 AliasHandleResourceA(
557 NBTArguments * nbtarg)
561 #ifdef LIBALIAS_DEBUG
562 char oldbuf[INET_ADDRSTRLEN];
563 char newbuf[INET_ADDRSTRLEN];
566 if (q == NULL || (char *)(q + 1) > pmax)
569 /* Forward to Resource A position */
570 a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
572 /* Check out of length */
573 bcount = ntohs(q->rdlen);
575 /* Processing all in_addr array */
576 #ifdef LIBALIAS_DEBUG
577 printf("Arec [%s->%s]",
578 inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
579 inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)));
581 while (bcount != 0) {
582 if (a == NULL || (char *)(a + 1) > pmax)
584 #ifdef LIBALIAS_DEBUG
585 printf("..%s", inet_ntoa_r(a->addr, INET_NTOA_BUF(newbuf)));
587 if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
588 if (*nbtarg->uh_sum != 0) {
592 sptr = (u_short *) & (a->addr); /* Old */
595 sptr = (u_short *) & nbtarg->newaddr; /* New */
598 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
600 a->addr = nbtarg->newaddr;
603 bcount -= SizeOfResourceA;
605 if (a == NULL || (char *)(a + 1) > pmax)
607 return ((u_char *) a);
611 u_short opcode:4, flags:8, resv:4;
615 AliasHandleResourceNULL(
618 NBTArguments * nbtarg)
620 NBTNsResourceNULL *n;
625 if (q == NULL || (char *)(q + 1) > pmax)
628 /* Forward to Resource NULL position */
629 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
631 /* Check out of length */
632 bcount = ntohs(q->rdlen);
634 /* Processing all in_addr array */
635 while (bcount != 0) {
636 if ((char *)(n + 1) > pmax) {
641 bcount -= sizeof(NBTNsResourceNULL);
643 if ((char *)(n + 1) > pmax)
646 return ((u_char *) n);
650 AliasHandleResourceNS(
653 NBTArguments * nbtarg)
655 NBTNsResourceNULL *n;
660 if (q == NULL || (char *)(q + 1) > pmax)
663 /* Forward to Resource NULL position */
664 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
666 /* Check out of length */
667 bcount = ntohs(q->rdlen);
669 /* Resource Record Name Filed */
670 q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax); /* XXX */
672 if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
675 return ((u_char *) n + bcount);
680 } NBTNsResourceNBSTAT;
683 AliasHandleResourceNBSTAT(
686 NBTArguments * nbtarg)
688 NBTNsResourceNBSTAT *n;
693 if (q == NULL || (char *)(q + 1) > pmax)
696 /* Forward to Resource NBSTAT position */
697 n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
699 /* Check out of length */
700 bcount = ntohs(q->rdlen);
702 if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
705 return ((u_char *) n + bcount);
717 /* Resource Record Name Filed */
718 q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
720 if (q == NULL || (char *)(q + 1) > pmax)
722 #ifdef LIBALIAS_DEBUG
723 printf("type=%02x, count=%d\n", ntohs(q->type), count);
726 /* Type and Class filed */
727 switch (ntohs(q->type)) {
729 q = (NBTNsResource *) AliasHandleResourceNB(
736 q = (NBTNsResource *) AliasHandleResourceA(
743 q = (NBTNsResource *) AliasHandleResourceNS(
750 q = (NBTNsResource *) AliasHandleResourceNULL(
757 q = (NBTNsResource *) AliasHandleResourceNBSTAT(
764 #ifdef LIBALIAS_DEBUG
766 "\nUnknown Type of Resource %0x\n",
775 return ((u_char *) q);
781 struct ip *pip, /* IP packet to examine/patch */
782 struct alias_link *lnk,
783 struct in_addr *alias_address,
784 u_short * alias_port,
785 struct in_addr *original_address,
786 u_short * original_port)
797 /* Set up Common Parameter */
798 nbtarg.oldaddr = *alias_address;
799 nbtarg.oldport = *alias_port;
800 nbtarg.newaddr = *original_address;
801 nbtarg.newport = *original_port;
803 /* Calculate data length of UDP packet */
804 uh = (struct udphdr *)ip_next(pip);
805 nbtarg.uh_sum = &(uh->uh_sum);
806 nsh = (NbtNSHeader *)udp_next(uh);
807 p = (u_char *) (nsh + 1);
808 pmax = (char *)uh + ntohs(uh->uh_ulen);
810 if ((char *)(nsh + 1) > pmax)
813 #ifdef LIBALIAS_DEBUG
814 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
815 ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
816 nsh->dir ? "Response" : "Request",
825 (u_char *) p - (u_char *) nsh
829 /* Question Entries */
830 if (ntohs(nsh->qdcount) != 0) {
831 p = AliasHandleQuestion(
838 /* Answer Resource Records */
839 if (ntohs(nsh->ancount) != 0) {
840 p = AliasHandleResource(
847 /* Authority Resource Recodrs */
848 if (ntohs(nsh->nscount) != 0) {
849 p = AliasHandleResource(
856 /* Additional Resource Recodrs */
857 if (ntohs(nsh->arcount) != 0) {
858 p = AliasHandleResource(
865 #ifdef LIBALIAS_DEBUG
866 PrintRcode(nsh->rcode);
868 return ((p == NULL) ? -1 : 0);