7 #include "namespaces.hh"
8 #include "dnswriter.hh"
12 void appendSplit(vector<string>& ret, string& segment, char c)
14 if(segment.size()>254) {
15 ret.push_back(segment);
23 vector<string> segmentDNSText(const string& input )
25 // cerr<<"segmentDNSText("<<input<<")"<<endl;
29 alphtype unsigned char;
31 (void)dnstext_error; // silence warnings
32 (void)dnstext_en_main;
33 const char *p = input.c_str(), *pe = input.c_str() + input.length();
43 ret.push_back(segment);
50 action reportEscaped {
52 appendSplit(ret, segment, c);
54 action reportEscapedNumber {
60 action doneEscapedNumber {
61 appendSplit(ret, segment, val);
66 appendSplit(ret, segment, *(fpc));
69 escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber));
70 plain = ((extend-'\\'-'"')|'\n'|'\t') $ reportPlain;
71 txtElement = escaped | plain;
73 main := (('"' txtElement* '"' space?) >segmentBegin %segmentEnd)+;
75 # Initialize and execute.
80 if ( cs < dnstext_first_final ) {
81 throw runtime_error("Unable to parse DNS TXT '"+input+"'");
88 DNSName::string_t segmentDNSNameRaw(const char* realinput, size_t inputlen)
93 alphtype unsigned char;
95 (void)dnsnameraw_error; // silence warnings
96 (void)dnsnameraw_en_main;
98 DNSName::string_t ret;
100 if(!*realinput || *realinput == '.') {
101 ret.append(1, (char)0);
105 ret.reserve(inputlen+1);
107 const char *p = realinput, *pe = realinput + inputlen;
108 const char* eof = pe;
111 unsigned char labellen=0;
112 unsigned int lenpos=0;
116 throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen));
118 ret[lenpos]=labellen;
123 ret.append(1, (char)0);
127 action reportEscaped {
132 action reportEscapedNumber {
137 action doneEscapedNumber {
144 ret.append(1, *(fpc));
148 escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber));
149 plain = (extend-'\\'-'.') $ reportPlain;
150 labelElement = escaped | plain;
152 label = labelElement+ >labelBegin %labelEnd;
154 main:= label ('.' label )* '.'?;
156 #main := labelElement((labelElement+ '.') >labelBegin %labelEnd)+;
158 # label = (plain | escaped | escdecb)+ >label_init %label_fin;
159 # dnsname := '.'? label ('.' label >label_sep)* '.'?;
161 # Initialize and execute.
166 if ( cs < dnsnameraw_first_final ) {
167 throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': cs="+std::to_string(cs));
169 ret.append(1, (char)0);
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) {
178 val.reserve(in.size());
179 const char *p = in.c_str();
180 const char *pe = p + in.size();
182 uint8_t escaped_octet = 0;
183 // Keeps track of how many chars we read from the source string
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
192 machine dns_text_to_string;
194 action doEscapedNumber {
196 escaped_octet += fc-'0';
200 action doneEscapedNumber {
201 val += escaped_octet;
210 action incrementCounter {
214 # generated rules, define required actions
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);
228 # instantiate machine rules
235 (void) dns_text_to_string_first_final;
236 (void) dns_text_to_string_error;
237 (void) dns_text_to_string_en_main;
243 size_t parseSVCBValueListFromParsedRFC1035CharString(const std::string &in, std::vector<std::string> &val) {
245 const char *p = in.c_str();
246 const char *pe = p + in.size();
248 const char* eof = pe;
249 // Keeps track of how many chars we read from the source string
252 // Here we store the parsed value until we hit a comma or are done
256 machine dns_text_to_value_list;
257 alphtype unsigned char;
264 action addToValNoIncrement {
274 action incrementCounter {
278 # generated rules, define required actions
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 )* )?;
284 # instantiate machine rules
285 main := comma_separated;
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;
296 if ( cs < dns_text_to_value_list_first_final ) {
297 throw runtime_error("Unable to parse DNS SVCB value list '"+in+"'");
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;