]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnslabeltext.rl
Meson: Add systemd feature support for service files
[thirdparty/pdns.git] / pdns / dnslabeltext.rl
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <string>
6 #include "dnsname.hh"
7 #include "namespaces.hh"
8 #include "dnswriter.hh"
9 #include "misc.hh"
10
11 namespace {
12 void 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 }
20
21 }
22
23 vector<string> segmentDNSText(const string& input )
24 {
25 // cerr<<"segmentDNSText("<<input<<")"<<endl;
26 %%{
27 machine dnstext;
28 write data;
29 alphtype unsigned char;
30 }%%
31 (void)dnstext_error; // silence warnings
32 (void)dnstext_en_main;
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
69 escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber));
70 plain = ((extend-'\\'-'"')|'\n'|'\t') $ reportPlain;
71 txtElement = escaped | plain;
72
73 main := (('"' txtElement* '"' space?) >segmentBegin %segmentEnd)+;
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 };
86
87
88 DNSName::string_t segmentDNSNameRaw(const char* realinput, size_t inputlen)
89 {
90 %%{
91 machine dnsnameraw;
92 write data;
93 alphtype unsigned char;
94 }%%
95 (void)dnsnameraw_error; // silence warnings
96 (void)dnsnameraw_en_main;
97
98 DNSName::string_t ret;
99
100 if(!*realinput || *realinput == '.') {
101 ret.append(1, (char)0);
102 return ret;
103 }
104
105 ret.reserve(inputlen+1);
106
107 const char *p = realinput, *pe = realinput + inputlen;
108 const char* eof = pe;
109 int cs;
110 char val = 0;
111 unsigned char labellen=0;
112 unsigned int lenpos=0;
113 %%{
114 action labelEnd {
115 if (labellen > 63) {
116 throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen));
117 }
118 ret[lenpos]=labellen;
119 labellen=0;
120 }
121 action labelBegin {
122 lenpos=ret.size();
123 ret.append(1, (char)0);
124 labellen=0;
125 }
126
127 action reportEscaped {
128 char c = *fpc;
129 ret.append(1, c);
130 labellen++;
131 }
132 action reportEscapedNumber {
133 char c = *fpc;
134 val *= 10;
135 val += c-'0';
136 }
137 action doneEscapedNumber {
138 ret.append(1, val);
139 labellen++;
140 val=0;
141 }
142
143 action reportPlain {
144 ret.append(1, *(fpc));
145 labellen++;
146 }
147
148 escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber));
149 plain = (extend-'\\'-'.') $ reportPlain;
150 labelElement = escaped | plain;
151
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)* '.'?;
160
161 # Initialize and execute.
162 write init;
163 write exec;
164 }%%
165
166 if ( cs < dnsnameraw_first_final ) {
167 throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': cs="+std::to_string(cs));
168 }
169 ret.append(1, (char)0);
170 return ret;
171 };
172
173 // Reads an RFC 1035 character string from 'in', puts the resulting bytes in 'out'.
174 // Returns the amount of bytes read from 'in'
175 size_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();
180 const char *pe = p + in.size();
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
243 size_t parseSVCBValueListFromParsedRFC1035CharString(const std::string &in, std::vector<std::string> &val) {
244 val.clear();
245 const char *p = in.c_str();
246 const char *pe = p + in.size();
247 int cs = 0;
248 const char* eof = pe;
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;
257 alphtype unsigned char;
258
259 action addToVal {
260 tmp += fc;
261 counter++;
262 }
263
264 action addToValNoIncrement {
265 tmp += fc;
266 }
267
268 action addToVector {
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
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 )* )?;
283
284 # instantiate machine rules
285 main := comma_separated;
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
296 if ( cs < dns_text_to_value_list_first_final ) {
297 throw runtime_error("Unable to parse DNS SVCB value list '"+in+"'");
298 }
299
300 return counter;
301 }
302
303
304 #if 0
305 int 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