xref: /freebsd/sys/netinet/libalias/alias_nbt.c (revision 3416500aef140042c64bc149cb1ec6620483bc44)
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  *  TODO:
27  *       oClean up.
28  *       oConsidering for word alignment for other platform.
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
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 #ifdef _KERNEL
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/module.h>
49 #else
50 #include <errno.h>
51 #include <sys/types.h>
52 #include <stdio.h>
53 #include <strings.h>
54 #endif
55 
56 #include <netinet/in_systm.h>
57 #include <netinet/in.h>
58 #include <netinet/ip.h>
59 #include <netinet/udp.h>
60 
61 #ifdef _KERNEL
62 #include <netinet/libalias/alias_local.h>
63 #include <netinet/libalias/alias_mod.h>
64 #else
65 #include "alias_local.h"
66 #include "alias_mod.h"
67 #endif
68 
69 #define NETBIOS_NS_PORT_NUMBER 137
70 #define NETBIOS_DGM_PORT_NUMBER 138
71 
72 static int
73 AliasHandleUdpNbt(struct libalias *, struct ip *, struct alias_link *,
74 		  struct in_addr *, u_short);
75 
76 static int
77 AliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
78 		    struct in_addr *, u_short *, struct in_addr *, u_short *);
79 static int
80 fingerprint1(struct libalias *la, struct alias_data *ah)
81 {
82 
83 	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
84 	    ah->aaddr == NULL || ah->aport == NULL)
85 		return (-1);
86 	if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
87 	    || ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
88 		return (0);
89 	return (-1);
90 }
91 
92 static int
93 protohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
94 {
95 
96 	return (AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport));
97 }
98 
99 static int
100 fingerprint2(struct libalias *la, struct alias_data *ah)
101 {
102 
103 	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
104 	    ah->aaddr == NULL || ah->aport == NULL)
105 		return (-1);
106 	if (ntohs(*ah->dport) == NETBIOS_NS_PORT_NUMBER
107 	    || ntohs(*ah->sport) == NETBIOS_NS_PORT_NUMBER)
108 		return (0);
109 	return (-1);
110 }
111 
112 static int
113 protohandler2in(struct libalias *la, struct ip *pip, struct alias_data *ah)
114 {
115 
116 	AliasHandleUdpNbtNS(la, pip, ah->lnk, ah->aaddr, ah->aport,
117  			    ah->oaddr, ah->dport);
118 	return (0);
119 }
120 
121 static int
122 protohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
123 {
124 
125 	return (AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
126  	    ah->aaddr, ah->aport));
127 }
128 
129 /* Kernel module definition. */
130 struct proto_handler handlers[] = {
131 	{
132 	  .pri = 130,
133 	  .dir = IN|OUT,
134 	  .proto = UDP,
135 	  .fingerprint = &fingerprint1,
136 	  .protohandler = &protohandler1
137 	},
138 	{
139 	  .pri = 140,
140 	  .dir = IN,
141 	  .proto = UDP,
142 	  .fingerprint = &fingerprint2,
143 	  .protohandler = &protohandler2in
144 	},
145 	{
146 	  .pri = 140,
147 	  .dir = OUT,
148 	  .proto = UDP,
149 	  .fingerprint = &fingerprint2,
150 	  .protohandler = &protohandler2out
151 	},
152 	{ EOH }
153 };
154 
155 static int
156 mod_handler(module_t mod, int type, void *data)
157 {
158 	int error;
159 
160 	switch (type) {
161 	case MOD_LOAD:
162 		error = 0;
163 		LibAliasAttachHandlers(handlers);
164 		break;
165 	case MOD_UNLOAD:
166 		error = 0;
167 		LibAliasDetachHandlers(handlers);
168 		break;
169 	default:
170 		error = EINVAL;
171 	}
172 	return (error);
173 }
174 
175 #ifdef	_KERNEL
176 static
177 #endif
178 moduledata_t alias_mod = {
179        "alias_nbt", mod_handler, NULL
180 };
181 
182 #ifdef	_KERNEL
183 DECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
184 MODULE_VERSION(alias_nbt, 1);
185 MODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
186 #endif
187 
188 typedef struct {
189 	struct in_addr	oldaddr;
190 	u_short		oldport;
191 	struct in_addr	newaddr;
192 	u_short		newport;
193 	u_short        *uh_sum;
194 }		NBTArguments;
195 
196 typedef struct {
197 	unsigned char	type;
198 	unsigned char	flags;
199 	u_short		id;
200 	struct in_addr	source_ip;
201 	u_short		source_port;
202 	u_short		len;
203 	u_short		offset;
204 }		NbtDataHeader;
205 
206 #define OpQuery		0
207 #define OpUnknown	4
208 #define OpRegist	5
209 #define OpRelease	6
210 #define OpWACK		7
211 #define OpRefresh	8
212 typedef struct {
213 	u_short		nametrid;
214 	u_short		dir:	1, opcode:4, nmflags:7, rcode:4;
215 	u_short		qdcount;
216 	u_short		ancount;
217 	u_short		nscount;
218 	u_short		arcount;
219 }		NbtNSHeader;
220 
221 #define FMT_ERR		0x1
222 #define SRV_ERR		0x2
223 #define IMP_ERR		0x4
224 #define RFS_ERR		0x5
225 #define ACT_ERR		0x6
226 #define CFT_ERR		0x7
227 
228 
229 #ifdef LIBALIAS_DEBUG
230 static void
231 PrintRcode(u_char rcode)
232 {
233 
234 	switch (rcode) {
235 		case FMT_ERR:
236 		printf("\nFormat Error.");
237 	case SRV_ERR:
238 		printf("\nSever failure.");
239 	case IMP_ERR:
240 		printf("\nUnsupported request error.\n");
241 	case RFS_ERR:
242 		printf("\nRefused error.\n");
243 	case ACT_ERR:
244 		printf("\nActive error.\n");
245 	case CFT_ERR:
246 		printf("\nName in conflict error.\n");
247 	default:
248 		printf("\n?%c?=%0x\n", '?', rcode);
249 
250 	}
251 }
252 
253 #endif
254 
255 
256 /* Handling Name field */
257 static u_char  *
258 AliasHandleName(u_char * p, char *pmax)
259 {
260 
261 	u_char *s;
262 	u_char c;
263 	int compress;
264 
265 	/* Following length field */
266 
267 	if (p == NULL || (char *)p >= pmax)
268 		return (NULL);
269 
270 	if (*p & 0xc0) {
271 		p = p + 2;
272 		if ((char *)p > pmax)
273 			return (NULL);
274 		return ((u_char *) p);
275 	}
276 	while ((*p & 0x3f) != 0x00) {
277 		s = p + 1;
278 		if (*p == 0x20)
279 			compress = 1;
280 		else
281 			compress = 0;
282 
283 		/* Get next length field */
284 		p = (u_char *) (p + (*p & 0x3f) + 1);
285 		if ((char *)p > pmax) {
286 			p = NULL;
287 			break;
288 		}
289 #ifdef LIBALIAS_DEBUG
290 		printf(":");
291 #endif
292 		while (s < p) {
293 			if (compress == 1) {
294 				c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
295 #ifdef LIBALIAS_DEBUG
296 				if (isprint(c))
297 					printf("%c", c);
298 				else
299 					printf("<0x%02x>", c);
300 #endif
301 				s += 2;
302 			} else {
303 #ifdef LIBALIAS_DEBUG
304 				printf("%c", *s);
305 #endif
306 				s++;
307 			}
308 		}
309 #ifdef LIBALIAS_DEBUG
310 		printf(":");
311 		fflush(stdout);
312 #endif
313 	}
314 
315 	/* Set up to out of Name field */
316 	if (p == NULL || (char *)p >= pmax)
317 		p = NULL;
318 	else
319 		p++;
320 	return ((u_char *) p);
321 }
322 
323 /*
324  * NetBios Datagram Handler (IP/UDP)
325  */
326 #define DGM_DIRECT_UNIQ		0x10
327 #define DGM_DIRECT_GROUP	0x11
328 #define DGM_BROADCAST		0x12
329 #define DGM_ERROR			0x13
330 #define DGM_QUERY			0x14
331 #define DGM_POSITIVE_RES	0x15
332 #define DGM_NEGATIVE_RES	0x16
333 
334 static int
335 AliasHandleUdpNbt(
336     struct libalias *la,
337     struct ip *pip,		/* IP packet to examine/patch */
338     struct alias_link *lnk,
339     struct in_addr *alias_address,
340     u_short alias_port
341 )
342 {
343 	struct udphdr *uh;
344 	NbtDataHeader *ndh;
345 	u_char *p = NULL;
346 	char *pmax;
347 #ifdef LIBALIAS_DEBUG
348 	char addrbuf[INET_ADDRSTRLEN];
349 #endif
350 
351 	(void)la;
352 	(void)lnk;
353 
354 	/* Calculate data length of UDP packet */
355 	uh = (struct udphdr *)ip_next(pip);
356 	pmax = (char *)uh + ntohs(uh->uh_ulen);
357 
358 	ndh = (NbtDataHeader *)udp_next(uh);
359 	if ((char *)(ndh + 1) > pmax)
360 		return (-1);
361 #ifdef LIBALIAS_DEBUG
362 	printf("\nType=%02x,", ndh->type);
363 #endif
364 	switch (ndh->type) {
365 	case DGM_DIRECT_UNIQ:
366 	case DGM_DIRECT_GROUP:
367 	case DGM_BROADCAST:
368 		p = (u_char *) ndh + 14;
369 		p = AliasHandleName(p, pmax);	/* Source Name */
370 		p = AliasHandleName(p, pmax);	/* Destination Name */
371 		break;
372 	case DGM_ERROR:
373 		p = (u_char *) ndh + 11;
374 		break;
375 	case DGM_QUERY:
376 	case DGM_POSITIVE_RES:
377 	case DGM_NEGATIVE_RES:
378 		p = (u_char *) ndh + 10;
379 		p = AliasHandleName(p, pmax);	/* Destination Name */
380 		break;
381 	}
382 	if (p == NULL || (char *)p > pmax)
383 		p = NULL;
384 #ifdef LIBALIAS_DEBUG
385 	printf("%s:%d-->", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
386 	    ntohs(ndh->source_port));
387 #endif
388 	/* Doing an IP address and Port number Translation */
389 	if (uh->uh_sum != 0) {
390 		int acc;
391 		u_short *sptr;
392 
393 		acc = ndh->source_port;
394 		acc -= alias_port;
395 		sptr = (u_short *) & (ndh->source_ip);
396 		acc += *sptr++;
397 		acc += *sptr;
398 		sptr = (u_short *) alias_address;
399 		acc -= *sptr++;
400 		acc -= *sptr;
401 		ADJUST_CHECKSUM(acc, uh->uh_sum);
402 	}
403 	ndh->source_ip = *alias_address;
404 	ndh->source_port = alias_port;
405 #ifdef LIBALIAS_DEBUG
406 	printf("%s:%d\n", inet_ntoa_r(ndh->source_ip, INET_NTOA_BUF(addrbuf)),
407 	    ntohs(ndh->source_port));
408 	fflush(stdout);
409 #endif
410 	return ((p == NULL) ? -1 : 0);
411 }
412 
413 /* Question Section */
414 #define QS_TYPE_NB		0x0020
415 #define QS_TYPE_NBSTAT	0x0021
416 #define QS_CLAS_IN		0x0001
417 typedef struct {
418 	u_short		type;	/* The type of Request */
419 	u_short		class;	/* The class of Request */
420 }		NBTNsQuestion;
421 
422 static u_char  *
423 AliasHandleQuestion(
424     u_short count,
425     NBTNsQuestion * q,
426     char *pmax,
427     NBTArguments * nbtarg)
428 {
429 
430 	(void)nbtarg;
431 
432 	while (count != 0) {
433 		/* Name Filed */
434 		q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
435 
436 		if (q == NULL || (char *)(q + 1) > pmax) {
437 			q = NULL;
438 			break;
439 		}
440 		/* Type and Class filed */
441 		switch (ntohs(q->type)) {
442 		case QS_TYPE_NB:
443 		case QS_TYPE_NBSTAT:
444 			q = q + 1;
445 			break;
446 		default:
447 #ifdef LIBALIAS_DEBUG
448 			printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
449 #endif
450 			break;
451 		}
452 		count--;
453 	}
454 
455 	/* Set up to out of Question Section */
456 	return ((u_char *) q);
457 }
458 
459 /* Resource Record */
460 #define RR_TYPE_A		0x0001
461 #define RR_TYPE_NS		0x0002
462 #define RR_TYPE_NULL	0x000a
463 #define RR_TYPE_NB		0x0020
464 #define RR_TYPE_NBSTAT	0x0021
465 #define RR_CLAS_IN		0x0001
466 #define SizeOfNsResource	8
467 typedef struct {
468 	u_short		type;
469 	u_short		class;
470 	unsigned int	ttl;
471 	u_short		rdlen;
472 }		NBTNsResource;
473 
474 #define SizeOfNsRNB			6
475 typedef struct {
476 	u_short		g:	1  , ont:2, resv:13;
477 	struct in_addr	addr;
478 }		NBTNsRNB;
479 
480 static u_char  *
481 AliasHandleResourceNB(
482     NBTNsResource * q,
483     char *pmax,
484     NBTArguments * nbtarg)
485 {
486 	NBTNsRNB *nb;
487 	u_short bcount;
488 #ifdef LIBALIAS_DEBUG
489 	char oldbuf[INET_ADDRSTRLEN];
490 	char newbuf[INET_ADDRSTRLEN];
491 #endif
492 
493 	if (q == NULL || (char *)(q + 1) > pmax)
494 		return (NULL);
495 	/* Check out a length */
496 	bcount = ntohs(q->rdlen);
497 
498 	/* Forward to Resource NB position */
499 	nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
500 
501 	/* Processing all in_addr array */
502 #ifdef LIBALIAS_DEBUG
503 	printf("NB rec[%s->%s, %dbytes] ",
504 	    inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
505 	    inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)),
506 	    bcount);
507 #endif
508 	while (nb != NULL && bcount != 0) {
509 		if ((char *)(nb + 1) > pmax) {
510 			nb = NULL;
511 			break;
512 		}
513 #ifdef LIBALIAS_DEBUG
514 		printf("<%s>", inet_ntoa_r(nb->addr, INET_NTOA_BUF(newbuf)));
515 #endif
516 		if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
517 			if (*nbtarg->uh_sum != 0) {
518 				int acc;
519 				u_short *sptr;
520 
521 				sptr = (u_short *) & (nb->addr);
522 				acc = *sptr++;
523 				acc += *sptr;
524 				sptr = (u_short *) & (nbtarg->newaddr);
525 				acc -= *sptr++;
526 				acc -= *sptr;
527 				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
528 			}
529 			nb->addr = nbtarg->newaddr;
530 #ifdef LIBALIAS_DEBUG
531 			printf("O");
532 #endif
533 		}
534 #ifdef LIBALIAS_DEBUG
535 		else {
536 			printf(".");
537 		}
538 #endif
539 		nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
540 		bcount -= SizeOfNsRNB;
541 	}
542 	if (nb == NULL || (char *)(nb + 1) > pmax) {
543 		nb = NULL;
544 	}
545 	return ((u_char *) nb);
546 }
547 
548 #define SizeOfResourceA		6
549 typedef struct {
550 	struct in_addr	addr;
551 }		NBTNsResourceA;
552 
553 static u_char  *
554 AliasHandleResourceA(
555     NBTNsResource * q,
556     char *pmax,
557     NBTArguments * nbtarg)
558 {
559 	NBTNsResourceA *a;
560 	u_short bcount;
561 #ifdef LIBALIAS_DEBUG
562 	char oldbuf[INET_ADDRSTRLEN];
563 	char newbuf[INET_ADDRSTRLEN];
564 #endif
565 
566 	if (q == NULL || (char *)(q + 1) > pmax)
567 		return (NULL);
568 
569 	/* Forward to Resource A position */
570 	a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
571 
572 	/* Check out of length */
573 	bcount = ntohs(q->rdlen);
574 
575 	/* Processing all in_addr array */
576 #ifdef LIBALIAS_DEBUG
577 	printf("Arec [%s->%s]",
578 	    inet_ntoa_r(nbtarg->oldaddr, INET_NTOA_BUF(oldbuf)),
579 	    inet_ntoa_r(nbtarg->newaddr, INET_NTOA_BUF(newbuf)));
580 #endif
581 	while (bcount != 0) {
582 		if (a == NULL || (char *)(a + 1) > pmax)
583 			return (NULL);
584 #ifdef LIBALIAS_DEBUG
585 		printf("..%s", inet_ntoa_r(a->addr, INET_NTOA_BUF(newbuf)));
586 #endif
587 		if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
588 			if (*nbtarg->uh_sum != 0) {
589 				int acc;
590 				u_short *sptr;
591 
592 				sptr = (u_short *) & (a->addr);	/* Old */
593 				acc = *sptr++;
594 				acc += *sptr;
595 				sptr = (u_short *) & nbtarg->newaddr;	/* New */
596 				acc -= *sptr++;
597 				acc -= *sptr;
598 				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
599 			}
600 			a->addr = nbtarg->newaddr;
601 		}
602 		a++;		/* XXXX */
603 		bcount -= SizeOfResourceA;
604 	}
605 	if (a == NULL || (char *)(a + 1) > pmax)
606 		a = NULL;
607 	return ((u_char *) a);
608 }
609 
610 typedef struct {
611 	u_short		opcode:4, flags:8, resv:4;
612 }		NBTNsResourceNULL;
613 
614 static u_char  *
615 AliasHandleResourceNULL(
616     NBTNsResource * q,
617     char *pmax,
618     NBTArguments * nbtarg)
619 {
620 	NBTNsResourceNULL *n;
621 	u_short bcount;
622 
623 	(void)nbtarg;
624 
625 	if (q == NULL || (char *)(q + 1) > pmax)
626 		return (NULL);
627 
628 	/* Forward to Resource NULL position */
629 	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
630 
631 	/* Check out of length */
632 	bcount = ntohs(q->rdlen);
633 
634 	/* Processing all in_addr array */
635 	while (bcount != 0) {
636 		if ((char *)(n + 1) > pmax) {
637 			n = NULL;
638 			break;
639 		}
640 		n++;
641 		bcount -= sizeof(NBTNsResourceNULL);
642 	}
643 	if ((char *)(n + 1) > pmax)
644 		n = NULL;
645 
646 	return ((u_char *) n);
647 }
648 
649 static u_char  *
650 AliasHandleResourceNS(
651     NBTNsResource * q,
652     char *pmax,
653     NBTArguments * nbtarg)
654 {
655 	NBTNsResourceNULL *n;
656 	u_short bcount;
657 
658 	(void)nbtarg;
659 
660 	if (q == NULL || (char *)(q + 1) > pmax)
661 		return (NULL);
662 
663 	/* Forward to Resource NULL position */
664 	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
665 
666 	/* Check out of length */
667 	bcount = ntohs(q->rdlen);
668 
669 	/* Resource Record Name Filed */
670 	q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax);	/* XXX */
671 
672 	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
673 		return (NULL);
674 	else
675 		return ((u_char *) n + bcount);
676 }
677 
678 typedef struct {
679 	u_short		numnames;
680 }		NBTNsResourceNBSTAT;
681 
682 static u_char  *
683 AliasHandleResourceNBSTAT(
684     NBTNsResource * q,
685     char *pmax,
686     NBTArguments * nbtarg)
687 {
688 	NBTNsResourceNBSTAT *n;
689 	u_short bcount;
690 
691 	(void)nbtarg;
692 
693 	if (q == NULL || (char *)(q + 1) > pmax)
694 		return (NULL);
695 
696 	/* Forward to Resource NBSTAT position */
697 	n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
698 
699 	/* Check out of length */
700 	bcount = ntohs(q->rdlen);
701 
702 	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
703 		return (NULL);
704 	else
705 		return ((u_char *) n + bcount);
706 }
707 
708 static u_char  *
709 AliasHandleResource(
710     u_short count,
711     NBTNsResource * q,
712     char *pmax,
713     NBTArguments
714     * nbtarg)
715 {
716 	while (count != 0) {
717 		/* Resource Record Name Filed */
718 		q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
719 
720 		if (q == NULL || (char *)(q + 1) > pmax)
721 			break;
722 #ifdef LIBALIAS_DEBUG
723 		printf("type=%02x, count=%d\n", ntohs(q->type), count);
724 #endif
725 
726 		/* Type and Class filed */
727 		switch (ntohs(q->type)) {
728 		case RR_TYPE_NB:
729 			q = (NBTNsResource *) AliasHandleResourceNB(
730 			    q,
731 			    pmax,
732 			    nbtarg
733 			    );
734 			break;
735 		case RR_TYPE_A:
736 			q = (NBTNsResource *) AliasHandleResourceA(
737 			    q,
738 			    pmax,
739 			    nbtarg
740 			    );
741 			break;
742 		case RR_TYPE_NS:
743 			q = (NBTNsResource *) AliasHandleResourceNS(
744 			    q,
745 			    pmax,
746 			    nbtarg
747 			    );
748 			break;
749 		case RR_TYPE_NULL:
750 			q = (NBTNsResource *) AliasHandleResourceNULL(
751 			    q,
752 			    pmax,
753 			    nbtarg
754 			    );
755 			break;
756 		case RR_TYPE_NBSTAT:
757 			q = (NBTNsResource *) AliasHandleResourceNBSTAT(
758 			    q,
759 			    pmax,
760 			    nbtarg
761 			    );
762 			break;
763 		default:
764 #ifdef LIBALIAS_DEBUG
765 			printf(
766 			    "\nUnknown Type of Resource %0x\n",
767 			    ntohs(q->type)
768 			    );
769 			fflush(stdout);
770 #endif
771 			break;
772 		}
773 		count--;
774 	}
775 	return ((u_char *) q);
776 }
777 
778 static int
779 AliasHandleUdpNbtNS(
780     struct libalias *la,
781     struct ip *pip,		/* IP packet to examine/patch */
782     struct alias_link *lnk,
783     struct in_addr *alias_address,
784     u_short * alias_port,
785     struct in_addr *original_address,
786     u_short * original_port)
787 {
788 	struct udphdr *uh;
789 	NbtNSHeader *nsh;
790 	u_char *p;
791 	char *pmax;
792 	NBTArguments nbtarg;
793 
794 	(void)la;
795 	(void)lnk;
796 
797 	/* Set up Common Parameter */
798 	nbtarg.oldaddr = *alias_address;
799 	nbtarg.oldport = *alias_port;
800 	nbtarg.newaddr = *original_address;
801 	nbtarg.newport = *original_port;
802 
803 	/* Calculate data length of UDP packet */
804 	uh = (struct udphdr *)ip_next(pip);
805 	nbtarg.uh_sum = &(uh->uh_sum);
806 	nsh = (NbtNSHeader *)udp_next(uh);
807 	p = (u_char *) (nsh + 1);
808 	pmax = (char *)uh + ntohs(uh->uh_ulen);
809 
810 	if ((char *)(nsh + 1) > pmax)
811 		return (-1);
812 
813 #ifdef LIBALIAS_DEBUG
814 	printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
815 	    ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
816 	    nsh->dir ? "Response" : "Request",
817 	    nsh->nametrid,
818 	    nsh->opcode,
819 	    nsh->nmflags,
820 	    nsh->rcode,
821 	    ntohs(nsh->qdcount),
822 	    ntohs(nsh->ancount),
823 	    ntohs(nsh->nscount),
824 	    ntohs(nsh->arcount),
825 	    (u_char *) p - (u_char *) nsh
826 	    );
827 #endif
828 
829 	/* Question Entries */
830 	if (ntohs(nsh->qdcount) != 0) {
831 		p = AliasHandleQuestion(
832 		    ntohs(nsh->qdcount),
833 		    (NBTNsQuestion *) p,
834 		    pmax,
835 		    &nbtarg
836 		    );
837 	}
838 	/* Answer Resource Records */
839 	if (ntohs(nsh->ancount) != 0) {
840 		p = AliasHandleResource(
841 		    ntohs(nsh->ancount),
842 		    (NBTNsResource *) p,
843 		    pmax,
844 		    &nbtarg
845 		    );
846 	}
847 	/* Authority Resource Recodrs */
848 	if (ntohs(nsh->nscount) != 0) {
849 		p = AliasHandleResource(
850 		    ntohs(nsh->nscount),
851 		    (NBTNsResource *) p,
852 		    pmax,
853 		    &nbtarg
854 		    );
855 	}
856 	/* Additional Resource Recodrs */
857 	if (ntohs(nsh->arcount) != 0) {
858 		p = AliasHandleResource(
859 		    ntohs(nsh->arcount),
860 		    (NBTNsResource *) p,
861 		    pmax,
862 		    &nbtarg
863 		    );
864 	}
865 #ifdef LIBALIAS_DEBUG
866 	PrintRcode(nsh->rcode);
867 #endif
868 	return ((p == NULL) ? -1 : 0);
869 }
870