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