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