xref: /freebsd/sys/netinet/libalias/alias_nbt.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
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 
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 ) {
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 
197 void 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
259 typedef struct {
260 	u_short	type;	/* The type of Request */
261 	u_short	class;	/* The class of Request */
262 } NBTNsQuestion;
263 
264 u_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
298 typedef struct {
299  	u_short type;
300  	u_short class;
301  	unsigned int ttl;
302  	u_short rdlen;
303 } NBTNsResource;
304 
305 #define SizeOfNsRNB			6
306 typedef struct {
307 	u_short g:1, ont:2, resv:13;
308 	struct	in_addr	addr;
309 } NBTNsRNB;
310 
311 u_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
364 typedef struct {
365 	struct	in_addr	addr;
366 } NBTNsResourceA;
367 
368 u_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 
411 typedef struct {
412 	u_short opcode:4, flags:8, resv:4;
413 } NBTNsResourceNULL;
414 
415 u_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 
436 u_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 
454 typedef struct {
455 	u_short	numnames;
456 } NBTNsResourceNBSTAT;
457 
458 u_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 
473 u_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 
511 void 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