2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Written by Atsushi Murai <amurai@spec.co.jp>
5 * Copyright (c) 1998, System Planning and Engineering Co.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * oConsidering for word alignment for other platform.
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
37 alias_nbt.c performs special processing for NetBios over TCP/IP
40 Initial version: May, 1998 (Atsushi Murai <amurai@spec.co.jp>)
42 See HISTORY file for record of revisions.
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/module.h>
53 #include <sys/types.h>
58 #include <netinet/in_systm.h>
59 #include <netinet/in.h>
60 #include <netinet/ip.h>
61 #include <netinet/udp.h>
64 #include <netinet/libalias/alias_local.h>
65 #include <netinet/libalias/alias_mod.h>
67 #include "alias_local.h"
68 #include "alias_mod.h"
71 #define NETBIOS_NS_PORT_NUMBER 137
72 #define NETBIOS_DGM_PORT_NUMBER 138
75 AliasHandleUdpNbt(struct libalias *, struct ip *, struct alias_link *,
76 struct in_addr *, u_short);
79 AliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
80 struct in_addr *, u_short *, struct in_addr *, u_short *);
82 fingerprint1(struct libalias *la, struct alias_data *ah)
85 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
86 ah->aaddr == NULL || ah->aport == NULL)
88 if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
89 || ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
95 protohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
98 return (AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport));
102 fingerprint2(struct libalias *la, struct alias_data *ah)
105 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
106 ah->aaddr == NULL || ah->aport == NULL)
108 if (ntohs(*ah->dport) == NETBIOS_NS_PORT_NUMBER
109 || ntohs(*ah->sport) == NETBIOS_NS_PORT_NUMBER)
115 protohandler2in(struct libalias *la, struct ip *pip, struct alias_data *ah)
118 AliasHandleUdpNbtNS(la, pip, ah->lnk, ah->aaddr, ah->aport,
119 ah->oaddr, ah->dport);
124 protohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
127 return (AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
128 ah->aaddr, ah->aport));
131 /* Kernel module definition. */
132 struct proto_handler handlers[] = {
137 .fingerprint = &fingerprint1,
138 .protohandler = &protohandler1
144 .fingerprint = &fingerprint2,
145 .protohandler = &protohandler2in
151 .fingerprint = &fingerprint2,
152 .protohandler = &protohandler2out
158 mod_handler(module_t mod, int type, void *data)
165 LibAliasAttachHandlers(handlers);
169 LibAliasDetachHandlers(handlers);
180 moduledata_t alias_mod = {
181 "alias_nbt", mod_handler, NULL
185 DECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
186 MODULE_VERSION(alias_nbt, 1);
187 MODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
191 struct in_addr oldaddr;
193 struct in_addr newaddr;
202 struct in_addr source_ip;
216 u_short dir: 1, opcode:4, nmflags:7, rcode:4;
231 #ifdef LIBALIAS_DEBUG
233 PrintRcode(u_char rcode)
238 printf("\nFormat Error.");
240 printf("\nSever failure.");
242 printf("\nUnsupported request error.\n");
244 printf("\nRefused error.\n");
246 printf("\nActive error.\n");
248 printf("\nName in conflict error.\n");
250 printf("\n?%c?=%0x\n", '?', rcode);
258 /* Handling Name field */
260 AliasHandleName(u_char * p, char *pmax)
267 /* Following length field */
269 if (p == NULL || (char *)p >= pmax)
274 if ((char *)p > pmax)
276 return ((u_char *) p);
278 while ((*p & 0x3f) != 0x00) {
285 /* Get next length field */
286 p = (u_char *) (p + (*p & 0x3f) + 1);
287 if ((char *)p > pmax) {
291 #ifdef LIBALIAS_DEBUG
296 c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
297 #ifdef LIBALIAS_DEBUG
301 printf("<0x%02x>", c);
305 #ifdef LIBALIAS_DEBUG
311 #ifdef LIBALIAS_DEBUG
317 /* Set up to out of Name field */
318 if (p == NULL || (char *)p >= pmax)
322 return ((u_char *) p);
326 * NetBios Datagram Handler (IP/UDP)
328 #define DGM_DIRECT_UNIQ 0x10
329 #define DGM_DIRECT_GROUP 0x11
330 #define DGM_BROADCAST 0x12
331 #define DGM_ERROR 0x13
332 #define DGM_QUERY 0x14
333 #define DGM_POSITIVE_RES 0x15
334 #define DGM_NEGATIVE_RES 0x16
339 struct ip *pip, /* IP packet to examine/patch */
340 struct alias_link *lnk,
341 struct in_addr *alias_address,
349 #ifdef LIBALIAS_DEBUG
350 char addrbuf[INET_ADDRSTRLEN];
356 /* Calculate data length of UDP packet */
357 uh = (struct udphdr *)ip_next(pip);
358 pmax = (char *)uh + ntohs(uh->uh_ulen);
360 ndh = (NbtDataHeader *)udp_next(uh);
361 if ((char *)(ndh + 1) > pmax)
363 #ifdef LIBALIAS_DEBUG
364 printf("\nType=%02x,", ndh->type);
367 case DGM_DIRECT_UNIQ:
368 case DGM_DIRECT_GROUP:
370 p = (u_char *) ndh + 14;
371 p = AliasHandleName(p, pmax); /* Source Name */
372 p = AliasHandleName(p, pmax); /* Destination Name */
375 p = (u_char *) ndh + 11;
378 case DGM_POSITIVE_RES:
379 case DGM_NEGATIVE_RES:
380 p = (u_char *) ndh + 10;
381 p = AliasHandleName(p, pmax); /* Destination Name */
384 if (p == NULL || (char *)p > pmax)
386 #ifdef LIBALIAS_DEBUG
387 printf("%s:%d-->", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
388 ntohs(ndh->source_port));
390 /* Doing an IP address and Port number Translation */
391 if (uh->uh_sum != 0) {
395 acc = ndh->source_port;
397 sptr = (u_short *) & (ndh->source_ip);
400 sptr = (u_short *) alias_address;
403 ADJUST_CHECKSUM(acc, uh->uh_sum);
405 ndh->source_ip = *alias_address;
406 ndh->source_port = alias_port;
407 #ifdef LIBALIAS_DEBUG
408 printf("%s:%d\n", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
409 ntohs(ndh->source_port));
412 return ((p == NULL) ? -1 : 0);
415 /* Question Section */
416 #define QS_TYPE_NB 0x0020
417 #define QS_TYPE_NBSTAT 0x0021
418 #define QS_CLAS_IN 0x0001
420 u_short type; /* The type of Request */
421 u_short class; /* The class of Request */
429 NBTArguments * nbtarg)
436 q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
438 if (q == NULL || (char *)(q + 1) > pmax) {
442 /* Type and Class filed */
443 switch (ntohs(q->type)) {
449 #ifdef LIBALIAS_DEBUG
450 printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
457 /* Set up to out of Question Section */
458 return ((u_char *) q);
461 /* Resource Record */
462 #define RR_TYPE_A 0x0001
463 #define RR_TYPE_NS 0x0002
464 #define RR_TYPE_NULL 0x000a
465 #define RR_TYPE_NB 0x0020
466 #define RR_TYPE_NBSTAT 0x0021
467 #define RR_CLAS_IN 0x0001
468 #define SizeOfNsResource 8
476 #define SizeOfNsRNB 6
478 u_short g: 1 , ont:2, resv:13;
483 AliasHandleResourceNB(
486 NBTArguments * nbtarg)
490 #ifdef LIBALIAS_DEBUG
491 char oldbuf[INET_ADDRSTRLEN];
492 char newbuf[INET_ADDRSTRLEN];
495 if (q == NULL || (char *)(q + 1) > pmax)
497 /* Check out a length */
498 bcount = ntohs(q->rdlen);
500 /* Forward to Resource NB position */
501 nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
503 /* Processing all in_addr array */
504 #ifdef LIBALIAS_DEBUG
505 printf("NB rec[%s->%s, %dbytes] ",
506 inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
507 inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)),
510 while (nb != NULL && bcount != 0) {
511 if ((char *)(nb + 1) > pmax) {
515 #ifdef LIBALIAS_DEBUG
516 printf("<%s>", inet_ntoa_r(nb->addr, INET_NTOA_BUF(newbuf)));
518 if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
519 if (*nbtarg->uh_sum != 0) {
523 sptr = (u_short *) & (nb->addr);
526 sptr = (u_short *) & (nbtarg->newaddr);
529 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
531 nb->addr = nbtarg->newaddr;
532 #ifdef LIBALIAS_DEBUG
536 #ifdef LIBALIAS_DEBUG
541 nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
542 bcount -= SizeOfNsRNB;
544 if (nb == NULL || (char *)(nb + 1) > pmax) {
547 return ((u_char *) nb);
550 #define SizeOfResourceA 6
556 AliasHandleResourceA(
559 NBTArguments * nbtarg)
563 #ifdef LIBALIAS_DEBUG
564 char oldbuf[INET_ADDRSTRLEN];
565 char newbuf[INET_ADDRSTRLEN];
568 if (q == NULL || (char *)(q + 1) > pmax)
571 /* Forward to Resource A position */
572 a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
574 /* Check out of length */
575 bcount = ntohs(q->rdlen);
577 /* Processing all in_addr array */
578 #ifdef LIBALIAS_DEBUG
579 printf("Arec [%s->%s]",
580 inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
581 inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)));
583 while (bcount != 0) {
584 if (a == NULL || (char *)(a + 1) > pmax)
586 #ifdef LIBALIAS_DEBUG
587 printf("..%s", inet_ntoa_r(a->addr, INET_NTOA_BUF(newbuf)));
589 if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
590 if (*nbtarg->uh_sum != 0) {
594 sptr = (u_short *) & (a->addr); /* Old */
597 sptr = (u_short *) & nbtarg->newaddr; /* New */
600 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
602 a->addr = nbtarg->newaddr;
605 bcount -= SizeOfResourceA;
607 if (a == NULL || (char *)(a + 1) > pmax)
609 return ((u_char *) a);
613 u_short opcode:4, flags:8, resv:4;
617 AliasHandleResourceNULL(
620 NBTArguments * nbtarg)
622 NBTNsResourceNULL *n;
627 if (q == NULL || (char *)(q + 1) > pmax)
630 /* Forward to Resource NULL position */
631 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
633 /* Check out of length */
634 bcount = ntohs(q->rdlen);
636 /* Processing all in_addr array */
637 while (bcount != 0) {
638 if ((char *)(n + 1) > pmax) {
643 bcount -= sizeof(NBTNsResourceNULL);
645 if ((char *)(n + 1) > pmax)
648 return ((u_char *) n);
652 AliasHandleResourceNS(
655 NBTArguments * nbtarg)
657 NBTNsResourceNULL *n;
662 if (q == NULL || (char *)(q + 1) > pmax)
665 /* Forward to Resource NULL position */
666 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
668 /* Check out of length */
669 bcount = ntohs(q->rdlen);
671 /* Resource Record Name Filed */
672 q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax); /* XXX */
674 if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
677 return ((u_char *) n + bcount);
682 } NBTNsResourceNBSTAT;
685 AliasHandleResourceNBSTAT(
688 NBTArguments * nbtarg)
690 NBTNsResourceNBSTAT *n;
695 if (q == NULL || (char *)(q + 1) > pmax)
698 /* Forward to Resource NBSTAT position */
699 n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
701 /* Check out of length */
702 bcount = ntohs(q->rdlen);
704 if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
707 return ((u_char *) n + bcount);
719 /* Resource Record Name Filed */
720 q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
722 if (q == NULL || (char *)(q + 1) > pmax)
724 #ifdef LIBALIAS_DEBUG
725 printf("type=%02x, count=%d\n", ntohs(q->type), count);
728 /* Type and Class filed */
729 switch (ntohs(q->type)) {
731 q = (NBTNsResource *) AliasHandleResourceNB(
738 q = (NBTNsResource *) AliasHandleResourceA(
745 q = (NBTNsResource *) AliasHandleResourceNS(
752 q = (NBTNsResource *) AliasHandleResourceNULL(
759 q = (NBTNsResource *) AliasHandleResourceNBSTAT(
766 #ifdef LIBALIAS_DEBUG
768 "\nUnknown Type of Resource %0x\n",
777 return ((u_char *) q);
783 struct ip *pip, /* IP packet to examine/patch */
784 struct alias_link *lnk,
785 struct in_addr *alias_address,
786 u_short * alias_port,
787 struct in_addr *original_address,
788 u_short * original_port)
799 /* Set up Common Parameter */
800 nbtarg.oldaddr = *alias_address;
801 nbtarg.oldport = *alias_port;
802 nbtarg.newaddr = *original_address;
803 nbtarg.newport = *original_port;
805 /* Calculate data length of UDP packet */
806 uh = (struct udphdr *)ip_next(pip);
807 nbtarg.uh_sum = &(uh->uh_sum);
808 nsh = (NbtNSHeader *)udp_next(uh);
809 p = (u_char *) (nsh + 1);
810 pmax = (char *)uh + ntohs(uh->uh_ulen);
812 if ((char *)(nsh + 1) > pmax)
815 #ifdef LIBALIAS_DEBUG
816 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
817 ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
818 nsh->dir ? "Response" : "Request",
827 (u_char *) p - (u_char *) nsh
831 /* Question Entries */
832 if (ntohs(nsh->qdcount) != 0) {
833 p = AliasHandleQuestion(
840 /* Answer Resource Records */
841 if (ntohs(nsh->ancount) != 0) {
842 p = AliasHandleResource(
849 /* Authority Resource Recodrs */
850 if (ntohs(nsh->nscount) != 0) {
851 p = AliasHandleResource(
858 /* Additional Resource Recodrs */
859 if (ntohs(nsh->arcount) != 0) {
860 p = AliasHandleResource(
867 #ifdef LIBALIAS_DEBUG
868 PrintRcode(nsh->rcode);
870 return ((p == NULL) ? -1 : 0);