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 */
getoffs(short * offs,const unsigned char * base,const unsigned char * s)8 static 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 */
getlens(unsigned char * lens,const char * s,int l)26 static 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 */
match(int * offset,const unsigned char * base,const unsigned char * dn,const char * end,const unsigned char * lens,int nlen)41 static 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 
__dn_comp(const char * src,unsigned char * dst,int space,unsigned char ** dnptrs,unsigned char ** lastdnptr)64 int __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 
122 weak_alias(__dn_comp, dn_comp);
123