1#include "libc.h"
2#include <resolv.h>
3#include <string.h>
4
5/* RFC 1035 message compression */
6
7/* label start offsets of a compressed domain name s */
8static int getoffs(short* offs, const unsigned char* base, const unsigned char* s) {
9    int i = 0;
10    for (;;) {
11        while (*s & 0xc0) {
12            if ((*s & 0xc0) != 0xc0)
13                return 0;
14            s = base + ((s[0] & 0x3f) << 8 | s[1]);
15        }
16        if (!*s)
17            return i;
18        if (s - base >= 0x4000)
19            return 0;
20        offs[i++] = s - base;
21        s += *s + 1;
22    }
23}
24
25/* label lengths of an ascii domain name s */
26static int getlens(unsigned char* lens, const char* s, int l) {
27    int i = 0, j = 0, k = 0;
28    for (;;) {
29        for (; j < l && s[j] != '.'; j++)
30            ;
31        if (j - k - 1u > 62)
32            return 0;
33        lens[i++] = j - k;
34        if (j == l)
35            return i;
36        k = ++j;
37    }
38}
39
40/* longest suffix match of an ascii domain with a compressed domain name dn */
41static int match(int* offset, const unsigned char* base, const unsigned char* dn, const char* end,
42                 const unsigned char* lens, int nlen) {
43    int l, o, m = 0;
44    short offs[128];
45    int noff = getoffs(offs, base, dn);
46    if (!noff)
47        return 0;
48    for (;;) {
49        l = lens[--nlen];
50        o = offs[--noff];
51        end -= l;
52        if (l != base[o] || memcmp(base + o + 1, end, l))
53            return m;
54        *offset = o;
55        m += l;
56        if (nlen)
57            m++;
58        if (!nlen || !noff)
59            return m;
60        end--;
61    }
62}
63
64int __dn_comp(const char* src, unsigned char* dst, int space, unsigned char** dnptrs,
65              unsigned char** lastdnptr) {
66    int i, j, n, m = 0, offset = 0, bestlen = 0, bestoff = 0;
67    unsigned char lens[127];
68    unsigned char** p;
69    const char* end;
70    size_t l = strnlen(src, 255);
71    if (l && src[l - 1] == '.')
72        l--;
73    if (l > 253 || space <= 0)
74        return -1;
75    if (!l) {
76        *dst = 0;
77        return 1;
78    }
79    end = src + l;
80    n = getlens(lens, src, l);
81    if (!n)
82        return -1;
83
84    p = dnptrs;
85    if (p && *p)
86        for (p++; *p; p++) {
87            m = match(&offset, *dnptrs, *p, end, lens, n);
88            if (m > bestlen) {
89                bestlen = m;
90                bestoff = offset;
91                if (m == l)
92                    break;
93            }
94        }
95
96    /* encode unmatched part */
97    if (space < l - bestlen + 2 + (bestlen - 1 < l - 1))
98        return -1;
99    memcpy(dst + 1, src, l - bestlen);
100    for (i = j = 0; i < l - bestlen; i += lens[j++] + 1)
101        dst[i] = lens[j];
102
103    /* add tail */
104    if (bestlen) {
105        dst[i++] = 0xc0 | bestoff >> 8;
106        dst[i++] = bestoff;
107    } else
108        dst[i++] = 0;
109
110    /* save dst pointer */
111    if (i > 2 && lastdnptr && dnptrs && *dnptrs) {
112        while (*p)
113            p++;
114        if (p + 1 < lastdnptr) {
115            *p++ = dst;
116            *p = 0;
117        }
118    }
119    return i;
120}
121
122weak_alias(__dn_comp, dn_comp);
123