diff options
Diffstat (limited to 'lib/libalias/alias_nbt.c')
-rw-r--r-- | lib/libalias/alias_nbt.c | 722 |
1 files changed, 722 insertions, 0 deletions
diff --git a/lib/libalias/alias_nbt.c b/lib/libalias/alias_nbt.c new file mode 100644 index 0000000..b51abd1 --- /dev/null +++ b/lib/libalias/alias_nbt.c @@ -0,0 +1,722 @@ +/*- + * Written by Atsushi Murai <amurai@spec.co.jp> + * Copyright (c) 1998, System Planning and Engineering Co. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * TODO: + * oClean up. + * oConsidering for word alignment for other platform. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + alias_nbt.c performs special processing for NetBios over TCP/IP + sessions by UDP. + + Initial version: May, 1998 (Atsushi Murai <amurai@spec.co.jp>) + + See HISTORY file for record of revisions. +*/ + +/* Includes */ +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/ip.h> +#include <netinet/udp.h> +#include <netinet/tcp.h> + +#include "alias_local.h" + +typedef struct { + struct in_addr oldaddr; + u_short oldport; + struct in_addr newaddr; + u_short newport; + u_short *uh_sum; +} NBTArguments; + +typedef struct { + unsigned char type; + unsigned char flags; + u_short id; + struct in_addr source_ip; + u_short source_port; + u_short len; + u_short offset; +} NbtDataHeader; + +#define OpQuery 0 +#define OpUnknown 4 +#define OpRegist 5 +#define OpRelease 6 +#define OpWACK 7 +#define OpRefresh 8 +typedef struct { + u_short nametrid; + u_short dir: 1, opcode:4, nmflags:7, rcode:4; + u_short qdcount; + u_short ancount; + u_short nscount; + u_short arcount; +} NbtNSHeader; + +#define FMT_ERR 0x1 +#define SRV_ERR 0x2 +#define IMP_ERR 0x4 +#define RFS_ERR 0x5 +#define ACT_ERR 0x6 +#define CFT_ERR 0x7 + + +#ifdef DEBUG +static void +PrintRcode(u_char rcode) +{ + + switch (rcode) { + case FMT_ERR: + printf("\nFormat Error."); + case SRV_ERR: + printf("\nSever failure."); + case IMP_ERR: + printf("\nUnsupported request error.\n"); + case RFS_ERR: + printf("\nRefused error.\n"); + case ACT_ERR: + printf("\nActive error.\n"); + case CFT_ERR: + printf("\nName in conflict error.\n"); + default: + printf("\n?%c?=%0x\n", '?', rcode); + + } +} + +#endif + + +/* Handling Name field */ +static u_char * +AliasHandleName(u_char * p, char *pmax) +{ + + u_char *s; + u_char c; + int compress; + + /* Following length field */ + + if (p == NULL || (char *)p >= pmax) + return (NULL); + + if (*p & 0xc0) { + p = p + 2; + if ((char *)p > pmax) + return (NULL); + return ((u_char *) p); + } + while ((*p & 0x3f) != 0x00) { + s = p + 1; + if (*p == 0x20) + compress = 1; + else + compress = 0; + + /* Get next length field */ + p = (u_char *) (p + (*p & 0x3f) + 1); + if ((char *)p > pmax) { + p = NULL; + break; + } +#ifdef DEBUG + printf(":"); +#endif + while (s < p) { + if (compress == 1) { + c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11)); +#ifdef DEBUG + if (isprint(c)) + printf("%c", c); + else + printf("<0x%02x>", c); +#endif + s += 2; + } else { +#ifdef DEBUG + printf("%c", *s); +#endif + s++; + } + } +#ifdef DEBUG + printf(":"); +#endif + fflush(stdout); + } + + /* Set up to out of Name field */ + if (p == NULL || (char *)p >= pmax) + p = NULL; + else + p++; + return ((u_char *) p); +} + +/* + * NetBios Datagram Handler (IP/UDP) + */ +#define DGM_DIRECT_UNIQ 0x10 +#define DGM_DIRECT_GROUP 0x11 +#define DGM_BROADCAST 0x12 +#define DGM_ERROR 0x13 +#define DGM_QUERY 0x14 +#define DGM_POSITIVE_RES 0x15 +#define DGM_NEGATIVE_RES 0x16 + +int +AliasHandleUdpNbt( + struct libalias *la, + struct ip *pip, /* IP packet to examine/patch */ + struct alias_link *lnk, + struct in_addr *alias_address, + u_short alias_port +) +{ + struct udphdr *uh; + NbtDataHeader *ndh; + u_char *p = NULL; + char *pmax; + + (void)la; + (void)lnk; + + /* Calculate data length of UDP packet */ + uh = (struct udphdr *)ip_next(pip); + pmax = (char *)uh + ntohs(uh->uh_ulen); + + ndh = (NbtDataHeader *)udp_next(uh); + if ((char *)(ndh + 1) > pmax) + return (-1); +#ifdef DEBUG + printf("\nType=%02x,", ndh->type); +#endif + switch (ndh->type) { + case DGM_DIRECT_UNIQ: + case DGM_DIRECT_GROUP: + case DGM_BROADCAST: + p = (u_char *) ndh + 14; + p = AliasHandleName(p, pmax); /* Source Name */ + p = AliasHandleName(p, pmax); /* Destination Name */ + break; + case DGM_ERROR: + p = (u_char *) ndh + 11; + break; + case DGM_QUERY: + case DGM_POSITIVE_RES: + case DGM_NEGATIVE_RES: + p = (u_char *) ndh + 10; + p = AliasHandleName(p, pmax); /* Destination Name */ + break; + } + if (p == NULL || (char *)p > pmax) + p = NULL; +#ifdef DEBUG + printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port)); +#endif + /* Doing an IP address and Port number Translation */ + if (uh->uh_sum != 0) { + int acc; + u_short *sptr; + + acc = ndh->source_port; + acc -= alias_port; + sptr = (u_short *) & (ndh->source_ip); + acc += *sptr++; + acc += *sptr; + sptr = (u_short *) alias_address; + acc -= *sptr++; + acc -= *sptr; + ADJUST_CHECKSUM(acc, uh->uh_sum); + } + ndh->source_ip = *alias_address; + ndh->source_port = alias_port; +#ifdef DEBUG + printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port)); + fflush(stdout); +#endif + return ((p == NULL) ? -1 : 0); +} + +/* Question Section */ +#define QS_TYPE_NB 0x0020 +#define QS_TYPE_NBSTAT 0x0021 +#define QS_CLAS_IN 0x0001 +typedef struct { + u_short type; /* The type of Request */ + u_short class; /* The class of Request */ +} NBTNsQuestion; + +static u_char * +AliasHandleQuestion( + u_short count, + NBTNsQuestion * q, + char *pmax, + NBTArguments * nbtarg) +{ + + (void)nbtarg; + + while (count != 0) { + /* Name Filed */ + q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax); + + if (q == NULL || (char *)(q + 1) > pmax) { + q = NULL; + break; + } + /* Type and Class filed */ + switch (ntohs(q->type)) { + case QS_TYPE_NB: + case QS_TYPE_NBSTAT: + q = q + 1; + break; + default: +#ifdef DEBUG + printf("\nUnknown Type on Question %0x\n", ntohs(q->type)); +#endif + break; + } + count--; + } + + /* Set up to out of Question Section */ + return ((u_char *) q); +} + +/* Resource Record */ +#define RR_TYPE_A 0x0001 +#define RR_TYPE_NS 0x0002 +#define RR_TYPE_NULL 0x000a +#define RR_TYPE_NB 0x0020 +#define RR_TYPE_NBSTAT 0x0021 +#define RR_CLAS_IN 0x0001 +#define SizeOfNsResource 8 +typedef struct { + u_short type; + u_short class; + unsigned int ttl; + u_short rdlen; +} NBTNsResource; + +#define SizeOfNsRNB 6 +typedef struct { + u_short g: 1 , ont:2, resv:13; + struct in_addr addr; +} NBTNsRNB; + +static u_char * +AliasHandleResourceNB( + NBTNsResource * q, + char *pmax, + NBTArguments * nbtarg) +{ + NBTNsRNB *nb; + u_short bcount; + + if (q == NULL || (char *)(q + 1) > pmax) + return (NULL); + /* Check out a length */ + bcount = ntohs(q->rdlen); + + /* Forward to Resource NB position */ + nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource); + + /* Processing all in_addr array */ +#ifdef DEBUG + printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr)); + printf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount); +#endif + while (nb != NULL && bcount != 0) { + if ((char *)(nb + 1) > pmax) { + nb = NULL; + break; + } +#ifdef DEBUG + printf("<%s>", inet_ntoa(nb->addr)); +#endif + if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) { + if (*nbtarg->uh_sum != 0) { + int acc; + u_short *sptr; + + sptr = (u_short *) & (nb->addr); + acc = *sptr++; + acc += *sptr; + sptr = (u_short *) & (nbtarg->newaddr); + acc -= *sptr++; + acc -= *sptr; + ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); + } + nb->addr = nbtarg->newaddr; +#ifdef DEBUG + printf("O"); +#endif + } +#ifdef DEBUG + else { + printf("."); + } +#endif + nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB); + bcount -= SizeOfNsRNB; + } + if (nb == NULL || (char *)(nb + 1) > pmax) { + nb = NULL; + } + return ((u_char *) nb); +} + +#define SizeOfResourceA 6 +typedef struct { + struct in_addr addr; +} NBTNsResourceA; + +static u_char * +AliasHandleResourceA( + NBTNsResource * q, + char *pmax, + NBTArguments * nbtarg) +{ + NBTNsResourceA *a; + u_short bcount; + + if (q == NULL || (char *)(q + 1) > pmax) + return (NULL); + + /* Forward to Resource A position */ + a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource)); + + /* Check out of length */ + bcount = ntohs(q->rdlen); + + /* Processing all in_addr array */ +#ifdef DEBUG + printf("Arec [%s", inet_ntoa(nbtarg->oldaddr)); + printf("->%s]", inet_ntoa(nbtarg->newaddr)); +#endif + while (bcount != 0) { + if (a == NULL || (char *)(a + 1) > pmax) + return (NULL); +#ifdef DEBUG + printf("..%s", inet_ntoa(a->addr)); +#endif + if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) { + if (*nbtarg->uh_sum != 0) { + int acc; + u_short *sptr; + + sptr = (u_short *) & (a->addr); /* Old */ + acc = *sptr++; + acc += *sptr; + sptr = (u_short *) & nbtarg->newaddr; /* New */ + acc -= *sptr++; + acc -= *sptr; + ADJUST_CHECKSUM(acc, *nbtarg->uh_sum); + } + a->addr = nbtarg->newaddr; + } + a++; /* XXXX */ + bcount -= SizeOfResourceA; + } + if (a == NULL || (char *)(a + 1) > pmax) + a = NULL; + return ((u_char *) a); +} + +typedef struct { + u_short opcode:4, flags:8, resv:4; +} NBTNsResourceNULL; + +static u_char * +AliasHandleResourceNULL( + NBTNsResource * q, + char *pmax, + NBTArguments * nbtarg) +{ + NBTNsResourceNULL *n; + u_short bcount; + + (void)nbtarg; + + if (q == NULL || (char *)(q + 1) > pmax) + return (NULL); + + /* Forward to Resource NULL position */ + n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource)); + + /* Check out of length */ + bcount = ntohs(q->rdlen); + + /* Processing all in_addr array */ + while (bcount != 0) { + if ((char *)(n + 1) > pmax) { + n = NULL; + break; + } + n++; + bcount -= sizeof(NBTNsResourceNULL); + } + if ((char *)(n + 1) > pmax) + n = NULL; + + return ((u_char *) n); +} + +static u_char * +AliasHandleResourceNS( + NBTNsResource * q, + char *pmax, + NBTArguments * nbtarg) +{ + NBTNsResourceNULL *n; + u_short bcount; + + (void)nbtarg; + + if (q == NULL || (char *)(q + 1) > pmax) + return (NULL); + + /* Forward to Resource NULL position */ + n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource)); + + /* Check out of length */ + bcount = ntohs(q->rdlen); + + /* Resource Record Name Filed */ + q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax); /* XXX */ + + if (q == NULL || (char *)((u_char *) n + bcount) > pmax) + return (NULL); + else + return ((u_char *) n + bcount); +} + +typedef struct { + u_short numnames; +} NBTNsResourceNBSTAT; + +static u_char * +AliasHandleResourceNBSTAT( + NBTNsResource * q, + char *pmax, + NBTArguments * nbtarg) +{ + NBTNsResourceNBSTAT *n; + u_short bcount; + + (void)nbtarg; + + if (q == NULL || (char *)(q + 1) > pmax) + return (NULL); + + /* Forward to Resource NBSTAT position */ + n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource)); + + /* Check out of length */ + bcount = ntohs(q->rdlen); + + if (q == NULL || (char *)((u_char *) n + bcount) > pmax) + return (NULL); + else + return ((u_char *) n + bcount); +} + +static u_char * +AliasHandleResource( + u_short count, + NBTNsResource * q, + char *pmax, + NBTArguments + * nbtarg) +{ + while (count != 0) { + /* Resource Record Name Filed */ + q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax); + + if (q == NULL || (char *)(q + 1) > pmax) + break; +#ifdef DEBUG + printf("type=%02x, count=%d\n", ntohs(q->type), count); +#endif + + /* Type and Class filed */ + switch (ntohs(q->type)) { + case RR_TYPE_NB: + q = (NBTNsResource *) AliasHandleResourceNB( + q, + pmax, + nbtarg + ); + break; + case RR_TYPE_A: + q = (NBTNsResource *) AliasHandleResourceA( + q, + pmax, + nbtarg + ); + break; + case RR_TYPE_NS: + q = (NBTNsResource *) AliasHandleResourceNS( + q, + pmax, + nbtarg + ); + break; + case RR_TYPE_NULL: + q = (NBTNsResource *) AliasHandleResourceNULL( + q, + pmax, + nbtarg + ); + break; + case RR_TYPE_NBSTAT: + q = (NBTNsResource *) AliasHandleResourceNBSTAT( + q, + pmax, + nbtarg + ); + break; + default: +#ifdef DEBUG + printf( + "\nUnknown Type of Resource %0x\n", + ntohs(q->type) + ); +#endif + break; + } + count--; + } + fflush(stdout); + return ((u_char *) q); +} + +int +AliasHandleUdpNbtNS( + struct libalias *la, + struct ip *pip, /* IP packet to examine/patch */ + struct alias_link *lnk, + struct in_addr *alias_address, + u_short * alias_port, + struct in_addr *original_address, + u_short * original_port) +{ + struct udphdr *uh; + NbtNSHeader *nsh; + u_char *p; + char *pmax; + NBTArguments nbtarg; + + (void)la; + (void)lnk; + + /* Set up Common Parameter */ + nbtarg.oldaddr = *alias_address; + nbtarg.oldport = *alias_port; + nbtarg.newaddr = *original_address; + nbtarg.newport = *original_port; + + /* Calculate data length of UDP packet */ + uh = (struct udphdr *)ip_next(pip); + nbtarg.uh_sum = &(uh->uh_sum); + nsh = (NbtNSHeader *)udp_next(uh); + p = (u_char *) (nsh + 1); + pmax = (char *)uh + ntohs(uh->uh_ulen); + + if ((char *)(nsh + 1) > pmax) + return (-1); + +#ifdef DEBUG + printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x" + ", an=%04x, ns=%04x, ar=%04x, [%d]-->", + nsh->dir ? "Response" : "Request", + nsh->nametrid, + nsh->opcode, + nsh->nmflags, + nsh->rcode, + ntohs(nsh->qdcount), + ntohs(nsh->ancount), + ntohs(nsh->nscount), + ntohs(nsh->arcount), + (u_char *) p - (u_char *) nsh + ); +#endif + + /* Question Entries */ + if (ntohs(nsh->qdcount) != 0) { + p = AliasHandleQuestion( + ntohs(nsh->qdcount), + (NBTNsQuestion *) p, + pmax, + &nbtarg + ); + } + /* Answer Resource Records */ + if (ntohs(nsh->ancount) != 0) { + p = AliasHandleResource( + ntohs(nsh->ancount), + (NBTNsResource *) p, + pmax, + &nbtarg + ); + } + /* Authority Resource Recodrs */ + if (ntohs(nsh->nscount) != 0) { + p = AliasHandleResource( + ntohs(nsh->nscount), + (NBTNsResource *) p, + pmax, + &nbtarg + ); + } + /* Additional Resource Recodrs */ + if (ntohs(nsh->arcount) != 0) { + p = AliasHandleResource( + ntohs(nsh->arcount), + (NBTNsResource *) p, + pmax, + &nbtarg + ); + } +#ifdef DEBUG + PrintRcode(nsh->rcode); +#endif + return ((p == NULL) ? -1 : 0); +} |