#include <sys/types.h>
#include <stdio.h>
#include <arpa/nameser.h>
static int dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs,
u_char **lastdnptr);
int
dn_expand(msg, eomorig, comp_dn, exp_dn, length)
u_char *msg, *eomorig, *comp_dn, *exp_dn;
int length;
{
register u_char *cp, *dn;
register int n, c;
u_char *eom;
int len = -1, checked = 0;
dn = exp_dn;
cp = comp_dn;
eom = exp_dn + length;
while (n = *cp++) {
switch (n & INDIR_MASK) {
case 0:
if (dn != exp_dn) {
if (dn >= eom)
return (-1);
*dn++ = '.';
}
if (dn+n >= eom)
return (-1);
checked += n + 1;
while (--n >= 0) {
if ((c = *cp++) == '.') {
if (dn + n + 2 >= eom)
return (-1);
*dn++ = '\\';
}
*dn++ = c;
if (cp >= eomorig)
return (-1);
}
break;
case INDIR_MASK:
if (len < 0)
len = cp - comp_dn + 1;
cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
if (cp < msg || cp >= eomorig)
return (-1);
checked += 2;
if (checked >= eomorig - msg)
return (-1);
break;
default:
return (-1);
}
}
*dn = '\0';
if (len < 0)
len = cp - comp_dn;
return (len);
}
int
dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
u_char *exp_dn, *comp_dn;
int length;
u_char **dnptrs, **lastdnptr;
{
register u_char *cp, *dn;
register int c, l;
u_char **cpp, **lpp, *sp, *eob;
u_char *msg;
dn = exp_dn;
cp = comp_dn;
eob = cp + length;
if (dnptrs != NULL) {
if ((msg = *dnptrs++) != NULL) {
for (cpp = dnptrs; *cpp != NULL; cpp++)
;
lpp = cpp;
}
} else
msg = NULL;
for (c = *dn++; c != '\0'; ) {
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 % 256;
return (cp - comp_dn);
}
if (lastdnptr != NULL && cpp < lastdnptr-1) {
*cpp++ = cp;
*cpp = NULL;
}
}
sp = cp++;
do {
if (c == '.') {
c = *dn++;
break;
}
if (c == '\\') {
if ((c = *dn++) == '\0')
break;
}
if (cp >= eob) {
if (msg != NULL)
*lpp = NULL;
return (-1);
}
*cp++ = c;
} while ((c = *dn++) != '\0');
if ((l = cp - sp - 1) == 0 && c == '\0') {
cp--;
break;
}
if (l <= 0 || l > MAXLABEL) {
if (msg != NULL)
*lpp = NULL;
return (-1);
}
*sp = l;
}
if (cp >= eob) {
if (msg != NULL)
*lpp = NULL;
return (-1);
}
*cp++ = '\0';
return (cp - comp_dn);
}
int
dn_skipname(comp_dn, eom)
u_char *comp_dn, *eom;
{
register u_char *cp;
register int n;
cp = comp_dn;
while (cp < eom && (n = *cp++)) {
switch (n & INDIR_MASK) {
case 0:
cp += n;
continue;
default:
return (-1);
case INDIR_MASK:
cp++;
}
break;
}
return (cp - comp_dn);
}
static int
dn_find(u_char *exp_dn, u_char *msg, u_char **dnptrs, u_char **lastdnptr)
{
register u_char *dn, *cp, **cpp;
register int n;
u_char *sp;
for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
dn = exp_dn;
sp = cp = *cpp;
while (n = *cp++) {
switch (n & INDIR_MASK) {
case 0:
while (--n >= 0) {
if (*dn == '.')
goto next;
if (*dn == '\\')
dn++;
if (*dn++ != *cp++)
goto next;
}
if ((n = *dn++) == '\0' && *cp == '\0')
return (sp - msg);
if (n == '.')
continue;
goto next;
default:
return (-1);
case INDIR_MASK:
cp = msg + (((n & 0x3f) << 8) | *cp);
}
}
if (*dn == '\0')
return (sp - msg);
next: ;
}
return (-1);
}
u_short
_getshort(msgp)
u_char *msgp;
{
register u_char *p = (u_char *) msgp;
#ifdef vax
register u_long u;
#else
register u_short u;
#endif
u = *p++ << 8;
return ((u_short)(u | *p));
}
u_long
_getlong(msgp)
u_char *msgp;
{
register u_char *p = (u_char *) msgp;
register u_long u;
u = *p++; u <<= 8;
u |= *p++; u <<= 8;
u |= *p++; u <<= 8;
return (u | *p);
}
void
putshort(s, msgp)
register u_short s;
register u_char *msgp;
{
msgp[1] = s;
msgp[0] = s >> 8;
}
void
putlong(l, msgp)
register u_long l;
register u_char *msgp;
{
msgp[3] = l;
msgp[2] = (l >>= 8);
msgp[1] = (l >>= 8);
msgp[0] = l >> 8;
}