alias_nbt.c revision 259858
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 259858 2013-12-25 02:06:57Z glebius $");
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
73259858SglebiusAliasHandleUdpNbt(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 *);
79259858Sglebiusstatic int
80190841Spisofingerprint1(struct libalias *la, struct alias_data *ah)
81162674Spiso{
82162674Spiso
83259858Sglebius	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
92259858Sglebiusstatic int
93162674Spisoprotohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
94162674Spiso{
95162674Spiso
96190938Spiso	return (AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport));
97162674Spiso}
98162674Spiso
99259858Sglebiusstatic int
100190841Spisofingerprint2(struct libalias *la, struct alias_data *ah)
101162674Spiso{
102162674Spiso
103259858Sglebius	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
104162674Spiso	    ah->aaddr == NULL || ah->aport == NULL)
105162674Spiso		return (-1);
106162674Spiso	if (ntohs(*ah->dport) == NETBIOS_NS_PORT_NUMBER
107162674Spiso	    || ntohs(*ah->sport) == NETBIOS_NS_PORT_NUMBER)
108162674Spiso		return (0);
109162674Spiso	return (-1);
110162674Spiso}
111162674Spiso
112259858Sglebiusstatic int
113162674Spisoprotohandler2in(struct libalias *la, struct ip *pip, struct alias_data *ah)
114162674Spiso{
115162674Spiso
116162674Spiso	AliasHandleUdpNbtNS(la, pip, ah->lnk, ah->aaddr, ah->aport,
117162674Spiso 			    ah->oaddr, ah->dport);
118162674Spiso	return (0);
119162674Spiso}
120162674Spiso
121259858Sglebiusstatic int
122162674Spisoprotohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
123162674Spiso{
124162674Spiso
125190938Spiso	return (AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
126190938Spiso 	    ah->aaddr, ah->aport));
127162674Spiso}
128162674Spiso
129162674Spiso/* Kernel module definition. */
130162674Spisostruct proto_handler handlers[] = {
131259858Sglebius	{
132259858Sglebius	  .pri = 130,
133259858Sglebius	  .dir = IN|OUT,
134259858Sglebius	  .proto = UDP,
135259858Sglebius	  .fingerprint = &fingerprint1,
136162674Spiso	  .protohandler = &protohandler1
137259858Sglebius	},
138259858Sglebius	{
139259858Sglebius	  .pri = 140,
140259858Sglebius	  .dir = IN,
141259858Sglebius	  .proto = UDP,
142259858Sglebius	  .fingerprint = &fingerprint2,
143162674Spiso	  .protohandler = &protohandler2in
144259858Sglebius	},
145259858Sglebius	{
146259858Sglebius	  .pri = 140,
147259858Sglebius	  .dir = OUT,
148259858Sglebius	  .proto = UDP,
149259858Sglebius	  .fingerprint = &fingerprint2,
150162674Spiso	  .protohandler = &protohandler2out
151259858Sglebius	},
152162674Spiso	{ EOH }
153162674Spiso};
154162674Spiso
155162674Spisostatic int
156162674Spisomod_handler(module_t mod, int type, void *data)
157162674Spiso{
158162674Spiso	int error;
159162674Spiso
160162674Spiso	switch (type) {
161162674Spiso	case MOD_LOAD:
162162674Spiso		error = 0;
163162674Spiso		LibAliasAttachHandlers(handlers);
164162674Spiso		break;
165162674Spiso	case MOD_UNLOAD:
166162674Spiso		error = 0;
167162674Spiso		LibAliasDetachHandlers(handlers);
168162674Spiso		break;
169162674Spiso	default:
170162674Spiso		error = EINVAL;
171162674Spiso	}
172162674Spiso	return (error);
173162674Spiso}
174162674Spiso
175162674Spiso#ifdef	_KERNEL
176259858Sglebiusstatic
177162674Spiso#endif
178162674Spisomoduledata_t alias_mod = {
179162674Spiso       "alias_nbt", mod_handler, NULL
180162674Spiso};
181162674Spiso
182162674Spiso#ifdef	_KERNEL
183162674SpisoDECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
184162674SpisoMODULE_VERSION(alias_nbt, 1);
185162674SpisoMODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
186162674Spiso#endif
187162674Spiso
18836321Samuraitypedef struct {
189127094Sdes	struct in_addr	oldaddr;
190127094Sdes	u_short		oldport;
191127094Sdes	struct in_addr	newaddr;
192127094Sdes	u_short		newport;
193127094Sdes	u_short        *uh_sum;
194127094Sdes}		NBTArguments;
19536321Samurai
19636321Samuraitypedef struct {
197127094Sdes	unsigned char	type;
198127094Sdes	unsigned char	flags;
199127094Sdes	u_short		id;
200127094Sdes	struct in_addr	source_ip;
201127094Sdes	u_short		source_port;
202127094Sdes	u_short		len;
203127094Sdes	u_short		offset;
204127094Sdes}		NbtDataHeader;
20536321Samurai
20636321Samurai#define OpQuery		0
20736321Samurai#define OpUnknown	4
20836321Samurai#define OpRegist	5
20936321Samurai#define OpRelease	6
21036321Samurai#define OpWACK		7
21136321Samurai#define OpRefresh	8
21236321Samuraitypedef struct {
213127094Sdes	u_short		nametrid;
214127094Sdes	u_short		dir:	1, opcode:4, nmflags:7, rcode:4;
215127094Sdes	u_short		qdcount;
216127094Sdes	u_short		ancount;
217127094Sdes	u_short		nscount;
218127094Sdes	u_short		arcount;
219127094Sdes}		NbtNSHeader;
22036321Samurai
22136321Samurai#define FMT_ERR		0x1
22236321Samurai#define SRV_ERR		0x2
22336321Samurai#define IMP_ERR		0x4
22436321Samurai#define RFS_ERR		0x5
22536321Samurai#define ACT_ERR		0x6
22636321Samurai#define CFT_ERR		0x7
22736321Samurai
22836321Samurai
229145961Sglebius#ifdef LIBALIAS_DEBUG
230127094Sdesstatic void
231127094SdesPrintRcode(u_char rcode)
232127094Sdes{
23336321Samurai
23436321Samurai	switch (rcode) {
23536321Samurai		case FMT_ERR:
236127094Sdes		printf("\nFormat Error.");
237127094Sdes	case SRV_ERR:
238127094Sdes		printf("\nSever failure.");
239127094Sdes	case IMP_ERR:
240127094Sdes		printf("\nUnsupported request error.\n");
241127094Sdes	case RFS_ERR:
242127094Sdes		printf("\nRefused error.\n");
243127094Sdes	case ACT_ERR:
244127094Sdes		printf("\nActive error.\n");
245127094Sdes	case CFT_ERR:
246127094Sdes		printf("\nName in conflict error.\n");
247127094Sdes	default:
248127094Sdes		printf("\n?%c?=%0x\n", '?', rcode);
24936321Samurai
25099207Sbrian	}
25136321Samurai}
252127094Sdes
25344616Sbrian#endif
25436321Samurai
25536321Samurai
25636321Samurai/* Handling Name field */
257127094Sdesstatic u_char  *
258127094SdesAliasHandleName(u_char * p, char *pmax)
259127094Sdes{
26036321Samurai
26136321Samurai	u_char *s;
26236321Samurai	u_char c;
263127094Sdes	int compress;
26436321Samurai
26536321Samurai	/* Following length field */
26641759Sdillon
26741759Sdillon	if (p == NULL || (char *)p >= pmax)
268127094Sdes		return (NULL);
26941759Sdillon
270127094Sdes	if (*p & 0xc0) {
27136321Samurai		p = p + 2;
27241759Sdillon		if ((char *)p > pmax)
273127094Sdes			return (NULL);
274127094Sdes		return ((u_char *) p);
27536321Samurai	}
276127094Sdes	while ((*p & 0x3f) != 0x00) {
27736321Samurai		s = p + 1;
278127094Sdes		if (*p == 0x20)
27936321Samurai			compress = 1;
28036321Samurai		else
28136321Samurai			compress = 0;
28299207Sbrian
283127094Sdes		/* Get next length field */
284127094Sdes		p = (u_char *) (p + (*p & 0x3f) + 1);
28541759Sdillon		if ((char *)p > pmax) {
28641759Sdillon			p = NULL;
28741759Sdillon			break;
28841759Sdillon		}
289145961Sglebius#ifdef LIBALIAS_DEBUG
29036321Samurai		printf(":");
29136321Samurai#endif
29236321Samurai		while (s < p) {
293127094Sdes			if (compress == 1) {
294127094Sdes				c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
295145961Sglebius#ifdef LIBALIAS_DEBUG
296127094Sdes				if (isprint(c))
297127094Sdes					printf("%c", c);
29836321Samurai				else
299127094Sdes					printf("<0x%02x>", c);
30036321Samurai#endif
301127094Sdes				s += 2;
30236321Samurai			} else {
303145961Sglebius#ifdef LIBALIAS_DEBUG
30436321Samurai				printf("%c", *s);
30536321Samurai#endif
30636321Samurai				s++;
30736321Samurai			}
30836321Samurai		}
309145961Sglebius#ifdef LIBALIAS_DEBUG
31036321Samurai		printf(":");
311145928Sglebius		fflush(stdout);
31236321Samurai#endif
313127094Sdes	}
31436321Samurai
31536321Samurai	/* Set up to out of Name field */
31641759Sdillon	if (p == NULL || (char *)p >= pmax)
317127094Sdes		p = NULL;
31841759Sdillon	else
319127094Sdes		p++;
320127094Sdes	return ((u_char *) p);
32136321Samurai}
32236321Samurai
32399207Sbrian/*
32436321Samurai * NetBios Datagram Handler (IP/UDP)
32536321Samurai */
32636321Samurai#define DGM_DIRECT_UNIQ		0x10
32736321Samurai#define DGM_DIRECT_GROUP	0x11
32836321Samurai#define DGM_BROADCAST		0x12
32936321Samurai#define DGM_ERROR			0x13
33036321Samurai#define DGM_QUERY			0x14
33136321Samurai#define DGM_POSITIVE_RES	0x15
33236321Samurai#define DGM_NEGATIVE_RES	0x16
33336321Samurai
334162674Spisostatic int
335127094SdesAliasHandleUdpNbt(
336127094Sdes    struct libalias *la,
337127094Sdes    struct ip *pip,		/* IP packet to examine/patch */
338131614Sdes    struct alias_link *lnk,
339127094Sdes    struct in_addr *alias_address,
340127094Sdes    u_short alias_port
341127094Sdes)
342127094Sdes{
343127094Sdes	struct udphdr *uh;
344127094Sdes	NbtDataHeader *ndh;
345127094Sdes	u_char *p = NULL;
346127094Sdes	char *pmax;
34799207Sbrian
348131614Sdes	(void)la;
349131614Sdes	(void)lnk;
350131614Sdes
351127094Sdes	/* Calculate data length of UDP packet */
352131699Sdes	uh = (struct udphdr *)ip_next(pip);
353127094Sdes	pmax = (char *)uh + ntohs(uh->uh_ulen);
35441759Sdillon
355131699Sdes	ndh = (NbtDataHeader *)udp_next(uh);
356127094Sdes	if ((char *)(ndh + 1) > pmax)
357127094Sdes		return (-1);
358145961Sglebius#ifdef LIBALIAS_DEBUG
359127094Sdes	printf("\nType=%02x,", ndh->type);
36036321Samurai#endif
361127094Sdes	switch (ndh->type) {
362127094Sdes	case DGM_DIRECT_UNIQ:
363127094Sdes	case DGM_DIRECT_GROUP:
364127094Sdes	case DGM_BROADCAST:
365127094Sdes		p = (u_char *) ndh + 14;
366127094Sdes		p = AliasHandleName(p, pmax);	/* Source Name */
367127094Sdes		p = AliasHandleName(p, pmax);	/* Destination Name */
368127094Sdes		break;
369127094Sdes	case DGM_ERROR:
370127094Sdes		p = (u_char *) ndh + 11;
371127094Sdes		break;
372127094Sdes	case DGM_QUERY:
373127094Sdes	case DGM_POSITIVE_RES:
374127094Sdes	case DGM_NEGATIVE_RES:
375127094Sdes		p = (u_char *) ndh + 10;
376127094Sdes		p = AliasHandleName(p, pmax);	/* Destination Name */
377127094Sdes		break;
37836321Samurai	}
379127094Sdes	if (p == NULL || (char *)p > pmax)
380127094Sdes		p = NULL;
381145961Sglebius#ifdef LIBALIAS_DEBUG
382127094Sdes	printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
38336321Samurai#endif
384108533Sschweikh	/* Doing an IP address and Port number Translation */
385127094Sdes	if (uh->uh_sum != 0) {
386127094Sdes		int acc;
387127094Sdes		u_short *sptr;
388127094Sdes
389127094Sdes		acc = ndh->source_port;
39036321Samurai		acc -= alias_port;
391127094Sdes		sptr = (u_short *) & (ndh->source_ip);
39236321Samurai		acc += *sptr++;
39336321Samurai		acc += *sptr;
39436321Samurai		sptr = (u_short *) alias_address;
39536321Samurai		acc -= *sptr++;
39636321Samurai		acc -= *sptr;
39774778Sbrian		ADJUST_CHECKSUM(acc, uh->uh_sum);
39836321Samurai	}
399127094Sdes	ndh->source_ip = *alias_address;
400127094Sdes	ndh->source_port = alias_port;
401145961Sglebius#ifdef LIBALIAS_DEBUG
402127094Sdes	printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
40336321Samurai	fflush(stdout);
40436321Samurai#endif
405127094Sdes	return ((p == NULL) ? -1 : 0);
40636321Samurai}
407127094Sdes
40836321Samurai/* Question Section */
40936321Samurai#define QS_TYPE_NB		0x0020
41036321Samurai#define QS_TYPE_NBSTAT	0x0021
41136321Samurai#define QS_CLAS_IN		0x0001
41236321Samuraitypedef struct {
413127094Sdes	u_short		type;	/* The type of Request */
414127094Sdes	u_short		class;	/* The class of Request */
415127094Sdes}		NBTNsQuestion;
41636321Samurai
417127094Sdesstatic u_char  *
41841759SdillonAliasHandleQuestion(
41941759Sdillon    u_short count,
420127094Sdes    NBTNsQuestion * q,
42141759Sdillon    char *pmax,
422127094Sdes    NBTArguments * nbtarg)
42336321Samurai{
42436321Samurai
425131614Sdes	(void)nbtarg;
426131614Sdes
427127094Sdes	while (count != 0) {
42836321Samurai		/* Name Filed */
429127094Sdes		q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
43036321Samurai
43141759Sdillon		if (q == NULL || (char *)(q + 1) > pmax) {
43241759Sdillon			q = NULL;
43341759Sdillon			break;
43441759Sdillon		}
43536321Samurai		/* Type and Class filed */
436127094Sdes		switch (ntohs(q->type)) {
437127094Sdes		case QS_TYPE_NB:
438127094Sdes		case QS_TYPE_NBSTAT:
439127094Sdes			q = q + 1;
44036321Samurai			break;
441127094Sdes		default:
442145961Sglebius#ifdef LIBALIAS_DEBUG
443127094Sdes			printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
44444616Sbrian#endif
44536321Samurai			break;
44636321Samurai		}
44736321Samurai		count--;
44836321Samurai	}
44936321Samurai
45036321Samurai	/* Set up to out of Question Section */
451127094Sdes	return ((u_char *) q);
45236321Samurai}
45336321Samurai
45436321Samurai/* Resource Record */
45536321Samurai#define RR_TYPE_A		0x0001
45636321Samurai#define RR_TYPE_NS		0x0002
45736321Samurai#define RR_TYPE_NULL	0x000a
45836321Samurai#define RR_TYPE_NB		0x0020
45936321Samurai#define RR_TYPE_NBSTAT	0x0021
46036321Samurai#define RR_CLAS_IN		0x0001
46136321Samurai#define SizeOfNsResource	8
46236321Samuraitypedef struct {
463127094Sdes	u_short		type;
464127094Sdes	u_short		class;
465127094Sdes	unsigned int	ttl;
466127094Sdes	u_short		rdlen;
467127094Sdes}		NBTNsResource;
46836321Samurai
46936321Samurai#define SizeOfNsRNB			6
47036321Samuraitypedef struct {
471127094Sdes	u_short		g:	1  , ont:2, resv:13;
472127094Sdes	struct in_addr	addr;
473127094Sdes}		NBTNsRNB;
47436321Samurai
475127094Sdesstatic u_char  *
47699207SbrianAliasHandleResourceNB(
477127094Sdes    NBTNsResource * q,
47899207Sbrian    char *pmax,
479127094Sdes    NBTArguments * nbtarg)
48036321Samurai{
481127094Sdes	NBTNsRNB *nb;
48236321Samurai	u_short bcount;
48336321Samurai
48441759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
485127094Sdes		return (NULL);
48636321Samurai	/* Check out a length */
48736321Samurai	bcount = ntohs(q->rdlen);
48836321Samurai
48936321Samurai	/* Forward to Resource NB position */
490127094Sdes	nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
49136321Samurai
49236321Samurai	/* Processing all in_addr array */
493145961Sglebius#ifdef LIBALIAS_DEBUG
49436321Samurai	printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
495127094Sdes	printf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount);
49636321Samurai#endif
497127094Sdes	while (nb != NULL && bcount != 0) {
49841759Sdillon		if ((char *)(nb + 1) > pmax) {
49941759Sdillon			nb = NULL;
50041759Sdillon			break;
50141759Sdillon		}
502145961Sglebius#ifdef LIBALIAS_DEBUG
503127094Sdes		printf("<%s>", inet_ntoa(nb->addr));
50436321Samurai#endif
505127094Sdes		if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
506127094Sdes			if (*nbtarg->uh_sum != 0) {
507127094Sdes				int acc;
508127094Sdes				u_short *sptr;
50936321Samurai
510127094Sdes				sptr = (u_short *) & (nb->addr);
511127094Sdes				acc = *sptr++;
512127094Sdes				acc += *sptr;
513127094Sdes				sptr = (u_short *) & (nbtarg->newaddr);
514127094Sdes				acc -= *sptr++;
515127094Sdes				acc -= *sptr;
516127094Sdes				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
51736321Samurai			}
51836321Samurai			nb->addr = nbtarg->newaddr;
519145961Sglebius#ifdef LIBALIAS_DEBUG
52036321Samurai			printf("O");
52136321Samurai#endif
52236321Samurai		}
523145961Sglebius#ifdef LIBALIAS_DEBUG
524127094Sdes		else {
52536321Samurai			printf(".");
52636321Samurai		}
52736321Samurai#endif
528127094Sdes		nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
529127094Sdes		bcount -= SizeOfNsRNB;
53036321Samurai	}
53141759Sdillon	if (nb == NULL || (char *)(nb + 1) > pmax) {
53241759Sdillon		nb = NULL;
53341759Sdillon	}
534127094Sdes	return ((u_char *) nb);
53536321Samurai}
53636321Samurai
53736321Samurai#define SizeOfResourceA		6
53836321Samuraitypedef struct {
539127094Sdes	struct in_addr	addr;
540127094Sdes}		NBTNsResourceA;
54136321Samurai
542127094Sdesstatic u_char  *
54399207SbrianAliasHandleResourceA(
544127094Sdes    NBTNsResource * q,
54541759Sdillon    char *pmax,
546127094Sdes    NBTArguments * nbtarg)
54736321Samurai{
548127094Sdes	NBTNsResourceA *a;
54936321Samurai	u_short bcount;
55036321Samurai
55141759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
552127094Sdes		return (NULL);
55341759Sdillon
55436321Samurai	/* Forward to Resource A position */
555127094Sdes	a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
55636321Samurai
55736321Samurai	/* Check out of length */
55836321Samurai	bcount = ntohs(q->rdlen);
55936321Samurai
56036321Samurai	/* Processing all in_addr array */
561145961Sglebius#ifdef LIBALIAS_DEBUG
56236321Samurai	printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
563127094Sdes	printf("->%s]", inet_ntoa(nbtarg->newaddr));
56436321Samurai#endif
565127094Sdes	while (bcount != 0) {
56641759Sdillon		if (a == NULL || (char *)(a + 1) > pmax)
567127094Sdes			return (NULL);
568145961Sglebius#ifdef LIBALIAS_DEBUG
569127094Sdes		printf("..%s", inet_ntoa(a->addr));
57036321Samurai#endif
571127094Sdes		if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
572127094Sdes			if (*nbtarg->uh_sum != 0) {
573127094Sdes				int acc;
574127094Sdes				u_short *sptr;
57536321Samurai
576127094Sdes				sptr = (u_short *) & (a->addr);	/* Old */
577127094Sdes				acc = *sptr++;
578127094Sdes				acc += *sptr;
579127094Sdes				sptr = (u_short *) & nbtarg->newaddr;	/* New */
580127094Sdes				acc -= *sptr++;
581127094Sdes				acc -= *sptr;
582127094Sdes				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
58336321Samurai			}
58436321Samurai			a->addr = nbtarg->newaddr;
58536321Samurai		}
586127094Sdes		a++;		/* XXXX */
58736321Samurai		bcount -= SizeOfResourceA;
58836321Samurai	}
58941759Sdillon	if (a == NULL || (char *)(a + 1) > pmax)
590127094Sdes		a = NULL;
591127094Sdes	return ((u_char *) a);
59236321Samurai}
59336321Samurai
59436321Samuraitypedef struct {
595127094Sdes	u_short		opcode:4, flags:8, resv:4;
596127094Sdes}		NBTNsResourceNULL;
59736321Samurai
598127094Sdesstatic u_char  *
59999207SbrianAliasHandleResourceNULL(
600127094Sdes    NBTNsResource * q,
60141759Sdillon    char *pmax,
602127094Sdes    NBTArguments * nbtarg)
60336321Samurai{
604127094Sdes	NBTNsResourceNULL *n;
60536321Samurai	u_short bcount;
60636321Samurai
607131614Sdes	(void)nbtarg;
608131614Sdes
60941759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
610127094Sdes		return (NULL);
61141759Sdillon
61236321Samurai	/* Forward to Resource NULL position */
613127094Sdes	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
61436321Samurai
61536321Samurai	/* Check out of length */
61636321Samurai	bcount = ntohs(q->rdlen);
61736321Samurai
61836321Samurai	/* Processing all in_addr array */
619127094Sdes	while (bcount != 0) {
62041759Sdillon		if ((char *)(n + 1) > pmax) {
62141759Sdillon			n = NULL;
62241759Sdillon			break;
62341759Sdillon		}
62436321Samurai		n++;
62536321Samurai		bcount -= sizeof(NBTNsResourceNULL);
62636321Samurai	}
62741759Sdillon	if ((char *)(n + 1) > pmax)
62841759Sdillon		n = NULL;
62936321Samurai
630127094Sdes	return ((u_char *) n);
63136321Samurai}
63236321Samurai
633127094Sdesstatic u_char  *
63499207SbrianAliasHandleResourceNS(
635127094Sdes    NBTNsResource * q,
63641759Sdillon    char *pmax,
637127094Sdes    NBTArguments * nbtarg)
63836321Samurai{
639127094Sdes	NBTNsResourceNULL *n;
64036321Samurai	u_short bcount;
64136321Samurai
642131614Sdes	(void)nbtarg;
643131614Sdes
64441759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
645127094Sdes		return (NULL);
64641759Sdillon
64736321Samurai	/* Forward to Resource NULL position */
648127094Sdes	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
64936321Samurai
65036321Samurai	/* Check out of length */
65136321Samurai	bcount = ntohs(q->rdlen);
65236321Samurai
65336321Samurai	/* Resource Record Name Filed */
654127094Sdes	q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax);	/* XXX */
65536321Samurai
656127094Sdes	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
657127094Sdes		return (NULL);
65841759Sdillon	else
659127094Sdes		return ((u_char *) n + bcount);
66036321Samurai}
66136321Samurai
66236321Samuraitypedef struct {
663127094Sdes	u_short		numnames;
664127094Sdes}		NBTNsResourceNBSTAT;
66536321Samurai
666127094Sdesstatic u_char  *
66741759SdillonAliasHandleResourceNBSTAT(
668127094Sdes    NBTNsResource * q,
66941759Sdillon    char *pmax,
670127094Sdes    NBTArguments * nbtarg)
67136321Samurai{
672127094Sdes	NBTNsResourceNBSTAT *n;
67336321Samurai	u_short bcount;
67436321Samurai
675131614Sdes	(void)nbtarg;
676131614Sdes
67741759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
678127094Sdes		return (NULL);
67941759Sdillon
68036321Samurai	/* Forward to Resource NBSTAT position */
681127094Sdes	n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
68236321Samurai
68336321Samurai	/* Check out of length */
68436321Samurai	bcount = ntohs(q->rdlen);
68536321Samurai
686127094Sdes	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
687127094Sdes		return (NULL);
68841759Sdillon	else
689127094Sdes		return ((u_char *) n + bcount);
69036321Samurai}
69136321Samurai
692127094Sdesstatic u_char  *
69341759SdillonAliasHandleResource(
69499207Sbrian    u_short count,
695127094Sdes    NBTNsResource * q,
69641759Sdillon    char *pmax,
69799207Sbrian    NBTArguments
698127094Sdes    * nbtarg)
69936321Samurai{
700127094Sdes	while (count != 0) {
70136321Samurai		/* Resource Record Name Filed */
702127094Sdes		q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
70341759Sdillon
70441759Sdillon		if (q == NULL || (char *)(q + 1) > pmax)
70541759Sdillon			break;
706145961Sglebius#ifdef LIBALIAS_DEBUG
707127094Sdes		printf("type=%02x, count=%d\n", ntohs(q->type), count);
70836321Samurai#endif
70936321Samurai
71036321Samurai		/* Type and Class filed */
711127094Sdes		switch (ntohs(q->type)) {
712127094Sdes		case RR_TYPE_NB:
713127094Sdes			q = (NBTNsResource *) AliasHandleResourceNB(
714127094Sdes			    q,
715127094Sdes			    pmax,
716127094Sdes			    nbtarg
717127094Sdes			    );
718127094Sdes			break;
719127094Sdes		case RR_TYPE_A:
720127094Sdes			q = (NBTNsResource *) AliasHandleResourceA(
721127094Sdes			    q,
722127094Sdes			    pmax,
723127094Sdes			    nbtarg
724127094Sdes			    );
725127094Sdes			break;
726127094Sdes		case RR_TYPE_NS:
727127094Sdes			q = (NBTNsResource *) AliasHandleResourceNS(
728127094Sdes			    q,
729127094Sdes			    pmax,
730127094Sdes			    nbtarg
731127094Sdes			    );
732127094Sdes			break;
733127094Sdes		case RR_TYPE_NULL:
734127094Sdes			q = (NBTNsResource *) AliasHandleResourceNULL(
735127094Sdes			    q,
736127094Sdes			    pmax,
737127094Sdes			    nbtarg
738127094Sdes			    );
739127094Sdes			break;
740127094Sdes		case RR_TYPE_NBSTAT:
741127094Sdes			q = (NBTNsResource *) AliasHandleResourceNBSTAT(
742127094Sdes			    q,
743127094Sdes			    pmax,
744127094Sdes			    nbtarg
745127094Sdes			    );
746127094Sdes			break;
747127094Sdes		default:
748145961Sglebius#ifdef LIBALIAS_DEBUG
749127094Sdes			printf(
750127094Sdes			    "\nUnknown Type of Resource %0x\n",
751127094Sdes			    ntohs(q->type)
752127094Sdes			    );
753145928Sglebius			fflush(stdout);
75444616Sbrian#endif
755127094Sdes			break;
75636321Samurai		}
75736321Samurai		count--;
75836321Samurai	}
759127094Sdes	return ((u_char *) q);
76036321Samurai}
76136321Samurai
762162674Spisostatic int
763127094SdesAliasHandleUdpNbtNS(
764127094Sdes    struct libalias *la,
765127094Sdes    struct ip *pip,		/* IP packet to examine/patch */
766131614Sdes    struct alias_link *lnk,
767127094Sdes    struct in_addr *alias_address,
768127094Sdes    u_short * alias_port,
769127094Sdes    struct in_addr *original_address,
770127094Sdes    u_short * original_port)
77136321Samurai{
772127094Sdes	struct udphdr *uh;
773127094Sdes	NbtNSHeader *nsh;
774127094Sdes	u_char *p;
775127094Sdes	char *pmax;
776127094Sdes	NBTArguments nbtarg;
77736321Samurai
778131614Sdes	(void)la;
779131614Sdes	(void)lnk;
780131614Sdes
78199207Sbrian	/* Set up Common Parameter */
782127094Sdes	nbtarg.oldaddr = *alias_address;
783127094Sdes	nbtarg.oldport = *alias_port;
784127094Sdes	nbtarg.newaddr = *original_address;
785127094Sdes	nbtarg.newport = *original_port;
78636321Samurai
787127094Sdes	/* Calculate data length of UDP packet */
788131699Sdes	uh = (struct udphdr *)ip_next(pip);
789127094Sdes	nbtarg.uh_sum = &(uh->uh_sum);
790131699Sdes	nsh = (NbtNSHeader *)udp_next(uh);
791127094Sdes	p = (u_char *) (nsh + 1);
792127094Sdes	pmax = (char *)uh + ntohs(uh->uh_ulen);
79336321Samurai
794127094Sdes	if ((char *)(nsh + 1) > pmax)
795127094Sdes		return (-1);
79641759Sdillon
797145961Sglebius#ifdef LIBALIAS_DEBUG
798127094Sdes	printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
799127094Sdes	    ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
800127094Sdes	    nsh->dir ? "Response" : "Request",
801127094Sdes	    nsh->nametrid,
802127094Sdes	    nsh->opcode,
803127094Sdes	    nsh->nmflags,
804127094Sdes	    nsh->rcode,
805127094Sdes	    ntohs(nsh->qdcount),
806127094Sdes	    ntohs(nsh->ancount),
807127094Sdes	    ntohs(nsh->nscount),
808127094Sdes	    ntohs(nsh->arcount),
809127094Sdes	    (u_char *) p - (u_char *) nsh
810127094Sdes	    );
81136321Samurai#endif
81236321Samurai
81336321Samurai	/* Question Entries */
814127094Sdes	if (ntohs(nsh->qdcount) != 0) {
815127094Sdes		p = AliasHandleQuestion(
816127094Sdes		    ntohs(nsh->qdcount),
817127094Sdes		    (NBTNsQuestion *) p,
818127094Sdes		    pmax,
819127094Sdes		    &nbtarg
820127094Sdes		    );
82136321Samurai	}
82236321Samurai	/* Answer Resource Records */
823127094Sdes	if (ntohs(nsh->ancount) != 0) {
824127094Sdes		p = AliasHandleResource(
825127094Sdes		    ntohs(nsh->ancount),
826127094Sdes		    (NBTNsResource *) p,
827127094Sdes		    pmax,
828127094Sdes		    &nbtarg
829127094Sdes		    );
83036321Samurai	}
83136321Samurai	/* Authority Resource Recodrs */
832127094Sdes	if (ntohs(nsh->nscount) != 0) {
833127094Sdes		p = AliasHandleResource(
834127094Sdes		    ntohs(nsh->nscount),
835127094Sdes		    (NBTNsResource *) p,
836127094Sdes		    pmax,
837127094Sdes		    &nbtarg
838127094Sdes		    );
83936321Samurai	}
84036321Samurai	/* Additional Resource Recodrs */
841127094Sdes	if (ntohs(nsh->arcount) != 0) {
842127094Sdes		p = AliasHandleResource(
843127094Sdes		    ntohs(nsh->arcount),
844127094Sdes		    (NBTNsResource *) p,
845127094Sdes		    pmax,
846127094Sdes		    &nbtarg
847127094Sdes		    );
84836321Samurai	}
849145961Sglebius#ifdef LIBALIAS_DEBUG
850127094Sdes	PrintRcode(nsh->rcode);
85136321Samurai#endif
852127094Sdes	return ((p == NULL) ? -1 : 0);
85336321Samurai}
854