5582e56d9d
With the first part of my previous Summer of Code work, we get: -made libalias modular: -support for 'particular' protocols (like ftp/irc/etcetc) is no more hardcoded inside libalias, but it's available through external modules loadable at runtime -modules are available both in kernel (/boot/kernel/alias_*.ko) and user land (/lib/libalias_*) -protocols/applications modularized are: cuseeme, ftp, irc, nbt, pptp, skinny and smedia -added logging support for kernel side -cleanup After a buildworld, do a 'mergemaster -i' to install the file libalias.conf in /etc or manually copy it. During startup (and after every HUP signal) user land applications running the new libalias will try to read a file in /etc called libalias.conf: that file contains the list of modules to load. User land applications affected by this commit are ppp and natd: if libalias.conf is present in /etc you won't notice any difference. The only kernel land bit affected by this commit is ng_nat: if you are using ng_nat, and it doesn't correctly handle ftp/irc/etcetc sessions anymore, remember to kldload the correspondent module (i.e. kldload alias_ftp). General information and details about the inner working are available in the libalias man page under the section 'MODULAR ARCHITECTURE (AND ipfw(4) SUPPORT)'. NOTA BENE: this commit affects _ONLY_ libalias, ipfw in-kernel nat support will be part of the next libalias-related commit. Approved by: glebius Reviewed by: glebius, ru
855 lines
18 KiB
C
855 lines
18 KiB
C
/*-
|
|
* 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 */
|
|
#ifdef _KERNEL
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/module.h>
|
|
#else
|
|
#include <errno.h>
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#endif
|
|
|
|
#include <netinet/in_systm.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/udp.h>
|
|
|
|
#ifdef _KERNEL
|
|
#include <netinet/libalias/alias_local.h>
|
|
#include <netinet/libalias/alias_mod.h>
|
|
#else
|
|
#include "alias_local.h"
|
|
#include "alias_mod.h"
|
|
#endif
|
|
|
|
#define NETBIOS_NS_PORT_NUMBER 137
|
|
#define NETBIOS_DGM_PORT_NUMBER 138
|
|
|
|
static int
|
|
AliasHandleUdpNbt(struct libalias *, struct ip *, struct alias_link *,
|
|
struct in_addr *, u_short);
|
|
|
|
static int
|
|
AliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
|
|
struct in_addr *, u_short *, struct in_addr *, u_short *);
|
|
static int
|
|
fingerprint1(struct libalias *la, struct ip *pip, struct alias_data *ah)
|
|
{
|
|
|
|
if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
|
|
ah->aaddr == NULL || ah->aport == NULL)
|
|
return (-1);
|
|
if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
|
|
|| ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
|
|
return (0);
|
|
return (-1);
|
|
}
|
|
|
|
static int
|
|
protohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
|
|
{
|
|
|
|
AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport);
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
fingerprint2(struct libalias *la, struct ip *pip, struct alias_data *ah)
|
|
{
|
|
|
|
if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
|
|
ah->aaddr == NULL || ah->aport == NULL)
|
|
return (-1);
|
|
if (ntohs(*ah->dport) == NETBIOS_NS_PORT_NUMBER
|
|
|| ntohs(*ah->sport) == NETBIOS_NS_PORT_NUMBER)
|
|
return (0);
|
|
return (-1);
|
|
}
|
|
|
|
static int
|
|
protohandler2in(struct libalias *la, struct ip *pip, struct alias_data *ah)
|
|
{
|
|
|
|
AliasHandleUdpNbtNS(la, pip, ah->lnk, ah->aaddr, ah->aport,
|
|
ah->oaddr, ah->dport);
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
protohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
|
|
{
|
|
|
|
AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
|
|
ah->aaddr, ah->aport);
|
|
return (0);
|
|
}
|
|
|
|
/* Kernel module definition. */
|
|
struct proto_handler handlers[] = {
|
|
{
|
|
.pri = 130,
|
|
.dir = IN|OUT,
|
|
.proto = UDP,
|
|
.fingerprint = &fingerprint1,
|
|
.protohandler = &protohandler1
|
|
},
|
|
{
|
|
.pri = 140,
|
|
.dir = IN,
|
|
.proto = UDP,
|
|
.fingerprint = &fingerprint2,
|
|
.protohandler = &protohandler2in
|
|
},
|
|
{
|
|
.pri = 140,
|
|
.dir = OUT,
|
|
.proto = UDP,
|
|
.fingerprint = &fingerprint2,
|
|
.protohandler = &protohandler2out
|
|
},
|
|
{ EOH }
|
|
};
|
|
|
|
static int
|
|
mod_handler(module_t mod, int type, void *data)
|
|
{
|
|
int error;
|
|
|
|
switch (type) {
|
|
case MOD_LOAD:
|
|
error = 0;
|
|
LibAliasAttachHandlers(handlers);
|
|
break;
|
|
case MOD_UNLOAD:
|
|
error = 0;
|
|
LibAliasDetachHandlers(handlers);
|
|
break;
|
|
default:
|
|
error = EINVAL;
|
|
}
|
|
return (error);
|
|
}
|
|
|
|
#ifdef _KERNEL
|
|
static
|
|
#endif
|
|
moduledata_t alias_mod = {
|
|
"alias_nbt", mod_handler, NULL
|
|
};
|
|
|
|
#ifdef _KERNEL
|
|
DECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
|
|
MODULE_VERSION(alias_nbt, 1);
|
|
MODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
|
|
#endif
|
|
|
|
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 LIBALIAS_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 LIBALIAS_DEBUG
|
|
printf(":");
|
|
#endif
|
|
while (s < p) {
|
|
if (compress == 1) {
|
|
c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
|
|
#ifdef LIBALIAS_DEBUG
|
|
if (isprint(c))
|
|
printf("%c", c);
|
|
else
|
|
printf("<0x%02x>", c);
|
|
#endif
|
|
s += 2;
|
|
} else {
|
|
#ifdef LIBALIAS_DEBUG
|
|
printf("%c", *s);
|
|
#endif
|
|
s++;
|
|
}
|
|
}
|
|
#ifdef LIBALIAS_DEBUG
|
|
printf(":");
|
|
fflush(stdout);
|
|
#endif
|
|
}
|
|
|
|
/* 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
|
|
|
|
static 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 LIBALIAS_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 LIBALIAS_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 LIBALIAS_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 LIBALIAS_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 LIBALIAS_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 LIBALIAS_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 LIBALIAS_DEBUG
|
|
printf("O");
|
|
#endif
|
|
}
|
|
#ifdef LIBALIAS_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 LIBALIAS_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 LIBALIAS_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 LIBALIAS_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 LIBALIAS_DEBUG
|
|
printf(
|
|
"\nUnknown Type of Resource %0x\n",
|
|
ntohs(q->type)
|
|
);
|
|
fflush(stdout);
|
|
#endif
|
|
break;
|
|
}
|
|
count--;
|
|
}
|
|
return ((u_char *) q);
|
|
}
|
|
|
|
static 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 LIBALIAS_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 LIBALIAS_DEBUG
|
|
PrintRcode(nsh->rcode);
|
|
#endif
|
|
return ((p == NULL) ? -1 : 0);
|
|
}
|