alias_nbt.c revision 190841
177696Sbrian/*-
236321Samurai * Written by Atsushi Murai <amurai@spec.co.jp>
377696Sbrian * Copyright (c) 1998, System Planning and Engineering Co.
477696Sbrian * All rights reserved.
536321Samurai *
677696Sbrian * Redistribution and use in source and binary forms, with or without
777696Sbrian * modification, are permitted provided that the following conditions
877696Sbrian * are met:
977696Sbrian * 1. Redistributions of source code must retain the above copyright
1077696Sbrian *    notice, this list of conditions and the following disclaimer.
1177696Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1277696Sbrian *    notice, this list of conditions and the following disclaimer in the
1377696Sbrian *    documentation and/or other materials provided with the distribution.
1436321Samurai *
1577696Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1677696Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1777696Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1877696Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1977696Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2077696Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2177696Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2277696Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2377696Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2477696Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2577696Sbrian * SUCH DAMAGE.
2636321Samurai *  TODO:
2799207Sbrian *       oClean up.
2836321Samurai *       oConsidering for word alignment for other platform.
2936321Samurai */
3084195Sdillon
3184195Sdillon#include <sys/cdefs.h>
3284195Sdillon__FBSDID("$FreeBSD: head/sys/netinet/libalias/alias_nbt.c 190841 2009-04-08 11:56:49Z piso $");
3384195Sdillon
3436321Samurai/*
3536321Samurai    alias_nbt.c performs special processing for NetBios over TCP/IP
3636321Samurai    sessions by UDP.
3736321Samurai
3836321Samurai    Initial version:  May, 1998  (Atsushi Murai <amurai@spec.co.jp>)
3936321Samurai
4036321Samurai    See HISTORY file for record of revisions.
4136321Samurai*/
4236321Samurai
4336321Samurai/* Includes */
44145921Sglebius#ifdef _KERNEL
45145921Sglebius#include <sys/param.h>
46162674Spiso#include <sys/systm.h>
47162674Spiso#include <sys/kernel.h>
48162674Spiso#include <sys/module.h>
49145921Sglebius#else
50162674Spiso#include <errno.h>
51145921Sglebius#include <sys/types.h>
5299207Sbrian#include <stdio.h>
53187304Spiso#include <strings.h>
54145921Sglebius#endif
55145921Sglebius
5636321Samurai#include <netinet/in_systm.h>
5736321Samurai#include <netinet/in.h>
5836321Samurai#include <netinet/ip.h>
5936321Samurai#include <netinet/udp.h>
6036321Samurai
61145921Sglebius#ifdef _KERNEL
62145921Sglebius#include <netinet/libalias/alias_local.h>
63162674Spiso#include <netinet/libalias/alias_mod.h>
64145921Sglebius#else
6536321Samurai#include "alias_local.h"
66162674Spiso#include "alias_mod.h"
67145921Sglebius#endif
6836321Samurai
69162674Spiso#define NETBIOS_NS_PORT_NUMBER 137
70162674Spiso#define NETBIOS_DGM_PORT_NUMBER 138
71162674Spiso
72162674Spisostatic int
73162674SpisoAliasHandleUdpNbt(struct libalias *, struct ip *, struct alias_link *,
74162674Spiso		  struct in_addr *, u_short);
75162674Spiso
76162674Spisostatic int
77162674SpisoAliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
78162674Spiso		    struct in_addr *, u_short *, struct in_addr *, u_short *);
79162674Spisostatic int
80190841Spisofingerprint1(struct libalias *la, struct alias_data *ah)
81162674Spiso{
82162674Spiso
83162674Spiso	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
84162674Spiso	    ah->aaddr == NULL || ah->aport == NULL)
85162674Spiso		return (-1);
86162674Spiso	if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
87162674Spiso	    || ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
88162674Spiso		return (0);
89162674Spiso	return (-1);
90162674Spiso}
91162674Spiso
92162674Spisostatic int
93162674Spisoprotohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
94162674Spiso{
95162674Spiso
96162674Spiso	AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport);
97162674Spiso	return (0);
98162674Spiso}
99162674Spiso
100162674Spisostatic int
101190841Spisofingerprint2(struct libalias *la, struct alias_data *ah)
102162674Spiso{
103162674Spiso
104162674Spiso	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
105162674Spiso	    ah->aaddr == NULL || ah->aport == NULL)
106162674Spiso		return (-1);
107162674Spiso	if (ntohs(*ah->dport) == NETBIOS_NS_PORT_NUMBER
108162674Spiso	    || ntohs(*ah->sport) == NETBIOS_NS_PORT_NUMBER)
109162674Spiso		return (0);
110162674Spiso	return (-1);
111162674Spiso}
112162674Spiso
113162674Spisostatic int
114162674Spisoprotohandler2in(struct libalias *la, struct ip *pip, struct alias_data *ah)
115162674Spiso{
116162674Spiso
117162674Spiso	AliasHandleUdpNbtNS(la, pip, ah->lnk, ah->aaddr, ah->aport,
118162674Spiso 			    ah->oaddr, ah->dport);
119162674Spiso	return (0);
120162674Spiso}
121162674Spiso
122162674Spisostatic int
123162674Spisoprotohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
124162674Spiso{
125162674Spiso
126162674Spiso	AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
127162674Spiso 			    ah->aaddr, ah->aport);
128162674Spiso	return (0);
129162674Spiso}
130162674Spiso
131162674Spiso/* Kernel module definition. */
132162674Spisostruct proto_handler handlers[] = {
133162674Spiso	{
134162674Spiso	  .pri = 130,
135162674Spiso	  .dir = IN|OUT,
136162674Spiso	  .proto = UDP,
137162674Spiso	  .fingerprint = &fingerprint1,
138162674Spiso	  .protohandler = &protohandler1
139162674Spiso	},
140162674Spiso	{
141162674Spiso	  .pri = 140,
142162674Spiso	  .dir = IN,
143162674Spiso	  .proto = UDP,
144162674Spiso	  .fingerprint = &fingerprint2,
145162674Spiso	  .protohandler = &protohandler2in
146162674Spiso	},
147162674Spiso	{
148162674Spiso	  .pri = 140,
149162674Spiso	  .dir = OUT,
150162674Spiso	  .proto = UDP,
151162674Spiso	  .fingerprint = &fingerprint2,
152162674Spiso	  .protohandler = &protohandler2out
153162674Spiso	},
154162674Spiso	{ EOH }
155162674Spiso};
156162674Spiso
157162674Spisostatic int
158162674Spisomod_handler(module_t mod, int type, void *data)
159162674Spiso{
160162674Spiso	int error;
161162674Spiso
162162674Spiso	switch (type) {
163162674Spiso	case MOD_LOAD:
164162674Spiso		error = 0;
165162674Spiso		LibAliasAttachHandlers(handlers);
166162674Spiso		break;
167162674Spiso	case MOD_UNLOAD:
168162674Spiso		error = 0;
169162674Spiso		LibAliasDetachHandlers(handlers);
170162674Spiso		break;
171162674Spiso	default:
172162674Spiso		error = EINVAL;
173162674Spiso	}
174162674Spiso	return (error);
175162674Spiso}
176162674Spiso
177162674Spiso#ifdef	_KERNEL
178162674Spisostatic
179162674Spiso#endif
180162674Spisomoduledata_t alias_mod = {
181162674Spiso       "alias_nbt", mod_handler, NULL
182162674Spiso};
183162674Spiso
184162674Spiso#ifdef	_KERNEL
185162674SpisoDECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
186162674SpisoMODULE_VERSION(alias_nbt, 1);
187162674SpisoMODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
188162674Spiso#endif
189162674Spiso
19036321Samuraitypedef struct {
191127094Sdes	struct in_addr	oldaddr;
192127094Sdes	u_short		oldport;
193127094Sdes	struct in_addr	newaddr;
194127094Sdes	u_short		newport;
195127094Sdes	u_short        *uh_sum;
196127094Sdes}		NBTArguments;
19736321Samurai
19836321Samuraitypedef struct {
199127094Sdes	unsigned char	type;
200127094Sdes	unsigned char	flags;
201127094Sdes	u_short		id;
202127094Sdes	struct in_addr	source_ip;
203127094Sdes	u_short		source_port;
204127094Sdes	u_short		len;
205127094Sdes	u_short		offset;
206127094Sdes}		NbtDataHeader;
20736321Samurai
20836321Samurai#define OpQuery		0
20936321Samurai#define OpUnknown	4
21036321Samurai#define OpRegist	5
21136321Samurai#define OpRelease	6
21236321Samurai#define OpWACK		7
21336321Samurai#define OpRefresh	8
21436321Samuraitypedef struct {
215127094Sdes	u_short		nametrid;
216127094Sdes	u_short		dir:	1, opcode:4, nmflags:7, rcode:4;
217127094Sdes	u_short		qdcount;
218127094Sdes	u_short		ancount;
219127094Sdes	u_short		nscount;
220127094Sdes	u_short		arcount;
221127094Sdes}		NbtNSHeader;
22236321Samurai
22336321Samurai#define FMT_ERR		0x1
22436321Samurai#define SRV_ERR		0x2
22536321Samurai#define IMP_ERR		0x4
22636321Samurai#define RFS_ERR		0x5
22736321Samurai#define ACT_ERR		0x6
22836321Samurai#define CFT_ERR		0x7
22936321Samurai
23036321Samurai
231145961Sglebius#ifdef LIBALIAS_DEBUG
232127094Sdesstatic void
233127094SdesPrintRcode(u_char rcode)
234127094Sdes{
23536321Samurai
23636321Samurai	switch (rcode) {
23736321Samurai		case FMT_ERR:
238127094Sdes		printf("\nFormat Error.");
239127094Sdes	case SRV_ERR:
240127094Sdes		printf("\nSever failure.");
241127094Sdes	case IMP_ERR:
242127094Sdes		printf("\nUnsupported request error.\n");
243127094Sdes	case RFS_ERR:
244127094Sdes		printf("\nRefused error.\n");
245127094Sdes	case ACT_ERR:
246127094Sdes		printf("\nActive error.\n");
247127094Sdes	case CFT_ERR:
248127094Sdes		printf("\nName in conflict error.\n");
249127094Sdes	default:
250127094Sdes		printf("\n?%c?=%0x\n", '?', rcode);
25136321Samurai
25299207Sbrian	}
25336321Samurai}
254127094Sdes
25544616Sbrian#endif
25636321Samurai
25736321Samurai
25836321Samurai/* Handling Name field */
259127094Sdesstatic u_char  *
260127094SdesAliasHandleName(u_char * p, char *pmax)
261127094Sdes{
26236321Samurai
26336321Samurai	u_char *s;
26436321Samurai	u_char c;
265127094Sdes	int compress;
26636321Samurai
26736321Samurai	/* Following length field */
26841759Sdillon
26941759Sdillon	if (p == NULL || (char *)p >= pmax)
270127094Sdes		return (NULL);
27141759Sdillon
272127094Sdes	if (*p & 0xc0) {
27336321Samurai		p = p + 2;
27441759Sdillon		if ((char *)p > pmax)
275127094Sdes			return (NULL);
276127094Sdes		return ((u_char *) p);
27736321Samurai	}
278127094Sdes	while ((*p & 0x3f) != 0x00) {
27936321Samurai		s = p + 1;
280127094Sdes		if (*p == 0x20)
28136321Samurai			compress = 1;
28236321Samurai		else
28336321Samurai			compress = 0;
28499207Sbrian
285127094Sdes		/* Get next length field */
286127094Sdes		p = (u_char *) (p + (*p & 0x3f) + 1);
28741759Sdillon		if ((char *)p > pmax) {
28841759Sdillon			p = NULL;
28941759Sdillon			break;
29041759Sdillon		}
291145961Sglebius#ifdef LIBALIAS_DEBUG
29236321Samurai		printf(":");
29336321Samurai#endif
29436321Samurai		while (s < p) {
295127094Sdes			if (compress == 1) {
296127094Sdes				c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
297145961Sglebius#ifdef LIBALIAS_DEBUG
298127094Sdes				if (isprint(c))
299127094Sdes					printf("%c", c);
30036321Samurai				else
301127094Sdes					printf("<0x%02x>", c);
30236321Samurai#endif
303127094Sdes				s += 2;
30436321Samurai			} else {
305145961Sglebius#ifdef LIBALIAS_DEBUG
30636321Samurai				printf("%c", *s);
30736321Samurai#endif
30836321Samurai				s++;
30936321Samurai			}
31036321Samurai		}
311145961Sglebius#ifdef LIBALIAS_DEBUG
31236321Samurai		printf(":");
313145928Sglebius		fflush(stdout);
31436321Samurai#endif
315127094Sdes	}
31636321Samurai
31736321Samurai	/* Set up to out of Name field */
31841759Sdillon	if (p == NULL || (char *)p >= pmax)
319127094Sdes		p = NULL;
32041759Sdillon	else
321127094Sdes		p++;
322127094Sdes	return ((u_char *) p);
32336321Samurai}
32436321Samurai
32599207Sbrian/*
32636321Samurai * NetBios Datagram Handler (IP/UDP)
32736321Samurai */
32836321Samurai#define DGM_DIRECT_UNIQ		0x10
32936321Samurai#define DGM_DIRECT_GROUP	0x11
33036321Samurai#define DGM_BROADCAST		0x12
33136321Samurai#define DGM_ERROR			0x13
33236321Samurai#define DGM_QUERY			0x14
33336321Samurai#define DGM_POSITIVE_RES	0x15
33436321Samurai#define DGM_NEGATIVE_RES	0x16
33536321Samurai
336162674Spisostatic int
337127094SdesAliasHandleUdpNbt(
338127094Sdes    struct libalias *la,
339127094Sdes    struct ip *pip,		/* IP packet to examine/patch */
340131614Sdes    struct alias_link *lnk,
341127094Sdes    struct in_addr *alias_address,
342127094Sdes    u_short alias_port
343127094Sdes)
344127094Sdes{
345127094Sdes	struct udphdr *uh;
346127094Sdes	NbtDataHeader *ndh;
347127094Sdes	u_char *p = NULL;
348127094Sdes	char *pmax;
34999207Sbrian
350131614Sdes	(void)la;
351131614Sdes	(void)lnk;
352131614Sdes
353127094Sdes	/* Calculate data length of UDP packet */
354131699Sdes	uh = (struct udphdr *)ip_next(pip);
355127094Sdes	pmax = (char *)uh + ntohs(uh->uh_ulen);
35641759Sdillon
357131699Sdes	ndh = (NbtDataHeader *)udp_next(uh);
358127094Sdes	if ((char *)(ndh + 1) > pmax)
359127094Sdes		return (-1);
360145961Sglebius#ifdef LIBALIAS_DEBUG
361127094Sdes	printf("\nType=%02x,", ndh->type);
36236321Samurai#endif
363127094Sdes	switch (ndh->type) {
364127094Sdes	case DGM_DIRECT_UNIQ:
365127094Sdes	case DGM_DIRECT_GROUP:
366127094Sdes	case DGM_BROADCAST:
367127094Sdes		p = (u_char *) ndh + 14;
368127094Sdes		p = AliasHandleName(p, pmax);	/* Source Name */
369127094Sdes		p = AliasHandleName(p, pmax);	/* Destination Name */
370127094Sdes		break;
371127094Sdes	case DGM_ERROR:
372127094Sdes		p = (u_char *) ndh + 11;
373127094Sdes		break;
374127094Sdes	case DGM_QUERY:
375127094Sdes	case DGM_POSITIVE_RES:
376127094Sdes	case DGM_NEGATIVE_RES:
377127094Sdes		p = (u_char *) ndh + 10;
378127094Sdes		p = AliasHandleName(p, pmax);	/* Destination Name */
379127094Sdes		break;
38036321Samurai	}
381127094Sdes	if (p == NULL || (char *)p > pmax)
382127094Sdes		p = NULL;
383145961Sglebius#ifdef LIBALIAS_DEBUG
384127094Sdes	printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
38536321Samurai#endif
386108533Sschweikh	/* Doing an IP address and Port number Translation */
387127094Sdes	if (uh->uh_sum != 0) {
388127094Sdes		int acc;
389127094Sdes		u_short *sptr;
390127094Sdes
391127094Sdes		acc = ndh->source_port;
39236321Samurai		acc -= alias_port;
393127094Sdes		sptr = (u_short *) & (ndh->source_ip);
39436321Samurai		acc += *sptr++;
39536321Samurai		acc += *sptr;
39636321Samurai		sptr = (u_short *) alias_address;
39736321Samurai		acc -= *sptr++;
39836321Samurai		acc -= *sptr;
39974778Sbrian		ADJUST_CHECKSUM(acc, uh->uh_sum);
40036321Samurai	}
401127094Sdes	ndh->source_ip = *alias_address;
402127094Sdes	ndh->source_port = alias_port;
403145961Sglebius#ifdef LIBALIAS_DEBUG
404127094Sdes	printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
40536321Samurai	fflush(stdout);
40636321Samurai#endif
407127094Sdes	return ((p == NULL) ? -1 : 0);
40836321Samurai}
409127094Sdes
41036321Samurai/* Question Section */
41136321Samurai#define QS_TYPE_NB		0x0020
41236321Samurai#define QS_TYPE_NBSTAT	0x0021
41336321Samurai#define QS_CLAS_IN		0x0001
41436321Samuraitypedef struct {
415127094Sdes	u_short		type;	/* The type of Request */
416127094Sdes	u_short		class;	/* The class of Request */
417127094Sdes}		NBTNsQuestion;
41836321Samurai
419127094Sdesstatic u_char  *
42041759SdillonAliasHandleQuestion(
42141759Sdillon    u_short count,
422127094Sdes    NBTNsQuestion * q,
42341759Sdillon    char *pmax,
424127094Sdes    NBTArguments * nbtarg)
42536321Samurai{
42636321Samurai
427131614Sdes	(void)nbtarg;
428131614Sdes
429127094Sdes	while (count != 0) {
43036321Samurai		/* Name Filed */
431127094Sdes		q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
43236321Samurai
43341759Sdillon		if (q == NULL || (char *)(q + 1) > pmax) {
43441759Sdillon			q = NULL;
43541759Sdillon			break;
43641759Sdillon		}
43736321Samurai		/* Type and Class filed */
438127094Sdes		switch (ntohs(q->type)) {
439127094Sdes		case QS_TYPE_NB:
440127094Sdes		case QS_TYPE_NBSTAT:
441127094Sdes			q = q + 1;
44236321Samurai			break;
443127094Sdes		default:
444145961Sglebius#ifdef LIBALIAS_DEBUG
445127094Sdes			printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
44644616Sbrian#endif
44736321Samurai			break;
44836321Samurai		}
44936321Samurai		count--;
45036321Samurai	}
45136321Samurai
45236321Samurai	/* Set up to out of Question Section */
453127094Sdes	return ((u_char *) q);
45436321Samurai}
45536321Samurai
45636321Samurai/* Resource Record */
45736321Samurai#define RR_TYPE_A		0x0001
45836321Samurai#define RR_TYPE_NS		0x0002
45936321Samurai#define RR_TYPE_NULL	0x000a
46036321Samurai#define RR_TYPE_NB		0x0020
46136321Samurai#define RR_TYPE_NBSTAT	0x0021
46236321Samurai#define RR_CLAS_IN		0x0001
46336321Samurai#define SizeOfNsResource	8
46436321Samuraitypedef struct {
465127094Sdes	u_short		type;
466127094Sdes	u_short		class;
467127094Sdes	unsigned int	ttl;
468127094Sdes	u_short		rdlen;
469127094Sdes}		NBTNsResource;
47036321Samurai
47136321Samurai#define SizeOfNsRNB			6
47236321Samuraitypedef struct {
473127094Sdes	u_short		g:	1  , ont:2, resv:13;
474127094Sdes	struct in_addr	addr;
475127094Sdes}		NBTNsRNB;
47636321Samurai
477127094Sdesstatic u_char  *
47899207SbrianAliasHandleResourceNB(
479127094Sdes    NBTNsResource * q,
48099207Sbrian    char *pmax,
481127094Sdes    NBTArguments * nbtarg)
48236321Samurai{
483127094Sdes	NBTNsRNB *nb;
48436321Samurai	u_short bcount;
48536321Samurai
48641759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
487127094Sdes		return (NULL);
48836321Samurai	/* Check out a length */
48936321Samurai	bcount = ntohs(q->rdlen);
49036321Samurai
49136321Samurai	/* Forward to Resource NB position */
492127094Sdes	nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
49336321Samurai
49436321Samurai	/* Processing all in_addr array */
495145961Sglebius#ifdef LIBALIAS_DEBUG
49636321Samurai	printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
497127094Sdes	printf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount);
49836321Samurai#endif
499127094Sdes	while (nb != NULL && bcount != 0) {
50041759Sdillon		if ((char *)(nb + 1) > pmax) {
50141759Sdillon			nb = NULL;
50241759Sdillon			break;
50341759Sdillon		}
504145961Sglebius#ifdef LIBALIAS_DEBUG
505127094Sdes		printf("<%s>", inet_ntoa(nb->addr));
50636321Samurai#endif
507127094Sdes		if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
508127094Sdes			if (*nbtarg->uh_sum != 0) {
509127094Sdes				int acc;
510127094Sdes				u_short *sptr;
51136321Samurai
512127094Sdes				sptr = (u_short *) & (nb->addr);
513127094Sdes				acc = *sptr++;
514127094Sdes				acc += *sptr;
515127094Sdes				sptr = (u_short *) & (nbtarg->newaddr);
516127094Sdes				acc -= *sptr++;
517127094Sdes				acc -= *sptr;
518127094Sdes				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
51936321Samurai			}
52036321Samurai			nb->addr = nbtarg->newaddr;
521145961Sglebius#ifdef LIBALIAS_DEBUG
52236321Samurai			printf("O");
52336321Samurai#endif
52436321Samurai		}
525145961Sglebius#ifdef LIBALIAS_DEBUG
526127094Sdes		else {
52736321Samurai			printf(".");
52836321Samurai		}
52936321Samurai#endif
530127094Sdes		nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
531127094Sdes		bcount -= SizeOfNsRNB;
53236321Samurai	}
53341759Sdillon	if (nb == NULL || (char *)(nb + 1) > pmax) {
53441759Sdillon		nb = NULL;
53541759Sdillon	}
536127094Sdes	return ((u_char *) nb);
53736321Samurai}
53836321Samurai
53936321Samurai#define SizeOfResourceA		6
54036321Samuraitypedef struct {
541127094Sdes	struct in_addr	addr;
542127094Sdes}		NBTNsResourceA;
54336321Samurai
544127094Sdesstatic u_char  *
54599207SbrianAliasHandleResourceA(
546127094Sdes    NBTNsResource * q,
54741759Sdillon    char *pmax,
548127094Sdes    NBTArguments * nbtarg)
54936321Samurai{
550127094Sdes	NBTNsResourceA *a;
55136321Samurai	u_short bcount;
55236321Samurai
55341759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
554127094Sdes		return (NULL);
55541759Sdillon
55636321Samurai	/* Forward to Resource A position */
557127094Sdes	a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
55836321Samurai
55936321Samurai	/* Check out of length */
56036321Samurai	bcount = ntohs(q->rdlen);
56136321Samurai
56236321Samurai	/* Processing all in_addr array */
563145961Sglebius#ifdef LIBALIAS_DEBUG
56436321Samurai	printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
565127094Sdes	printf("->%s]", inet_ntoa(nbtarg->newaddr));
56636321Samurai#endif
567127094Sdes	while (bcount != 0) {
56841759Sdillon		if (a == NULL || (char *)(a + 1) > pmax)
569127094Sdes			return (NULL);
570145961Sglebius#ifdef LIBALIAS_DEBUG
571127094Sdes		printf("..%s", inet_ntoa(a->addr));
57236321Samurai#endif
573127094Sdes		if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
574127094Sdes			if (*nbtarg->uh_sum != 0) {
575127094Sdes				int acc;
576127094Sdes				u_short *sptr;
57736321Samurai
578127094Sdes				sptr = (u_short *) & (a->addr);	/* Old */
579127094Sdes				acc = *sptr++;
580127094Sdes				acc += *sptr;
581127094Sdes				sptr = (u_short *) & nbtarg->newaddr;	/* New */
582127094Sdes				acc -= *sptr++;
583127094Sdes				acc -= *sptr;
584127094Sdes				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
58536321Samurai			}
58636321Samurai			a->addr = nbtarg->newaddr;
58736321Samurai		}
588127094Sdes		a++;		/* XXXX */
58936321Samurai		bcount -= SizeOfResourceA;
59036321Samurai	}
59141759Sdillon	if (a == NULL || (char *)(a + 1) > pmax)
592127094Sdes		a = NULL;
593127094Sdes	return ((u_char *) a);
59436321Samurai}
59536321Samurai
59636321Samuraitypedef struct {
597127094Sdes	u_short		opcode:4, flags:8, resv:4;
598127094Sdes}		NBTNsResourceNULL;
59936321Samurai
600127094Sdesstatic u_char  *
60199207SbrianAliasHandleResourceNULL(
602127094Sdes    NBTNsResource * q,
60341759Sdillon    char *pmax,
604127094Sdes    NBTArguments * nbtarg)
60536321Samurai{
606127094Sdes	NBTNsResourceNULL *n;
60736321Samurai	u_short bcount;
60836321Samurai
609131614Sdes	(void)nbtarg;
610131614Sdes
61141759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
612127094Sdes		return (NULL);
61341759Sdillon
61436321Samurai	/* Forward to Resource NULL position */
615127094Sdes	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
61636321Samurai
61736321Samurai	/* Check out of length */
61836321Samurai	bcount = ntohs(q->rdlen);
61936321Samurai
62036321Samurai	/* Processing all in_addr array */
621127094Sdes	while (bcount != 0) {
62241759Sdillon		if ((char *)(n + 1) > pmax) {
62341759Sdillon			n = NULL;
62441759Sdillon			break;
62541759Sdillon		}
62636321Samurai		n++;
62736321Samurai		bcount -= sizeof(NBTNsResourceNULL);
62836321Samurai	}
62941759Sdillon	if ((char *)(n + 1) > pmax)
63041759Sdillon		n = NULL;
63136321Samurai
632127094Sdes	return ((u_char *) n);
63336321Samurai}
63436321Samurai
635127094Sdesstatic u_char  *
63699207SbrianAliasHandleResourceNS(
637127094Sdes    NBTNsResource * q,
63841759Sdillon    char *pmax,
639127094Sdes    NBTArguments * nbtarg)
64036321Samurai{
641127094Sdes	NBTNsResourceNULL *n;
64236321Samurai	u_short bcount;
64336321Samurai
644131614Sdes	(void)nbtarg;
645131614Sdes
64641759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
647127094Sdes		return (NULL);
64841759Sdillon
64936321Samurai	/* Forward to Resource NULL position */
650127094Sdes	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
65136321Samurai
65236321Samurai	/* Check out of length */
65336321Samurai	bcount = ntohs(q->rdlen);
65436321Samurai
65536321Samurai	/* Resource Record Name Filed */
656127094Sdes	q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax);	/* XXX */
65736321Samurai
658127094Sdes	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
659127094Sdes		return (NULL);
66041759Sdillon	else
661127094Sdes		return ((u_char *) n + bcount);
66236321Samurai}
66336321Samurai
66436321Samuraitypedef struct {
665127094Sdes	u_short		numnames;
666127094Sdes}		NBTNsResourceNBSTAT;
66736321Samurai
668127094Sdesstatic u_char  *
66941759SdillonAliasHandleResourceNBSTAT(
670127094Sdes    NBTNsResource * q,
67141759Sdillon    char *pmax,
672127094Sdes    NBTArguments * nbtarg)
67336321Samurai{
674127094Sdes	NBTNsResourceNBSTAT *n;
67536321Samurai	u_short bcount;
67636321Samurai
677131614Sdes	(void)nbtarg;
678131614Sdes
67941759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
680127094Sdes		return (NULL);
68141759Sdillon
68236321Samurai	/* Forward to Resource NBSTAT position */
683127094Sdes	n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
68436321Samurai
68536321Samurai	/* Check out of length */
68636321Samurai	bcount = ntohs(q->rdlen);
68736321Samurai
688127094Sdes	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
689127094Sdes		return (NULL);
69041759Sdillon	else
691127094Sdes		return ((u_char *) n + bcount);
69236321Samurai}
69336321Samurai
694127094Sdesstatic u_char  *
69541759SdillonAliasHandleResource(
69699207Sbrian    u_short count,
697127094Sdes    NBTNsResource * q,
69841759Sdillon    char *pmax,
69999207Sbrian    NBTArguments
700127094Sdes    * nbtarg)
70136321Samurai{
702127094Sdes	while (count != 0) {
70336321Samurai		/* Resource Record Name Filed */
704127094Sdes		q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
70541759Sdillon
70641759Sdillon		if (q == NULL || (char *)(q + 1) > pmax)
70741759Sdillon			break;
708145961Sglebius#ifdef LIBALIAS_DEBUG
709127094Sdes		printf("type=%02x, count=%d\n", ntohs(q->type), count);
71036321Samurai#endif
71136321Samurai
71236321Samurai		/* Type and Class filed */
713127094Sdes		switch (ntohs(q->type)) {
714127094Sdes		case RR_TYPE_NB:
715127094Sdes			q = (NBTNsResource *) AliasHandleResourceNB(
716127094Sdes			    q,
717127094Sdes			    pmax,
718127094Sdes			    nbtarg
719127094Sdes			    );
720127094Sdes			break;
721127094Sdes		case RR_TYPE_A:
722127094Sdes			q = (NBTNsResource *) AliasHandleResourceA(
723127094Sdes			    q,
724127094Sdes			    pmax,
725127094Sdes			    nbtarg
726127094Sdes			    );
727127094Sdes			break;
728127094Sdes		case RR_TYPE_NS:
729127094Sdes			q = (NBTNsResource *) AliasHandleResourceNS(
730127094Sdes			    q,
731127094Sdes			    pmax,
732127094Sdes			    nbtarg
733127094Sdes			    );
734127094Sdes			break;
735127094Sdes		case RR_TYPE_NULL:
736127094Sdes			q = (NBTNsResource *) AliasHandleResourceNULL(
737127094Sdes			    q,
738127094Sdes			    pmax,
739127094Sdes			    nbtarg
740127094Sdes			    );
741127094Sdes			break;
742127094Sdes		case RR_TYPE_NBSTAT:
743127094Sdes			q = (NBTNsResource *) AliasHandleResourceNBSTAT(
744127094Sdes			    q,
745127094Sdes			    pmax,
746127094Sdes			    nbtarg
747127094Sdes			    );
748127094Sdes			break;
749127094Sdes		default:
750145961Sglebius#ifdef LIBALIAS_DEBUG
751127094Sdes			printf(
752127094Sdes			    "\nUnknown Type of Resource %0x\n",
753127094Sdes			    ntohs(q->type)
754127094Sdes			    );
755145928Sglebius			fflush(stdout);
75644616Sbrian#endif
757127094Sdes			break;
75836321Samurai		}
75936321Samurai		count--;
76036321Samurai	}
761127094Sdes	return ((u_char *) q);
76236321Samurai}
76336321Samurai
764162674Spisostatic int
765127094SdesAliasHandleUdpNbtNS(
766127094Sdes    struct libalias *la,
767127094Sdes    struct ip *pip,		/* IP packet to examine/patch */
768131614Sdes    struct alias_link *lnk,
769127094Sdes    struct in_addr *alias_address,
770127094Sdes    u_short * alias_port,
771127094Sdes    struct in_addr *original_address,
772127094Sdes    u_short * original_port)
77336321Samurai{
774127094Sdes	struct udphdr *uh;
775127094Sdes	NbtNSHeader *nsh;
776127094Sdes	u_char *p;
777127094Sdes	char *pmax;
778127094Sdes	NBTArguments nbtarg;
77936321Samurai
780131614Sdes	(void)la;
781131614Sdes	(void)lnk;
782131614Sdes
78399207Sbrian	/* Set up Common Parameter */
784127094Sdes	nbtarg.oldaddr = *alias_address;
785127094Sdes	nbtarg.oldport = *alias_port;
786127094Sdes	nbtarg.newaddr = *original_address;
787127094Sdes	nbtarg.newport = *original_port;
78836321Samurai
789127094Sdes	/* Calculate data length of UDP packet */
790131699Sdes	uh = (struct udphdr *)ip_next(pip);
791127094Sdes	nbtarg.uh_sum = &(uh->uh_sum);
792131699Sdes	nsh = (NbtNSHeader *)udp_next(uh);
793127094Sdes	p = (u_char *) (nsh + 1);
794127094Sdes	pmax = (char *)uh + ntohs(uh->uh_ulen);
79536321Samurai
796127094Sdes	if ((char *)(nsh + 1) > pmax)
797127094Sdes		return (-1);
79841759Sdillon
799145961Sglebius#ifdef LIBALIAS_DEBUG
800127094Sdes	printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
801127094Sdes	    ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
802127094Sdes	    nsh->dir ? "Response" : "Request",
803127094Sdes	    nsh->nametrid,
804127094Sdes	    nsh->opcode,
805127094Sdes	    nsh->nmflags,
806127094Sdes	    nsh->rcode,
807127094Sdes	    ntohs(nsh->qdcount),
808127094Sdes	    ntohs(nsh->ancount),
809127094Sdes	    ntohs(nsh->nscount),
810127094Sdes	    ntohs(nsh->arcount),
811127094Sdes	    (u_char *) p - (u_char *) nsh
812127094Sdes	    );
81336321Samurai#endif
81436321Samurai
81536321Samurai	/* Question Entries */
816127094Sdes	if (ntohs(nsh->qdcount) != 0) {
817127094Sdes		p = AliasHandleQuestion(
818127094Sdes		    ntohs(nsh->qdcount),
819127094Sdes		    (NBTNsQuestion *) p,
820127094Sdes		    pmax,
821127094Sdes		    &nbtarg
822127094Sdes		    );
82336321Samurai	}
82436321Samurai	/* Answer Resource Records */
825127094Sdes	if (ntohs(nsh->ancount) != 0) {
826127094Sdes		p = AliasHandleResource(
827127094Sdes		    ntohs(nsh->ancount),
828127094Sdes		    (NBTNsResource *) p,
829127094Sdes		    pmax,
830127094Sdes		    &nbtarg
831127094Sdes		    );
83236321Samurai	}
83336321Samurai	/* Authority Resource Recodrs */
834127094Sdes	if (ntohs(nsh->nscount) != 0) {
835127094Sdes		p = AliasHandleResource(
836127094Sdes		    ntohs(nsh->nscount),
837127094Sdes		    (NBTNsResource *) p,
838127094Sdes		    pmax,
839127094Sdes		    &nbtarg
840127094Sdes		    );
84136321Samurai	}
84236321Samurai	/* Additional Resource Recodrs */
843127094Sdes	if (ntohs(nsh->arcount) != 0) {
844127094Sdes		p = AliasHandleResource(
845127094Sdes		    ntohs(nsh->arcount),
846127094Sdes		    (NBTNsResource *) p,
847127094Sdes		    pmax,
848127094Sdes		    &nbtarg
849127094Sdes		    );
85036321Samurai	}
851145961Sglebius#ifdef LIBALIAS_DEBUG
852127094Sdes	PrintRcode(nsh->rcode);
85336321Samurai#endif
854127094Sdes	return ((p == NULL) ? -1 : 0);
85536321Samurai}
856