2 * SPDX-License-Identifier: BSD-2-Clause
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);
78 AliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
79 struct in_addr *, u_short *, struct in_addr *, u_short *);
82 fingerprint1(struct libalias *la, struct alias_data *ah)
84 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
85 ah->aaddr == NULL || ah->aport == NULL)
87 if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
88 || ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
94 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)
102 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
103 ah->aaddr == NULL || ah->aport == NULL)
105 if (ntohs(*ah->dport) == NETBIOS_NS_PORT_NUMBER
106 || ntohs(*ah->sport) == NETBIOS_NS_PORT_NUMBER)
112 protohandler2in(struct libalias *la, struct ip *pip, struct alias_data *ah)
114 AliasHandleUdpNbtNS(la, pip, ah->lnk, ah->aaddr, ah->aport,
115 ah->oaddr, ah->dport);
120 protohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
122 return (AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
123 ah->aaddr, ah->aport));
126 /* Kernel module definition. */
127 struct proto_handler handlers[] = {
132 .fingerprint = &fingerprint1,
133 .protohandler = &protohandler1
139 .fingerprint = &fingerprint2,
140 .protohandler = &protohandler2in
146 .fingerprint = &fingerprint2,
147 .protohandler = &protohandler2out
153 mod_handler(module_t mod, int type, void *data)
160 LibAliasAttachHandlers(handlers);
164 LibAliasDetachHandlers(handlers);
175 moduledata_t alias_mod = {
176 "alias_nbt", mod_handler, NULL
180 DECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
181 MODULE_VERSION(alias_nbt, 1);
182 MODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
186 struct in_addr oldaddr;
188 struct in_addr newaddr;
197 struct in_addr source_ip;
211 u_short dir:1, opcode:4, nmflags:7, rcode:4;
225 #ifdef LIBALIAS_DEBUG
227 PrintRcode(u_char rcode)
231 printf("\nFormat Error.");
233 printf("\nSever failure.");
235 printf("\nUnsupported request error.\n");
237 printf("\nRefused error.\n");
239 printf("\nActive error.\n");
241 printf("\nName in conflict error.\n");
243 printf("\n?%c?=%0x\n", '?', rcode);
249 /* Handling Name field */
251 AliasHandleName(u_char *p, char *pmax)
254 #ifdef LIBALIAS_DEBUG
259 /* Following length field */
261 if (p == NULL || (char *)p >= pmax)
266 if ((char *)p > pmax)
268 return ((u_char *)p);
270 while ((*p & 0x3f) != 0x00) {
277 /* Get next length field */
278 p = (u_char *)(p + (*p & 0x3f) + 1);
279 if ((char *)p > pmax) {
283 #ifdef LIBALIAS_DEBUG
288 #ifdef LIBALIAS_DEBUG
289 c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
293 printf("<0x%02x>", c);
297 #ifdef LIBALIAS_DEBUG
303 #ifdef LIBALIAS_DEBUG
309 /* Set up to out of Name field */
310 if (p == NULL || (char *)p >= pmax)
314 return ((u_char *)p);
318 * NetBios Datagram Handler (IP/UDP)
320 #define DGM_DIRECT_UNIQ 0x10
321 #define DGM_DIRECT_GROUP 0x11
322 #define DGM_BROADCAST 0x12
323 #define DGM_ERROR 0x13
324 #define DGM_QUERY 0x14
325 #define DGM_POSITIVE_RES 0x15
326 #define DGM_NEGATIVE_RES 0x16
331 struct ip *pip, /* IP packet to examine/patch */
332 struct alias_link *lnk,
333 struct in_addr *alias_address,
340 #ifdef LIBALIAS_DEBUG
341 char addrbuf[INET_ADDRSTRLEN];
347 /* Calculate data length of UDP packet */
348 uh = (struct udphdr *)ip_next(pip);
349 pmax = (char *)uh + ntohs(uh->uh_ulen);
351 ndh = (NbtDataHeader *)udp_next(uh);
352 if ((char *)(ndh + 1) > pmax)
354 #ifdef LIBALIAS_DEBUG
355 printf("\nType=%02x,", ndh->type);
358 case DGM_DIRECT_UNIQ:
359 case DGM_DIRECT_GROUP:
361 p = (u_char *)ndh + 14;
362 p = AliasHandleName(p, pmax); /* Source Name */
363 p = AliasHandleName(p, pmax); /* Destination Name */
366 p = (u_char *)ndh + 11;
369 case DGM_POSITIVE_RES:
370 case DGM_NEGATIVE_RES:
371 p = (u_char *)ndh + 10;
372 p = AliasHandleName(p, pmax); /* Destination Name */
375 if (p == NULL || (char *)p > pmax)
377 #ifdef LIBALIAS_DEBUG
378 printf("%s:%d-->", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
379 ntohs(ndh->source_port));
381 /* Doing an IP address and Port number Translation */
382 if (uh->uh_sum != 0) {
386 acc = ndh->source_port;
388 sptr = (u_short *)&(ndh->source_ip);
391 sptr = (u_short *)alias_address;
394 ADJUST_CHECKSUM(acc, uh->uh_sum);
396 ndh->source_ip = *alias_address;
397 ndh->source_port = alias_port;
398 #ifdef LIBALIAS_DEBUG
399 printf("%s:%d\n", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
400 ntohs(ndh->source_port));
403 return ((p == NULL) ? -1 : 0);
406 /* Question Section */
407 #define QS_TYPE_NB 0x0020
408 #define QS_TYPE_NBSTAT 0x0021
409 #define QS_CLAS_IN 0x0001
411 u_short type; /* The type of Request */
412 u_short class; /* The class of Request */
420 NBTArguments * nbtarg)
426 q = (NBTNsQuestion *)AliasHandleName((u_char *)q, pmax);
428 if (q == NULL || (char *)(q + 1) > pmax) {
432 /* Type and Class filed */
433 switch (ntohs(q->type)) {
439 #ifdef LIBALIAS_DEBUG
440 printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
447 /* Set up to out of Question Section */
448 return ((u_char *)q);
451 /* Resource Record */
452 #define RR_TYPE_A 0x0001
453 #define RR_TYPE_NS 0x0002
454 #define RR_TYPE_NULL 0x000a
455 #define RR_TYPE_NB 0x0020
456 #define RR_TYPE_NBSTAT 0x0021
457 #define RR_CLAS_IN 0x0001
458 #define SizeOfNsResource 8
466 #define SizeOfNsRNB 6
468 u_short g:1, ont:2, resv:13;
473 AliasHandleResourceNB(
476 NBTArguments *nbtarg)
480 #ifdef LIBALIAS_DEBUG
481 char oldbuf[INET_ADDRSTRLEN];
482 char newbuf[INET_ADDRSTRLEN];
485 if (q == NULL || (char *)(q + 1) > pmax)
487 /* Check out a length */
488 bcount = ntohs(q->rdlen);
490 /* Forward to Resource NB position */
491 nb = (NBTNsRNB *)((u_char *)q + SizeOfNsResource);
493 /* Processing all in_addr array */
494 #ifdef LIBALIAS_DEBUG
495 printf("NB rec[%s->%s, %dbytes] ",
496 inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
497 inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)),
500 while (nb != NULL && bcount != 0) {
501 if ((char *)(nb + 1) > pmax) {
505 #ifdef LIBALIAS_DEBUG
506 printf("<%s>", inet_ntoa_r(nb->addr, INET_NTOA_BUF(newbuf)));
508 if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
509 if (*nbtarg->uh_sum != 0) {
513 sptr = (u_short *)&(nb->addr);
516 sptr = (u_short *)&(nbtarg->newaddr);
519 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
521 nb->addr = nbtarg->newaddr;
522 #ifdef LIBALIAS_DEBUG
526 #ifdef LIBALIAS_DEBUG
531 nb = (NBTNsRNB *)((u_char *)nb + SizeOfNsRNB);
532 bcount -= SizeOfNsRNB;
534 if (nb == NULL || (char *)(nb + 1) > pmax) {
537 return ((u_char *)nb);
540 #define SizeOfResourceA 6
546 AliasHandleResourceA(
549 NBTArguments *nbtarg)
553 #ifdef LIBALIAS_DEBUG
554 char oldbuf[INET_ADDRSTRLEN];
555 char newbuf[INET_ADDRSTRLEN];
558 if (q == NULL || (char *)(q + 1) > pmax)
561 /* Forward to Resource A position */
562 a = (NBTNsResourceA *)((u_char *)q + sizeof(NBTNsResource));
564 /* Check out of length */
565 bcount = ntohs(q->rdlen);
567 /* Processing all in_addr array */
568 #ifdef LIBALIAS_DEBUG
569 printf("Arec [%s->%s]",
570 inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
571 inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)));
573 while (bcount != 0) {
574 if (a == NULL || (char *)(a + 1) > pmax)
576 #ifdef LIBALIAS_DEBUG
577 printf("..%s", inet_ntoa_r(a->addr, INET_NTOA_BUF(newbuf)));
579 if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
580 if (*nbtarg->uh_sum != 0) {
584 sptr = (u_short *)&(a->addr); /* Old */
587 sptr = (u_short *)&nbtarg->newaddr; /* New */
590 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
592 a->addr = nbtarg->newaddr;
595 bcount -= SizeOfResourceA;
597 if (a == NULL || (char *)(a + 1) > pmax)
599 return ((u_char *)a);
603 u_short opcode:4, flags:8, resv:4;
607 AliasHandleResourceNULL(
610 NBTArguments *nbtarg)
612 NBTNsResourceNULL *n;
617 if (q == NULL || (char *)(q + 1) > pmax)
620 /* Forward to Resource NULL position */
621 n = (NBTNsResourceNULL *)((u_char *)q + sizeof(NBTNsResource));
623 /* Check out of length */
624 bcount = ntohs(q->rdlen);
626 /* Processing all in_addr array */
627 while (bcount != 0) {
628 if ((char *)(n + 1) > pmax) {
633 bcount -= sizeof(NBTNsResourceNULL);
635 if ((char *)(n + 1) > pmax)
638 return ((u_char *)n);
642 AliasHandleResourceNS(
645 NBTArguments *nbtarg)
647 NBTNsResourceNULL *n;
652 if (q == NULL || (char *)(q + 1) > pmax)
655 /* Forward to Resource NULL position */
656 n = (NBTNsResourceNULL *)((u_char *)q + sizeof(NBTNsResource));
658 /* Check out of length */
659 bcount = ntohs(q->rdlen);
661 /* Resource Record Name Filed */
662 q = (NBTNsResource *)AliasHandleName((u_char *)n, pmax); /* XXX */
664 if (q == NULL || (char *)((u_char *)n + bcount) > pmax)
667 return ((u_char *)n + bcount);
672 } NBTNsResourceNBSTAT;
675 AliasHandleResourceNBSTAT(
678 NBTArguments *nbtarg)
680 NBTNsResourceNBSTAT *n;
685 if (q == NULL || (char *)(q + 1) > pmax)
688 /* Forward to Resource NBSTAT position */
689 n = (NBTNsResourceNBSTAT *)((u_char *)q + sizeof(NBTNsResource));
691 /* Check out of length */
692 bcount = ntohs(q->rdlen);
694 if (q == NULL || (char *)((u_char *)n + bcount) > pmax)
697 return ((u_char *)n + bcount);
705 NBTArguments *nbtarg)
708 /* Resource Record Name Filed */
709 q = (NBTNsResource *)AliasHandleName((u_char *)q, pmax);
711 if (q == NULL || (char *)(q + 1) > pmax)
713 #ifdef LIBALIAS_DEBUG
714 printf("type=%02x, count=%d\n", ntohs(q->type), count);
717 /* Type and Class filed */
718 switch (ntohs(q->type)) {
720 q = (NBTNsResource *)AliasHandleResourceNB(
724 q = (NBTNsResource *)AliasHandleResourceA(
728 q = (NBTNsResource *)AliasHandleResourceNS(
732 q = (NBTNsResource *)AliasHandleResourceNULL(
736 q = (NBTNsResource *)AliasHandleResourceNBSTAT(
740 #ifdef LIBALIAS_DEBUG
742 "\nUnknown Type of Resource %0x\n",
751 return ((u_char *)q);
757 struct ip *pip, /* IP packet to examine/patch */
758 struct alias_link *lnk,
759 struct in_addr *alias_address,
761 struct in_addr *original_address,
762 u_short *original_port)
773 /* Set up Common Parameter */
774 nbtarg.oldaddr = *alias_address;
775 nbtarg.oldport = *alias_port;
776 nbtarg.newaddr = *original_address;
777 nbtarg.newport = *original_port;
779 /* Calculate data length of UDP packet */
780 uh = (struct udphdr *)ip_next(pip);
781 nbtarg.uh_sum = &(uh->uh_sum);
782 nsh = (NbtNSHeader *)udp_next(uh);
783 p = (u_char *)(nsh + 1);
784 pmax = (char *)uh + ntohs(uh->uh_ulen);
786 if ((char *)(nsh + 1) > pmax)
789 #ifdef LIBALIAS_DEBUG
790 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
791 ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
792 nsh->dir ? "Response" : "Request",
801 (u_char *)p - (u_char *)nsh
805 /* Question Entries */
806 if (ntohs(nsh->qdcount) != 0) {
807 p = AliasHandleQuestion(
814 /* Answer Resource Records */
815 if (ntohs(nsh->ancount) != 0) {
816 p = AliasHandleResource(
823 /* Authority Resource Recodrs */
824 if (ntohs(nsh->nscount) != 0) {
825 p = AliasHandleResource(
832 /* Additional Resource Recodrs */
833 if (ntohs(nsh->arcount) != 0) {
834 p = AliasHandleResource(
841 #ifdef LIBALIAS_DEBUG
842 PrintRcode(nsh->rcode);
844 return ((p == NULL) ? -1 : 0);