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: src/sys/netinet/libalias/alias_nbt.c,v 1.20.6.1 2008/11/25 02:59:29 kensmith Exp $");
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>
55 #include <netinet/in_systm.h>
56 #include <netinet/in.h>
57 #include <netinet/ip.h>
58 #include <netinet/udp.h>
61 #include <netinet/libalias/alias_local.h>
62 #include <netinet/libalias/alias_mod.h>
64 #include "alias_local.h"
65 #include "alias_mod.h"
68 #define NETBIOS_NS_PORT_NUMBER 137
69 #define NETBIOS_DGM_PORT_NUMBER 138
72 AliasHandleUdpNbt(struct libalias *, struct ip *, struct alias_link *,
73 struct in_addr *, u_short);
76 AliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
77 struct in_addr *, u_short *, struct in_addr *, u_short *);
79 fingerprint1(struct libalias *la, struct ip *pip, struct alias_data *ah)
82 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
83 ah->aaddr == NULL || ah->aport == NULL)
85 if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
86 || ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
92 protohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
95 AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport);
100 fingerprint2(struct libalias *la, struct ip *pip, 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 AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
126 ah->aaddr, ah->aport);
130 /* Kernel module definition. */
131 struct proto_handler handlers[] = {
136 .fingerprint = &fingerprint1,
137 .protohandler = &protohandler1
143 .fingerprint = &fingerprint2,
144 .protohandler = &protohandler2in
150 .fingerprint = &fingerprint2,
151 .protohandler = &protohandler2out
157 mod_handler(module_t mod, int type, void *data)
164 LibAliasAttachHandlers(handlers);
168 LibAliasDetachHandlers(handlers);
179 moduledata_t alias_mod = {
180 "alias_nbt", mod_handler, NULL
184 DECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
185 MODULE_VERSION(alias_nbt, 1);
186 MODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
190 struct in_addr oldaddr;
192 struct in_addr newaddr;
201 struct in_addr source_ip;
215 u_short dir: 1, opcode:4, nmflags:7, rcode:4;
230 #ifdef LIBALIAS_DEBUG
232 PrintRcode(u_char rcode)
237 kprintf("\nFormat Error.");
239 kprintf("\nSever failure.");
241 kprintf("\nUnsupported request error.\n");
243 kprintf("\nRefused error.\n");
245 kprintf("\nActive error.\n");
247 kprintf("\nName in conflict error.\n");
249 kprintf("\n?%c?=%0x\n", '?', rcode);
257 /* Handling Name field */
259 AliasHandleName(u_char * p, char *pmax)
266 /* Following length field */
268 if (p == NULL || (char *)p >= pmax)
273 if ((char *)p > pmax)
275 return ((u_char *) p);
277 while ((*p & 0x3f) != 0x00) {
284 /* Get next length field */
285 p = (u_char *) (p + (*p & 0x3f) + 1);
286 if ((char *)p > pmax) {
290 #ifdef LIBALIAS_DEBUG
295 c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
296 #ifdef LIBALIAS_DEBUG
300 kprintf("<0x%02x>", c);
304 #ifdef LIBALIAS_DEBUG
310 #ifdef LIBALIAS_DEBUG
316 /* Set up to out of Name field */
317 if (p == NULL || (char *)p >= pmax)
321 return ((u_char *) p);
325 * NetBios Datagram Handler (IP/UDP)
327 #define DGM_DIRECT_UNIQ 0x10
328 #define DGM_DIRECT_GROUP 0x11
329 #define DGM_BROADCAST 0x12
330 #define DGM_ERROR 0x13
331 #define DGM_QUERY 0x14
332 #define DGM_POSITIVE_RES 0x15
333 #define DGM_NEGATIVE_RES 0x16
338 struct ip *pip, /* IP packet to examine/patch */
339 struct alias_link *lnk,
340 struct in_addr *alias_address,
352 /* Calculate data length of UDP packet */
353 uh = (struct udphdr *)ip_next(pip);
354 pmax = (char *)uh + ntohs(uh->uh_ulen);
356 ndh = (NbtDataHeader *)udp_next(uh);
357 if ((char *)(ndh + 1) > pmax)
359 #ifdef LIBALIAS_DEBUG
360 kprintf("\nType=%02x,", ndh->type);
363 case DGM_DIRECT_UNIQ:
364 case DGM_DIRECT_GROUP:
366 p = (u_char *) ndh + 14;
367 p = AliasHandleName(p, pmax); /* Source Name */
368 p = AliasHandleName(p, pmax); /* Destination Name */
371 p = (u_char *) ndh + 11;
374 case DGM_POSITIVE_RES:
375 case DGM_NEGATIVE_RES:
376 p = (u_char *) ndh + 10;
377 p = AliasHandleName(p, pmax); /* Destination Name */
380 if (p == NULL || (char *)p > pmax)
382 #ifdef LIBALIAS_DEBUG
383 kprintf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
385 /* Doing an IP address and Port number Translation */
386 if (uh->uh_sum != 0) {
390 acc = ndh->source_port;
392 sptr = (u_short *) & (ndh->source_ip);
395 sptr = (u_short *) alias_address;
398 ADJUST_CHECKSUM(acc, uh->uh_sum);
400 ndh->source_ip = *alias_address;
401 ndh->source_port = alias_port;
402 #ifdef LIBALIAS_DEBUG
403 kprintf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
406 return ((p == NULL) ? -1 : 0);
409 /* Question Section */
410 #define QS_TYPE_NB 0x0020
411 #define QS_TYPE_NBSTAT 0x0021
412 #define QS_CLAS_IN 0x0001
414 u_short type; /* The type of Request */
415 u_short class; /* The class of Request */
423 NBTArguments * nbtarg)
430 q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
432 if (q == NULL || (char *)(q + 1) > pmax) {
436 /* Type and Class filed */
437 switch (ntohs(q->type)) {
443 #ifdef LIBALIAS_DEBUG
444 kprintf("\nUnknown Type on Question %0x\n", ntohs(q->type));
451 /* Set up to out of Question Section */
452 return ((u_char *) q);
455 /* Resource Record */
456 #define RR_TYPE_A 0x0001
457 #define RR_TYPE_NS 0x0002
458 #define RR_TYPE_NULL 0x000a
459 #define RR_TYPE_NB 0x0020
460 #define RR_TYPE_NBSTAT 0x0021
461 #define RR_CLAS_IN 0x0001
462 #define SizeOfNsResource 8
470 #define SizeOfNsRNB 6
472 u_short g: 1 , ont:2, resv:13;
477 AliasHandleResourceNB(
480 NBTArguments * nbtarg)
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 kprintf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
496 kprintf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount);
498 while (nb != NULL && bcount != 0) {
499 if ((char *)(nb + 1) > pmax) {
503 #ifdef LIBALIAS_DEBUG
504 kprintf("<%s>", inet_ntoa(nb->addr));
506 if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
507 if (*nbtarg->uh_sum != 0) {
511 sptr = (u_short *) & (nb->addr);
514 sptr = (u_short *) & (nbtarg->newaddr);
517 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
519 nb->addr = nbtarg->newaddr;
520 #ifdef LIBALIAS_DEBUG
524 #ifdef LIBALIAS_DEBUG
529 nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
530 bcount -= SizeOfNsRNB;
532 if (nb == NULL || (char *)(nb + 1) > pmax) {
535 return ((u_char *) nb);
538 #define SizeOfResourceA 6
544 AliasHandleResourceA(
547 NBTArguments * nbtarg)
552 if (q == NULL || (char *)(q + 1) > pmax)
555 /* Forward to Resource A position */
556 a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
558 /* Check out of length */
559 bcount = ntohs(q->rdlen);
561 /* Processing all in_addr array */
562 #ifdef LIBALIAS_DEBUG
563 kprintf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
564 kprintf("->%s]", inet_ntoa(nbtarg->newaddr));
566 while (bcount != 0) {
567 if (a == NULL || (char *)(a + 1) > pmax)
569 #ifdef LIBALIAS_DEBUG
570 kprintf("..%s", inet_ntoa(a->addr));
572 if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
573 if (*nbtarg->uh_sum != 0) {
577 sptr = (u_short *) & (a->addr); /* Old */
580 sptr = (u_short *) & nbtarg->newaddr; /* New */
583 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
585 a->addr = nbtarg->newaddr;
588 bcount -= SizeOfResourceA;
590 if (a == NULL || (char *)(a + 1) > pmax)
592 return ((u_char *) a);
596 u_short opcode:4, flags:8, resv:4;
600 AliasHandleResourceNULL(
603 NBTArguments * nbtarg)
605 NBTNsResourceNULL *n;
610 if (q == NULL || (char *)(q + 1) > pmax)
613 /* Forward to Resource NULL position */
614 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
616 /* Check out of length */
617 bcount = ntohs(q->rdlen);
619 /* Processing all in_addr array */
620 while (bcount != 0) {
621 if ((char *)(n + 1) > pmax) {
626 bcount -= sizeof(NBTNsResourceNULL);
628 if ((char *)(n + 1) > pmax)
631 return ((u_char *) n);
635 AliasHandleResourceNS(
638 NBTArguments * nbtarg)
640 NBTNsResourceNULL *n;
645 if (q == NULL || (char *)(q + 1) > pmax)
648 /* Forward to Resource NULL position */
649 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
651 /* Check out of length */
652 bcount = ntohs(q->rdlen);
654 /* Resource Record Name Filed */
655 q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax); /* XXX */
657 if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
660 return ((u_char *) n + bcount);
665 } NBTNsResourceNBSTAT;
668 AliasHandleResourceNBSTAT(
671 NBTArguments * nbtarg)
673 NBTNsResourceNBSTAT *n;
678 if (q == NULL || (char *)(q + 1) > pmax)
681 /* Forward to Resource NBSTAT position */
682 n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
684 /* Check out of length */
685 bcount = ntohs(q->rdlen);
687 if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
690 return ((u_char *) n + bcount);
702 /* Resource Record Name Filed */
703 q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
705 if (q == NULL || (char *)(q + 1) > pmax)
707 #ifdef LIBALIAS_DEBUG
708 kprintf("type=%02x, count=%d\n", ntohs(q->type), count);
711 /* Type and Class filed */
712 switch (ntohs(q->type)) {
714 q = (NBTNsResource *) AliasHandleResourceNB(
721 q = (NBTNsResource *) AliasHandleResourceA(
728 q = (NBTNsResource *) AliasHandleResourceNS(
735 q = (NBTNsResource *) AliasHandleResourceNULL(
742 q = (NBTNsResource *) AliasHandleResourceNBSTAT(
749 #ifdef LIBALIAS_DEBUG
751 "\nUnknown Type of Resource %0x\n",
760 return ((u_char *) q);
766 struct ip *pip, /* IP packet to examine/patch */
767 struct alias_link *lnk,
768 struct in_addr *alias_address,
769 u_short * alias_port,
770 struct in_addr *original_address,
771 u_short * original_port)
782 /* Set up Common Parameter */
783 nbtarg.oldaddr = *alias_address;
784 nbtarg.oldport = *alias_port;
785 nbtarg.newaddr = *original_address;
786 nbtarg.newport = *original_port;
788 /* Calculate data length of UDP packet */
789 uh = (struct udphdr *)ip_next(pip);
790 nbtarg.uh_sum = &(uh->uh_sum);
791 nsh = (NbtNSHeader *)udp_next(uh);
792 p = (u_char *) (nsh + 1);
793 pmax = (char *)uh + ntohs(uh->uh_ulen);
795 if ((char *)(nsh + 1) > pmax)
798 #ifdef LIBALIAS_DEBUG
799 kprintf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
800 ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
801 nsh->dir ? "Response" : "Request",
810 (u_char *) p - (u_char *) nsh
814 /* Question Entries */
815 if (ntohs(nsh->qdcount) != 0) {
816 p = AliasHandleQuestion(
823 /* Answer Resource Records */
824 if (ntohs(nsh->ancount) != 0) {
825 p = AliasHandleResource(
832 /* Authority Resource Recodrs */
833 if (ntohs(nsh->nscount) != 0) {
834 p = AliasHandleResource(
841 /* Additional Resource Recodrs */
842 if (ntohs(nsh->arcount) != 0) {
843 p = AliasHandleResource(
850 #ifdef LIBALIAS_DEBUG
851 PrintRcode(nsh->rcode);
853 return ((p == NULL) ? -1 : 0);