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