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