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