blob: cce2b982e217f5fe96e639e60d224b51b32d2ac4 [file] [log] [blame]
#include "libc.h"
#include <resolv.h>
#include <string.h>
/* RFC 1035 message compression */
/* label start offsets of a compressed domain name s */
static int getoffs(short* offs, const unsigned char* base, const unsigned char* s) {
int i = 0;
for (;;) {
while (*s & 0xc0) {
if ((*s & 0xc0) != 0xc0)
return 0;
s = base + ((s[0] & 0x3f) << 8 | s[1]);
}
if (!*s)
return i;
if (s - base >= 0x4000)
return 0;
offs[i++] = s - base;
s += *s + 1;
}
}
/* label lengths of an ascii domain name s */
static int getlens(unsigned char* lens, const char* s, int l) {
int i = 0, j = 0, k = 0;
for (;;) {
for (; j < l && s[j] != '.'; j++)
;
if (j - k - 1u > 62)
return 0;
lens[i++] = j - k;
if (j == l)
return i;
k = ++j;
}
}
/* longest suffix match of an ascii domain with a compressed domain name dn */
static int match(int* offset, const unsigned char* base, const unsigned char* dn, const char* end,
const unsigned char* lens, int nlen) {
int l, o, m = 0;
short offs[128];
int noff = getoffs(offs, base, dn);
if (!noff)
return 0;
for (;;) {
l = lens[--nlen];
o = offs[--noff];
end -= l;
if (l != base[o] || memcmp(base + o + 1, end, l))
return m;
*offset = o;
m += l;
if (nlen)
m++;
if (!nlen || !noff)
return m;
end--;
}
}
int __dn_comp(const char* src, unsigned char* dst, int space, unsigned char** dnptrs,
unsigned char** lastdnptr) {
int i, j, n, m = 0, offset = 0, bestlen = 0, bestoff = 0;
unsigned char lens[127];
unsigned char** p;
const char* end;
size_t l = strnlen(src, 255);
if (l && src[l - 1] == '.')
l--;
if (l > 253 || space <= 0)
return -1;
if (!l) {
*dst = 0;
return 1;
}
end = src + l;
n = getlens(lens, src, l);
if (!n)
return -1;
p = dnptrs;
if (p && *p)
for (p++; *p; p++) {
m = match(&offset, *dnptrs, *p, end, lens, n);
if (m > bestlen) {
bestlen = m;
bestoff = offset;
if (m == l)
break;
}
}
/* encode unmatched part */
if (space < l - bestlen + 2 + (bestlen - 1 < l - 1))
return -1;
memcpy(dst + 1, src, l - bestlen);
for (i = j = 0; i < l - bestlen; i += lens[j++] + 1)
dst[i] = lens[j];
/* add tail */
if (bestlen) {
dst[i++] = 0xc0 | bestoff >> 8;
dst[i++] = bestoff;
} else
dst[i++] = 0;
/* save dst pointer */
if (i > 2 && lastdnptr && dnptrs && *dnptrs) {
while (*p)
p++;
if (p + 1 < lastdnptr) {
*p++ = dst;
*p = 0;
}
}
return i;
}
weak_alias(__dn_comp, dn_comp);