OSDN Git Service

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