alias_nbt.c revision 296373
1254721Semaste/*-
2254721Semaste * Written by Atsushi Murai <amurai@spec.co.jp>
3254721Semaste * Copyright (c) 1998, System Planning and Engineering Co.
4254721Semaste * All rights reserved.
5254721Semaste *
6254721Semaste * Redistribution and use in source and binary forms, with or without
7254721Semaste * modification, are permitted provided that the following conditions
8254721Semaste * are met:
9254721Semaste * 1. Redistributions of source code must retain the above copyright
10254721Semaste *    notice, this list of conditions and the following disclaimer.
11254721Semaste * 2. Redistributions in binary form must reproduce the above copyright
12254721Semaste *    notice, this list of conditions and the following disclaimer in the
13254721Semaste *    documentation and/or other materials provided with the distribution.
14254721Semaste *
15254721Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16254721Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17254721Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18254721Semaste * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19254721Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20254721Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21254721Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22254721Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23254721Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24254721Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25254721Semaste * SUCH DAMAGE.
26254721Semaste *  TODO:
27254721Semaste *       oClean up.
28254721Semaste *       oConsidering for word alignment for other platform.
29254721Semaste */
30254721Semaste
31254721Semaste#include <sys/cdefs.h>
32254721Semaste__FBSDID("$FreeBSD: releng/10.3/sys/netinet/libalias/alias_nbt.c 190938 2009-04-11 15:19:09Z piso $");
33254721Semaste
34254721Semaste/*
35254721Semaste    alias_nbt.c performs special processing for NetBios over TCP/IP
36254721Semaste    sessions by UDP.
37254721Semaste
38254721Semaste    Initial version:  May, 1998  (Atsushi Murai <amurai@spec.co.jp>)
39254721Semaste
40254721Semaste    See HISTORY file for record of revisions.
41254721Semaste*/
42254721Semaste
43254721Semaste/* Includes */
44254721Semaste#ifdef _KERNEL
45254721Semaste#include <sys/param.h>
46254721Semaste#include <sys/systm.h>
47254721Semaste#include <sys/kernel.h>
48254721Semaste#include <sys/module.h>
49254721Semaste#else
50254721Semaste#include <errno.h>
51254721Semaste#include <sys/types.h>
52254721Semaste#include <stdio.h>
53254721Semaste#include <strings.h>
54254721Semaste#endif
55254721Semaste
56254721Semaste#include <netinet/in_systm.h>
57254721Semaste#include <netinet/in.h>
58254721Semaste#include <netinet/ip.h>
59254721Semaste#include <netinet/udp.h>
60254721Semaste
61254721Semaste#ifdef _KERNEL
62254721Semaste#include <netinet/libalias/alias_local.h>
63254721Semaste#include <netinet/libalias/alias_mod.h>
64254721Semaste#else
65254721Semaste#include "alias_local.h"
66254721Semaste#include "alias_mod.h"
67254721Semaste#endif
68254721Semaste
69254721Semaste#define NETBIOS_NS_PORT_NUMBER 137
70254721Semaste#define NETBIOS_DGM_PORT_NUMBER 138
71254721Semaste
72254721Semastestatic int
73254721SemasteAliasHandleUdpNbt(struct libalias *, struct ip *, struct alias_link *,
74254721Semaste		  struct in_addr *, u_short);
75254721Semaste
76254721Semastestatic int
77254721SemasteAliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
78254721Semaste		    struct in_addr *, u_short *, struct in_addr *, u_short *);
79254721Semastestatic int
80254721Semastefingerprint1(struct libalias *la, struct alias_data *ah)
81254721Semaste{
82254721Semaste
83254721Semaste	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
84254721Semaste	    ah->aaddr == NULL || ah->aport == NULL)
85254721Semaste		return (-1);
86254721Semaste	if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
87254721Semaste	    || ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
88254721Semaste		return (0);
89254721Semaste	return (-1);
90254721Semaste}
91254721Semaste
92254721Semastestatic int
93254721Semasteprotohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
94254721Semaste{
95254721Semaste
96254721Semaste	return (AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport));
97254721Semaste}
98254721Semaste
99254721Semastestatic int
100254721Semastefingerprint2(struct libalias *la, struct alias_data *ah)
101254721Semaste{
102254721Semaste
103254721Semaste	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
104254721Semaste	    ah->aaddr == NULL || ah->aport == NULL)
105254721Semaste		return (-1);
106254721Semaste	if (ntohs(*ah->dport) == NETBIOS_NS_PORT_NUMBER
107254721Semaste	    || ntohs(*ah->sport) == NETBIOS_NS_PORT_NUMBER)
108254721Semaste		return (0);
109254721Semaste	return (-1);
110254721Semaste}
111254721Semaste
112254721Semastestatic int
113254721Semasteprotohandler2in(struct libalias *la, struct ip *pip, struct alias_data *ah)
114254721Semaste{
115254721Semaste
116254721Semaste	AliasHandleUdpNbtNS(la, pip, ah->lnk, ah->aaddr, ah->aport,
117254721Semaste 			    ah->oaddr, ah->dport);
118254721Semaste	return (0);
119254721Semaste}
120254721Semaste
121254721Semastestatic int
122254721Semasteprotohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
123254721Semaste{
124254721Semaste
125254721Semaste	return (AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
126254721Semaste 	    ah->aaddr, ah->aport));
127254721Semaste}
128254721Semaste
129254721Semaste/* Kernel module definition. */
130254721Semastestruct proto_handler handlers[] = {
131254721Semaste	{
132254721Semaste	  .pri = 130,
133254721Semaste	  .dir = IN|OUT,
134254721Semaste	  .proto = UDP,
135254721Semaste	  .fingerprint = &fingerprint1,
136254721Semaste	  .protohandler = &protohandler1
137254721Semaste	},
138254721Semaste	{
139254721Semaste	  .pri = 140,
140254721Semaste	  .dir = IN,
141254721Semaste	  .proto = UDP,
142254721Semaste	  .fingerprint = &fingerprint2,
143254721Semaste	  .protohandler = &protohandler2in
144254721Semaste	},
145254721Semaste	{
146254721Semaste	  .pri = 140,
147254721Semaste	  .dir = OUT,
148254721Semaste	  .proto = UDP,
149254721Semaste	  .fingerprint = &fingerprint2,
150254721Semaste	  .protohandler = &protohandler2out
151254721Semaste	},
152254721Semaste	{ EOH }
153254721Semaste};
154254721Semaste
155254721Semastestatic int
156254721Semastemod_handler(module_t mod, int type, void *data)
157254721Semaste{
158254721Semaste	int error;
159254721Semaste
160254721Semaste	switch (type) {
161254721Semaste	case MOD_LOAD:
162254721Semaste		error = 0;
163254721Semaste		LibAliasAttachHandlers(handlers);
164254721Semaste		break;
165254721Semaste	case MOD_UNLOAD:
166254721Semaste		error = 0;
167254721Semaste		LibAliasDetachHandlers(handlers);
168254721Semaste		break;
169254721Semaste	default:
170254721Semaste		error = EINVAL;
171254721Semaste	}
172254721Semaste	return (error);
173254721Semaste}
174254721Semaste
175254721Semaste#ifdef	_KERNEL
176254721Semastestatic
177254721Semaste#endif
178254721Semastemoduledata_t alias_mod = {
179254721Semaste       "alias_nbt", mod_handler, NULL
180254721Semaste};
181254721Semaste
182254721Semaste#ifdef	_KERNEL
183254721SemasteDECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
184254721SemasteMODULE_VERSION(alias_nbt, 1);
185254721SemasteMODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
186254721Semaste#endif
187254721Semaste
188254721Semastetypedef struct {
189254721Semaste	struct in_addr	oldaddr;
190254721Semaste	u_short		oldport;
191254721Semaste	struct in_addr	newaddr;
192254721Semaste	u_short		newport;
193254721Semaste	u_short        *uh_sum;
194254721Semaste}		NBTArguments;
195254721Semaste
196254721Semastetypedef struct {
197254721Semaste	unsigned char	type;
198254721Semaste	unsigned char	flags;
199254721Semaste	u_short		id;
200254721Semaste	struct in_addr	source_ip;
201254721Semaste	u_short		source_port;
202254721Semaste	u_short		len;
203254721Semaste	u_short		offset;
204254721Semaste}		NbtDataHeader;
205254721Semaste
206254721Semaste#define OpQuery		0
207254721Semaste#define OpUnknown	4
208254721Semaste#define OpRegist	5
209254721Semaste#define OpRelease	6
210254721Semaste#define OpWACK		7
211254721Semaste#define OpRefresh	8
212254721Semastetypedef struct {
213254721Semaste	u_short		nametrid;
214254721Semaste	u_short		dir:	1, opcode:4, nmflags:7, rcode:4;
215254721Semaste	u_short		qdcount;
216254721Semaste	u_short		ancount;
217254721Semaste	u_short		nscount;
218254721Semaste	u_short		arcount;
219254721Semaste}		NbtNSHeader;
220254721Semaste
221254721Semaste#define FMT_ERR		0x1
222254721Semaste#define SRV_ERR		0x2
223254721Semaste#define IMP_ERR		0x4
224254721Semaste#define RFS_ERR		0x5
225254721Semaste#define ACT_ERR		0x6
226254721Semaste#define CFT_ERR		0x7
227254721Semaste
228254721Semaste
229254721Semaste#ifdef LIBALIAS_DEBUG
230254721Semastestatic void
231254721SemastePrintRcode(u_char rcode)
232254721Semaste{
233254721Semaste
234254721Semaste	switch (rcode) {
235254721Semaste		case FMT_ERR:
236254721Semaste		printf("\nFormat Error.");
237254721Semaste	case SRV_ERR:
238254721Semaste		printf("\nSever failure.");
239254721Semaste	case IMP_ERR:
240254721Semaste		printf("\nUnsupported request error.\n");
241254721Semaste	case RFS_ERR:
242254721Semaste		printf("\nRefused error.\n");
243254721Semaste	case ACT_ERR:
244254721Semaste		printf("\nActive error.\n");
245254721Semaste	case CFT_ERR:
246254721Semaste		printf("\nName in conflict error.\n");
247254721Semaste	default:
248254721Semaste		printf("\n?%c?=%0x\n", '?', rcode);
249254721Semaste
250254721Semaste	}
251254721Semaste}
252254721Semaste
253254721Semaste#endif
254254721Semaste
255254721Semaste
256254721Semaste/* Handling Name field */
257254721Semastestatic u_char  *
258254721SemasteAliasHandleName(u_char * p, char *pmax)
259254721Semaste{
260254721Semaste
261254721Semaste	u_char *s;
262254721Semaste	u_char c;
263254721Semaste	int compress;
264254721Semaste
265254721Semaste	/* Following length field */
266254721Semaste
267254721Semaste	if (p == NULL || (char *)p >= pmax)
268254721Semaste		return (NULL);
269254721Semaste
270254721Semaste	if (*p & 0xc0) {
271254721Semaste		p = p + 2;
272254721Semaste		if ((char *)p > pmax)
273254721Semaste			return (NULL);
274254721Semaste		return ((u_char *) p);
275254721Semaste	}
276254721Semaste	while ((*p & 0x3f) != 0x00) {
277254721Semaste		s = p + 1;
278254721Semaste		if (*p == 0x20)
279254721Semaste			compress = 1;
280254721Semaste		else
281254721Semaste			compress = 0;
282254721Semaste
283254721Semaste		/* Get next length field */
284254721Semaste		p = (u_char *) (p + (*p & 0x3f) + 1);
285254721Semaste		if ((char *)p > pmax) {
286254721Semaste			p = NULL;
287254721Semaste			break;
288254721Semaste		}
289254721Semaste#ifdef LIBALIAS_DEBUG
290254721Semaste		printf(":");
291254721Semaste#endif
292254721Semaste		while (s < p) {
293254721Semaste			if (compress == 1) {
294254721Semaste				c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
295254721Semaste#ifdef LIBALIAS_DEBUG
296254721Semaste				if (isprint(c))
297254721Semaste					printf("%c", c);
298254721Semaste				else
299254721Semaste					printf("<0x%02x>", c);
300254721Semaste#endif
301254721Semaste				s += 2;
302254721Semaste			} else {
303254721Semaste#ifdef LIBALIAS_DEBUG
304254721Semaste				printf("%c", *s);
305254721Semaste#endif
306254721Semaste				s++;
307254721Semaste			}
308254721Semaste		}
309254721Semaste#ifdef LIBALIAS_DEBUG
310254721Semaste		printf(":");
311254721Semaste		fflush(stdout);
312254721Semaste#endif
313254721Semaste	}
314254721Semaste
315254721Semaste	/* Set up to out of Name field */
316254721Semaste	if (p == NULL || (char *)p >= pmax)
317254721Semaste		p = NULL;
318254721Semaste	else
319254721Semaste		p++;
320254721Semaste	return ((u_char *) p);
321254721Semaste}
322254721Semaste
323254721Semaste/*
324254721Semaste * NetBios Datagram Handler (IP/UDP)
325254721Semaste */
326254721Semaste#define DGM_DIRECT_UNIQ		0x10
327254721Semaste#define DGM_DIRECT_GROUP	0x11
328254721Semaste#define DGM_BROADCAST		0x12
329254721Semaste#define DGM_ERROR			0x13
330254721Semaste#define DGM_QUERY			0x14
331254721Semaste#define DGM_POSITIVE_RES	0x15
332254721Semaste#define DGM_NEGATIVE_RES	0x16
333254721Semaste
334254721Semastestatic int
335254721SemasteAliasHandleUdpNbt(
336254721Semaste    struct libalias *la,
337254721Semaste    struct ip *pip,		/* IP packet to examine/patch */
338254721Semaste    struct alias_link *lnk,
339254721Semaste    struct in_addr *alias_address,
340254721Semaste    u_short alias_port
341254721Semaste)
342254721Semaste{
343254721Semaste	struct udphdr *uh;
344254721Semaste	NbtDataHeader *ndh;
345254721Semaste	u_char *p = NULL;
346254721Semaste	char *pmax;
347254721Semaste
348254721Semaste	(void)la;
349254721Semaste	(void)lnk;
350254721Semaste
351254721Semaste	/* Calculate data length of UDP packet */
352254721Semaste	uh = (struct udphdr *)ip_next(pip);
353254721Semaste	pmax = (char *)uh + ntohs(uh->uh_ulen);
354
355	ndh = (NbtDataHeader *)udp_next(uh);
356	if ((char *)(ndh + 1) > pmax)
357		return (-1);
358#ifdef LIBALIAS_DEBUG
359	printf("\nType=%02x,", ndh->type);
360#endif
361	switch (ndh->type) {
362	case DGM_DIRECT_UNIQ:
363	case DGM_DIRECT_GROUP:
364	case DGM_BROADCAST:
365		p = (u_char *) ndh + 14;
366		p = AliasHandleName(p, pmax);	/* Source Name */
367		p = AliasHandleName(p, pmax);	/* Destination Name */
368		break;
369	case DGM_ERROR:
370		p = (u_char *) ndh + 11;
371		break;
372	case DGM_QUERY:
373	case DGM_POSITIVE_RES:
374	case DGM_NEGATIVE_RES:
375		p = (u_char *) ndh + 10;
376		p = AliasHandleName(p, pmax);	/* Destination Name */
377		break;
378	}
379	if (p == NULL || (char *)p > pmax)
380		p = NULL;
381#ifdef LIBALIAS_DEBUG
382	printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
383#endif
384	/* Doing an IP address and Port number Translation */
385	if (uh->uh_sum != 0) {
386		int acc;
387		u_short *sptr;
388
389		acc = ndh->source_port;
390		acc -= alias_port;
391		sptr = (u_short *) & (ndh->source_ip);
392		acc += *sptr++;
393		acc += *sptr;
394		sptr = (u_short *) alias_address;
395		acc -= *sptr++;
396		acc -= *sptr;
397		ADJUST_CHECKSUM(acc, uh->uh_sum);
398	}
399	ndh->source_ip = *alias_address;
400	ndh->source_port = alias_port;
401#ifdef LIBALIAS_DEBUG
402	printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
403	fflush(stdout);
404#endif
405	return ((p == NULL) ? -1 : 0);
406}
407
408/* Question Section */
409#define QS_TYPE_NB		0x0020
410#define QS_TYPE_NBSTAT	0x0021
411#define QS_CLAS_IN		0x0001
412typedef struct {
413	u_short		type;	/* The type of Request */
414	u_short		class;	/* The class of Request */
415}		NBTNsQuestion;
416
417static u_char  *
418AliasHandleQuestion(
419    u_short count,
420    NBTNsQuestion * q,
421    char *pmax,
422    NBTArguments * nbtarg)
423{
424
425	(void)nbtarg;
426
427	while (count != 0) {
428		/* Name Filed */
429		q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
430
431		if (q == NULL || (char *)(q + 1) > pmax) {
432			q = NULL;
433			break;
434		}
435		/* Type and Class filed */
436		switch (ntohs(q->type)) {
437		case QS_TYPE_NB:
438		case QS_TYPE_NBSTAT:
439			q = q + 1;
440			break;
441		default:
442#ifdef LIBALIAS_DEBUG
443			printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
444#endif
445			break;
446		}
447		count--;
448	}
449
450	/* Set up to out of Question Section */
451	return ((u_char *) q);
452}
453
454/* Resource Record */
455#define RR_TYPE_A		0x0001
456#define RR_TYPE_NS		0x0002
457#define RR_TYPE_NULL	0x000a
458#define RR_TYPE_NB		0x0020
459#define RR_TYPE_NBSTAT	0x0021
460#define RR_CLAS_IN		0x0001
461#define SizeOfNsResource	8
462typedef struct {
463	u_short		type;
464	u_short		class;
465	unsigned int	ttl;
466	u_short		rdlen;
467}		NBTNsResource;
468
469#define SizeOfNsRNB			6
470typedef struct {
471	u_short		g:	1  , ont:2, resv:13;
472	struct in_addr	addr;
473}		NBTNsRNB;
474
475static u_char  *
476AliasHandleResourceNB(
477    NBTNsResource * q,
478    char *pmax,
479    NBTArguments * nbtarg)
480{
481	NBTNsRNB *nb;
482	u_short bcount;
483
484	if (q == NULL || (char *)(q + 1) > pmax)
485		return (NULL);
486	/* Check out a length */
487	bcount = ntohs(q->rdlen);
488
489	/* Forward to Resource NB position */
490	nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
491
492	/* Processing all in_addr array */
493#ifdef LIBALIAS_DEBUG
494	printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
495	printf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount);
496#endif
497	while (nb != NULL && bcount != 0) {
498		if ((char *)(nb + 1) > pmax) {
499			nb = NULL;
500			break;
501		}
502#ifdef LIBALIAS_DEBUG
503		printf("<%s>", inet_ntoa(nb->addr));
504#endif
505		if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
506			if (*nbtarg->uh_sum != 0) {
507				int acc;
508				u_short *sptr;
509
510				sptr = (u_short *) & (nb->addr);
511				acc = *sptr++;
512				acc += *sptr;
513				sptr = (u_short *) & (nbtarg->newaddr);
514				acc -= *sptr++;
515				acc -= *sptr;
516				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
517			}
518			nb->addr = nbtarg->newaddr;
519#ifdef LIBALIAS_DEBUG
520			printf("O");
521#endif
522		}
523#ifdef LIBALIAS_DEBUG
524		else {
525			printf(".");
526		}
527#endif
528		nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
529		bcount -= SizeOfNsRNB;
530	}
531	if (nb == NULL || (char *)(nb + 1) > pmax) {
532		nb = NULL;
533	}
534	return ((u_char *) nb);
535}
536
537#define SizeOfResourceA		6
538typedef struct {
539	struct in_addr	addr;
540}		NBTNsResourceA;
541
542static u_char  *
543AliasHandleResourceA(
544    NBTNsResource * q,
545    char *pmax,
546    NBTArguments * nbtarg)
547{
548	NBTNsResourceA *a;
549	u_short bcount;
550
551	if (q == NULL || (char *)(q + 1) > pmax)
552		return (NULL);
553
554	/* Forward to Resource A position */
555	a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
556
557	/* Check out of length */
558	bcount = ntohs(q->rdlen);
559
560	/* Processing all in_addr array */
561#ifdef LIBALIAS_DEBUG
562	printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
563	printf("->%s]", inet_ntoa(nbtarg->newaddr));
564#endif
565	while (bcount != 0) {
566		if (a == NULL || (char *)(a + 1) > pmax)
567			return (NULL);
568#ifdef LIBALIAS_DEBUG
569		printf("..%s", inet_ntoa(a->addr));
570#endif
571		if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
572			if (*nbtarg->uh_sum != 0) {
573				int acc;
574				u_short *sptr;
575
576				sptr = (u_short *) & (a->addr);	/* Old */
577				acc = *sptr++;
578				acc += *sptr;
579				sptr = (u_short *) & nbtarg->newaddr;	/* New */
580				acc -= *sptr++;
581				acc -= *sptr;
582				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
583			}
584			a->addr = nbtarg->newaddr;
585		}
586		a++;		/* XXXX */
587		bcount -= SizeOfResourceA;
588	}
589	if (a == NULL || (char *)(a + 1) > pmax)
590		a = NULL;
591	return ((u_char *) a);
592}
593
594typedef struct {
595	u_short		opcode:4, flags:8, resv:4;
596}		NBTNsResourceNULL;
597
598static u_char  *
599AliasHandleResourceNULL(
600    NBTNsResource * q,
601    char *pmax,
602    NBTArguments * nbtarg)
603{
604	NBTNsResourceNULL *n;
605	u_short bcount;
606
607	(void)nbtarg;
608
609	if (q == NULL || (char *)(q + 1) > pmax)
610		return (NULL);
611
612	/* Forward to Resource NULL position */
613	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
614
615	/* Check out of length */
616	bcount = ntohs(q->rdlen);
617
618	/* Processing all in_addr array */
619	while (bcount != 0) {
620		if ((char *)(n + 1) > pmax) {
621			n = NULL;
622			break;
623		}
624		n++;
625		bcount -= sizeof(NBTNsResourceNULL);
626	}
627	if ((char *)(n + 1) > pmax)
628		n = NULL;
629
630	return ((u_char *) n);
631}
632
633static u_char  *
634AliasHandleResourceNS(
635    NBTNsResource * q,
636    char *pmax,
637    NBTArguments * nbtarg)
638{
639	NBTNsResourceNULL *n;
640	u_short bcount;
641
642	(void)nbtarg;
643
644	if (q == NULL || (char *)(q + 1) > pmax)
645		return (NULL);
646
647	/* Forward to Resource NULL position */
648	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
649
650	/* Check out of length */
651	bcount = ntohs(q->rdlen);
652
653	/* Resource Record Name Filed */
654	q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax);	/* XXX */
655
656	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
657		return (NULL);
658	else
659		return ((u_char *) n + bcount);
660}
661
662typedef struct {
663	u_short		numnames;
664}		NBTNsResourceNBSTAT;
665
666static u_char  *
667AliasHandleResourceNBSTAT(
668    NBTNsResource * q,
669    char *pmax,
670    NBTArguments * nbtarg)
671{
672	NBTNsResourceNBSTAT *n;
673	u_short bcount;
674
675	(void)nbtarg;
676
677	if (q == NULL || (char *)(q + 1) > pmax)
678		return (NULL);
679
680	/* Forward to Resource NBSTAT position */
681	n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
682
683	/* Check out of length */
684	bcount = ntohs(q->rdlen);
685
686	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
687		return (NULL);
688	else
689		return ((u_char *) n + bcount);
690}
691
692static u_char  *
693AliasHandleResource(
694    u_short count,
695    NBTNsResource * q,
696    char *pmax,
697    NBTArguments
698    * nbtarg)
699{
700	while (count != 0) {
701		/* Resource Record Name Filed */
702		q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
703
704		if (q == NULL || (char *)(q + 1) > pmax)
705			break;
706#ifdef LIBALIAS_DEBUG
707		printf("type=%02x, count=%d\n", ntohs(q->type), count);
708#endif
709
710		/* Type and Class filed */
711		switch (ntohs(q->type)) {
712		case RR_TYPE_NB:
713			q = (NBTNsResource *) AliasHandleResourceNB(
714			    q,
715			    pmax,
716			    nbtarg
717			    );
718			break;
719		case RR_TYPE_A:
720			q = (NBTNsResource *) AliasHandleResourceA(
721			    q,
722			    pmax,
723			    nbtarg
724			    );
725			break;
726		case RR_TYPE_NS:
727			q = (NBTNsResource *) AliasHandleResourceNS(
728			    q,
729			    pmax,
730			    nbtarg
731			    );
732			break;
733		case RR_TYPE_NULL:
734			q = (NBTNsResource *) AliasHandleResourceNULL(
735			    q,
736			    pmax,
737			    nbtarg
738			    );
739			break;
740		case RR_TYPE_NBSTAT:
741			q = (NBTNsResource *) AliasHandleResourceNBSTAT(
742			    q,
743			    pmax,
744			    nbtarg
745			    );
746			break;
747		default:
748#ifdef LIBALIAS_DEBUG
749			printf(
750			    "\nUnknown Type of Resource %0x\n",
751			    ntohs(q->type)
752			    );
753			fflush(stdout);
754#endif
755			break;
756		}
757		count--;
758	}
759	return ((u_char *) q);
760}
761
762static int
763AliasHandleUdpNbtNS(
764    struct libalias *la,
765    struct ip *pip,		/* IP packet to examine/patch */
766    struct alias_link *lnk,
767    struct in_addr *alias_address,
768    u_short * alias_port,
769    struct in_addr *original_address,
770    u_short * original_port)
771{
772	struct udphdr *uh;
773	NbtNSHeader *nsh;
774	u_char *p;
775	char *pmax;
776	NBTArguments nbtarg;
777
778	(void)la;
779	(void)lnk;
780
781	/* Set up Common Parameter */
782	nbtarg.oldaddr = *alias_address;
783	nbtarg.oldport = *alias_port;
784	nbtarg.newaddr = *original_address;
785	nbtarg.newport = *original_port;
786
787	/* Calculate data length of UDP packet */
788	uh = (struct udphdr *)ip_next(pip);
789	nbtarg.uh_sum = &(uh->uh_sum);
790	nsh = (NbtNSHeader *)udp_next(uh);
791	p = (u_char *) (nsh + 1);
792	pmax = (char *)uh + ntohs(uh->uh_ulen);
793
794	if ((char *)(nsh + 1) > pmax)
795		return (-1);
796
797#ifdef LIBALIAS_DEBUG
798	printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
799	    ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
800	    nsh->dir ? "Response" : "Request",
801	    nsh->nametrid,
802	    nsh->opcode,
803	    nsh->nmflags,
804	    nsh->rcode,
805	    ntohs(nsh->qdcount),
806	    ntohs(nsh->ancount),
807	    ntohs(nsh->nscount),
808	    ntohs(nsh->arcount),
809	    (u_char *) p - (u_char *) nsh
810	    );
811#endif
812
813	/* Question Entries */
814	if (ntohs(nsh->qdcount) != 0) {
815		p = AliasHandleQuestion(
816		    ntohs(nsh->qdcount),
817		    (NBTNsQuestion *) p,
818		    pmax,
819		    &nbtarg
820		    );
821	}
822	/* Answer Resource Records */
823	if (ntohs(nsh->ancount) != 0) {
824		p = AliasHandleResource(
825		    ntohs(nsh->ancount),
826		    (NBTNsResource *) p,
827		    pmax,
828		    &nbtarg
829		    );
830	}
831	/* Authority Resource Recodrs */
832	if (ntohs(nsh->nscount) != 0) {
833		p = AliasHandleResource(
834		    ntohs(nsh->nscount),
835		    (NBTNsResource *) p,
836		    pmax,
837		    &nbtarg
838		    );
839	}
840	/* Additional Resource Recodrs */
841	if (ntohs(nsh->arcount) != 0) {
842		p = AliasHandleResource(
843		    ntohs(nsh->arcount),
844		    (NBTNsResource *) p,
845		    pmax,
846		    &nbtarg
847		    );
848	}
849#ifdef LIBALIAS_DEBUG
850	PrintRcode(nsh->rcode);
851#endif
852	return ((p == NULL) ? -1 : 0);
853}
854