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,
351 /* Calculate data length of UDP packet */
352 uh = (struct udphdr *)ip_next(pip);
353 pmax = (char *)uh + ntohs(uh->uh_ulen);
355 ndh = (NbtDataHeader *)udp_next(uh);
356 if ((char *)(ndh + 1) > pmax)
358 #ifdef LIBALIAS_DEBUG
359 printf("\nType=%02x,", ndh->type);
362 case DGM_DIRECT_UNIQ:
363 case DGM_DIRECT_GROUP:
365 p = (u_char *) ndh + 14;
366 p = AliasHandleName(p, pmax); /* Source Name */
367 p = AliasHandleName(p, pmax); /* Destination Name */
370 p = (u_char *) ndh + 11;
373 case DGM_POSITIVE_RES:
374 case DGM_NEGATIVE_RES:
375 p = (u_char *) ndh + 10;
376 p = AliasHandleName(p, pmax); /* Destination Name */
379 if (p == NULL || (char *)p > pmax)
381 #ifdef LIBALIAS_DEBUG
382 printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
384 /* Doing an IP address and Port number Translation */
385 if (uh->uh_sum != 0) {
389 acc = ndh->source_port;
391 sptr = (u_short *) & (ndh->source_ip);
394 sptr = (u_short *) alias_address;
397 ADJUST_CHECKSUM(acc, uh->uh_sum);
399 ndh->source_ip = *alias_address;
400 ndh->source_port = alias_port;
401 #ifdef LIBALIAS_DEBUG
402 printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
405 return ((p == NULL) ? -1 : 0);
408 /* Question Section */
409 #define QS_TYPE_NB 0x0020
410 #define QS_TYPE_NBSTAT 0x0021
411 #define QS_CLAS_IN 0x0001
413 u_short type; /* The type of Request */
414 u_short class; /* The class of Request */
422 NBTArguments * nbtarg)
429 q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
431 if (q == NULL || (char *)(q + 1) > pmax) {
435 /* Type and Class filed */
436 switch (ntohs(q->type)) {
442 #ifdef LIBALIAS_DEBUG
443 printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
450 /* Set up to out of Question Section */
451 return ((u_char *) q);
454 /* Resource Record */
455 #define RR_TYPE_A 0x0001
456 #define RR_TYPE_NS 0x0002
457 #define RR_TYPE_NULL 0x000a
458 #define RR_TYPE_NB 0x0020
459 #define RR_TYPE_NBSTAT 0x0021
460 #define RR_CLAS_IN 0x0001
461 #define SizeOfNsResource 8
469 #define SizeOfNsRNB 6
471 u_short g: 1 , ont:2, resv:13;
476 AliasHandleResourceNB(
479 NBTArguments * nbtarg)
484 if (q == NULL || (char *)(q + 1) > pmax)
486 /* Check out a length */
487 bcount = ntohs(q->rdlen);
489 /* Forward to Resource NB position */
490 nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
492 /* Processing all in_addr array */
493 #ifdef LIBALIAS_DEBUG
494 printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
495 printf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount);
497 while (nb != NULL && bcount != 0) {
498 if ((char *)(nb + 1) > pmax) {
502 #ifdef LIBALIAS_DEBUG
503 printf("<%s>", inet_ntoa(nb->addr));
505 if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
506 if (*nbtarg->uh_sum != 0) {
510 sptr = (u_short *) & (nb->addr);
513 sptr = (u_short *) & (nbtarg->newaddr);
516 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
518 nb->addr = nbtarg->newaddr;
519 #ifdef LIBALIAS_DEBUG
523 #ifdef LIBALIAS_DEBUG
528 nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
529 bcount -= SizeOfNsRNB;
531 if (nb == NULL || (char *)(nb + 1) > pmax) {
534 return ((u_char *) nb);
537 #define SizeOfResourceA 6
543 AliasHandleResourceA(
546 NBTArguments * nbtarg)
551 if (q == NULL || (char *)(q + 1) > pmax)
554 /* Forward to Resource A position */
555 a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
557 /* Check out of length */
558 bcount = ntohs(q->rdlen);
560 /* Processing all in_addr array */
561 #ifdef LIBALIAS_DEBUG
562 printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
563 printf("->%s]", inet_ntoa(nbtarg->newaddr));
565 while (bcount != 0) {
566 if (a == NULL || (char *)(a + 1) > pmax)
568 #ifdef LIBALIAS_DEBUG
569 printf("..%s", inet_ntoa(a->addr));
571 if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
572 if (*nbtarg->uh_sum != 0) {
576 sptr = (u_short *) & (a->addr); /* Old */
579 sptr = (u_short *) & nbtarg->newaddr; /* New */
582 ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
584 a->addr = nbtarg->newaddr;
587 bcount -= SizeOfResourceA;
589 if (a == NULL || (char *)(a + 1) > pmax)
591 return ((u_char *) a);
595 u_short opcode:4, flags:8, resv:4;
599 AliasHandleResourceNULL(
602 NBTArguments * nbtarg)
604 NBTNsResourceNULL *n;
609 if (q == NULL || (char *)(q + 1) > pmax)
612 /* Forward to Resource NULL position */
613 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
615 /* Check out of length */
616 bcount = ntohs(q->rdlen);
618 /* Processing all in_addr array */
619 while (bcount != 0) {
620 if ((char *)(n + 1) > pmax) {
625 bcount -= sizeof(NBTNsResourceNULL);
627 if ((char *)(n + 1) > pmax)
630 return ((u_char *) n);
634 AliasHandleResourceNS(
637 NBTArguments * nbtarg)
639 NBTNsResourceNULL *n;
644 if (q == NULL || (char *)(q + 1) > pmax)
647 /* Forward to Resource NULL position */
648 n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
650 /* Check out of length */
651 bcount = ntohs(q->rdlen);
653 /* Resource Record Name Filed */
654 q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax); /* XXX */
656 if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
659 return ((u_char *) n + bcount);
664 } NBTNsResourceNBSTAT;
667 AliasHandleResourceNBSTAT(
670 NBTArguments * nbtarg)
672 NBTNsResourceNBSTAT *n;
677 if (q == NULL || (char *)(q + 1) > pmax)
680 /* Forward to Resource NBSTAT position */
681 n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
683 /* Check out of length */
684 bcount = ntohs(q->rdlen);
686 if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
689 return ((u_char *) n + bcount);
701 /* Resource Record Name Filed */
702 q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
704 if (q == NULL || (char *)(q + 1) > pmax)
706 #ifdef LIBALIAS_DEBUG
707 printf("type=%02x, count=%d\n", ntohs(q->type), count);
710 /* Type and Class filed */
711 switch (ntohs(q->type)) {
713 q = (NBTNsResource *) AliasHandleResourceNB(
720 q = (NBTNsResource *) AliasHandleResourceA(
727 q = (NBTNsResource *) AliasHandleResourceNS(
734 q = (NBTNsResource *) AliasHandleResourceNULL(
741 q = (NBTNsResource *) AliasHandleResourceNBSTAT(
748 #ifdef LIBALIAS_DEBUG
750 "\nUnknown Type of Resource %0x\n",
759 return ((u_char *) q);
765 struct ip *pip, /* IP packet to examine/patch */
766 struct alias_link *lnk,
767 struct in_addr *alias_address,
768 u_short * alias_port,
769 struct in_addr *original_address,
770 u_short * original_port)
781 /* Set up Common Parameter */
782 nbtarg.oldaddr = *alias_address;
783 nbtarg.oldport = *alias_port;
784 nbtarg.newaddr = *original_address;
785 nbtarg.newport = *original_port;
787 /* Calculate data length of UDP packet */
788 uh = (struct udphdr *)ip_next(pip);
789 nbtarg.uh_sum = &(uh->uh_sum);
790 nsh = (NbtNSHeader *)udp_next(uh);
791 p = (u_char *) (nsh + 1);
792 pmax = (char *)uh + ntohs(uh->uh_ulen);
794 if ((char *)(nsh + 1) > pmax)
797 #ifdef LIBALIAS_DEBUG
798 printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
799 ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
800 nsh->dir ? "Response" : "Request",
809 (u_char *) p - (u_char *) nsh
813 /* Question Entries */
814 if (ntohs(nsh->qdcount) != 0) {
815 p = AliasHandleQuestion(
822 /* Answer Resource Records */
823 if (ntohs(nsh->ancount) != 0) {
824 p = AliasHandleResource(
831 /* Authority Resource Recodrs */
832 if (ntohs(nsh->nscount) != 0) {
833 p = AliasHandleResource(
840 /* Additional Resource Recodrs */
841 if (ntohs(nsh->arcount) != 0) {
842 p = AliasHandleResource(
849 #ifdef LIBALIAS_DEBUG
850 PrintRcode(nsh->rcode);
852 return ((p == NULL) ? -1 : 0);