xref: /dragonfly/lib/libalias/alias_nbt.c (revision 984263bc)
1 /*-
2  * Written by Atsushi Murai <amurai@spec.co.jp>
3  * Copyright (c) 1998, System Planning and Engineering Co.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/lib/libalias/alias_nbt.c,v 1.4.2.3 2001/08/01 09:52:26 obrien Exp $
28  *
29  *  TODO:
30  *       oClean up.
31  *       oConsidering for word alignment for other platform.
32  */
33 /*
34     alias_nbt.c performs special processing for NetBios over TCP/IP
35     sessions by UDP.
36 
37     Initial version:  May, 1998  (Atsushi Murai <amurai@spec.co.jp>)
38 
39     See HISTORY file for record of revisions.
40 */
41 
42 /* Includes */
43 #include <ctype.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <sys/types.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <netinet/ip.h>
51 #include <netinet/udp.h>
52 #include <netinet/tcp.h>
53 
54 #include "alias_local.h"
55 
56 typedef struct {
57 	struct in_addr		oldaddr;
58 	u_short 			oldport;
59 	struct in_addr		newaddr;
60 	u_short 			newport;
61 	u_short 			*uh_sum;
62 } NBTArguments;
63 
64 typedef struct {
65 	unsigned char   type;
66 	unsigned char   flags;
67 	u_short  		id;
68 	struct in_addr  source_ip;
69 	u_short			source_port;
70 	u_short			len;
71 	u_short			offset;
72 } NbtDataHeader;
73 
74 #define OpQuery		0
75 #define OpUnknown	4
76 #define OpRegist	5
77 #define OpRelease	6
78 #define OpWACK		7
79 #define OpRefresh	8
80 typedef struct {
81 	u_short			nametrid;
82 	u_short 		dir:1, opcode:4, nmflags:7, rcode:4;
83 	u_short			qdcount;
84 	u_short			ancount;
85 	u_short			nscount;
86 	u_short			arcount;
87 } NbtNSHeader;
88 
89 #define FMT_ERR		0x1
90 #define SRV_ERR		0x2
91 #define IMP_ERR		0x4
92 #define RFS_ERR		0x5
93 #define ACT_ERR		0x6
94 #define CFT_ERR		0x7
95 
96 
97 #ifdef DEBUG
98 static void PrintRcode( u_char rcode )  {
99 
100 	switch (rcode) {
101 		case FMT_ERR:
102 			printf("\nFormat Error.");
103 		case SRV_ERR:
104 			printf("\nSever failure.");
105 		case IMP_ERR:
106 			printf("\nUnsupported request error.\n");
107 		case RFS_ERR:
108 			printf("\nRefused error.\n");
109 		case ACT_ERR:
110 			printf("\nActive error.\n");
111 		case CFT_ERR:
112 			printf("\nName in conflict error.\n");
113 		default:
114 			printf("\n???=%0x\n", rcode );
115 
116 	}
117 }
118 #endif
119 
120 
121 /* Handling Name field */
122 static u_char *AliasHandleName ( u_char *p, char *pmax ) {
123 
124 	u_char *s;
125 	u_char c;
126 	int		compress;
127 
128 	/* Following length field */
129 
130 	if (p == NULL || (char *)p >= pmax)
131 		return(NULL);
132 
133 	if (*p & 0xc0 ) {
134 		p = p + 2;
135 		if ((char *)p > pmax)
136 			return(NULL);
137 		return ((u_char *)p);
138 	}
139 	while ( ( *p & 0x3f) != 0x00 ) {
140 		s = p + 1;
141 		if ( *p == 0x20 )
142 			compress = 1;
143 		else
144 			compress = 0;
145 
146 	 	/* Get next length field */
147 		p = (u_char *)(p + (*p & 0x3f) + 1);
148 		if ((char *)p > pmax) {
149 			p = NULL;
150 			break;
151 		}
152 #ifdef DEBUG
153 		printf(":");
154 #endif
155 		while (s < p) {
156 			if ( compress == 1 ) {
157 				c = (u_char )(((((*s & 0x0f) << 4) | (*(s+1) & 0x0f)) - 0x11));
158 #ifdef DEBUG
159 				if (isprint( c ) )
160 					printf("%c", c );
161 				else
162 					printf("<0x%02x>", c );
163 #endif
164 				s +=2;
165 			} else {
166 #ifdef DEBUG
167 				printf("%c", *s);
168 #endif
169 				s++;
170 			}
171 		}
172 #ifdef DEBUG
173 		printf(":");
174 #endif
175 		fflush(stdout);
176     }
177 
178 	/* Set up to out of Name field */
179 	if (p == NULL || (char *)p >= pmax)
180 	    p = NULL;
181 	else
182 	    p++;
183 	return ((u_char *)p);
184 }
185 
186 /*
187  * NetBios Datagram Handler (IP/UDP)
188  */
189 #define DGM_DIRECT_UNIQ		0x10
190 #define DGM_DIRECT_GROUP	0x11
191 #define DGM_BROADCAST		0x12
192 #define DGM_ERROR			0x13
193 #define DGM_QUERY			0x14
194 #define DGM_POSITIVE_RES	0x15
195 #define DGM_NEGATIVE_RES	0x16
196 
197 int AliasHandleUdpNbt(
198 	struct ip 		  	*pip,	 /* IP packet to examine/patch */
199 	struct alias_link 	*link,
200 	struct in_addr		*alias_address,
201     u_short 		alias_port
202 ) {
203     struct udphdr *	uh;
204     NbtDataHeader 	*ndh;
205     u_char		*p = NULL;
206     char		*pmax;
207 
208     /* Calculate data length of UDP packet */
209     uh =  (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
210     pmax = (char *)uh + ntohs( uh->uh_ulen );
211 
212 	ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr)));
213     if ((char *)(ndh + 1) > pmax)
214 	    return(-1);
215 #ifdef DEBUG
216 	printf("\nType=%02x,", ndh->type );
217 #endif
218 	switch ( ndh->type ) {
219 		case DGM_DIRECT_UNIQ:
220 		case DGM_DIRECT_GROUP:
221 		case DGM_BROADCAST:
222 			p = (u_char *)ndh + 14;
223 		    p = AliasHandleName ( p, pmax ); /* Source Name */
224 		    p = AliasHandleName ( p, pmax ); /* Destination Name */
225 			break;
226 		case DGM_ERROR:
227 			p = (u_char *)ndh + 11;
228 			break;
229 		case DGM_QUERY:
230 		case DGM_POSITIVE_RES:
231 		case DGM_NEGATIVE_RES:
232 			p = (u_char *)ndh + 10;
233 		    p = AliasHandleName ( p, pmax ); /* Destination Name */
234 			break;
235 	}
236     if (p == NULL || (char *)p > pmax)
237 	    p = NULL;
238 #ifdef DEBUG
239 	printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
240 #endif
241 	/* Doing a IP address and Port number Translation */
242 	if ( uh->uh_sum != 0 ) {
243 		int				acc;
244 		u_short			*sptr;
245 		acc  = ndh->source_port;
246 		acc -= alias_port;
247 		sptr = (u_short *) &(ndh->source_ip);
248 		acc += *sptr++;
249 		acc += *sptr;
250 		sptr = (u_short *) alias_address;
251 		acc -= *sptr++;
252 		acc -= *sptr;
253 		ADJUST_CHECKSUM(acc, uh->uh_sum);
254 	}
255     ndh->source_ip = *alias_address;
256     ndh->source_port = alias_port;
257 #ifdef DEBUG
258 	printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
259 	fflush(stdout);
260 #endif
261     return((p == NULL) ? -1 : 0);
262 }
263 /* Question Section */
264 #define QS_TYPE_NB		0x0020
265 #define QS_TYPE_NBSTAT	0x0021
266 #define QS_CLAS_IN		0x0001
267 typedef struct {
268 	u_short	type;	/* The type of Request */
269 	u_short	class;	/* The class of Request */
270 } NBTNsQuestion;
271 
272 static u_char *
273 AliasHandleQuestion(
274     u_short count,
275 							NBTNsQuestion *q,
276     char *pmax,
277 							NBTArguments  *nbtarg)
278 {
279 
280 	while ( count != 0 ) {
281 		/* Name Filed */
282 		q = (NBTNsQuestion *)AliasHandleName((u_char *)q, pmax);
283 
284 		if (q == NULL || (char *)(q + 1) > pmax) {
285 			q = NULL;
286 			break;
287 		}
288 
289 		/* Type and Class filed */
290 		switch ( ntohs(q->type) ) {
291 			case QS_TYPE_NB:
292 			case QS_TYPE_NBSTAT:
293 				q= q+1;
294 			break;
295 			default:
296 #ifdef DEBUG
297 				printf("\nUnknown Type on Question %0x\n", ntohs(q->type) );
298 #endif
299 			break;
300 		}
301 		count--;
302 	}
303 
304 	/* Set up to out of Question Section */
305 	return ((u_char *)q);
306 }
307 
308 /* Resource Record */
309 #define RR_TYPE_A		0x0001
310 #define RR_TYPE_NS		0x0002
311 #define RR_TYPE_NULL	0x000a
312 #define RR_TYPE_NB		0x0020
313 #define RR_TYPE_NBSTAT	0x0021
314 #define RR_CLAS_IN		0x0001
315 #define SizeOfNsResource	8
316 typedef struct {
317  	u_short type;
318  	u_short class;
319  	unsigned int ttl;
320  	u_short rdlen;
321 } NBTNsResource;
322 
323 #define SizeOfNsRNB			6
324 typedef struct {
325 	u_short g:1, ont:2, resv:13;
326 	struct	in_addr	addr;
327 } NBTNsRNB;
328 
329 static u_char *
330 AliasHandleResourceNB(
331     NBTNsResource *q,
332     char *pmax,
333 							   NBTArguments  *nbtarg)
334 {
335 	NBTNsRNB	*nb;
336 	u_short bcount;
337 
338 	if (q == NULL || (char *)(q + 1) > pmax)
339 		return(NULL);
340 	/* Check out a length */
341 	bcount = ntohs(q->rdlen);
342 
343 	/* Forward to Resource NB position */
344 	nb = (NBTNsRNB *)((u_char *)q + SizeOfNsResource);
345 
346 	/* Processing all in_addr array */
347 #ifdef DEBUG
348 	printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
349             printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount);
350 #endif
351 	while ( nb != NULL && bcount != 0 )  {
352 		if ((char *)(nb + 1) > pmax) {
353 			nb = NULL;
354 			break;
355 		}
356 #ifdef DEBUG
357 		printf("<%s>", inet_ntoa(nb->addr) );
358 #endif
359 		if (!bcmp(&nbtarg->oldaddr,&nb->addr, sizeof(struct in_addr) ) ) {
360 			if ( *nbtarg->uh_sum != 0 ) {
361             	int acc;
362             	u_short *sptr;
363 
364             	sptr = (u_short *) &(nb->addr);
365             	acc = *sptr++;
366             	acc += *sptr;
367             	sptr = (u_short *) &(nbtarg->newaddr);
368             	acc -= *sptr++;
369             	acc -= *sptr;
370             	ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
371 			}
372 
373 			nb->addr = nbtarg->newaddr;
374 #ifdef DEBUG
375 			printf("O");
376 #endif
377 		}
378 #ifdef DEBUG
379 		 else {
380 			printf(".");
381 		}
382 #endif
383 		nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB);
384 	 	bcount -= SizeOfNsRNB;
385 	}
386 	if (nb == NULL || (char *)(nb + 1) > pmax) {
387 		nb = NULL;
388 	}
389 
390 	return ((u_char *)nb);
391 }
392 
393 #define SizeOfResourceA		6
394 typedef struct {
395 	struct	in_addr	addr;
396 } NBTNsResourceA;
397 
398 static u_char *
399 AliasHandleResourceA(
400     NBTNsResource *q,
401     char *pmax,
402 						 	  NBTArguments  *nbtarg)
403 {
404 	NBTNsResourceA	*a;
405 	u_short bcount;
406 
407 	if (q == NULL || (char *)(q + 1) > pmax)
408 		return(NULL);
409 
410 	/* Forward to Resource A position */
411 	a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) );
412 
413 	/* Check out of length */
414 	bcount = ntohs(q->rdlen);
415 
416 	/* Processing all in_addr array */
417 #ifdef DEBUG
418 	printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
419         printf("->%s]",inet_ntoa(nbtarg->newaddr ));
420 #endif
421 	while ( bcount != 0 )  {
422 		if (a == NULL || (char *)(a + 1) > pmax)
423 			return(NULL);
424 #ifdef DEBUG
425 		printf("..%s", inet_ntoa(a->addr) );
426 #endif
427 		if ( !bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr) ) ) {
428 			if ( *nbtarg->uh_sum != 0 ) {
429             	int acc;
430             	u_short *sptr;
431 
432             	sptr = (u_short *) &(a->addr);		 /* Old */
433             	acc = *sptr++;
434             	acc += *sptr;
435             	sptr = (u_short *) &nbtarg->newaddr; /* New */
436             	acc -= *sptr++;
437             	acc -= *sptr;
438             	ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
439 			}
440 
441 			a->addr = nbtarg->newaddr;
442 		}
443 		a++;	/*XXXX*/
444 		bcount -= SizeOfResourceA;
445 	}
446 	if (a == NULL || (char *)(a + 1) > pmax)
447 		a =  NULL;
448 	return ((u_char *)a);
449 }
450 
451 typedef struct {
452 	u_short opcode:4, flags:8, resv:4;
453 } NBTNsResourceNULL;
454 
455 static u_char *
456 AliasHandleResourceNULL(
457     NBTNsResource *q,
458     char *pmax,
459 						 	     NBTArguments  *nbtarg)
460 {
461 	NBTNsResourceNULL	*n;
462 	u_short bcount;
463 
464 	if (q == NULL || (char *)(q + 1) > pmax)
465 		return(NULL);
466 
467 	/* Forward to Resource NULL position */
468 	n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
469 
470 	/* Check out of length */
471 	bcount = ntohs(q->rdlen);
472 
473 	/* Processing all in_addr array */
474 	while ( bcount != 0 )  {
475 		if ((char *)(n + 1) > pmax) {
476 			n = NULL;
477 			break;
478 		}
479 		n++;
480 		bcount -= sizeof(NBTNsResourceNULL);
481 	}
482 	if ((char *)(n + 1) > pmax)
483 		n = NULL;
484 
485 	return ((u_char *)n);
486 }
487 
488 static u_char *
489 AliasHandleResourceNS(
490     NBTNsResource *q,
491     char *pmax,
492 						 	     NBTArguments  *nbtarg)
493 {
494 	NBTNsResourceNULL	*n;
495 	u_short bcount;
496 
497 	if (q == NULL || (char *)(q + 1) > pmax)
498 		return(NULL);
499 
500 	/* Forward to Resource NULL position */
501 	n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
502 
503 	/* Check out of length */
504 	bcount = ntohs(q->rdlen);
505 
506 	/* Resource Record Name Filed */
507 	q = (NBTNsResource *)AliasHandleName( (u_char *)n, pmax ); /* XXX */
508 
509 	if (q == NULL || (char *)((u_char *)n + bcount) > pmax)
510 		return(NULL);
511 	else
512 	return ((u_char *)n + bcount);
513 }
514 
515 typedef struct {
516 	u_short	numnames;
517 } NBTNsResourceNBSTAT;
518 
519 static u_char *
520 AliasHandleResourceNBSTAT(
521     NBTNsResource *q,
522     char *pmax,
523 						 	       NBTArguments  *nbtarg)
524 {
525 	NBTNsResourceNBSTAT	*n;
526 	u_short bcount;
527 
528 	if (q == NULL || (char *)(q + 1) > pmax)
529 		return(NULL);
530 
531 	/* Forward to Resource NBSTAT position */
532 	n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) );
533 
534 	/* Check out of length */
535 	bcount = ntohs(q->rdlen);
536 
537 	if (q == NULL || (char *)((u_char *)n + bcount) > pmax)
538 		return(NULL);
539 	else
540 	return ((u_char *)n + bcount);
541 }
542 
543 static u_char *
544 AliasHandleResource(
545     u_short count,
546 							NBTNsResource *q,
547     char *pmax,
548     NBTArguments
549     *nbtarg)
550 {
551 	while ( count != 0 ) {
552 		/* Resource Record Name Filed */
553 		q = (NBTNsResource *)AliasHandleName( (u_char *)q, pmax );
554 
555 		if (q == NULL || (char *)(q + 1) > pmax)
556 			break;
557 #ifdef DEBUG
558 		printf("type=%02x, count=%d\n", ntohs(q->type), count );
559 #endif
560 
561 		/* Type and Class filed */
562 		switch ( ntohs(q->type) ) {
563 			case RR_TYPE_NB:
564 				q = (NBTNsResource *)AliasHandleResourceNB(
565 				    q,
566 				    pmax,
567 				    nbtarg
568 				);
569 				break;
570 			case RR_TYPE_A:
571 				q = (NBTNsResource *)AliasHandleResourceA(
572 				    q,
573 				    pmax,
574 				    nbtarg
575 				);
576 				break;
577 			case RR_TYPE_NS:
578 				q = (NBTNsResource *)AliasHandleResourceNS(
579 				    q,
580 				    pmax,
581 				    nbtarg
582 				);
583 				break;
584 			case RR_TYPE_NULL:
585 				q = (NBTNsResource *)AliasHandleResourceNULL(
586 				    q,
587 				    pmax,
588 				    nbtarg
589 				);
590 				break;
591 			case RR_TYPE_NBSTAT:
592 				q = (NBTNsResource *)AliasHandleResourceNBSTAT(
593 				    q,
594 				    pmax,
595 				    nbtarg
596 				);
597 				break;
598 			default:
599 #ifdef DEBUG
600 				printf(
601 				    "\nUnknown Type of Resource %0x\n",
602 				    ntohs(q->type)
603 				);
604 #endif
605 				break;
606 		}
607 		count--;
608 	}
609 	fflush(stdout);
610 	return ((u_char *)q);
611 }
612 
613 int AliasHandleUdpNbtNS(
614 	struct ip 		  	*pip,	 /* IP packet to examine/patch */
615 	struct alias_link 	*link,
616 	struct in_addr		*alias_address,
617 	u_short 			*alias_port,
618 	struct in_addr		*original_address,
619 	u_short 			*original_port )
620 {
621     struct udphdr *	uh;
622 	NbtNSHeader	  * nsh;
623 	u_char		  * p;
624 	char		*pmax;
625 	NBTArguments    nbtarg;
626 
627 	/* Set up Common Parameter */
628 	nbtarg.oldaddr	=	*alias_address;
629 	nbtarg.oldport	=	*alias_port;
630 	nbtarg.newaddr	=	*original_address;
631 	nbtarg.newport	=	*original_port;
632 
633     /* Calculate data length of UDP packet */
634     uh =  (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
635 	nbtarg.uh_sum	=	&(uh->uh_sum);
636 	nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr)));
637 	p = (u_char *)(nsh + 1);
638     pmax = (char *)uh + ntohs( uh->uh_ulen );
639 
640     if ((char *)(nsh + 1) > pmax)
641 	return(-1);
642 
643 #ifdef DEBUG
644     printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
645 	   ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
646 		nsh->dir ? "Response": "Request",
647 		nsh->nametrid,
648 		nsh->opcode,
649 		nsh->nmflags,
650 		nsh->rcode,
651 		ntohs(nsh->qdcount),
652 		ntohs(nsh->ancount),
653 		ntohs(nsh->nscount),
654 		ntohs(nsh->arcount),
655 	(u_char *)p -(u_char *)nsh
656     );
657 #endif
658 
659 	/* Question Entries */
660 	if (ntohs(nsh->qdcount) !=0 ) {
661 	p = AliasHandleQuestion(
662 	    ntohs(nsh->qdcount),
663 	    (NBTNsQuestion *)p,
664 	    pmax,
665 	    &nbtarg
666 	);
667 	}
668 
669 	/* Answer Resource Records */
670 	if (ntohs(nsh->ancount) !=0 ) {
671 	p = AliasHandleResource(
672 	    ntohs(nsh->ancount),
673 	    (NBTNsResource *)p,
674 	    pmax,
675 	    &nbtarg
676 	);
677 	}
678 
679 	/* Authority Resource Recodrs */
680 	if (ntohs(nsh->nscount) !=0 ) {
681 	p = AliasHandleResource(
682 	    ntohs(nsh->nscount),
683 	    (NBTNsResource *)p,
684 	    pmax,
685 	    &nbtarg
686 	);
687 	}
688 
689 	/* Additional Resource Recodrs */
690 	if (ntohs(nsh->arcount) !=0 ) {
691 	p = AliasHandleResource(
692 	    ntohs(nsh->arcount),
693 	    (NBTNsResource *)p,
694 	    pmax,
695 	    &nbtarg
696 	);
697 	}
698 
699 #ifdef DEBUG
700 	 	PrintRcode(nsh->rcode);
701 #endif
702     return ((p == NULL) ? -1 : 0);
703 }
704