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
,
344 #ifdef LIBALIAS_DEBUG
345 char abuf
[INET_ADDRSTRLEN
];
355 /* Calculate data length of UDP packet */
356 uh
= (struct udphdr
*)ip_next(pip
);
357 pmax
= (char *)uh
+ ntohs(uh
->uh_ulen
);
359 ndh
= (NbtDataHeader
*)udp_next(uh
);
360 if ((char *)(ndh
+ 1) > pmax
)
362 #ifdef LIBALIAS_DEBUG
363 kprintf("\nType=%02x,", ndh
->type
);
366 case DGM_DIRECT_UNIQ
:
367 case DGM_DIRECT_GROUP
:
369 p
= (u_char
*) ndh
+ 14;
370 p
= AliasHandleName(p
, pmax
); /* Source Name */
371 p
= AliasHandleName(p
, pmax
); /* Destination Name */
374 p
= (u_char
*) ndh
+ 11;
377 case DGM_POSITIVE_RES
:
378 case DGM_NEGATIVE_RES
:
379 p
= (u_char
*) ndh
+ 10;
380 p
= AliasHandleName(p
, pmax
); /* Destination Name */
383 if (p
== NULL
|| (char *)p
> pmax
)
385 #ifdef LIBALIAS_DEBUG
386 kprintf("%s:%d-->", kinet_ntoa(ndh
->source_ip
, abuf
),
387 ntohs(ndh
->source_port
));
389 /* Doing an IP address and Port number Translation */
390 if (uh
->uh_sum
!= 0) {
394 acc
= ndh
->source_port
;
396 sptr
= (u_short
*) & (ndh
->source_ip
);
399 sptr
= (u_short
*) alias_address
;
402 ADJUST_CHECKSUM(acc
, uh
->uh_sum
);
404 ndh
->source_ip
= *alias_address
;
405 ndh
->source_port
= alias_port
;
406 #ifdef LIBALIAS_DEBUG
407 kprintf("%s:%d\n", kinet_ntoa(ndh
->source_ip
, abuf
),
408 ntohs(ndh
->source_port
));
411 return ((p
== NULL
) ? -1 : 0);
414 /* Question Section */
415 #define QS_TYPE_NB 0x0020
416 #define QS_TYPE_NBSTAT 0x0021
417 #define QS_CLAS_IN 0x0001
419 u_short type
; /* The type of Request */
420 u_short
class; /* The class of Request */
428 NBTArguments
* nbtarg
)
435 q
= (NBTNsQuestion
*) AliasHandleName((u_char
*) q
, pmax
);
437 if (q
== NULL
|| (char *)(q
+ 1) > pmax
) {
441 /* Type and Class filed */
442 switch (ntohs(q
->type
)) {
448 #ifdef LIBALIAS_DEBUG
449 kprintf("\nUnknown Type on Question %0x\n", ntohs(q
->type
));
456 /* Set up to out of Question Section */
457 return ((u_char
*) q
);
460 /* Resource Record */
461 #define RR_TYPE_A 0x0001
462 #define RR_TYPE_NS 0x0002
463 #define RR_TYPE_NULL 0x000a
464 #define RR_TYPE_NB 0x0020
465 #define RR_TYPE_NBSTAT 0x0021
466 #define RR_CLAS_IN 0x0001
467 #define SizeOfNsResource 8
475 #define SizeOfNsRNB 6
477 u_short g
: 1 , ont
:2, resv
:13;
482 AliasHandleResourceNB(
485 NBTArguments
* nbtarg
)
489 #ifdef LIBALIAS_DEBUG
490 char abuf
[INET_ADDRSTRLEN
];
493 if (q
== NULL
|| (char *)(q
+ 1) > pmax
)
495 /* Check out a length */
496 bcount
= ntohs(q
->rdlen
);
498 /* Forward to Resource NB position */
499 nb
= (NBTNsRNB
*) ((u_char
*) q
+ SizeOfNsResource
);
501 /* Processing all in_addr array */
502 #ifdef LIBALIAS_DEBUG
503 kprintf("NB rec[%s", kinet_ntoa(nbtarg
->oldaddr
, abuf
));
504 kprintf("->%s, %dbytes] ", kinet_ntoa(nbtarg
->newaddr
, abuf
), bcount
);
506 while (nb
!= NULL
&& bcount
!= 0) {
507 if ((char *)(nb
+ 1) > pmax
) {
511 #ifdef LIBALIAS_DEBUG
512 kprintf("<%s>", kinet_ntoa(nb
->addr
, abuf
));
514 if (!bcmp(&nbtarg
->oldaddr
, &nb
->addr
, sizeof(struct in_addr
))) {
515 if (*nbtarg
->uh_sum
!= 0) {
519 sptr
= (u_short
*) & (nb
->addr
);
522 sptr
= (u_short
*) & (nbtarg
->newaddr
);
525 ADJUST_CHECKSUM(acc
, *nbtarg
->uh_sum
);
527 nb
->addr
= nbtarg
->newaddr
;
528 #ifdef LIBALIAS_DEBUG
532 #ifdef LIBALIAS_DEBUG
537 nb
= (NBTNsRNB
*) ((u_char
*) nb
+ SizeOfNsRNB
);
538 bcount
-= SizeOfNsRNB
;
540 if (nb
== NULL
|| (char *)(nb
+ 1) > pmax
) {
543 return ((u_char
*) nb
);
546 #define SizeOfResourceA 6
552 AliasHandleResourceA(
555 NBTArguments
* nbtarg
)
559 #ifdef LIBALIAS_DEBUG
560 char abuf
[INET_ADDRSTRLEN
];
563 if (q
== NULL
|| (char *)(q
+ 1) > pmax
)
566 /* Forward to Resource A position */
567 a
= (NBTNsResourceA
*) ((u_char
*) q
+ sizeof(NBTNsResource
));
569 /* Check out of length */
570 bcount
= ntohs(q
->rdlen
);
572 /* Processing all in_addr array */
573 #ifdef LIBALIAS_DEBUG
574 kprintf("Arec [%s", kinet_ntoa(nbtarg
->oldaddr
, abuf
));
575 kprintf("->%s]", kinet_ntoa(nbtarg
->newaddr
, abuf
));
577 while (bcount
!= 0) {
578 if (a
== NULL
|| (char *)(a
+ 1) > pmax
)
580 #ifdef LIBALIAS_DEBUG
581 kprintf("..%s", kinet_ntoa(a
->addr
, abuf
));
583 if (!bcmp(&nbtarg
->oldaddr
, &a
->addr
, sizeof(struct in_addr
))) {
584 if (*nbtarg
->uh_sum
!= 0) {
588 sptr
= (u_short
*) & (a
->addr
); /* Old */
591 sptr
= (u_short
*) & nbtarg
->newaddr
; /* New */
594 ADJUST_CHECKSUM(acc
, *nbtarg
->uh_sum
);
596 a
->addr
= nbtarg
->newaddr
;
599 bcount
-= SizeOfResourceA
;
601 if (a
== NULL
|| (char *)(a
+ 1) > pmax
)
603 return ((u_char
*) a
);
607 u_short opcode
:4, flags
:8, resv
:4;
611 AliasHandleResourceNULL(
614 NBTArguments
* nbtarg
)
616 NBTNsResourceNULL
*n
;
621 if (q
== NULL
|| (char *)(q
+ 1) > pmax
)
624 /* Forward to Resource NULL position */
625 n
= (NBTNsResourceNULL
*) ((u_char
*) q
+ sizeof(NBTNsResource
));
627 /* Check out of length */
628 bcount
= ntohs(q
->rdlen
);
630 /* Processing all in_addr array */
631 while (bcount
!= 0) {
632 if ((char *)(n
+ 1) > pmax
) {
637 bcount
-= sizeof(NBTNsResourceNULL
);
639 if ((char *)(n
+ 1) > pmax
)
642 return ((u_char
*) n
);
646 AliasHandleResourceNS(
649 NBTArguments
* nbtarg
)
651 NBTNsResourceNULL
*n
;
656 if (q
== NULL
|| (char *)(q
+ 1) > pmax
)
659 /* Forward to Resource NULL position */
660 n
= (NBTNsResourceNULL
*) ((u_char
*) q
+ sizeof(NBTNsResource
));
662 /* Check out of length */
663 bcount
= ntohs(q
->rdlen
);
665 /* Resource Record Name Filed */
666 q
= (NBTNsResource
*) AliasHandleName((u_char
*) n
, pmax
); /* XXX */
668 if (q
== NULL
|| (char *)((u_char
*) n
+ bcount
) > pmax
)
671 return ((u_char
*) n
+ bcount
);
676 } NBTNsResourceNBSTAT
;
679 AliasHandleResourceNBSTAT(
682 NBTArguments
* nbtarg
)
684 NBTNsResourceNBSTAT
*n
;
689 if (q
== NULL
|| (char *)(q
+ 1) > pmax
)
692 /* Forward to Resource NBSTAT position */
693 n
= (NBTNsResourceNBSTAT
*) ((u_char
*) q
+ sizeof(NBTNsResource
));
695 /* Check out of length */
696 bcount
= ntohs(q
->rdlen
);
698 if (q
== NULL
|| (char *)((u_char
*) n
+ bcount
) > pmax
)
701 return ((u_char
*) n
+ bcount
);
713 /* Resource Record Name Filed */
714 q
= (NBTNsResource
*) AliasHandleName((u_char
*) q
, pmax
);
716 if (q
== NULL
|| (char *)(q
+ 1) > pmax
)
718 #ifdef LIBALIAS_DEBUG
719 kprintf("type=%02x, count=%d\n", ntohs(q
->type
), count
);
722 /* Type and Class filed */
723 switch (ntohs(q
->type
)) {
725 q
= (NBTNsResource
*) AliasHandleResourceNB(
732 q
= (NBTNsResource
*) AliasHandleResourceA(
739 q
= (NBTNsResource
*) AliasHandleResourceNS(
746 q
= (NBTNsResource
*) AliasHandleResourceNULL(
753 q
= (NBTNsResource
*) AliasHandleResourceNBSTAT(
760 #ifdef LIBALIAS_DEBUG
762 "\nUnknown Type of Resource %0x\n",
771 return ((u_char
*) q
);
777 struct ip
*pip
, /* IP packet to examine/patch */
778 struct alias_link
*lnk
,
779 struct in_addr
*alias_address
,
780 u_short
* alias_port
,
781 struct in_addr
*original_address
,
782 u_short
* original_port
)
793 /* Set up Common Parameter */
794 nbtarg
.oldaddr
= *alias_address
;
795 nbtarg
.oldport
= *alias_port
;
796 nbtarg
.newaddr
= *original_address
;
797 nbtarg
.newport
= *original_port
;
799 /* Calculate data length of UDP packet */
800 uh
= (struct udphdr
*)ip_next(pip
);
801 nbtarg
.uh_sum
= &(uh
->uh_sum
);
802 nsh
= (NbtNSHeader
*)udp_next(uh
);
803 p
= (u_char
*) (nsh
+ 1);
804 pmax
= (char *)uh
+ ntohs(uh
->uh_ulen
);
806 if ((char *)(nsh
+ 1) > pmax
)
809 #ifdef LIBALIAS_DEBUG
810 kprintf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
811 ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
812 nsh
->dir
? "Response" : "Request",
821 (u_char
*) p
- (u_char
*) nsh
825 /* Question Entries */
826 if (ntohs(nsh
->qdcount
) != 0) {
827 p
= AliasHandleQuestion(
834 /* Answer Resource Records */
835 if (ntohs(nsh
->ancount
) != 0) {
836 p
= AliasHandleResource(
843 /* Authority Resource Recodrs */
844 if (ntohs(nsh
->nscount
) != 0) {
845 p
= AliasHandleResource(
852 /* Additional Resource Recodrs */
853 if (ntohs(nsh
->arcount
) != 0) {
854 p
= AliasHandleResource(
861 #ifdef LIBALIAS_DEBUG
862 PrintRcode(nsh
->rcode
);
864 return ((p
== NULL
) ? -1 : 0);