date and time created 85/03/01 10:42:09 by ralph
[unix-history] / usr / src / lib / libc / net / res_comp.c
#ifndef lint
static char sccsid[] = "@(#)res_comp.c 4.1 (Berkeley) %G%";
#endif
#include <sys/types.h>
#include <stdio.h>
#include <ctype.h>
#include <nameser.h>
/*
* Expand compressed domain name format to full domain name.
* Return size of compressed name or -1 if there was an error.
*/
dn_expand(msg, comp_dn, exp_dn, length)
char *msg, *comp_dn, *exp_dn;
int length;
{
register char *cp, *dn;
register int n, c;
char *eom;
int len = 0;
dn = exp_dn;
cp = comp_dn;
eom = exp_dn + length - 1;
/*
* fetch next label in domain name
*/
while (n = *cp++) {
/*
* Check for indirection
*/
switch (n & INDIR_MASK) {
case 0:
if (dn != exp_dn)
*dn++ = '.';
if (dn+n >= eom)
return (-1);
while (--n >= 0)
if (islower(c = *cp++))
*dn++ = toupper(c);
else
*dn++ = c;
break;
case INDIR_MASK:
if (len == 0)
len = cp - comp_dn + 1;
cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
break;
default:
return (-1); /* flag error */
}
}
*dn = '\0';
if (len == 0)
len = cp - comp_dn;
return (len);
}
/*
* Compress domain name. Return the size of the compressed name or -1.
* Dnptrs is a list of pointers to previous compressed names. dnptrs[0]
* is a pointer to the beginning of the message. The list ends with NULL.
*/
dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
char *exp_dn, *comp_dn;
int length;
char **dnptrs, **lastdnptr;
{
register char *cp, *dn;
register int c, l;
char **cpp, **lpp, *sp, *eob;
char *msg;
dn = exp_dn;
cp = comp_dn;
eob = comp_dn + length;
if (dnptrs != NULL) {
if ((msg = *dnptrs++) != NULL) {
for (cpp = dnptrs; *cpp != NULL; cpp++)
;
lpp = cpp; /* end of list to search */
}
} else
msg = NULL;
for (c = *dn++; c != '\0'; ) {
/* look to see if we can use pointers */
if (msg != NULL) {
if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
if (cp+1 >= eob)
return (-1);
*cp++ = (l >> 8) | INDIR_MASK;
*cp++ = l;
return (cp - comp_dn);
}
/* not found, save it */
if (lastdnptr != NULL && cpp < lastdnptr-1) {
*cpp++ = cp;
*cpp = NULL;
}
}
sp = cp++; /* save ptr to length byte */
do {
if (c == '.') {
c = *dn++;
break;
}
if (cp >= eob)
return (-1);
*cp++ = c;
} while ((c = *dn++) != '\0');
if ((l = cp - sp - 1) <= 0 || l > MAXLABEL)
return (-1);
*sp = l;
}
if (cp >= eob)
return (-1);
*cp++ = '\0';
return (cp - comp_dn);
}
/*
* Skip over a compressed domain name. Return the size.
*/
dn_skip(buf)
char *buf;
{
register char *cp;
register int n;
cp = buf;
while (n = *cp++) {
/*
* check for indirection
*/
switch (n & INDIR_MASK) {
case 0: /* normal case, n == len */
cp += n;
continue;
default: /* illegal type */
return (-1);
case INDIR_MASK: /* indirection */
cp++;
}
break;
}
return (cp - buf);
}
/*
* Search for expanded name from a list of previously compressed names.
* Return the offset from msg if found or -1.
*/
dn_find(exp_dn, msg, dnptrs, lastdnptr)
char *exp_dn, *msg;
char **dnptrs, **lastdnptr;
{
register char *dn, *cp, **cpp;
register int n;
char *sp;
for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
dn = exp_dn;
sp = cp = *cpp;
while (n = *cp++) {
/*
* check for indirection
*/
switch (n & INDIR_MASK) {
case 0: /* normal case, n == len */
while (--n >= 0)
if (*dn++ != *cp++)
goto next;
if ((n = *dn++) == '\0' && *cp == '\0')
return (sp - msg);
if (n == '.')
continue;
goto next;
default: /* illegal type */
return (-1);
case INDIR_MASK: /* indirection */
cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
}
}
if (*dn == '\0')
return (sp - msg);
next: ;
}
return (-1);
}