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;
230 #ifdef LIBALIAS_DEBUG
232 PrintRcode(u_char rcode)
237 printf("\nFormat Error.");
239 printf("\nSever failure.");
241 printf("\nUnsupported request error.\n");
243 printf("\nRefused error.\n");
245 printf("\nActive error.\n");
247 printf("\nName in conflict error.\n");
249 printf("\n?%c?=%0x\n", '?', rcode);
255 /* Handling Name field */
257 AliasHandleName(u_char * p, char *pmax)
264 /* Following length field */
266 if (p == NULL || (char *)p >= pmax)
271 if ((char *)p > pmax)
273 return ((u_char *) p);
275 while ((*p & 0x3f) != 0x00) {
282 /* Get next length field */
283 p = (u_char *) (p + (*p & 0x3f) + 1);
284 if ((char *)p > pmax) {
288 #ifdef LIBALIAS_DEBUG
293 c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
294 #ifdef LIBALIAS_DEBUG
298 printf("<0x%02x>", c);
302 #ifdef LIBALIAS_DEBUG
308 #ifdef LIBALIAS_DEBUG
314 /* Set up to out of Name field */
315 if (p == NULL || (char *)p >= pmax)
319 return ((u_char *) p);
323 * NetBios Datagram Handler (IP/UDP)
325 #define DGM_DIRECT_UNIQ 0x10
326 #define DGM_DIRECT_GROUP 0x11
327 #define DGM_BROADCAST 0x12
328 #define DGM_ERROR 0x13
329 #define DGM_QUERY 0x14
330 #define DGM_POSITIVE_RES 0x15
331 #define DGM_NEGATIVE_RES 0x16
336 struct ip *pip, /* IP packet to examine/patch */
337 struct alias_link *lnk,
338 struct in_addr *alias_address,
346 #ifdef LIBALIAS_DEBUG
347 char addrbuf[INET_ADDRSTRLEN];
353 /* Calculate data length of UDP packet */
354 uh = (struct udphdr *)ip_next(pip);
355 pmax = (char *)uh + ntohs(uh->uh_ulen);
357 ndh = (NbtDataHeader *)udp_next(uh);
358 if ((char *)(ndh + 1) > pmax)
360 #ifdef LIBALIAS_DEBUG
361 printf("\nType=%02x,", ndh->type);
364 case DGM_DIRECT_UNIQ:
365 case DGM_DIRECT_GROUP:
367 p = (u_char *) ndh + 14;
368 p = AliasHandleName(p, pmax); /* Source Name */
369 p = AliasHandleName(p, pmax); /* Destination Name */
372 p = (u_char *) ndh + 11;
375 case DGM_POSITIVE_RES:
376 case DGM_NEGATIVE_RES:
377 p = (u_char *) ndh + 10;
378 p = AliasHandleName(p, pmax); /* Destination Name */
381 if (p == NULL || (char *)p > pmax)
383 #ifdef LIBALIAS_DEBUG
384 printf("%s:%d-->", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
385 ntohs(ndh->source_port));
387 /* Doing an IP address and Port number Translation */
388 if (uh->uh_sum != 0) {
392 acc = ndh->source_port;
394 sptr = (u_short *) & (ndh->source_ip);
397 sptr = (u_short *) alias_address;
400 ADJUST_CHECKSUM(acc, uh->uh_sum);
402 ndh->source_ip = *alias_address;
403 ndh->source_port = alias_port;
404 #ifdef LIBALIAS_DEBUG
405 printf("%s:%d\n", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
406 ntohs(ndh->source_port));
409 return ((p == NULL) ? -1 : 0);
412 /* Question Section */
413 #define QS_TYPE_NB 0x0020
414 #define QS_TYPE_NBSTAT 0x0021
415 #define QS_CLAS_IN 0x0001
417 u_short type; /* The type of Request */
418 u_short class; /* The class of Request */
426 NBTArguments * nbtarg)
433 q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
435 if (q == NULL || (char *)(q + 1) > pmax) {
439 /* Type and Class filed */
440 switch (ntohs(q->type)) {
446 #ifdef LIBALIAS_DEBUG
447 printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
454 /* Set up to out of Question Section */
455 return ((u_char *) q);
458 /* Resource Record */
459 #define RR_TYPE_A 0x0001
460 #define RR_TYPE_NS 0x0002
461 #define RR_TYPE_NULL 0x000a
462 #define RR_TYPE_NB 0x0020
463 #define RR_TYPE_NBSTAT 0x0021
464 #define RR_CLAS_IN 0x0001
465 #define SizeOfNsResource 8
473 #define SizeOfNsRNB 6
475 u_short g: 1 , ont:2, resv:13;
480 AliasHandleResourceNB(
483 NBTArguments * nbtarg)
487 #ifdef LIBALIAS_DEBUG
488 char oldbuf[INET_ADDRSTRLEN];
489 char newbuf[INET_ADDRSTRLEN];
492 if (q == NULL || (char *)(q + 1) > pmax)
494 /* Check out a length */
495 bcount = ntohs(q->rdlen);
497 /* Forward to Resource NB position */
498 nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
500 /* Processing all in_addr array */
501 #ifdef LIBALIAS_DEBUG
502 printf("NB rec[%s->%s, %dbytes] ",
503 inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
504 inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)),
507 while (nb != NULL && bcount != 0) {
508 if ((char *)(nb + 1) > pmax) {
512 #ifdef LIBALIAS_DEBUG
513 printf("<%s>", inet_ntoa_r(nb->addr, INET_NTOA_BUF(newbuf)));
515 if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
516 if (*nbtarg->uh_sum != 0) {
520 sptr = (u_short *) & (nb->addr);
523 sptr = (u_short *) & (nbtarg->newaddr);
526 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
528 nb->addr = nbtarg->newaddr;
529 #ifdef LIBALIAS_DEBUG
533 #ifdef LIBALIAS_DEBUG
538 nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
539 bcount -= SizeOfNsRNB;
541 if (nb == NULL || (char *)(nb + 1) > pmax) {
544 return ((u_char *) nb);
547 #define SizeOfResourceA 6
553 AliasHandleResourceA(
556 NBTArguments * nbtarg)
560 #ifdef LIBALIAS_DEBUG
561 char oldbuf[INET_ADDRSTRLEN];
562 char newbuf[INET_ADDRSTRLEN];
565 if (q == NULL || (char *)(q + 1) > pmax)
568 /* Forward to Resource A position */
569 a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
571 /* Check out of length */
572 bcount = ntohs(q->rdlen);
574 /* Processing all in_addr array */
575 #ifdef LIBALIAS_DEBUG
576 printf("Arec [%s->%s]",
577 inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
578 inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)));
580 while (bcount != 0) {
581 if (a == NULL || (char *)(a + 1) > pmax)
583 #ifdef LIBALIAS_DEBUG
584 printf("..%s", inet_ntoa_r(a->addr, INET_NTOA_BUF(newbuf)));
586 if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
587 if (*nbtarg->uh_sum != 0) {
591 sptr = (u_short *) & (a->addr); /* Old */
594 sptr = (u_short *) & nbtarg->newaddr; /* New */
597 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
599 a->addr = nbtarg->newaddr;
602 bcount -= SizeOfResourceA;
604 if (a == NULL || (char *)(a + 1) > pmax)
606 return ((u_char *) a);
610 u_short opcode:4, flags:8, resv:4;
614 AliasHandleResourceNULL(
617 NBTArguments * nbtarg)
619 NBTNsResourceNULL *n;
624 if (q == NULL || (char *)(q + 1) > pmax)
627 /* Forward to Resource NULL position */
628 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
630 /* Check out of length */
631 bcount = ntohs(q->rdlen);
633 /* Processing all in_addr array */
634 while (bcount != 0) {
635 if ((char *)(n + 1) > pmax) {
640 bcount -= sizeof(NBTNsResourceNULL);
642 if ((char *)(n + 1) > pmax)
645 return ((u_char *) n);
649 AliasHandleResourceNS(
652 NBTArguments * nbtarg)
654 NBTNsResourceNULL *n;
659 if (q == NULL || (char *)(q + 1) > pmax)
662 /* Forward to Resource NULL position */
663 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
665 /* Check out of length */
666 bcount = ntohs(q->rdlen);
668 /* Resource Record Name Filed */
669 q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax); /* XXX */
671 if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
674 return ((u_char *) n + bcount);
679 } NBTNsResourceNBSTAT;
682 AliasHandleResourceNBSTAT(
685 NBTArguments * nbtarg)
687 NBTNsResourceNBSTAT *n;
692 if (q == NULL || (char *)(q + 1) > pmax)
695 /* Forward to Resource NBSTAT position */
696 n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
698 /* Check out of length */
699 bcount = ntohs(q->rdlen);
701 if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
704 return ((u_char *) n + bcount);
716 /* Resource Record Name Filed */
717 q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
719 if (q == NULL || (char *)(q + 1) > pmax)
721 #ifdef LIBALIAS_DEBUG
722 printf("type=%02x, count=%d\n", ntohs(q->type), count);
725 /* Type and Class filed */
726 switch (ntohs(q->type)) {
728 q = (NBTNsResource *) AliasHandleResourceNB(
735 q = (NBTNsResource *) AliasHandleResourceA(
742 q = (NBTNsResource *) AliasHandleResourceNS(
749 q = (NBTNsResource *) AliasHandleResourceNULL(
756 q = (NBTNsResource *) AliasHandleResourceNBSTAT(
763 #ifdef LIBALIAS_DEBUG
765 "\nUnknown Type of Resource %0x\n",
774 return ((u_char *) q);
780 struct ip *pip, /* IP packet to examine/patch */
781 struct alias_link *lnk,
782 struct in_addr *alias_address,
783 u_short * alias_port,
784 struct in_addr *original_address,
785 u_short * original_port)
796 /* Set up Common Parameter */
797 nbtarg.oldaddr = *alias_address;
798 nbtarg.oldport = *alias_port;
799 nbtarg.newaddr = *original_address;
800 nbtarg.newport = *original_port;
802 /* Calculate data length of UDP packet */
803 uh = (struct udphdr *)ip_next(pip);
804 nbtarg.uh_sum = &(uh->uh_sum);
805 nsh = (NbtNSHeader *)udp_next(uh);
806 p = (u_char *) (nsh + 1);
807 pmax = (char *)uh + ntohs(uh->uh_ulen);
809 if ((char *)(nsh + 1) > pmax)
812 #ifdef LIBALIAS_DEBUG
813 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
814 ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
815 nsh->dir ? "Response" : "Request",
824 (u_char *) p - (u_char *) nsh
828 /* Question Entries */
829 if (ntohs(nsh->qdcount) != 0) {
830 p = AliasHandleQuestion(
837 /* Answer Resource Records */
838 if (ntohs(nsh->ancount) != 0) {
839 p = AliasHandleResource(
846 /* Authority Resource Recodrs */
847 if (ntohs(nsh->nscount) != 0) {
848 p = AliasHandleResource(
855 /* Additional Resource Recodrs */
856 if (ntohs(nsh->arcount) != 0) {
857 p = AliasHandleResource(
864 #ifdef LIBALIAS_DEBUG
865 PrintRcode(nsh->rcode);
867 return ((p == NULL) ? -1 : 0);