All except rrtype-specific stuff complete but largely untest. That is
[adns] / src / parse.c
CommitLineData
98a3f706 1/**/
2
3#include "internal.h"
4
5int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len) {
6 char qbuf[10];
7 int i, ch;
8
9 while (len) {
10 qbuf[0]= 0;
11 for (i=0; i<len; i++) {
12 ch= buf[i];
13 if (ch == '.' || ch == '"' || ch == '(' || ch == ')' ||
14 ch == '@' || ch == ';' || ch == '$') {
15 sprintf(qbuf,"\\%c",ch);
16 break;
17 } else if (ch <= ' ' || ch >= 127) {
18 sprintf(qbuf,"\\%03o",ch);
19 break;
20 }
21 }
22 if (!adns__vbuf_append(vb,buf,i) || !adns__vbuf_append(vb,qbuf,strlen(qbuf)))
23 return 0;
24 buf+= i; len-= i;
25 }
26 return 1;
27}
28
29adns_status adns__get_label(const byte *dgram, int dglen, int *max_io,
30 int *cbyte_io, int *lablen_r, int *labstart_r,
31 int *namelen_io) {
32 /* If succeeds, *lablen_r may be set to -1 to indicate truncation/overrun */
33 int max, cbyte, lablen, namelen;
34
35 max= *max_io;
36 cbyte= *cbyte_io;
37
38 for (;;) {
39 if (cbyte+2 > max) goto x_truncated;
40 GET_W(cbyte,lablen);
41 if (!(lablen & 0x0c000)) break;
42 if ((lablen & 0x0c000) != 0x0c000) return adns_s_unknownreply;
43 if (cbyte_io) { *cbyte_io= cbyte; cbyte_io= 0; }
44 cbyte= DNS_HDRSIZE+(lablen&0x3fff);
45 *max_io= max= dglen;
46 }
47 if (labstart_r) *labstart_r= cbyte;
48 if (lablen) {
49 namelen= *namelen_io;
50 if (namelen) namelen++;
51 namelen+= lablen;
52 if (namelen > DNS_MAXDOMAIN) return adns_s_domaintoolong;
53 *namelen_io= namelen;
54 cbyte+= lablen;
55 if (cbyte > max) goto x_truncated;
56 }
57 if (cbyte_io) *cbyte_io= cbyte;
58 *lablen_r= lablen;
59 return adns_s_ok;
60
61 x_truncated:
62 *lablen_r= -1;
63 return adns_s_ok;
64}
65
66adns_status adns__get_domain_perm(adns_state ads, adns_query qu, int serv,
67 const byte *dgram, int dglen,
68 int *cbyte_io, int max, int *domainstart_r) {
69 /* Returns 0 for OK (*domainstart_r >=0) or truncated (*domainstart_r == -1)
70 * or any other adns_s_* value.
71 */
72 int cbyte, sused, lablen, labstart, namelen, i, ch;
73 adns_status st;
74
75 /* If we follow a pointer we set cbyte_io to 0 to indicate that
76 * we've lost our original starting and ending points; we don't
77 * put the end of the pointed-to thing into the original *cbyte_io.
78 */
79 cbyte= *cbyte_io;
80 sused= qu->ans.used;
81 namelen= 0;
82 for (;;) {
83 st= adns__get_label(dgram,dglen,&max, &cbyte,&lablen,&labstart,&namelen);
84 if (st) return st;
85 if (lablen<0) goto x_truncated;
86 if (!lablen) break;
87 if (qu->ans.used != sused)
88 if (!adns__vbuf_append(&qu->ans,".",1)) return adns_s_nolocalmem;
89 if (qu->flags & adns_qf_anyquote) {
90 if (!vbuf__append_quoted1035(&qu->ans,dgram+labstart,lablen))
91 return adns_s_nolocalmem;
92 } else {
93 if (!ctype_alpha(dgram[labstart])) return adns_s_invaliddomain;
94 for (i= cbyte+1; i<cbyte+lablen; i++) {
95 ch= dgram[cbyte];
96 if (ch != '-' && !ctype_alpha(ch) && !ctype_digit(ch))
97 return adns_s_invaliddomain;
98 }
99 if (!adns__vbuf_append(&qu->ans,dgram+labstart,lablen))
100 return adns_s_nolocalmem;
101 }
102 }
103 if (cbyte_io) *cbyte_io= cbyte;
104 if (!adns__vbuf_append(&qu->ans,"",1)) return adns_s_nolocalmem;
105 *domainstart_r= sused;
106 return adns_s_ok;
107
108 x_truncated:
109 *domainstart_r= -1;
110 return cbyte_io ? -1 : adns_s_serverfaulty;
111}
112
113adns_status adns__get_domain_temp(adns_state ads, adns_query qu, int serv,
114 const byte *dgram, int dglen,
115 int *cbyte_io, int max, int *domainstart_r) {
116 int sused;
117 adns_status st;
118
119 sused= qu->ans.used;
120 st= adns__get_domain_perm(ads,qu,serv,dgram,dglen,cbyte_io,max,domainstart_r);
121 qu->ans.used= sused;
122 return st;
123}
124
125adns_status adns__get_rr_temp(adns_state ads, adns_query qu, int serv,
126 const byte *dgram, int dglen, int *cbyte_io,
127 int *type_r, int *class_r, int *rdlen_r, int *rdstart_r,
128 const byte *eo_dgram, int eo_dglen, int eo_cbyte,
129 int *eo_matched_r) {
130 /* _s_ok can have *type_r == -1 and other output invalid, for truncation
131 * type_r and class_r must be !0, other _r may be 0.
132 * eo_dgram==0 for no comparison, otherwise all eo_ must be valid.
133 */
134 int cbyte, tmp, rdlen, mismatch;
135 int max, lablen, labstart, namelen, ch;
136 int eo_max, eo_lablen, eo_labstart, eo_namelen, eo_ch;
137 adns_status st;
138
139 cbyte= *cbyte_io;
140 mismatch= eo_dgram ? 1 : 0;
141
142 namelen= 0; eo_namelen= 0;
143 max= dglen; eo_max= eo_dglen;
144 for (;;) {
145 st= adns__get_label(dgram,dglen,&max,
146 &cbyte,&lablen,&labstart,&namelen);
147 if (st) return st;
148 if (lablen<0) goto x_truncated;
149
150 if (!mismatch) {
151 st= adns__get_label(eo_dgram,eo_dglen,&eo_max,
152 &eo_cbyte,&eo_lablen,&eo_labstart,&eo_namelen);
153 if (st) return st;
154 assert(eo_lablen>=0);
155 if (lablen != eo_lablen) mismatch= 1;
156 while (!mismatch && lablen-- > 0) {
157 ch= dgram[labstart++]; if (ctype_alpha(ch)) ch &= ~32;
158 eo_ch= eo_dgram[eo_labstart++]; if (ctype_alpha(eo_ch)) eo_ch &= ~32;
159 if (ch != eo_ch) mismatch= 1;
160 }
161 }
162 }
163 if (eo_matched_r) *eo_matched_r= !mismatch;
164
165 if (cbyte+10>dglen) goto x_truncated;
166 GET_W(cbyte,tmp); *type_r= tmp;
167 GET_W(cbyte,tmp); *class_r= tmp;
168 cbyte+= 4; /* we skip the TTL */
169 GET_W(cbyte,rdlen); if (rdlen_r) *rdlen_r= tmp;
170 if (rdstart_r) *rdstart_r= cbyte;
171 cbyte+= rdlen;
172 if (cbyte>dglen) goto x_truncated;
173 *cbyte_io= cbyte;
174 return adns_s_ok;
175
176 x_truncated:
177 *type_r= -1;
178 return 0;;
179}