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