]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnslabeltext.rl
dnsdist: Fix DNS over plain HTTP broken by `reloadAllCertificates()`
[thirdparty/pdns.git] / pdns / dnslabeltext.rl
CommitLineData
bac8f21b
BH
1#include <stdlib.h>
2#include <string.h>
3#include <stdio.h>
4#include <unistd.h>
5#include <string>
bae1b0a2 6#include "dnsname.hh"
bac8f21b 7#include "namespaces.hh"
f56d26c9 8#include "dnswriter.hh"
b1a048a9 9#include "misc.hh"
bac8f21b 10
bac8f21b
BH
11namespace {
12void appendSplit(vector<string>& ret, string& segment, char c)
13{
14 if(segment.size()>254) {
15 ret.push_back(segment);
16 segment.clear();
17 }
18 segment.append(1, c);
19}
3c115e0f 20
bac8f21b
BH
21}
22
23vector<string> segmentDNSText(const string& input )
24{
fc634e87 25 // cerr<<"segmentDNSText("<<input<<")"<<endl;
2fa33bce
BH
26%%{
27 machine dnstext;
28 write data;
916a0fda 29 alphtype unsigned char;
2fa33bce 30}%%
f8499e52
BH
31 (void)dnstext_error; // silence warnings
32 (void)dnstext_en_main;
bac8f21b
BH
33 const char *p = input.c_str(), *pe = input.c_str() + input.length();
34 const char* eof = pe;
35 int cs;
36 char val = 0;
37
38 string segment;
39 vector<string> ret;
40
41 %%{
42 action segmentEnd {
43 ret.push_back(segment);
44 segment.clear();
45 }
46 action segmentBegin {
47 segment.clear();
48 }
49
50 action reportEscaped {
51 char c = *fpc;
52 appendSplit(ret, segment, c);
53 }
54 action reportEscapedNumber {
55 char c = *fpc;
56 val *= 10;
57 val += c-'0';
58
59 }
60 action doneEscapedNumber {
61 appendSplit(ret, segment, val);
62 val=0;
63 }
64
65 action reportPlain {
66 appendSplit(ret, segment, *(fpc));
67 }
68
35261869 69 escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber));
973efd35 70 plain = ((extend-'\\'-'"')|'\n'|'\t') $ reportPlain;
2fa33bce
BH
71 txtElement = escaped | plain;
72
73 main := (('"' txtElement* '"' space?) >segmentBegin %segmentEnd)+;
bac8f21b
BH
74
75 # Initialize and execute.
76 write init;
77 write exec;
78 }%%
79
80 if ( cs < dnstext_first_final ) {
81 throw runtime_error("Unable to parse DNS TXT '"+input+"'");
82 }
83
84 return ret;
85};
2fa33bce 86
bae1b0a2 87
beb9fad5 88DNSName::string_t segmentDNSNameRaw(const char* realinput, size_t inputlen)
3c115e0f 89{
90%%{
bae1b0a2 91 machine dnsnameraw;
3c115e0f 92 write data;
93 alphtype unsigned char;
94}%%
bae1b0a2 95 (void)dnsnameraw_error; // silence warnings
96 (void)dnsnameraw_en_main;
1f3151e8 97
bae1b0a2 98 DNSName::string_t ret;
1f3151e8 99
bae1b0a2 100 if(!*realinput || *realinput == '.') {
101 ret.append(1, (char)0);
102 return ret;
103 }
1f3151e8 104
bae1b0a2 105 ret.reserve(inputlen+1);
1f3151e8 106
bae1b0a2 107 const char *p = realinput, *pe = realinput + inputlen;
3c115e0f 108 const char* eof = pe;
109 int cs;
110 char val = 0;
abb8aeb0 111 unsigned char labellen=0;
bae1b0a2 112 unsigned int lenpos=0;
3c115e0f 113 %%{
114 action labelEnd {
abb8aeb0 115 if (labellen > 63) {
d0a4a4bc
RG
116 throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen));
117 }
bae1b0a2 118 ret[lenpos]=labellen;
119 labellen=0;
3c115e0f 120 }
121 action labelBegin {
bae1b0a2 122 lenpos=ret.size();
123 ret.append(1, (char)0);
124 labellen=0;
3c115e0f 125 }
126
127 action reportEscaped {
128 char c = *fpc;
bae1b0a2 129 ret.append(1, c);
130 labellen++;
3c115e0f 131 }
132 action reportEscapedNumber {
133 char c = *fpc;
134 val *= 10;
135 val += c-'0';
3c115e0f 136 }
137 action doneEscapedNumber {
bae1b0a2 138 ret.append(1, val);
139 labellen++;
3c115e0f 140 val=0;
141 }
142
143 action reportPlain {
bae1b0a2 144 ret.append(1, *(fpc));
145 labellen++;
3c115e0f 146 }
147
148 escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber));
564ec901 149 plain = (extend-'\\'-'.') $ reportPlain;
3c115e0f 150 labelElement = escaped | plain;
151
bae1b0a2 152 label = labelElement+ >labelBegin %labelEnd;
153
154 main:= label ('.' label )* '.'?;
155
156 #main := labelElement((labelElement+ '.') >labelBegin %labelEnd)+;
157
158 # label = (plain | escaped | escdecb)+ >label_init %label_fin;
159 # dnsname := '.'? label ('.' label >label_sep)* '.'?;
3c115e0f 160
161 # Initialize and execute.
162 write init;
163 write exec;
164 }%%
165
bae1b0a2 166 if ( cs < dnsnameraw_first_final ) {
167 throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': cs="+std::to_string(cs));
3c115e0f 168 }
bae1b0a2 169 ret.append(1, (char)0);
3c115e0f 170 return ret;
171};
172
b1a048a9
PL
173// Reads an RFC 1035 character string from 'in', puts the resulting bytes in 'out'.
174// Returns the amount of bytes read from 'in'
175size_t parseRFC1035CharString(const std::string &in, std::string &val) {
176
177 val.clear();
178 val.reserve(in.size());
179 const char *p = in.c_str();
ca749ae1 180 const char *pe = p + in.size();
b1a048a9
PL
181 int cs = 0;
182 uint8_t escaped_octet = 0;
183 // Keeps track of how many chars we read from the source string
184 size_t counter=0;
185
186/* This parses an RFC 1035 char-string.
187 * It was created from the ABNF in draft-ietf-dnsop-svcb-https-02 with
188 * https://github.com/zinid/abnfc and modified to put all the characters in the
189 * right place.
190 */
191%%{
192 machine dns_text_to_string;
193
194 action doEscapedNumber {
195 escaped_octet *= 10;
196 escaped_octet += fc-'0';
197 counter++;
198 }
199
200 action doneEscapedNumber {
201 val += escaped_octet;
202 escaped_octet = 0;
203 }
204
205 action addToVal {
206 val += fc;
207 counter++;
208 }
209
210 action incrementCounter {
211 counter++;
212 }
213
214 # generated rules, define required actions
215 DIGIT = 0x30..0x39;
216 DQUOTE = "\"";
217 HTAB = "\t";
218 SP = " ";
219 WSP = (SP | HTAB)@addToVal;
220 non_special = "!" | 0x23..0x27 | 0x2a..0x3a | 0x3c..0x5b | 0x5d..0x7e;
221 non_digit = 0x21..0x2f | 0x3a..0x7e;
222 dec_octet = ( ( "0" | "1" ) DIGIT{2} ) | ( "2" ( ( 0x30..0x34 DIGIT ) | ( "5" 0x30..0x35 ) ) );
223 escaped = '\\'@incrementCounter ( non_digit$addToVal | dec_octet$doEscapedNumber@doneEscapedNumber );
224 contiguous = ( non_special$addToVal | escaped )+;
225 quoted = DQUOTE@incrementCounter ( contiguous | ( '\\'? WSP ) )* DQUOTE@incrementCounter;
226 char_string = (contiguous | quoted);
227
228 # instantiate machine rules
229 main := char_string;
230 write data;
231 write init;
232}%%
233
234 // silence warnings
235 (void) dns_text_to_string_first_final;
236 (void) dns_text_to_string_error;
237 (void) dns_text_to_string_en_main;
238 %% write exec;
239
240 return counter;
241}
242
e701f9d4 243size_t parseSVCBValueListFromParsedRFC1035CharString(const std::string &in, std::vector<std::string> &val) {
78788348
PL
244 val.clear();
245 const char *p = in.c_str();
246 const char *pe = p + in.size();
247 int cs = 0;
e701f9d4 248 const char* eof = pe;
78788348
PL
249 // Keeps track of how many chars we read from the source string
250 size_t counter=0;
251
252 // Here we store the parsed value until we hit a comma or are done
253 std::string tmp;
254
255%%{
256 machine dns_text_to_value_list;
e701f9d4 257 alphtype unsigned char;
78788348 258
e701f9d4
PL
259 action addToVal {
260 tmp += fc;
78788348
PL
261 counter++;
262 }
263
e701f9d4 264 action addToValNoIncrement {
78788348 265 tmp += fc;
78788348
PL
266 }
267
e701f9d4 268 action addToVector {
78788348
PL
269 val.push_back(tmp);
270 tmp.clear();
271 counter++;
272 }
273
274 action incrementCounter {
275 counter++;
276 }
277
278 # generated rules, define required actions
e701f9d4
PL
279 OCTET = 0x00..0xff;
280 item_allowed = 0x00..0x2b | 0x2d..0x5b | 0x5d..0xff;
281 escaped_item = ( item_allowed$addToVal | '\\,'$incrementCounter@addToValNoIncrement | '\\\\'$incrementCounter@addToValNoIncrement )+;
282 comma_separated = ( escaped_item%addToVector ( ","@incrementCounter escaped_item%addToVector )* )?;
78788348
PL
283
284 # instantiate machine rules
e701f9d4 285 main := comma_separated;
78788348
PL
286 write data;
287 write init;
288}%%
289
290 // silence warnings
291 (void) dns_text_to_value_list_first_final;
292 (void) dns_text_to_value_list_error;
293 (void) dns_text_to_value_list_en_main;
294 %% write exec;
295
dda5e234
PD
296 if ( cs < dns_text_to_value_list_first_final ) {
297 throw runtime_error("Unable to parse DNS SVCB value list '"+in+"'");
298 }
299
78788348
PL
300 return counter;
301}
3c115e0f 302
bae1b0a2 303
bac8f21b
BH
304#if 0
305int main()
306{
307 //char blah[]="\"blah\" \"bleh\" \"bloeh\\\"bleh\" \"\\97enzo\"";
308 char blah[]="\"v=spf1 ip4:67.106.74.128/25 ip4:63.138.42.224/28 ip4:65.204.46.224/27 \\013\\010ip4:66.104.217.176/28 \\013\\010ip4:209.48.147.0/27 ~all\"";
309 //char blah[]="\"abc \\097\\098 def\"";
310 printf("Input: '%s'\n", blah);
311 vector<string> res=dnstext(blah);
312 cerr<<res.size()<<" segments"<<endl;
313 cerr<<res[0]<<endl;
314}
315#endif