alias_nbt.c revision 36321
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:$
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
64typedef 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
72typedef 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
88typedef 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 *******************************************************************/
107void putip(void *dest,void *src)
108{
109  memcpy(dest,src,4);
110}
111
112void 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 */
135u_char *AliasHandleName ( u_char *p ) {
136
137	u_char *s;
138	u_char c;
139	int		compress;
140
141	/* Following length field */
142	if (*p & 0xc0 ) {
143		p = p + 2;
144		return ((u_char *)p);
145	}
146	while ( ( *p & 0x3f) != 0x00 ) {
147		s = p + 1;
148		if ( *p == 0x20 )
149			compress = 1;
150		else
151			compress = 0;
152
153	 	/* Get next length field */
154		p = (u_char *)(p + (*p & 0x3f) + 1);
155#ifdef DEBUG
156		printf(":");
157#endif
158		while (s < p) {
159			if ( compress == 1 ) {
160				c = (u_char )(((((*s & 0x0f) << 4) | (*(s+1) & 0x0f)) - 0x11));
161#ifdef DEBUG
162				if (isprint( c ) )
163					printf("%c", c );
164				else
165					printf("<0x%02x>", c );
166#endif
167				s +=2;
168			} else {
169#ifdef DEBUG
170				printf("%c", *s);
171#endif
172				s++;
173			}
174		}
175#ifdef DEBUG
176		printf(":");
177#endif
178		fflush(stdout);
179    }
180
181	/* Set up to out of Name field */
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
197void 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;
206
207    /* Calculate data length of UDP packet */
208    uh =  (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
209	ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr)));
210#ifdef DEBUG
211	printf("\nType=%02x,", ndh->type );
212#endif
213	switch ( ndh->type ) {
214		case DGM_DIRECT_UNIQ:
215		case DGM_DIRECT_GROUP:
216		case DGM_BROADCAST:
217			p = (u_char *)ndh + 14;
218			p = AliasHandleName ( p ); /* Source Name */
219			p = AliasHandleName ( p ); /* Destination Name */
220			break;
221		case DGM_ERROR:
222			p = (u_char *)ndh + 11;
223			break;
224		case DGM_QUERY:
225		case DGM_POSITIVE_RES:
226		case DGM_NEGATIVE_RES:
227			p = (u_char *)ndh + 10;
228			p = AliasHandleName ( p ); /* Destination Name */
229			break;
230	}
231#ifdef DEBUG
232	printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
233#endif
234	/* Doing a IP address and Port number Translation */
235	if ( uh->uh_sum != 0 ) {
236		int				acc;
237		u_short			*sptr;
238		acc  = ndh->source_port;
239		acc -= alias_port;
240		sptr = (u_short *) &(ndh->source_ip);
241		acc += *sptr++;
242		acc += *sptr;
243		sptr = (u_short *) alias_address;
244		acc -= *sptr++;
245		acc -= *sptr;
246		ADJUST_CHECKSUM(acc, uh->uh_sum)
247	}
248    ndh->source_ip = *alias_address;
249    ndh->source_port = alias_port;
250#ifdef DEBUG
251	printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
252	fflush(stdout);
253#endif
254}
255/* Question Section */
256#define QS_TYPE_NB		0x0020
257#define QS_TYPE_NBSTAT	0x0021
258#define QS_CLAS_IN		0x0001
259typedef struct {
260	u_short	type;	/* The type of Request */
261	u_short	class;	/* The class of Request */
262} NBTNsQuestion;
263
264u_char *AliasHandleQuestion(u_short count,
265							NBTNsQuestion *q,
266							NBTArguments  *nbtarg)
267{
268
269	while ( count != 0 ) {
270		/* Name Filed */
271		q = (NBTNsQuestion *)AliasHandleName((u_char *)q );
272
273		/* Type and Class filed */
274		switch ( ntohs(q->type) ) {
275			case QS_TYPE_NB:
276			case QS_TYPE_NBSTAT:
277				q= q+1;
278			break;
279			default:
280				printf("\nUnknown Type on Question %0x\n", ntohs(q->type) );
281			break;
282		}
283		count--;
284	}
285
286	/* Set up to out of Question Section */
287	return ((u_char *)q);
288}
289
290/* Resource Record */
291#define RR_TYPE_A		0x0001
292#define RR_TYPE_NS		0x0002
293#define RR_TYPE_NULL	0x000a
294#define RR_TYPE_NB		0x0020
295#define RR_TYPE_NBSTAT	0x0021
296#define RR_CLAS_IN		0x0001
297#define SizeOfNsResource	8
298typedef struct {
299 	u_short type;
300 	u_short class;
301 	unsigned int ttl;
302 	u_short rdlen;
303} NBTNsResource;
304
305#define SizeOfNsRNB			6
306typedef struct {
307	u_short g:1, ont:2, resv:13;
308	struct	in_addr	addr;
309} NBTNsRNB;
310
311u_char *AliasHandleResourceNB( NBTNsResource *q,
312							   NBTArguments  *nbtarg)
313{
314	NBTNsRNB	*nb;
315	u_short bcount;
316
317	/* Check out a length */
318	bcount = ntohs(q->rdlen);
319
320	/* Forward to Resource NB position */
321	nb = (NBTNsRNB *)((u_char *)q + SizeOfNsResource);
322
323	/* Processing all in_addr array */
324#ifdef DEBUG
325	printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
326            printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount);
327#endif
328	while ( bcount != 0 )  {
329#ifdef DEBUG
330		printf("<%s>", inet_ntoa(nb->addr) );
331#endif
332		if (!bcmp(&nbtarg->oldaddr,&nb->addr, sizeof(struct in_addr) ) ) {
333			if ( *nbtarg->uh_sum != 0 ) {
334            	int acc;
335            	u_short *sptr;
336
337            	sptr = (u_short *) &(nb->addr);
338            	acc = *sptr++;
339            	acc += *sptr;
340            	sptr = (u_short *) &(nbtarg->newaddr);
341            	acc -= *sptr++;
342            	acc -= *sptr;
343            	ADJUST_CHECKSUM(acc, *nbtarg->uh_sum)
344			}
345
346			nb->addr = nbtarg->newaddr;
347#ifdef DEBUG
348			printf("O");
349#endif
350		}
351#ifdef DEBUG
352		 else {
353			printf(".");
354		}
355#endif
356		nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB);
357	 	bcount -= SizeOfNsRNB;
358	}
359
360	return ((u_char *)nb);
361}
362
363#define SizeOfResourceA		6
364typedef struct {
365	struct	in_addr	addr;
366} NBTNsResourceA;
367
368u_char *AliasHandleResourceA( NBTNsResource *q,
369						 	  NBTArguments  *nbtarg)
370{
371	NBTNsResourceA	*a;
372	u_short bcount;
373
374	/* Forward to Resource A position */
375	a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) );
376
377	/* Check out of length */
378	bcount = ntohs(q->rdlen);
379
380	/* Processing all in_addr array */
381#ifdef DEBUG
382	printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
383        printf("->%s]",inet_ntoa(nbtarg->newaddr ));
384#endif
385	while ( bcount != 0 )  {
386#ifdef DEBUG
387		printf("..%s", inet_ntoa(a->addr) );
388#endif
389		if ( !bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr) ) ) {
390			if ( *nbtarg->uh_sum != 0 ) {
391            	int acc;
392            	u_short *sptr;
393
394            	sptr = (u_short *) &(a->addr);		 /* Old */
395            	acc = *sptr++;
396            	acc += *sptr;
397            	sptr = (u_short *) &nbtarg->newaddr; /* New */
398            	acc -= *sptr++;
399            	acc -= *sptr;
400            	ADJUST_CHECKSUM(acc, *nbtarg->uh_sum)
401			}
402
403			a->addr = nbtarg->newaddr;
404		}
405		a++;	/*XXXX*/
406		bcount -= SizeOfResourceA;
407	}
408	return ((u_char *)a);
409}
410
411typedef struct {
412	u_short opcode:4, flags:8, resv:4;
413} NBTNsResourceNULL;
414
415u_char *AliasHandleResourceNULL( NBTNsResource *q,
416						 	     NBTArguments  *nbtarg)
417{
418	NBTNsResourceNULL	*n;
419	u_short bcount;
420
421	/* Forward to Resource NULL position */
422	n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
423
424	/* Check out of length */
425	bcount = ntohs(q->rdlen);
426
427	/* Processing all in_addr array */
428	while ( bcount != 0 )  {
429		n++;
430		bcount -= sizeof(NBTNsResourceNULL);
431	}
432
433	return ((u_char *)n);
434}
435
436u_char *AliasHandleResourceNS( NBTNsResource *q,
437						 	     NBTArguments  *nbtarg)
438{
439	NBTNsResourceNULL	*n;
440	u_short bcount;
441
442	/* Forward to Resource NULL position */
443	n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
444
445	/* Check out of length */
446	bcount = ntohs(q->rdlen);
447
448	/* Resource Record Name Filed */
449	q = (NBTNsResource *)AliasHandleName( (u_char *)n ); /* XXX */
450
451	return ((u_char *)n + bcount);
452}
453
454typedef struct {
455	u_short	numnames;
456} NBTNsResourceNBSTAT;
457
458u_char *AliasHandleResourceNBSTAT( NBTNsResource *q,
459						 	       NBTArguments  *nbtarg)
460{
461	NBTNsResourceNBSTAT	*n;
462	u_short bcount;
463
464	/* Forward to Resource NBSTAT position */
465	n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) );
466
467	/* Check out of length */
468	bcount = ntohs(q->rdlen);
469
470	return ((u_char *)n + bcount);
471}
472
473u_char *AliasHandleResource(u_short count,
474							NBTNsResource *q,
475							NBTArguments  *nbtarg)
476{
477	while ( count != 0 ) {
478		/* Resource Record Name Filed */
479		q = (NBTNsResource *)AliasHandleName( (u_char *)q );
480#ifdef DEBUG
481		printf("type=%02x, count=%d\n", ntohs(q->type), count );
482#endif
483
484		/* Type and Class filed */
485		switch ( ntohs(q->type) ) {
486			case RR_TYPE_NB:
487				q = (NBTNsResource *)AliasHandleResourceNB( q, nbtarg );
488				break;
489			case RR_TYPE_A:
490				q = (NBTNsResource *)AliasHandleResourceA( q, nbtarg );
491				break;
492			case RR_TYPE_NS:
493				q = (NBTNsResource *)AliasHandleResourceNS( q, nbtarg );
494				break;
495			case RR_TYPE_NULL:
496				q = (NBTNsResource *)AliasHandleResourceNULL( q, nbtarg );
497				break;
498			case RR_TYPE_NBSTAT:
499				q = (NBTNsResource *)AliasHandleResourceNBSTAT( q, nbtarg );
500				break;
501			default: printf("\nUnknown Type of Resource %0x\n",
502								 ntohs(q->type) );
503				break;
504		}
505		count--;
506	}
507	fflush(stdout);
508	return ((u_char *)q);
509}
510
511void AliasHandleUdpNbtNS(
512	struct ip 		  	*pip,	 /* IP packet to examine/patch */
513	struct alias_link 	*link,
514	struct in_addr		*alias_address,
515	u_short 			*alias_port,
516	struct in_addr		*original_address,
517	u_short 			*original_port )
518{
519    struct udphdr *	uh;
520	NbtNSHeader	  * nsh;
521	u_short		    dlen;
522	u_char		  * p;
523	NBTArguments    nbtarg;
524
525	/* Set up Common Parameter */
526	nbtarg.oldaddr	=	*alias_address;
527	nbtarg.oldport	=	*alias_port;
528	nbtarg.newaddr	=	*original_address;
529	nbtarg.newport	=	*original_port;
530
531    /* Calculate data length of UDP packet */
532    uh =  (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
533	nbtarg.uh_sum	=	&(uh->uh_sum);
534    dlen = ntohs( uh->uh_ulen );
535	nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr)));
536	p = (u_char *)(nsh + 1);
537
538#ifdef DEBUG
539	printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x, an=%04x, ns=%04x, ar=%04x, [%d]-->",
540		nsh->dir ? "Response": "Request",
541		nsh->nametrid,
542		nsh->opcode,
543		nsh->nmflags,
544		nsh->rcode,
545		ntohs(nsh->qdcount),
546		ntohs(nsh->ancount),
547		ntohs(nsh->nscount),
548		ntohs(nsh->arcount),
549		(u_char *)p -(u_char *)nsh);
550#endif
551
552	/* Question Entries */
553	if (ntohs(nsh->qdcount) !=0 ) {
554	p = AliasHandleQuestion(ntohs(nsh->qdcount), (NBTNsQuestion *)p, &nbtarg );
555	}
556
557	/* Answer Resource Records */
558	if (ntohs(nsh->ancount) !=0 ) {
559	p = AliasHandleResource(ntohs(nsh->ancount), (NBTNsResource *)p, &nbtarg );
560	}
561
562	/* Authority Resource Recodrs */
563	if (ntohs(nsh->nscount) !=0 ) {
564	p = AliasHandleResource(ntohs(nsh->nscount), (NBTNsResource *)p, &nbtarg );
565	}
566
567	/* Additional Resource Recodrs */
568	if (ntohs(nsh->arcount) !=0 ) {
569	p = AliasHandleResource(ntohs(nsh->arcount), (NBTNsResource *)p, &nbtarg );
570	}
571
572#ifdef DEBUG
573	 	PrintRcode(nsh->rcode);
574#endif
575	return;
576}
577