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