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