alias_nbt.c revision 162674
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 162674 2006-09-26 23:26:53Z 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>
53145921Sglebius#endif
54145921Sglebius
5536321Samurai#include <netinet/in_systm.h>
5636321Samurai#include <netinet/in.h>
5736321Samurai#include <netinet/ip.h>
5836321Samurai#include <netinet/udp.h>
5936321Samurai
60145921Sglebius#ifdef _KERNEL
61145921Sglebius#include <netinet/libalias/alias_local.h>
62162674Spiso#include <netinet/libalias/alias_mod.h>
63145921Sglebius#else
6436321Samurai#include "alias_local.h"
65162674Spiso#include "alias_mod.h"
66145921Sglebius#endif
6736321Samurai
68162674Spiso#define NETBIOS_NS_PORT_NUMBER 137
69162674Spiso#define NETBIOS_DGM_PORT_NUMBER 138
70162674Spiso
71162674Spisostatic int
72162674SpisoAliasHandleUdpNbt(struct libalias *, struct ip *, struct alias_link *,
73162674Spiso		  struct in_addr *, u_short);
74162674Spiso
75162674Spisostatic int
76162674SpisoAliasHandleUdpNbtNS(struct libalias *, struct ip *, struct alias_link *,
77162674Spiso		    struct in_addr *, u_short *, struct in_addr *, u_short *);
78162674Spisostatic int
79162674Spisofingerprint1(struct libalias *la, struct ip *pip, struct alias_data *ah)
80162674Spiso{
81162674Spiso
82162674Spiso	if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
83162674Spiso	    ah->aaddr == NULL || ah->aport == NULL)
84162674Spiso		return (-1);
85162674Spiso	if (ntohs(*ah->dport) == NETBIOS_DGM_PORT_NUMBER
86162674Spiso	    || ntohs(*ah->sport) == NETBIOS_DGM_PORT_NUMBER)
87162674Spiso		return (0);
88162674Spiso	return (-1);
89162674Spiso}
90162674Spiso
91162674Spisostatic int
92162674Spisoprotohandler1(struct libalias *la, struct ip *pip, struct alias_data *ah)
93162674Spiso{
94162674Spiso
95162674Spiso	AliasHandleUdpNbt(la, pip, ah->lnk, ah->aaddr, *ah->aport);
96162674Spiso	return (0);
97162674Spiso}
98162674Spiso
99162674Spisostatic int
100162674Spisofingerprint2(struct libalias *la, struct ip *pip, struct alias_data *ah)
101162674Spiso{
102162674Spiso
103162674Spiso	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
112162674Spisostatic 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
121162674Spisostatic int
122162674Spisoprotohandler2out(struct libalias *la, struct ip *pip, struct alias_data *ah)
123162674Spiso{
124162674Spiso
125162674Spiso	AliasHandleUdpNbtNS(la, pip, ah->lnk, &pip->ip_src, ah->sport,
126162674Spiso 			    ah->aaddr, ah->aport);
127162674Spiso	return (0);
128162674Spiso}
129162674Spiso
130162674Spiso/* Kernel module definition. */
131162674Spisostruct proto_handler handlers[] = {
132162674Spiso	{
133162674Spiso	  .pri = 130,
134162674Spiso	  .dir = IN|OUT,
135162674Spiso	  .proto = UDP,
136162674Spiso	  .fingerprint = &fingerprint1,
137162674Spiso	  .protohandler = &protohandler1
138162674Spiso	},
139162674Spiso	{
140162674Spiso	  .pri = 140,
141162674Spiso	  .dir = IN,
142162674Spiso	  .proto = UDP,
143162674Spiso	  .fingerprint = &fingerprint2,
144162674Spiso	  .protohandler = &protohandler2in
145162674Spiso	},
146162674Spiso	{
147162674Spiso	  .pri = 140,
148162674Spiso	  .dir = OUT,
149162674Spiso	  .proto = UDP,
150162674Spiso	  .fingerprint = &fingerprint2,
151162674Spiso	  .protohandler = &protohandler2out
152162674Spiso	},
153162674Spiso	{ EOH }
154162674Spiso};
155162674Spiso
156162674Spisostatic int
157162674Spisomod_handler(module_t mod, int type, void *data)
158162674Spiso{
159162674Spiso	int error;
160162674Spiso
161162674Spiso	switch (type) {
162162674Spiso	case MOD_LOAD:
163162674Spiso		error = 0;
164162674Spiso		LibAliasAttachHandlers(handlers);
165162674Spiso		break;
166162674Spiso	case MOD_UNLOAD:
167162674Spiso		error = 0;
168162674Spiso		LibAliasDetachHandlers(handlers);
169162674Spiso		break;
170162674Spiso	default:
171162674Spiso		error = EINVAL;
172162674Spiso	}
173162674Spiso	return (error);
174162674Spiso}
175162674Spiso
176162674Spiso#ifdef	_KERNEL
177162674Spisostatic
178162674Spiso#endif
179162674Spisomoduledata_t alias_mod = {
180162674Spiso       "alias_nbt", mod_handler, NULL
181162674Spiso};
182162674Spiso
183162674Spiso#ifdef	_KERNEL
184162674SpisoDECLARE_MODULE(alias_nbt, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
185162674SpisoMODULE_VERSION(alias_nbt, 1);
186162674SpisoMODULE_DEPEND(alias_nbt, libalias, 1, 1, 1);
187162674Spiso#endif
188162674Spiso
18936321Samuraitypedef struct {
190127094Sdes	struct in_addr	oldaddr;
191127094Sdes	u_short		oldport;
192127094Sdes	struct in_addr	newaddr;
193127094Sdes	u_short		newport;
194127094Sdes	u_short        *uh_sum;
195127094Sdes}		NBTArguments;
19636321Samurai
19736321Samuraitypedef struct {
198127094Sdes	unsigned char	type;
199127094Sdes	unsigned char	flags;
200127094Sdes	u_short		id;
201127094Sdes	struct in_addr	source_ip;
202127094Sdes	u_short		source_port;
203127094Sdes	u_short		len;
204127094Sdes	u_short		offset;
205127094Sdes}		NbtDataHeader;
20636321Samurai
20736321Samurai#define OpQuery		0
20836321Samurai#define OpUnknown	4
20936321Samurai#define OpRegist	5
21036321Samurai#define OpRelease	6
21136321Samurai#define OpWACK		7
21236321Samurai#define OpRefresh	8
21336321Samuraitypedef struct {
214127094Sdes	u_short		nametrid;
215127094Sdes	u_short		dir:	1, opcode:4, nmflags:7, rcode:4;
216127094Sdes	u_short		qdcount;
217127094Sdes	u_short		ancount;
218127094Sdes	u_short		nscount;
219127094Sdes	u_short		arcount;
220127094Sdes}		NbtNSHeader;
22136321Samurai
22236321Samurai#define FMT_ERR		0x1
22336321Samurai#define SRV_ERR		0x2
22436321Samurai#define IMP_ERR		0x4
22536321Samurai#define RFS_ERR		0x5
22636321Samurai#define ACT_ERR		0x6
22736321Samurai#define CFT_ERR		0x7
22836321Samurai
22936321Samurai
230145961Sglebius#ifdef LIBALIAS_DEBUG
231127094Sdesstatic void
232127094SdesPrintRcode(u_char rcode)
233127094Sdes{
23436321Samurai
23536321Samurai	switch (rcode) {
23636321Samurai		case FMT_ERR:
237127094Sdes		printf("\nFormat Error.");
238127094Sdes	case SRV_ERR:
239127094Sdes		printf("\nSever failure.");
240127094Sdes	case IMP_ERR:
241127094Sdes		printf("\nUnsupported request error.\n");
242127094Sdes	case RFS_ERR:
243127094Sdes		printf("\nRefused error.\n");
244127094Sdes	case ACT_ERR:
245127094Sdes		printf("\nActive error.\n");
246127094Sdes	case CFT_ERR:
247127094Sdes		printf("\nName in conflict error.\n");
248127094Sdes	default:
249127094Sdes		printf("\n?%c?=%0x\n", '?', rcode);
25036321Samurai
25199207Sbrian	}
25236321Samurai}
253127094Sdes
25444616Sbrian#endif
25536321Samurai
25636321Samurai
25736321Samurai/* Handling Name field */
258127094Sdesstatic u_char  *
259127094SdesAliasHandleName(u_char * p, char *pmax)
260127094Sdes{
26136321Samurai
26236321Samurai	u_char *s;
26336321Samurai	u_char c;
264127094Sdes	int compress;
26536321Samurai
26636321Samurai	/* Following length field */
26741759Sdillon
26841759Sdillon	if (p == NULL || (char *)p >= pmax)
269127094Sdes		return (NULL);
27041759Sdillon
271127094Sdes	if (*p & 0xc0) {
27236321Samurai		p = p + 2;
27341759Sdillon		if ((char *)p > pmax)
274127094Sdes			return (NULL);
275127094Sdes		return ((u_char *) p);
27636321Samurai	}
277127094Sdes	while ((*p & 0x3f) != 0x00) {
27836321Samurai		s = p + 1;
279127094Sdes		if (*p == 0x20)
28036321Samurai			compress = 1;
28136321Samurai		else
28236321Samurai			compress = 0;
28399207Sbrian
284127094Sdes		/* Get next length field */
285127094Sdes		p = (u_char *) (p + (*p & 0x3f) + 1);
28641759Sdillon		if ((char *)p > pmax) {
28741759Sdillon			p = NULL;
28841759Sdillon			break;
28941759Sdillon		}
290145961Sglebius#ifdef LIBALIAS_DEBUG
29136321Samurai		printf(":");
29236321Samurai#endif
29336321Samurai		while (s < p) {
294127094Sdes			if (compress == 1) {
295127094Sdes				c = (u_char) (((((*s & 0x0f) << 4) | (*(s + 1) & 0x0f)) - 0x11));
296145961Sglebius#ifdef LIBALIAS_DEBUG
297127094Sdes				if (isprint(c))
298127094Sdes					printf("%c", c);
29936321Samurai				else
300127094Sdes					printf("<0x%02x>", c);
30136321Samurai#endif
302127094Sdes				s += 2;
30336321Samurai			} else {
304145961Sglebius#ifdef LIBALIAS_DEBUG
30536321Samurai				printf("%c", *s);
30636321Samurai#endif
30736321Samurai				s++;
30836321Samurai			}
30936321Samurai		}
310145961Sglebius#ifdef LIBALIAS_DEBUG
31136321Samurai		printf(":");
312145928Sglebius		fflush(stdout);
31336321Samurai#endif
314127094Sdes	}
31536321Samurai
31636321Samurai	/* Set up to out of Name field */
31741759Sdillon	if (p == NULL || (char *)p >= pmax)
318127094Sdes		p = NULL;
31941759Sdillon	else
320127094Sdes		p++;
321127094Sdes	return ((u_char *) p);
32236321Samurai}
32336321Samurai
32499207Sbrian/*
32536321Samurai * NetBios Datagram Handler (IP/UDP)
32636321Samurai */
32736321Samurai#define DGM_DIRECT_UNIQ		0x10
32836321Samurai#define DGM_DIRECT_GROUP	0x11
32936321Samurai#define DGM_BROADCAST		0x12
33036321Samurai#define DGM_ERROR			0x13
33136321Samurai#define DGM_QUERY			0x14
33236321Samurai#define DGM_POSITIVE_RES	0x15
33336321Samurai#define DGM_NEGATIVE_RES	0x16
33436321Samurai
335162674Spisostatic int
336127094SdesAliasHandleUdpNbt(
337127094Sdes    struct libalias *la,
338127094Sdes    struct ip *pip,		/* IP packet to examine/patch */
339131614Sdes    struct alias_link *lnk,
340127094Sdes    struct in_addr *alias_address,
341127094Sdes    u_short alias_port
342127094Sdes)
343127094Sdes{
344127094Sdes	struct udphdr *uh;
345127094Sdes	NbtDataHeader *ndh;
346127094Sdes	u_char *p = NULL;
347127094Sdes	char *pmax;
34899207Sbrian
349131614Sdes	(void)la;
350131614Sdes	(void)lnk;
351131614Sdes
352127094Sdes	/* Calculate data length of UDP packet */
353131699Sdes	uh = (struct udphdr *)ip_next(pip);
354127094Sdes	pmax = (char *)uh + ntohs(uh->uh_ulen);
35541759Sdillon
356131699Sdes	ndh = (NbtDataHeader *)udp_next(uh);
357127094Sdes	if ((char *)(ndh + 1) > pmax)
358127094Sdes		return (-1);
359145961Sglebius#ifdef LIBALIAS_DEBUG
360127094Sdes	printf("\nType=%02x,", ndh->type);
36136321Samurai#endif
362127094Sdes	switch (ndh->type) {
363127094Sdes	case DGM_DIRECT_UNIQ:
364127094Sdes	case DGM_DIRECT_GROUP:
365127094Sdes	case DGM_BROADCAST:
366127094Sdes		p = (u_char *) ndh + 14;
367127094Sdes		p = AliasHandleName(p, pmax);	/* Source Name */
368127094Sdes		p = AliasHandleName(p, pmax);	/* Destination Name */
369127094Sdes		break;
370127094Sdes	case DGM_ERROR:
371127094Sdes		p = (u_char *) ndh + 11;
372127094Sdes		break;
373127094Sdes	case DGM_QUERY:
374127094Sdes	case DGM_POSITIVE_RES:
375127094Sdes	case DGM_NEGATIVE_RES:
376127094Sdes		p = (u_char *) ndh + 10;
377127094Sdes		p = AliasHandleName(p, pmax);	/* Destination Name */
378127094Sdes		break;
37936321Samurai	}
380127094Sdes	if (p == NULL || (char *)p > pmax)
381127094Sdes		p = NULL;
382145961Sglebius#ifdef LIBALIAS_DEBUG
383127094Sdes	printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
38436321Samurai#endif
385108533Sschweikh	/* Doing an IP address and Port number Translation */
386127094Sdes	if (uh->uh_sum != 0) {
387127094Sdes		int acc;
388127094Sdes		u_short *sptr;
389127094Sdes
390127094Sdes		acc = ndh->source_port;
39136321Samurai		acc -= alias_port;
392127094Sdes		sptr = (u_short *) & (ndh->source_ip);
39336321Samurai		acc += *sptr++;
39436321Samurai		acc += *sptr;
39536321Samurai		sptr = (u_short *) alias_address;
39636321Samurai		acc -= *sptr++;
39736321Samurai		acc -= *sptr;
39874778Sbrian		ADJUST_CHECKSUM(acc, uh->uh_sum);
39936321Samurai	}
400127094Sdes	ndh->source_ip = *alias_address;
401127094Sdes	ndh->source_port = alias_port;
402145961Sglebius#ifdef LIBALIAS_DEBUG
403127094Sdes	printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port));
40436321Samurai	fflush(stdout);
40536321Samurai#endif
406127094Sdes	return ((p == NULL) ? -1 : 0);
40736321Samurai}
408127094Sdes
40936321Samurai/* Question Section */
41036321Samurai#define QS_TYPE_NB		0x0020
41136321Samurai#define QS_TYPE_NBSTAT	0x0021
41236321Samurai#define QS_CLAS_IN		0x0001
41336321Samuraitypedef struct {
414127094Sdes	u_short		type;	/* The type of Request */
415127094Sdes	u_short		class;	/* The class of Request */
416127094Sdes}		NBTNsQuestion;
41736321Samurai
418127094Sdesstatic u_char  *
41941759SdillonAliasHandleQuestion(
42041759Sdillon    u_short count,
421127094Sdes    NBTNsQuestion * q,
42241759Sdillon    char *pmax,
423127094Sdes    NBTArguments * nbtarg)
42436321Samurai{
42536321Samurai
426131614Sdes	(void)nbtarg;
427131614Sdes
428127094Sdes	while (count != 0) {
42936321Samurai		/* Name Filed */
430127094Sdes		q = (NBTNsQuestion *) AliasHandleName((u_char *) q, pmax);
43136321Samurai
43241759Sdillon		if (q == NULL || (char *)(q + 1) > pmax) {
43341759Sdillon			q = NULL;
43441759Sdillon			break;
43541759Sdillon		}
43636321Samurai		/* Type and Class filed */
437127094Sdes		switch (ntohs(q->type)) {
438127094Sdes		case QS_TYPE_NB:
439127094Sdes		case QS_TYPE_NBSTAT:
440127094Sdes			q = q + 1;
44136321Samurai			break;
442127094Sdes		default:
443145961Sglebius#ifdef LIBALIAS_DEBUG
444127094Sdes			printf("\nUnknown Type on Question %0x\n", ntohs(q->type));
44544616Sbrian#endif
44636321Samurai			break;
44736321Samurai		}
44836321Samurai		count--;
44936321Samurai	}
45036321Samurai
45136321Samurai	/* Set up to out of Question Section */
452127094Sdes	return ((u_char *) q);
45336321Samurai}
45436321Samurai
45536321Samurai/* Resource Record */
45636321Samurai#define RR_TYPE_A		0x0001
45736321Samurai#define RR_TYPE_NS		0x0002
45836321Samurai#define RR_TYPE_NULL	0x000a
45936321Samurai#define RR_TYPE_NB		0x0020
46036321Samurai#define RR_TYPE_NBSTAT	0x0021
46136321Samurai#define RR_CLAS_IN		0x0001
46236321Samurai#define SizeOfNsResource	8
46336321Samuraitypedef struct {
464127094Sdes	u_short		type;
465127094Sdes	u_short		class;
466127094Sdes	unsigned int	ttl;
467127094Sdes	u_short		rdlen;
468127094Sdes}		NBTNsResource;
46936321Samurai
47036321Samurai#define SizeOfNsRNB			6
47136321Samuraitypedef struct {
472127094Sdes	u_short		g:	1  , ont:2, resv:13;
473127094Sdes	struct in_addr	addr;
474127094Sdes}		NBTNsRNB;
47536321Samurai
476127094Sdesstatic u_char  *
47799207SbrianAliasHandleResourceNB(
478127094Sdes    NBTNsResource * q,
47999207Sbrian    char *pmax,
480127094Sdes    NBTArguments * nbtarg)
48136321Samurai{
482127094Sdes	NBTNsRNB *nb;
48336321Samurai	u_short bcount;
48436321Samurai
48541759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
486127094Sdes		return (NULL);
48736321Samurai	/* Check out a length */
48836321Samurai	bcount = ntohs(q->rdlen);
48936321Samurai
49036321Samurai	/* Forward to Resource NB position */
491127094Sdes	nb = (NBTNsRNB *) ((u_char *) q + SizeOfNsResource);
49236321Samurai
49336321Samurai	/* Processing all in_addr array */
494145961Sglebius#ifdef LIBALIAS_DEBUG
49536321Samurai	printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
496127094Sdes	printf("->%s, %dbytes] ", inet_ntoa(nbtarg->newaddr), bcount);
49736321Samurai#endif
498127094Sdes	while (nb != NULL && bcount != 0) {
49941759Sdillon		if ((char *)(nb + 1) > pmax) {
50041759Sdillon			nb = NULL;
50141759Sdillon			break;
50241759Sdillon		}
503145961Sglebius#ifdef LIBALIAS_DEBUG
504127094Sdes		printf("<%s>", inet_ntoa(nb->addr));
50536321Samurai#endif
506127094Sdes		if (!bcmp(&nbtarg->oldaddr, &nb->addr, sizeof(struct in_addr))) {
507127094Sdes			if (*nbtarg->uh_sum != 0) {
508127094Sdes				int acc;
509127094Sdes				u_short *sptr;
51036321Samurai
511127094Sdes				sptr = (u_short *) & (nb->addr);
512127094Sdes				acc = *sptr++;
513127094Sdes				acc += *sptr;
514127094Sdes				sptr = (u_short *) & (nbtarg->newaddr);
515127094Sdes				acc -= *sptr++;
516127094Sdes				acc -= *sptr;
517127094Sdes				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
51836321Samurai			}
51936321Samurai			nb->addr = nbtarg->newaddr;
520145961Sglebius#ifdef LIBALIAS_DEBUG
52136321Samurai			printf("O");
52236321Samurai#endif
52336321Samurai		}
524145961Sglebius#ifdef LIBALIAS_DEBUG
525127094Sdes		else {
52636321Samurai			printf(".");
52736321Samurai		}
52836321Samurai#endif
529127094Sdes		nb = (NBTNsRNB *) ((u_char *) nb + SizeOfNsRNB);
530127094Sdes		bcount -= SizeOfNsRNB;
53136321Samurai	}
53241759Sdillon	if (nb == NULL || (char *)(nb + 1) > pmax) {
53341759Sdillon		nb = NULL;
53441759Sdillon	}
535127094Sdes	return ((u_char *) nb);
53636321Samurai}
53736321Samurai
53836321Samurai#define SizeOfResourceA		6
53936321Samuraitypedef struct {
540127094Sdes	struct in_addr	addr;
541127094Sdes}		NBTNsResourceA;
54236321Samurai
543127094Sdesstatic u_char  *
54499207SbrianAliasHandleResourceA(
545127094Sdes    NBTNsResource * q,
54641759Sdillon    char *pmax,
547127094Sdes    NBTArguments * nbtarg)
54836321Samurai{
549127094Sdes	NBTNsResourceA *a;
55036321Samurai	u_short bcount;
55136321Samurai
55241759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
553127094Sdes		return (NULL);
55441759Sdillon
55536321Samurai	/* Forward to Resource A position */
556127094Sdes	a = (NBTNsResourceA *) ((u_char *) q + sizeof(NBTNsResource));
55736321Samurai
55836321Samurai	/* Check out of length */
55936321Samurai	bcount = ntohs(q->rdlen);
56036321Samurai
56136321Samurai	/* Processing all in_addr array */
562145961Sglebius#ifdef LIBALIAS_DEBUG
56336321Samurai	printf("Arec [%s", inet_ntoa(nbtarg->oldaddr));
564127094Sdes	printf("->%s]", inet_ntoa(nbtarg->newaddr));
56536321Samurai#endif
566127094Sdes	while (bcount != 0) {
56741759Sdillon		if (a == NULL || (char *)(a + 1) > pmax)
568127094Sdes			return (NULL);
569145961Sglebius#ifdef LIBALIAS_DEBUG
570127094Sdes		printf("..%s", inet_ntoa(a->addr));
57136321Samurai#endif
572127094Sdes		if (!bcmp(&nbtarg->oldaddr, &a->addr, sizeof(struct in_addr))) {
573127094Sdes			if (*nbtarg->uh_sum != 0) {
574127094Sdes				int acc;
575127094Sdes				u_short *sptr;
57636321Samurai
577127094Sdes				sptr = (u_short *) & (a->addr);	/* Old */
578127094Sdes				acc = *sptr++;
579127094Sdes				acc += *sptr;
580127094Sdes				sptr = (u_short *) & nbtarg->newaddr;	/* New */
581127094Sdes				acc -= *sptr++;
582127094Sdes				acc -= *sptr;
583127094Sdes				ADJUST_CHECKSUM(acc, *nbtarg->uh_sum);
58436321Samurai			}
58536321Samurai			a->addr = nbtarg->newaddr;
58636321Samurai		}
587127094Sdes		a++;		/* XXXX */
58836321Samurai		bcount -= SizeOfResourceA;
58936321Samurai	}
59041759Sdillon	if (a == NULL || (char *)(a + 1) > pmax)
591127094Sdes		a = NULL;
592127094Sdes	return ((u_char *) a);
59336321Samurai}
59436321Samurai
59536321Samuraitypedef struct {
596127094Sdes	u_short		opcode:4, flags:8, resv:4;
597127094Sdes}		NBTNsResourceNULL;
59836321Samurai
599127094Sdesstatic u_char  *
60099207SbrianAliasHandleResourceNULL(
601127094Sdes    NBTNsResource * q,
60241759Sdillon    char *pmax,
603127094Sdes    NBTArguments * nbtarg)
60436321Samurai{
605127094Sdes	NBTNsResourceNULL *n;
60636321Samurai	u_short bcount;
60736321Samurai
608131614Sdes	(void)nbtarg;
609131614Sdes
61041759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
611127094Sdes		return (NULL);
61241759Sdillon
61336321Samurai	/* Forward to Resource NULL position */
614127094Sdes	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
61536321Samurai
61636321Samurai	/* Check out of length */
61736321Samurai	bcount = ntohs(q->rdlen);
61836321Samurai
61936321Samurai	/* Processing all in_addr array */
620127094Sdes	while (bcount != 0) {
62141759Sdillon		if ((char *)(n + 1) > pmax) {
62241759Sdillon			n = NULL;
62341759Sdillon			break;
62441759Sdillon		}
62536321Samurai		n++;
62636321Samurai		bcount -= sizeof(NBTNsResourceNULL);
62736321Samurai	}
62841759Sdillon	if ((char *)(n + 1) > pmax)
62941759Sdillon		n = NULL;
63036321Samurai
631127094Sdes	return ((u_char *) n);
63236321Samurai}
63336321Samurai
634127094Sdesstatic u_char  *
63599207SbrianAliasHandleResourceNS(
636127094Sdes    NBTNsResource * q,
63741759Sdillon    char *pmax,
638127094Sdes    NBTArguments * nbtarg)
63936321Samurai{
640127094Sdes	NBTNsResourceNULL *n;
64136321Samurai	u_short bcount;
64236321Samurai
643131614Sdes	(void)nbtarg;
644131614Sdes
64541759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
646127094Sdes		return (NULL);
64741759Sdillon
64836321Samurai	/* Forward to Resource NULL position */
649127094Sdes	n = (NBTNsResourceNULL *) ((u_char *) q + sizeof(NBTNsResource));
65036321Samurai
65136321Samurai	/* Check out of length */
65236321Samurai	bcount = ntohs(q->rdlen);
65336321Samurai
65436321Samurai	/* Resource Record Name Filed */
655127094Sdes	q = (NBTNsResource *) AliasHandleName((u_char *) n, pmax);	/* XXX */
65636321Samurai
657127094Sdes	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
658127094Sdes		return (NULL);
65941759Sdillon	else
660127094Sdes		return ((u_char *) n + bcount);
66136321Samurai}
66236321Samurai
66336321Samuraitypedef struct {
664127094Sdes	u_short		numnames;
665127094Sdes}		NBTNsResourceNBSTAT;
66636321Samurai
667127094Sdesstatic u_char  *
66841759SdillonAliasHandleResourceNBSTAT(
669127094Sdes    NBTNsResource * q,
67041759Sdillon    char *pmax,
671127094Sdes    NBTArguments * nbtarg)
67236321Samurai{
673127094Sdes	NBTNsResourceNBSTAT *n;
67436321Samurai	u_short bcount;
67536321Samurai
676131614Sdes	(void)nbtarg;
677131614Sdes
67841759Sdillon	if (q == NULL || (char *)(q + 1) > pmax)
679127094Sdes		return (NULL);
68041759Sdillon
68136321Samurai	/* Forward to Resource NBSTAT position */
682127094Sdes	n = (NBTNsResourceNBSTAT *) ((u_char *) q + sizeof(NBTNsResource));
68336321Samurai
68436321Samurai	/* Check out of length */
68536321Samurai	bcount = ntohs(q->rdlen);
68636321Samurai
687127094Sdes	if (q == NULL || (char *)((u_char *) n + bcount) > pmax)
688127094Sdes		return (NULL);
68941759Sdillon	else
690127094Sdes		return ((u_char *) n + bcount);
69136321Samurai}
69236321Samurai
693127094Sdesstatic u_char  *
69441759SdillonAliasHandleResource(
69599207Sbrian    u_short count,
696127094Sdes    NBTNsResource * q,
69741759Sdillon    char *pmax,
69899207Sbrian    NBTArguments
699127094Sdes    * nbtarg)
70036321Samurai{
701127094Sdes	while (count != 0) {
70236321Samurai		/* Resource Record Name Filed */
703127094Sdes		q = (NBTNsResource *) AliasHandleName((u_char *) q, pmax);
70441759Sdillon
70541759Sdillon		if (q == NULL || (char *)(q + 1) > pmax)
70641759Sdillon			break;
707145961Sglebius#ifdef LIBALIAS_DEBUG
708127094Sdes		printf("type=%02x, count=%d\n", ntohs(q->type), count);
70936321Samurai#endif
71036321Samurai
71136321Samurai		/* Type and Class filed */
712127094Sdes		switch (ntohs(q->type)) {
713127094Sdes		case RR_TYPE_NB:
714127094Sdes			q = (NBTNsResource *) AliasHandleResourceNB(
715127094Sdes			    q,
716127094Sdes			    pmax,
717127094Sdes			    nbtarg
718127094Sdes			    );
719127094Sdes			break;
720127094Sdes		case RR_TYPE_A:
721127094Sdes			q = (NBTNsResource *) AliasHandleResourceA(
722127094Sdes			    q,
723127094Sdes			    pmax,
724127094Sdes			    nbtarg
725127094Sdes			    );
726127094Sdes			break;
727127094Sdes		case RR_TYPE_NS:
728127094Sdes			q = (NBTNsResource *) AliasHandleResourceNS(
729127094Sdes			    q,
730127094Sdes			    pmax,
731127094Sdes			    nbtarg
732127094Sdes			    );
733127094Sdes			break;
734127094Sdes		case RR_TYPE_NULL:
735127094Sdes			q = (NBTNsResource *) AliasHandleResourceNULL(
736127094Sdes			    q,
737127094Sdes			    pmax,
738127094Sdes			    nbtarg
739127094Sdes			    );
740127094Sdes			break;
741127094Sdes		case RR_TYPE_NBSTAT:
742127094Sdes			q = (NBTNsResource *) AliasHandleResourceNBSTAT(
743127094Sdes			    q,
744127094Sdes			    pmax,
745127094Sdes			    nbtarg
746127094Sdes			    );
747127094Sdes			break;
748127094Sdes		default:
749145961Sglebius#ifdef LIBALIAS_DEBUG
750127094Sdes			printf(
751127094Sdes			    "\nUnknown Type of Resource %0x\n",
752127094Sdes			    ntohs(q->type)
753127094Sdes			    );
754145928Sglebius			fflush(stdout);
75544616Sbrian#endif
756127094Sdes			break;
75736321Samurai		}
75836321Samurai		count--;
75936321Samurai	}
760127094Sdes	return ((u_char *) q);
76136321Samurai}
76236321Samurai
763162674Spisostatic int
764127094SdesAliasHandleUdpNbtNS(
765127094Sdes    struct libalias *la,
766127094Sdes    struct ip *pip,		/* IP packet to examine/patch */
767131614Sdes    struct alias_link *lnk,
768127094Sdes    struct in_addr *alias_address,
769127094Sdes    u_short * alias_port,
770127094Sdes    struct in_addr *original_address,
771127094Sdes    u_short * original_port)
77236321Samurai{
773127094Sdes	struct udphdr *uh;
774127094Sdes	NbtNSHeader *nsh;
775127094Sdes	u_char *p;
776127094Sdes	char *pmax;
777127094Sdes	NBTArguments nbtarg;
77836321Samurai
779131614Sdes	(void)la;
780131614Sdes	(void)lnk;
781131614Sdes
78299207Sbrian	/* Set up Common Parameter */
783127094Sdes	nbtarg.oldaddr = *alias_address;
784127094Sdes	nbtarg.oldport = *alias_port;
785127094Sdes	nbtarg.newaddr = *original_address;
786127094Sdes	nbtarg.newport = *original_port;
78736321Samurai
788127094Sdes	/* Calculate data length of UDP packet */
789131699Sdes	uh = (struct udphdr *)ip_next(pip);
790127094Sdes	nbtarg.uh_sum = &(uh->uh_sum);
791131699Sdes	nsh = (NbtNSHeader *)udp_next(uh);
792127094Sdes	p = (u_char *) (nsh + 1);
793127094Sdes	pmax = (char *)uh + ntohs(uh->uh_ulen);
79436321Samurai
795127094Sdes	if ((char *)(nsh + 1) > pmax)
796127094Sdes		return (-1);
79741759Sdillon
798145961Sglebius#ifdef LIBALIAS_DEBUG
799127094Sdes	printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
800127094Sdes	    ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
801127094Sdes	    nsh->dir ? "Response" : "Request",
802127094Sdes	    nsh->nametrid,
803127094Sdes	    nsh->opcode,
804127094Sdes	    nsh->nmflags,
805127094Sdes	    nsh->rcode,
806127094Sdes	    ntohs(nsh->qdcount),
807127094Sdes	    ntohs(nsh->ancount),
808127094Sdes	    ntohs(nsh->nscount),
809127094Sdes	    ntohs(nsh->arcount),
810127094Sdes	    (u_char *) p - (u_char *) nsh
811127094Sdes	    );
81236321Samurai#endif
81336321Samurai
81436321Samurai	/* Question Entries */
815127094Sdes	if (ntohs(nsh->qdcount) != 0) {
816127094Sdes		p = AliasHandleQuestion(
817127094Sdes		    ntohs(nsh->qdcount),
818127094Sdes		    (NBTNsQuestion *) p,
819127094Sdes		    pmax,
820127094Sdes		    &nbtarg
821127094Sdes		    );
82236321Samurai	}
82336321Samurai	/* Answer Resource Records */
824127094Sdes	if (ntohs(nsh->ancount) != 0) {
825127094Sdes		p = AliasHandleResource(
826127094Sdes		    ntohs(nsh->ancount),
827127094Sdes		    (NBTNsResource *) p,
828127094Sdes		    pmax,
829127094Sdes		    &nbtarg
830127094Sdes		    );
83136321Samurai	}
83236321Samurai	/* Authority Resource Recodrs */
833127094Sdes	if (ntohs(nsh->nscount) != 0) {
834127094Sdes		p = AliasHandleResource(
835127094Sdes		    ntohs(nsh->nscount),
836127094Sdes		    (NBTNsResource *) p,
837127094Sdes		    pmax,
838127094Sdes		    &nbtarg
839127094Sdes		    );
84036321Samurai	}
84136321Samurai	/* Additional Resource Recodrs */
842127094Sdes	if (ntohs(nsh->arcount) != 0) {
843127094Sdes		p = AliasHandleResource(
844127094Sdes		    ntohs(nsh->arcount),
845127094Sdes		    (NBTNsResource *) p,
846127094Sdes		    pmax,
847127094Sdes		    &nbtarg
848127094Sdes		    );
84936321Samurai	}
850145961Sglebius#ifdef LIBALIAS_DEBUG
851127094Sdes	PrintRcode(nsh->rcode);
85236321Samurai#endif
853127094Sdes	return ((p == NULL) ? -1 : 0);
85436321Samurai}
855