Skip site navigation (1)Skip section navigation (2)
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>