xref: /csrg-svn/lib/libc/net/res_comp.c (revision 61151)
161023Skarels /*-
2*61151Sbostic  * Copyright (c) 1985, 1993
3*61151Sbostic  *	The Regents of the University of California.  All rights reserved.
433679Sbostic  *
542627Sbostic  * %sccs.include.redist.c%
661023Skarels  * -
761023Skarels  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
861023Skarels  *
961023Skarels  * Permission to use, copy, modify, and distribute this software for any
1061023Skarels  * purpose with or without fee is hereby granted, provided that the above
1161023Skarels  * copyright notice and this permission notice appear in all copies, and that
1261023Skarels  * the name of Digital Equipment Corporation not be used in advertising or
1361023Skarels  * publicity pertaining to distribution of the document or software without
1461023Skarels  * specific, written prior permission.
1561023Skarels  *
1661023Skarels  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
1761023Skarels  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
1861023Skarels  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
1961023Skarels  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
2061023Skarels  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
2161023Skarels  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
2261023Skarels  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2361023Skarels  * SOFTWARE.
2461023Skarels  * -
2561023Skarels  * --Copyright--
2618546Sralph  */
2718546Sralph 
2826631Sdonn #if defined(LIBC_SCCS) && !defined(lint)
29*61151Sbostic static char sccsid[] = "@(#)res_comp.c	8.1 (Berkeley) 06/04/93";
3061023Skarels static char rcsid[] = "$Id: res_comp.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $";
3133679Sbostic #endif /* LIBC_SCCS and not lint */
3221384Sdist 
3347588Sbostic #include <sys/param.h>
3446604Sbostic #include <arpa/nameser.h>
3546604Sbostic #include <netinet/in.h>
3646604Sbostic #include <resolv.h>
3718140Sralph #include <stdio.h>
3818140Sralph 
3961023Skarels static int dn_find();
4041093Sleres 
4118140Sralph /*
4218342Sralph  * Expand compressed domain name 'comp_dn' to full domain name.
4318342Sralph  * 'msg' is a pointer to the begining of the message,
4426112Skarels  * 'eomorig' points to the first location after the message,
4518342Sralph  * 'exp_dn' is a pointer to a buffer of size 'length' for the result.
4618140Sralph  * Return size of compressed name or -1 if there was an error.
4718140Sralph  */
dn_expand(msg,eomorig,comp_dn,exp_dn,length)4826112Skarels dn_expand(msg, eomorig, comp_dn, exp_dn, length)
4946604Sbostic 	const u_char *msg, *eomorig, *comp_dn;
5046604Sbostic 	u_char *exp_dn;
5126112Skarels 	int length;
5218140Sralph {
5332647Skarels 	register u_char *cp, *dn;
5418140Sralph 	register int n, c;
5532647Skarels 	u_char *eom;
5631686Skarels 	int len = -1, checked = 0;
5718140Sralph 
5818140Sralph 	dn = exp_dn;
5946604Sbostic 	cp = (u_char *)comp_dn;
6039788Sbloom 	eom = exp_dn + length;
6118140Sralph 	/*
6218140Sralph 	 * fetch next label in domain name
6318140Sralph 	 */
6418140Sralph 	while (n = *cp++) {
6518140Sralph 		/*
6618140Sralph 		 * Check for indirection
6718140Sralph 		 */
6818140Sralph 		switch (n & INDIR_MASK) {
6918140Sralph 		case 0:
7018342Sralph 			if (dn != exp_dn) {
7118342Sralph 				if (dn >= eom)
7218342Sralph 					return (-1);
7318140Sralph 				*dn++ = '.';
7418342Sralph 			}
7518140Sralph 			if (dn+n >= eom)
7618140Sralph 				return (-1);
7731686Skarels 			checked += n + 1;
7826064Skjd 			while (--n >= 0) {
7926812Sbloom 				if ((c = *cp++) == '.') {
8044325Sbloom 					if (dn + n + 2 >= eom)
8126812Sbloom 						return (-1);
8226812Sbloom 					*dn++ = '\\';
8318342Sralph 				}
8426812Sbloom 				*dn++ = c;
8526112Skarels 				if (cp >= eomorig)	/* out of range */
8626064Skjd 					return(-1);
8726064Skjd 			}
8818140Sralph 			break;
8918140Sralph 
9018140Sralph 		case INDIR_MASK:
9118342Sralph 			if (len < 0)
9218140Sralph 				len = cp - comp_dn + 1;
9346604Sbostic 			cp = (u_char *)msg + (((n & 0x3f) << 8) | (*cp & 0xff));
9426112Skarels 			if (cp < msg || cp >= eomorig)	/* out of range */
9526064Skjd 				return(-1);
9631686Skarels 			checked += 2;
9731686Skarels 			/*
9831686Skarels 			 * Check for loops in the compressed name;
9931686Skarels 			 * if we've looked at the whole message,
10031686Skarels 			 * there must be a loop.
10131686Skarels 			 */
10231686Skarels 			if (checked >= eomorig - msg)
10331686Skarels 				return (-1);
10418140Sralph 			break;
10518140Sralph 
10618140Sralph 		default:
10718140Sralph 			return (-1);			/* flag error */
10818140Sralph 		}
10918140Sralph 	}
11018140Sralph 	*dn = '\0';
11118342Sralph 	if (len < 0)
11218140Sralph 		len = cp - comp_dn;
11318140Sralph 	return (len);
11418140Sralph }
11518140Sralph 
11618140Sralph /*
11718342Sralph  * Compress domain name 'exp_dn' into 'comp_dn'.
11818342Sralph  * Return the size of the compressed name or -1.
11918342Sralph  * 'length' is the size of the array pointed to by 'comp_dn'.
12018342Sralph  * 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
12118140Sralph  * is a pointer to the beginning of the message. The list ends with NULL.
12218342Sralph  * 'lastdnptr' is a pointer to the end of the arrary pointed to
12318342Sralph  * by 'dnptrs'. Side effect is to update the list of pointers for
12418342Sralph  * labels inserted into the message as we compress the name.
12518342Sralph  * If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
12618342Sralph  * is NULL, we don't update the list.
12718140Sralph  */
dn_comp(exp_dn,comp_dn,length,dnptrs,lastdnptr)12818140Sralph dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
12946604Sbostic 	const u_char *exp_dn;
13046604Sbostic 	u_char *comp_dn, **dnptrs, **lastdnptr;
13118140Sralph 	int length;
13218140Sralph {
13332647Skarels 	register u_char *cp, *dn;
13418140Sralph 	register int c, l;
13532647Skarels 	u_char **cpp, **lpp, *sp, *eob;
13632647Skarels 	u_char *msg;
13718140Sralph 
13846604Sbostic 	dn = (u_char *)exp_dn;
13918140Sralph 	cp = comp_dn;
14025360Sbloom 	eob = cp + length;
14118140Sralph 	if (dnptrs != NULL) {
14218140Sralph 		if ((msg = *dnptrs++) != NULL) {
14318140Sralph 			for (cpp = dnptrs; *cpp != NULL; cpp++)
14418140Sralph 				;
14518140Sralph 			lpp = cpp;	/* end of list to search */
14618140Sralph 		}
14718140Sralph 	} else
14818140Sralph 		msg = NULL;
14918140Sralph 	for (c = *dn++; c != '\0'; ) {
15018140Sralph 		/* look to see if we can use pointers */
15118140Sralph 		if (msg != NULL) {
15218140Sralph 			if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
15318140Sralph 				if (cp+1 >= eob)
15418140Sralph 					return (-1);
15518140Sralph 				*cp++ = (l >> 8) | INDIR_MASK;
15626240Skjd 				*cp++ = l % 256;
15718140Sralph 				return (cp - comp_dn);
15818140Sralph 			}
15918140Sralph 			/* not found, save it */
16018140Sralph 			if (lastdnptr != NULL && cpp < lastdnptr-1) {
16118140Sralph 				*cpp++ = cp;
16218140Sralph 				*cpp = NULL;
16318140Sralph 			}
16418140Sralph 		}
16518140Sralph 		sp = cp++;	/* save ptr to length byte */
16618140Sralph 		do {
16718140Sralph 			if (c == '.') {
16818140Sralph 				c = *dn++;
16918140Sralph 				break;
17018140Sralph 			}
17118342Sralph 			if (c == '\\') {
17218342Sralph 				if ((c = *dn++) == '\0')
17318342Sralph 					break;
17418342Sralph 			}
17539788Sbloom 			if (cp >= eob) {
17639788Sbloom 				if (msg != NULL)
17739788Sbloom 					*lpp = NULL;
17818140Sralph 				return (-1);
17939788Sbloom 			}
18018140Sralph 			*cp++ = c;
18118140Sralph 		} while ((c = *dn++) != '\0');
18218342Sralph 		/* catch trailing '.'s but not '..' */
18318342Sralph 		if ((l = cp - sp - 1) == 0 && c == '\0') {
18418342Sralph 			cp--;
18518342Sralph 			break;
18618342Sralph 		}
18739788Sbloom 		if (l <= 0 || l > MAXLABEL) {
18839788Sbloom 			if (msg != NULL)
18939788Sbloom 				*lpp = NULL;
19018140Sralph 			return (-1);
19139788Sbloom 		}
19218140Sralph 		*sp = l;
19318140Sralph 	}
19439788Sbloom 	if (cp >= eob) {
19539788Sbloom 		if (msg != NULL)
19639788Sbloom 			*lpp = NULL;
19718140Sralph 		return (-1);
19839788Sbloom 	}
19918140Sralph 	*cp++ = '\0';
20018140Sralph 	return (cp - comp_dn);
20118140Sralph }
20218140Sralph 
20318140Sralph /*
20418342Sralph  * Skip over a compressed domain name. Return the size or -1.
20518140Sralph  */
__dn_skipname(comp_dn,eom)20646496Sbostic __dn_skipname(comp_dn, eom)
20747045Sbostic 	const u_char *comp_dn, *eom;
20818140Sralph {
20932647Skarels 	register u_char *cp;
21018140Sralph 	register int n;
21118140Sralph 
21247045Sbostic 	cp = (u_char *)comp_dn;
21332647Skarels 	while (cp < eom && (n = *cp++)) {
21418140Sralph 		/*
21518140Sralph 		 * check for indirection
21618140Sralph 		 */
21718140Sralph 		switch (n & INDIR_MASK) {
21818140Sralph 		case 0:		/* normal case, n == len */
21918140Sralph 			cp += n;
22018140Sralph 			continue;
22118140Sralph 		default:	/* illegal type */
22218140Sralph 			return (-1);
22318140Sralph 		case INDIR_MASK:	/* indirection */
22418140Sralph 			cp++;
22518140Sralph 		}
22618140Sralph 		break;
22718140Sralph 	}
22818342Sralph 	return (cp - comp_dn);
22918140Sralph }
23018140Sralph 
23118140Sralph /*
23218140Sralph  * Search for expanded name from a list of previously compressed names.
23318140Sralph  * Return the offset from msg if found or -1.
23433617Skarels  * dnptrs is the pointer to the first name on the list,
23533617Skarels  * not the pointer to the start of the message.
23618140Sralph  */
23761023Skarels static int
dn_find(exp_dn,msg,dnptrs,lastdnptr)23818140Sralph dn_find(exp_dn, msg, dnptrs, lastdnptr)
23932647Skarels 	u_char *exp_dn, *msg;
24032647Skarels 	u_char **dnptrs, **lastdnptr;
24118140Sralph {
24232647Skarels 	register u_char *dn, *cp, **cpp;
24318140Sralph 	register int n;
24432647Skarels 	u_char *sp;
24518140Sralph 
24633617Skarels 	for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
24718140Sralph 		dn = exp_dn;
24818140Sralph 		sp = cp = *cpp;
24918140Sralph 		while (n = *cp++) {
25018140Sralph 			/*
25118140Sralph 			 * check for indirection
25218140Sralph 			 */
25318140Sralph 			switch (n & INDIR_MASK) {
25418140Sralph 			case 0:		/* normal case, n == len */
25518342Sralph 				while (--n >= 0) {
25639788Sbloom 					if (*dn == '.')
25739788Sbloom 						goto next;
25818342Sralph 					if (*dn == '\\')
25918342Sralph 						dn++;
26018140Sralph 					if (*dn++ != *cp++)
26118140Sralph 						goto next;
26218342Sralph 				}
26318140Sralph 				if ((n = *dn++) == '\0' && *cp == '\0')
26418140Sralph 					return (sp - msg);
26518140Sralph 				if (n == '.')
26618140Sralph 					continue;
26718140Sralph 				goto next;
26818140Sralph 
26918140Sralph 			default:	/* illegal type */
27018140Sralph 				return (-1);
27118140Sralph 
27218140Sralph 			case INDIR_MASK:	/* indirection */
27332647Skarels 				cp = msg + (((n & 0x3f) << 8) | *cp);
27418140Sralph 			}
27518140Sralph 		}
27618140Sralph 		if (*dn == '\0')
27718140Sralph 			return (sp - msg);
27818140Sralph 	next:	;
27918140Sralph 	}
28018140Sralph 	return (-1);
28118140Sralph }
28218528Sralph 
28318528Sralph /*
28418528Sralph  * Routines to insert/extract short/long's. Must account for byte
28518528Sralph  * order and non-alignment problems. This code at least has the
28618528Sralph  * advantage of being portable.
28733727Sbostic  *
28833727Sbostic  * used by sendmail.
28918528Sralph  */
29018528Sralph 
29118528Sralph u_short
_getshort(msgp)29230441Skjd _getshort(msgp)
29361023Skarels 	register u_char *msgp;
29418528Sralph {
29561023Skarels 	register u_int16_t u;
29618528Sralph 
29761023Skarels 	GETSHORT(u, msgp);
29861023Skarels 	return (u);
29918528Sralph }
30018528Sralph 
30161023Skarels u_int32_t
_getlong(msgp)30230441Skjd _getlong(msgp)
30361023Skarels 	register u_char *msgp;
30418528Sralph {
30561023Skarels 	register u_int32_t u;
30618528Sralph 
30761023Skarels 	GETLONG(u, msgp);
30861023Skarels 	return (u);
30918528Sralph }
31018528Sralph 
31147045Sbostic void
31261023Skarels #if defined(__STDC__) || defined(__cplusplus)
__putshort(register u_short s,register u_char * msgp)31347045Sbostic __putshort(register u_short s, register u_char *msgp)
31447045Sbostic #else
31546496Sbostic __putshort(s, msgp)
31661023Skarels 	register u_int16_t s;
31732647Skarels 	register u_char *msgp;
31847045Sbostic #endif
31918528Sralph {
32061023Skarels 	PUTSHORT(s, msgp);
32118528Sralph }
32218528Sralph 
32347045Sbostic void
__putlong(l,msgp)32446496Sbostic __putlong(l, msgp)
32561023Skarels 	register u_int32_t l;
32632647Skarels 	register u_char *msgp;
32718528Sralph {
32861023Skarels 	PUTLONG(l, msgp);
32918528Sralph }
330