Date: Sat, 12 Dec 1998 14:59:05 -0800 (PST) From: Matthew Dillon <dillon@apollo.backplane.com> To: committers@FreeBSD.ORG Subject: Proposed changes to fix bounds checking in alias_nbt.c Message-ID: <199812122259.OAA03354@apollo.backplane.com>
next in thread | raw e-mail | index | archive | help
While looking at PR bin/8962, I found that
/usr/src/lib/libalias/alias_nbt.c is completely broken - it does no
bounds checking whatsoever. None. Zilch.
Below is a proposed diff, and after that is the complete file. I would
appreciate it if someone looked over it. I cannot easily test it because
I don't run NAT.
Also: the formatting of the original source is phenominally aweful. I
did not try to fix it completely, so don't post followups about the bad
formatting please!
-Matt
Index: alias_local.h
===================================================================
RCS file: /home/ncvs/src/lib/libalias/alias_local.h,v
retrieving revision 1.6
diff -c -r1.6 alias_local.h
*** alias_local.h 1998/06/24 06:58:00 1.6
--- alias_local.h 1998/12/12 22:54:58
***************
*** 90,97 ****
/*lint -save -library Suppress flexelint warnings */
void AliasHandleFtpOut(struct ip *, struct alias_link *, int);
void AliasHandleIrcOut(struct ip *pip, struct alias_link *link, int maxsize );
! void AliasHandleUdpNbt(struct ip *, struct alias_link *, struct in_addr *, u_short);
! void AliasHandleUdpNbtNS(struct ip *, struct alias_link *, struct in_addr *, u_short *, struct in_addr *, u_short *);
void AliasHandleCUSeeMeOut(struct ip *, struct alias_link *);
void AliasHandleCUSeeMeIn(struct ip *, struct in_addr);
--- 90,97 ----
/*lint -save -library Suppress flexelint warnings */
void AliasHandleFtpOut(struct ip *, struct alias_link *, int);
void AliasHandleIrcOut(struct ip *pip, struct alias_link *link, int maxsize );
! int AliasHandleUdpNbt(struct ip *, struct alias_link *, struct in_addr *, u_short);
! int AliasHandleUdpNbtNS(struct ip *, struct alias_link *, struct in_addr *, u_short *, struct in_addr *, u_short *);
void AliasHandleCUSeeMeOut(struct ip *, struct alias_link *);
void AliasHandleCUSeeMeIn(struct ip *, struct in_addr);
Index: alias_nbt.c
===================================================================
RCS file: /home/ncvs/src/lib/libalias/alias_nbt.c,v
retrieving revision 1.1
diff -c -r1.1 alias_nbt.c
*** alias_nbt.c 1998/05/24 03:03:10 1.1
--- alias_nbt.c 1998/12/12 22:54:58
***************
*** 132,146 ****
/* Handling Name field */
! u_char *AliasHandleName ( u_char *p ) {
u_char *s;
u_char c;
int compress;
/* Following length field */
if (*p & 0xc0 ) {
p = p + 2;
return ((u_char *)p);
}
while ( ( *p & 0x3f) != 0x00 ) {
--- 132,152 ----
/* Handling Name field */
! u_char *AliasHandleName ( u_char *p, void *pmax ) {
u_char *s;
u_char c;
int compress;
/* Following length field */
+
+ if (p == NULL || (void *)p >= pmax)
+ return(NULL);
+
if (*p & 0xc0 ) {
p = p + 2;
+ if ((void *)p > pmax)
+ return(NULL);
return ((u_char *)p);
}
while ( ( *p & 0x3f) != 0x00 ) {
***************
*** 152,157 ****
--- 158,167 ----
/* Get next length field */
p = (u_char *)(p + (*p & 0x3f) + 1);
+ if ((void *)p > pmax) {
+ p = NULL;
+ break;
+ }
#ifdef DEBUG
printf(":");
#endif
***************
*** 178,186 ****
fflush(stdout);
}
! /* Set up to out of Name field */
p++;
! return ((u_char *)p);
}
/*
--- 188,199 ----
fflush(stdout);
}
! /* Set up to out of Name field */
! if (p == NULL || (void *)p >= pmax)
! p = NULL;
! else
p++;
! return ((u_char *)p);
}
/*
***************
*** 194,256 ****
#define DGM_POSITIVE_RES 0x15
#define DGM_NEGATIVE_RES 0x16
! void AliasHandleUdpNbt(
! struct ip *pip, /* IP packet to examine/patch */
struct alias_link *link,
struct in_addr *alias_address,
! u_short alias_port )
! {
struct udphdr * uh;
NbtDataHeader *ndh;
! u_char *p;
/* Calculate data length of UDP packet */
uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
! ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr)));
! #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 ); /* Source Name */
! p = AliasHandleName ( p ); /* 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 ); /* Destination Name */
! break;
! }
#ifdef DEBUG
! printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
#endif
/* Doing a 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
}
/* Question Section */
#define QS_TYPE_NB 0x0020
--- 207,277 ----
#define DGM_POSITIVE_RES 0x15
#define DGM_NEGATIVE_RES 0x16
! int AliasHandleUdpNbt(
! struct ip *pip, /* IP packet to examine/patch */
struct alias_link *link,
struct in_addr *alias_address,
! u_short alias_port
! ) {
struct udphdr * uh;
NbtDataHeader *ndh;
! u_char *p = NULL;
! void *pmax;
/* Calculate data length of UDP packet */
uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
! pmax = (char *)uh + ntohs( uh->uh_ulen );
!
! ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr)));
! if ((void *)(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 || (void *)p > pmax)
! p = NULL;
#ifdef DEBUG
! printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
#endif
/* Doing a 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
***************
*** 261,280 ****
u_short class; /* The class of Request */
} NBTNsQuestion;
! u_char *AliasHandleQuestion(u_short count,
! NBTNsQuestion *q,
! NBTArguments *nbtarg)
{
while ( count != 0 ) {
/* Name Filed */
! q = (NBTNsQuestion *)AliasHandleName((u_char *)q );
/* Type and Class filed */
switch ( ntohs(q->type) ) {
case QS_TYPE_NB:
case QS_TYPE_NBSTAT:
! q= q+1;
break;
default:
printf("\nUnknown Type on Question %0x\n", ntohs(q->type) );
--- 282,304 ----
u_short class; /* The class of Request */
} NBTNsQuestion;
! u_char *AliasHandleQuestion(u_short count, NBTNsQuestion *q, void *pmax, NBTArguments *nbtarg)
{
while ( count != 0 ) {
/* Name Filed */
! q = (NBTNsQuestion *)AliasHandleName((u_char *)q, pmax);
+ if (q == NULL || (void *)(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:
printf("\nUnknown Type on Question %0x\n", ntohs(q->type) );
***************
*** 308,319 ****
struct in_addr addr;
} NBTNsRNB;
! u_char *AliasHandleResourceNB( NBTNsResource *q,
! NBTArguments *nbtarg)
{
NBTNsRNB *nb;
u_short bcount;
/* Check out a length */
bcount = ntohs(q->rdlen);
--- 332,344 ----
struct in_addr addr;
} NBTNsRNB;
! u_char *AliasHandleResourceNB( NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
NBTNsRNB *nb;
u_short bcount;
+ if (q == NULL || (void *)(q + 1) > pmax)
+ return(NULL);
/* Check out a length */
bcount = ntohs(q->rdlen);
***************
*** 325,331 ****
printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount);
#endif
! while ( bcount != 0 ) {
#ifdef DEBUG
printf("<%s>", inet_ntoa(nb->addr) );
#endif
--- 350,360 ----
printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount);
#endif
! while ( nb != NULL && bcount != 0 ) {
! if ((void *)(nb + 1) > pmax) {
! nb = NULL;
! break;
! }
#ifdef DEBUG
printf("<%s>", inet_ntoa(nb->addr) );
#endif
***************
*** 356,361 ****
--- 385,393 ----
nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB);
bcount -= SizeOfNsRNB;
}
+ if (nb == NULL || (void *)(nb + 1) > pmax) {
+ nb = NULL;
+ }
return ((u_char *)nb);
}
***************
*** 365,376 ****
struct in_addr addr;
} NBTNsResourceA;
! u_char *AliasHandleResourceA( NBTNsResource *q,
! NBTArguments *nbtarg)
{
NBTNsResourceA *a;
u_short bcount;
/* Forward to Resource A position */
a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) );
--- 397,410 ----
struct in_addr addr;
} NBTNsResourceA;
! u_char *AliasHandleResourceA( NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
NBTNsResourceA *a;
u_short bcount;
+ if (q == NULL || (void *)(q + 1) > pmax)
+ return(NULL);
+
/* Forward to Resource A position */
a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) );
***************
*** 383,388 ****
--- 417,424 ----
printf("->%s]",inet_ntoa(nbtarg->newaddr ));
#endif
while ( bcount != 0 ) {
+ if (a == NULL || (void *)(a + 1) > pmax)
+ return(NULL);
#ifdef DEBUG
printf("..%s", inet_ntoa(a->addr) );
#endif
***************
*** 405,410 ****
--- 441,448 ----
a++; /*XXXX*/
bcount -= SizeOfResourceA;
}
+ if (a == NULL || (void *)(a + 1) > pmax)
+ a = NULL;
return ((u_char *)a);
}
***************
*** 412,423 ****
u_short opcode:4, flags:8, resv:4;
} NBTNsResourceNULL;
! u_char *AliasHandleResourceNULL( NBTNsResource *q,
! NBTArguments *nbtarg)
{
NBTNsResourceNULL *n;
u_short bcount;
/* Forward to Resource NULL position */
n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
--- 450,463 ----
u_short opcode:4, flags:8, resv:4;
} NBTNsResourceNULL;
! u_char *AliasHandleResourceNULL( NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
NBTNsResourceNULL *n;
u_short bcount;
+ if (q == NULL || (void *)(q + 1) > pmax)
+ return(NULL);
+
/* Forward to Resource NULL position */
n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
***************
*** 426,444 ****
/* Processing all in_addr array */
while ( bcount != 0 ) {
n++;
bcount -= sizeof(NBTNsResourceNULL);
}
return ((u_char *)n);
}
! u_char *AliasHandleResourceNS( NBTNsResource *q,
! NBTArguments *nbtarg)
{
NBTNsResourceNULL *n;
u_short bcount;
/* Forward to Resource NULL position */
n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
--- 466,492 ----
/* Processing all in_addr array */
while ( bcount != 0 ) {
+ if ((void *)(n + 1) > pmax) {
+ n = NULL;
+ break;
+ }
n++;
bcount -= sizeof(NBTNsResourceNULL);
}
+ if ((void *)(n + 1) > pmax)
+ n = NULL;
return ((u_char *)n);
}
! u_char *AliasHandleResourceNS( NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
NBTNsResourceNULL *n;
u_short bcount;
+ if (q == NULL || (void *)(q + 1) > pmax)
+ return(NULL);
+
/* Forward to Resource NULL position */
n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
***************
*** 446,482 ****
bcount = ntohs(q->rdlen);
/* Resource Record Name Filed */
! q = (NBTNsResource *)AliasHandleName( (u_char *)n ); /* XXX */
! return ((u_char *)n + bcount);
}
typedef struct {
u_short numnames;
} NBTNsResourceNBSTAT;
! u_char *AliasHandleResourceNBSTAT( NBTNsResource *q,
! NBTArguments *nbtarg)
{
NBTNsResourceNBSTAT *n;
u_short bcount;
/* Forward to Resource NBSTAT position */
n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) );
/* Check out of length */
bcount = ntohs(q->rdlen);
! return ((u_char *)n + bcount);
}
! u_char *AliasHandleResource(u_short count,
! NBTNsResource *q,
! NBTArguments *nbtarg)
{
while ( count != 0 ) {
/* Resource Record Name Filed */
! q = (NBTNsResource *)AliasHandleName( (u_char *)q );
#ifdef DEBUG
printf("type=%02x, count=%d\n", ntohs(q->type), count );
#endif
--- 494,539 ----
bcount = ntohs(q->rdlen);
/* Resource Record Name Filed */
! q = (NBTNsResource *)AliasHandleName( (u_char *)n, pmax ); /* XXX */
! if (q == NULL || (void *)((u_char *)n + bcount) > pmax)
! return(NULL);
! else
! return ((u_char *)n + bcount);
}
typedef struct {
u_short numnames;
} NBTNsResourceNBSTAT;
! u_char *AliasHandleResourceNBSTAT( NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
NBTNsResourceNBSTAT *n;
u_short bcount;
+ if (q == NULL || (void *)(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 || (void *)((u_char *)n + bcount) > pmax)
! return(NULL);
! else
! return ((u_char *)n + bcount);
}
! u_char *AliasHandleResource(u_short count, NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
while ( count != 0 ) {
/* Resource Record Name Filed */
! q = (NBTNsResource *)AliasHandleName( (u_char *)q, pmax );
!
! if (q == NULL || (void *)(q + 1) > pmax)
! break;
#ifdef DEBUG
printf("type=%02x, count=%d\n", ntohs(q->type), count );
#endif
***************
*** 484,505 ****
/* Type and Class filed */
switch ( ntohs(q->type) ) {
case RR_TYPE_NB:
! q = (NBTNsResource *)AliasHandleResourceNB( q, nbtarg );
break;
case RR_TYPE_A:
! q = (NBTNsResource *)AliasHandleResourceA( q, nbtarg );
break;
case RR_TYPE_NS:
! q = (NBTNsResource *)AliasHandleResourceNS( q, nbtarg );
break;
case RR_TYPE_NULL:
! q = (NBTNsResource *)AliasHandleResourceNULL( q, nbtarg );
break;
case RR_TYPE_NBSTAT:
! q = (NBTNsResource *)AliasHandleResourceNBSTAT( q, nbtarg );
break;
! default: printf("\nUnknown Type of Resource %0x\n",
! ntohs(q->type) );
break;
}
count--;
--- 541,562 ----
/* 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:
! printf("\nUnknown Type of Resource %0x\n", ntohs(q->type) );
break;
}
count--;
***************
*** 508,514 ****
return ((u_char *)q);
}
! void AliasHandleUdpNbtNS(
struct ip *pip, /* IP packet to examine/patch */
struct alias_link *link,
struct in_addr *alias_address,
--- 565,571 ----
return ((u_char *)q);
}
! int AliasHandleUdpNbtNS(
struct ip *pip, /* IP packet to examine/patch */
struct alias_link *link,
struct in_addr *alias_address,
***************
*** 518,525 ****
{
struct udphdr * uh;
NbtNSHeader * nsh;
- u_short dlen;
u_char * p;
NBTArguments nbtarg;
/* Set up Common Parameter */
--- 575,582 ----
{
struct udphdr * uh;
NbtNSHeader * nsh;
u_char * p;
+ void *pmax;
NBTArguments nbtarg;
/* Set up Common Parameter */
***************
*** 531,576 ****
/* Calculate data length of UDP packet */
uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
nbtarg.uh_sum = &(uh->uh_sum);
! dlen = ntohs( uh->uh_ulen );
! nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr)));
! p = (u_char *)(nsh + 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, &nbtarg );
! }
! /* Answer Resource Records */
! if (ntohs(nsh->ancount) !=0 ) {
! p = AliasHandleResource(ntohs(nsh->ancount), (NBTNsResource *)p, &nbtarg );
! }
! /* Authority Resource Recodrs */
! if (ntohs(nsh->nscount) !=0 ) {
! p = AliasHandleResource(ntohs(nsh->nscount), (NBTNsResource *)p, &nbtarg );
! }
! /* Add! if (ntohs(nsh->arcount) !=0 ) {
! p = AliasHandleResource(ntohs(nsh->arcount), (NBTNsResource *)p, &nbtarg );
! }
#ifdef DEBUG
! PrintRcode(nsh->rcode);
#endif
! return;
}
--- 588,638 ----
/* Calculate data length of UDP packet */
uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
nbtarg.uh_sum = &(uh->uh_sum);
! nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr)));
! p = (u_char *)(nsh + 1);
! pmax = (char *)uh + ntohs( uh->uh_ulen );
!
! if ((void *)(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);
}
+
--------------------------------------------------------------
/*
* Written by Atsushi Murai <amurai@spec.co.jp>
*
* Copyright (C) 1998, System Planning and Engineering Co. All rights reserverd.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the System Planning and Engineering Co. The name of the
* SPEC may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: alias_nbt.c,v 1.1 1998/05/24 03:03:10 amurai Exp $
*
* TODO:
* oClean up.
* oConsidering for word alignment for other platform.
*/
/*
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"
#define ADJUST_CHECKSUM(acc, cksum) { \
acc += cksum; \
if (acc < 0) \
{ \
acc = -acc; \
acc = (acc >> 16) + (acc & 0xffff); \
acc += acc >> 16; \
cksum = (u_short) ~acc; \
} \
else \
{ \
acc = (acc >> 16) + (acc & 0xffff); \
acc += acc >> 16; \
cksum = (u_short) acc; \
} \
}
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
/*******************************************************************
* copy an IP address from one buffer to another *
*******************************************************************/
void putip(void *dest,void *src)
{
memcpy(dest,src,4);
}
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???=%0x\n", rcode );
}
}
/* Handling Name field */
u_char *AliasHandleName ( u_char *p, void *pmax ) {
u_char *s;
u_char c;
int compress;
/* Following length field */
if (p == NULL || (void *)p >= pmax)
return(NULL);
if (*p & 0xc0 ) {
p = p + 2;
if ((void *)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 ((void *)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 || (void *)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 ip *pip, /* IP packet to examine/patch */
struct alias_link *link,
struct in_addr *alias_address,
u_short alias_port
) {
struct udphdr * uh;
NbtDataHeader *ndh;
u_char *p = NULL;
void *pmax;
/* Calculate data length of UDP packet */
uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
pmax = (char *)uh + ntohs( uh->uh_ulen );
ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr)));
if ((void *)(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 || (void *)p > pmax)
p = NULL;
#ifdef DEBUG
printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
#endif
/* Doing a 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;
u_char *AliasHandleQuestion(u_short count, NBTNsQuestion *q, void *pmax, NBTArguments *nbtarg)
{
while ( count != 0 ) {
/* Name Filed */
q = (NBTNsQuestion *)AliasHandleName((u_char *)q, pmax);
if (q == NULL || (void *)(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:
printf("\nUnknown Type on Question %0x\n", ntohs(q->type) );
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;
u_char *AliasHandleResourceNB( NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
NBTNsRNB *nb;
u_short bcount;
if (q == NULL || (void *)(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 ((void *)(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 || (void *)(nb + 1) > pmax) {
nb = NULL;
}
return ((u_char *)nb);
}
#define SizeOfResourceA 6
typedef struct {
struct in_addr addr;
} NBTNsResourceA;
u_char *AliasHandleResourceA( NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
NBTNsResourceA *a;
u_short bcount;
if (q == NULL || (void *)(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 || (void *)(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 || (void *)(a + 1) > pmax)
a = NULL;
return ((u_char *)a);
}
typedef struct {
u_short opcode:4, flags:8, resv:4;
} NBTNsResourceNULL;
u_char *AliasHandleResourceNULL( NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
NBTNsResourceNULL *n;
u_short bcount;
if (q == NULL || (void *)(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 ((void *)(n + 1) > pmax) {
n = NULL;
break;
}
n++;
bcount -= sizeof(NBTNsResourceNULL);
}
if ((void *)(n + 1) > pmax)
n = NULL;
return ((u_char *)n);
}
u_char *AliasHandleResourceNS( NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
NBTNsResourceNULL *n;
u_short bcount;
if (q == NULL || (void *)(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 || (void *)((u_char *)n + bcount) > pmax)
return(NULL);
else
return ((u_char *)n + bcount);
}
typedef struct {
u_short numnames;
} NBTNsResourceNBSTAT;
u_char *AliasHandleResourceNBSTAT( NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
NBTNsResourceNBSTAT *n;
u_short bcount;
if (q == NULL || (void *)(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 || (void *)((u_char *)n + bcount) > pmax)
return(NULL);
else
return ((u_char *)n + bcount);
}
u_char *AliasHandleResource(u_short count, NBTNsResource *q, void *pmax, NBTArguments *nbtarg)
{
while ( count != 0 ) {
/* Resource Record Name Filed */
q = (NBTNsResource *)AliasHandleName( (u_char *)q, pmax );
if (q == NULL || (void *)(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:
printf("\nUnknown Type of Resource %0x\n", ntohs(q->type) );
break;
}
count--;
}
fflush(stdout);
return ((u_char *)q);
}
int AliasHandleUdpNbtNS(
struct ip *pip, /* IP packet to examine/patch */
struct alias_link *link,
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;
void *pmax;
NBTArguments nbtarg;
/* 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 *) ((char *) pip + (pip->ip_hl << 2));
nbtarg.uh_sum = &(uh->uh_sum);
nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr)));
p = (u_char *)(nsh + 1);
pmax = (char *)uh + ntohs( uh->uh_ulen );
if ((void *)(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);
}
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe cvs-all" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199812122259.OAA03354>
