xref: /netbsd-src/external/bsd/nsd/dist/configparser.y (revision 811a4a0195236f69295602fbee687a174d42af9b)
1 /*
2  * configparser.y -- yacc grammar for NSD configuration files
3  *
4  * Copyright (c) 2001-2019, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 %{
11 #include "config.h"
12 
13 #include <assert.h>
14 #include <errno.h>
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include "options.h"
19 #include "util.h"
20 #include "dname.h"
21 #include "tsig.h"
22 #include "rrl.h"
23 
24 int yylex(void);
25 
26 #ifdef __cplusplus
27 extern "C"
28 #endif
29 
30 /* these need to be global, otherwise they cannot be used inside yacc */
31 extern config_parser_state_type *cfg_parser;
32 
33 static void append_acl(struct acl_options **list, struct acl_options *acl);
34 static void add_to_last_acl(struct acl_options **list, char *ac);
35 static int parse_boolean(const char *str, int *bln);
36 static int parse_expire_expr(const char *str, long long *num, uint8_t *expr);
37 static int parse_number(const char *str, long long *num);
38 static int parse_range(const char *str, long long *low, long long *high);
39 
40 struct component {
41 	struct component *next;
42 	char *str;
43 };
44 
45 %}
46 
47 %union {
48   char *str;
49   long long llng;
50   int bln;
51   struct ip_address_option *ip;
52   struct range_option *range;
53   struct cpu_option *cpu;
54   char **strv;
55   struct component *comp;
56 }
57 
58 %token <str> STRING
59 %type <llng> number
60 %type <bln> boolean
61 %type <ip> ip_address
62 %type <llng> service_cpu_affinity
63 %type <cpu> cpus
64 %type <strv> command
65 %type <comp> arguments
66 
67 /* server */
68 %token VAR_SERVER
69 %token VAR_SERVER_COUNT
70 %token VAR_IP_ADDRESS
71 %token VAR_IP_TRANSPARENT
72 %token VAR_IP_FREEBIND
73 %token VAR_REUSEPORT
74 %token VAR_SEND_BUFFER_SIZE
75 %token VAR_RECEIVE_BUFFER_SIZE
76 %token VAR_DEBUG_MODE
77 %token VAR_IP4_ONLY
78 %token VAR_IP6_ONLY
79 %token VAR_DO_IP4
80 %token VAR_DO_IP6
81 %token VAR_PORT
82 %token VAR_USE_SYSTEMD
83 %token VAR_VERBOSITY
84 %token VAR_USERNAME
85 %token VAR_CHROOT
86 %token VAR_ZONESDIR
87 %token VAR_ZONELISTFILE
88 %token VAR_DATABASE
89 %token VAR_LOGFILE
90 %token VAR_LOG_ONLY_SYSLOG
91 %token VAR_PIDFILE
92 %token VAR_DIFFFILE
93 %token VAR_XFRDFILE
94 %token VAR_XFRDIR
95 %token VAR_HIDE_VERSION
96 %token VAR_HIDE_IDENTITY
97 %token VAR_VERSION
98 %token VAR_IDENTITY
99 %token VAR_NSID
100 %token VAR_TCP_COUNT
101 %token VAR_TCP_REJECT_OVERFLOW
102 %token VAR_TCP_QUERY_COUNT
103 %token VAR_TCP_TIMEOUT
104 %token VAR_TCP_MSS
105 %token VAR_OUTGOING_TCP_MSS
106 %token VAR_IPV4_EDNS_SIZE
107 %token VAR_IPV6_EDNS_SIZE
108 %token VAR_STATISTICS
109 %token VAR_XFRD_RELOAD_TIMEOUT
110 %token VAR_LOG_TIME_ASCII
111 %token VAR_ROUND_ROBIN
112 %token VAR_MINIMAL_RESPONSES
113 %token VAR_CONFINE_TO_ZONE
114 %token VAR_REFUSE_ANY
115 %token VAR_ZONEFILES_CHECK
116 %token VAR_ZONEFILES_WRITE
117 %token VAR_RRL_SIZE
118 %token VAR_RRL_RATELIMIT
119 %token VAR_RRL_SLIP
120 %token VAR_RRL_IPV4_PREFIX_LENGTH
121 %token VAR_RRL_IPV6_PREFIX_LENGTH
122 %token VAR_RRL_WHITELIST_RATELIMIT
123 %token VAR_TLS_SERVICE_KEY
124 %token VAR_TLS_SERVICE_PEM
125 %token VAR_TLS_SERVICE_OCSP
126 %token VAR_TLS_PORT
127 %token VAR_TLS_CERT_BUNDLE
128 %token VAR_PROXY_PROTOCOL_PORT
129 %token VAR_CPU_AFFINITY
130 %token VAR_XFRD_CPU_AFFINITY
131 %token <llng> VAR_SERVER_CPU_AFFINITY
132 %token VAR_DROP_UPDATES
133 %token VAR_XFRD_TCP_MAX
134 %token VAR_XFRD_TCP_PIPELINE
135 
136 /* dnstap */
137 %token VAR_DNSTAP
138 %token VAR_DNSTAP_ENABLE
139 %token VAR_DNSTAP_SOCKET_PATH
140 %token VAR_DNSTAP_IP
141 %token VAR_DNSTAP_TLS
142 %token VAR_DNSTAP_TLS_SERVER_NAME
143 %token VAR_DNSTAP_TLS_CERT_BUNDLE
144 %token VAR_DNSTAP_TLS_CLIENT_KEY_FILE
145 %token VAR_DNSTAP_TLS_CLIENT_CERT_FILE
146 %token VAR_DNSTAP_SEND_IDENTITY
147 %token VAR_DNSTAP_SEND_VERSION
148 %token VAR_DNSTAP_IDENTITY
149 %token VAR_DNSTAP_VERSION
150 %token VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES
151 %token VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES
152 
153 /* remote-control */
154 %token VAR_REMOTE_CONTROL
155 %token VAR_CONTROL_ENABLE
156 %token VAR_CONTROL_INTERFACE
157 %token VAR_CONTROL_PORT
158 %token VAR_SERVER_KEY_FILE
159 %token VAR_SERVER_CERT_FILE
160 %token VAR_CONTROL_KEY_FILE
161 %token VAR_CONTROL_CERT_FILE
162 
163 /* key */
164 %token VAR_KEY
165 %token VAR_ALGORITHM
166 %token VAR_SECRET
167 
168 /* xot auth */
169 %token VAR_TLS_AUTH
170 %token VAR_TLS_AUTH_DOMAIN_NAME
171 %token VAR_TLS_AUTH_CLIENT_CERT
172 %token VAR_TLS_AUTH_CLIENT_KEY
173 %token VAR_TLS_AUTH_CLIENT_KEY_PW
174 
175 /* pattern */
176 %token VAR_PATTERN
177 %token VAR_NAME
178 %token VAR_ZONEFILE
179 %token VAR_NOTIFY
180 %token VAR_PROVIDE_XFR
181 %token VAR_ALLOW_QUERY
182 %token VAR_AXFR
183 %token VAR_UDP
184 %token VAR_NOTIFY_RETRY
185 %token VAR_ALLOW_NOTIFY
186 %token VAR_REQUEST_XFR
187 %token VAR_ALLOW_AXFR_FALLBACK
188 %token VAR_OUTGOING_INTERFACE
189 %token VAR_ANSWER_COOKIE
190 %token VAR_COOKIE_SECRET
191 %token VAR_COOKIE_SECRET_FILE
192 %token VAR_MAX_REFRESH_TIME
193 %token VAR_MIN_REFRESH_TIME
194 %token VAR_MAX_RETRY_TIME
195 %token VAR_MIN_RETRY_TIME
196 %token VAR_MIN_EXPIRE_TIME
197 %token VAR_MULTI_MASTER_CHECK
198 %token VAR_SIZE_LIMIT_XFR
199 %token VAR_ZONESTATS
200 %token VAR_INCLUDE_PATTERN
201 %token VAR_STORE_IXFR
202 %token VAR_IXFR_SIZE
203 %token VAR_IXFR_NUMBER
204 %token VAR_CREATE_IXFR
205 
206 /* zone */
207 %token VAR_ZONE
208 %token VAR_RRL_WHITELIST
209 
210 /* socket options */
211 %token VAR_SERVERS
212 %token VAR_BINDTODEVICE
213 %token VAR_SETFIB
214 
215 /* verify */
216 %token VAR_VERIFY
217 %token VAR_ENABLE
218 %token VAR_VERIFY_ZONE
219 %token VAR_VERIFY_ZONES
220 %token VAR_VERIFIER
221 %token VAR_VERIFIER_COUNT
222 %token VAR_VERIFIER_FEED_ZONE
223 %token VAR_VERIFIER_TIMEOUT
224 
225 %%
226 
227 blocks:
228     /* may be empty */
229   | blocks block ;
230 
231 block:
232     server
233   | dnstap
234   | remote_control
235   | key
236   | tls_auth
237   | pattern
238   | zone
239   | verify ;
240 
241 server:
242     VAR_SERVER server_block ;
243 
244 server_block:
245     server_block server_option | ;
246 
247 server_option:
248     VAR_IP_ADDRESS ip_address
249       {
250         struct ip_address_option *ip = cfg_parser->opt->ip_addresses;
251 
252         if(ip == NULL) {
253           cfg_parser->opt->ip_addresses = $2;
254         } else {
255           while(ip->next) { ip = ip->next; }
256           ip->next = $2;
257         }
258 
259         cfg_parser->ip = $2;
260       }
261     socket_options
262     {
263       cfg_parser->ip = NULL;
264     }
265   | VAR_SERVER_COUNT number
266     {
267       if ($2 > 0) {
268         cfg_parser->opt->server_count = (int)$2;
269       } else {
270         yyerror("expected a number greater than zero");
271       }
272     }
273   | VAR_IP_TRANSPARENT boolean
274     { cfg_parser->opt->ip_transparent = $2; }
275   | VAR_IP_FREEBIND boolean
276     { cfg_parser->opt->ip_freebind = $2; }
277   | VAR_SEND_BUFFER_SIZE number
278     { cfg_parser->opt->send_buffer_size = (int)$2; }
279   | VAR_RECEIVE_BUFFER_SIZE number
280     { cfg_parser->opt->receive_buffer_size = (int)$2; }
281   | VAR_DEBUG_MODE boolean
282     { cfg_parser->opt->debug_mode = $2; }
283   | VAR_USE_SYSTEMD boolean
284     { /* ignored, obsolete */ }
285   | VAR_HIDE_VERSION boolean
286     { cfg_parser->opt->hide_version = $2; }
287   | VAR_HIDE_IDENTITY boolean
288     { cfg_parser->opt->hide_identity = $2; }
289   | VAR_DROP_UPDATES boolean
290     { cfg_parser->opt->drop_updates = $2; }
291   | VAR_IP4_ONLY boolean
292     { if($2) { cfg_parser->opt->do_ip4 = 1; cfg_parser->opt->do_ip6 = 0; } }
293   | VAR_IP6_ONLY boolean
294     { if($2) { cfg_parser->opt->do_ip4 = 0; cfg_parser->opt->do_ip6 = 1; } }
295   | VAR_DO_IP4 boolean
296     { cfg_parser->opt->do_ip4 = $2; }
297   | VAR_DO_IP6 boolean
298     { cfg_parser->opt->do_ip6 = $2; }
299   | VAR_DATABASE STRING
300     { /* ignored, obsolete */ }
301   | VAR_IDENTITY STRING
302     { cfg_parser->opt->identity = region_strdup(cfg_parser->opt->region, $2); }
303   | VAR_VERSION STRING
304     { cfg_parser->opt->version = region_strdup(cfg_parser->opt->region, $2); }
305   | VAR_NSID STRING
306     {
307       unsigned char* nsid = 0;
308       size_t nsid_len = strlen($2);
309 
310       if (strncasecmp($2, "ascii_", 6) == 0) {
311         nsid_len -= 6; /* discard "ascii_" */
312         if(nsid_len < 65535) {
313           cfg_parser->opt->nsid = region_alloc(cfg_parser->opt->region, nsid_len*2+1);
314           hex_ntop((uint8_t*)$2+6, nsid_len, (char*)cfg_parser->opt->nsid, nsid_len*2+1);
315         } else {
316           yyerror("NSID too long");
317         }
318       } else if (nsid_len % 2 != 0) {
319         yyerror("the NSID must be a hex string of an even length.");
320       } else {
321         nsid_len = nsid_len / 2;
322         if(nsid_len < 65535) {
323           nsid = xalloc(nsid_len);
324           if (hex_pton($2, nsid, nsid_len) == -1) {
325             yyerror("hex string cannot be parsed in NSID.");
326           } else {
327             cfg_parser->opt->nsid = region_strdup(cfg_parser->opt->region, $2);
328           }
329           free(nsid);
330         } else {
331           yyerror("NSID too long");
332         }
333       }
334     }
335   | VAR_LOGFILE STRING
336     { cfg_parser->opt->logfile = region_strdup(cfg_parser->opt->region, $2); }
337   | VAR_LOG_ONLY_SYSLOG boolean
338     { cfg_parser->opt->log_only_syslog = $2; }
339   | VAR_TCP_COUNT number
340     {
341       if ($2 > 0) {
342         cfg_parser->opt->tcp_count = (int)$2;
343       } else {
344         yyerror("expected a number greater than zero");
345       }
346     }
347   | VAR_TCP_REJECT_OVERFLOW boolean
348     { cfg_parser->opt->tcp_reject_overflow = $2; }
349   | VAR_TCP_QUERY_COUNT number
350     { cfg_parser->opt->tcp_query_count = (int)$2; }
351   | VAR_TCP_TIMEOUT number
352     { cfg_parser->opt->tcp_timeout = (int)$2; }
353   | VAR_TCP_MSS number
354     { cfg_parser->opt->tcp_mss = (int)$2; }
355   | VAR_OUTGOING_TCP_MSS number
356     { cfg_parser->opt->outgoing_tcp_mss = (int)$2; }
357   | VAR_IPV4_EDNS_SIZE number
358     { cfg_parser->opt->ipv4_edns_size = (size_t)$2; }
359   | VAR_IPV6_EDNS_SIZE number
360     { cfg_parser->opt->ipv6_edns_size = (size_t)$2; }
361   | VAR_PIDFILE STRING
362     { cfg_parser->opt->pidfile = region_strdup(cfg_parser->opt->region, $2); }
363   | VAR_PORT number
364     {
365       /* port number, stored as a string */
366       char buf[16];
367       (void)snprintf(buf, sizeof(buf), "%lld", $2);
368       cfg_parser->opt->port = region_strdup(cfg_parser->opt->region, buf);
369     }
370   | VAR_REUSEPORT boolean
371     { cfg_parser->opt->reuseport = $2; }
372   | VAR_STATISTICS number
373     { cfg_parser->opt->statistics = (int)$2; }
374   | VAR_CHROOT STRING
375     { cfg_parser->opt->chroot = region_strdup(cfg_parser->opt->region, $2); }
376   | VAR_USERNAME STRING
377     { cfg_parser->opt->username = region_strdup(cfg_parser->opt->region, $2); }
378   | VAR_ZONESDIR STRING
379     { cfg_parser->opt->zonesdir = region_strdup(cfg_parser->opt->region, $2); }
380   | VAR_ZONELISTFILE STRING
381     { cfg_parser->opt->zonelistfile = region_strdup(cfg_parser->opt->region, $2); }
382   | VAR_DIFFFILE STRING
383     { /* ignored, obsolete */ }
384   | VAR_XFRDFILE STRING
385     { cfg_parser->opt->xfrdfile = region_strdup(cfg_parser->opt->region, $2); }
386   | VAR_XFRDIR STRING
387     { cfg_parser->opt->xfrdir = region_strdup(cfg_parser->opt->region, $2); }
388   | VAR_XFRD_RELOAD_TIMEOUT number
389     { cfg_parser->opt->xfrd_reload_timeout = (int)$2; }
390   | VAR_VERBOSITY number
391     { cfg_parser->opt->verbosity = (int)$2; }
392   | VAR_RRL_SIZE number
393     {
394 #ifdef RATELIMIT
395       if ($2 > 0) {
396         cfg_parser->opt->rrl_size = (size_t)$2;
397       } else {
398         yyerror("expected a number greater than zero");
399       }
400 #endif
401     }
402   | VAR_RRL_RATELIMIT number
403     {
404 #ifdef RATELIMIT
405       cfg_parser->opt->rrl_ratelimit = (size_t)$2;
406 #endif
407     }
408   | VAR_RRL_SLIP number
409     {
410 #ifdef RATELIMIT
411       cfg_parser->opt->rrl_slip = (size_t)$2;
412 #endif
413     }
414   | VAR_RRL_IPV4_PREFIX_LENGTH number
415     {
416 #ifdef RATELIMIT
417       if ($2 > 32) {
418         yyerror("invalid IPv4 prefix length");
419       } else {
420         cfg_parser->opt->rrl_ipv4_prefix_length = (size_t)$2;
421       }
422 #endif
423     }
424   | VAR_RRL_IPV6_PREFIX_LENGTH number
425     {
426 #ifdef RATELIMIT
427       if ($2 > 64) {
428         yyerror("invalid IPv6 prefix length");
429       } else {
430         cfg_parser->opt->rrl_ipv6_prefix_length = (size_t)$2;
431       }
432 #endif
433     }
434   | VAR_RRL_WHITELIST_RATELIMIT number
435     {
436 #ifdef RATELIMIT
437       cfg_parser->opt->rrl_whitelist_ratelimit = (size_t)$2;
438 #endif
439     }
440   | VAR_ZONEFILES_CHECK boolean
441     { cfg_parser->opt->zonefiles_check = $2; }
442   | VAR_ZONEFILES_WRITE number
443     { cfg_parser->opt->zonefiles_write = (int)$2; }
444   | VAR_LOG_TIME_ASCII boolean
445     {
446       cfg_parser->opt->log_time_ascii = $2;
447       log_time_asc = cfg_parser->opt->log_time_ascii;
448     }
449   | VAR_ROUND_ROBIN boolean
450     {
451       cfg_parser->opt->round_robin = $2;
452       round_robin = cfg_parser->opt->round_robin;
453     }
454   | VAR_MINIMAL_RESPONSES boolean
455     {
456       cfg_parser->opt->minimal_responses = $2;
457       minimal_responses = cfg_parser->opt->minimal_responses;
458     }
459   | VAR_CONFINE_TO_ZONE boolean
460     { cfg_parser->opt->confine_to_zone = $2; }
461   | VAR_REFUSE_ANY boolean
462     { cfg_parser->opt->refuse_any = $2; }
463   | VAR_TLS_SERVICE_KEY STRING
464     { cfg_parser->opt->tls_service_key = region_strdup(cfg_parser->opt->region, $2); }
465   | VAR_TLS_SERVICE_OCSP STRING
466     { cfg_parser->opt->tls_service_ocsp = region_strdup(cfg_parser->opt->region, $2); }
467   | VAR_TLS_SERVICE_PEM STRING
468     { cfg_parser->opt->tls_service_pem = region_strdup(cfg_parser->opt->region, $2); }
469   | VAR_TLS_PORT number
470     {
471       /* port number, stored as string */
472       char buf[16];
473       (void)snprintf(buf, sizeof(buf), "%lld", $2);
474       cfg_parser->opt->tls_port = region_strdup(cfg_parser->opt->region, buf);
475     }
476   | VAR_TLS_CERT_BUNDLE STRING
477     { cfg_parser->opt->tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); }
478   | VAR_PROXY_PROTOCOL_PORT number
479     {
480       struct proxy_protocol_port_list* elem = region_alloc_zero(
481 	cfg_parser->opt->region, sizeof(*elem));
482       elem->port = $2;
483       elem->next = cfg_parser->opt->proxy_protocol_port;
484       cfg_parser->opt->proxy_protocol_port = elem;
485     }
486   | VAR_ANSWER_COOKIE boolean
487     { cfg_parser->opt->answer_cookie = $2; }
488   | VAR_COOKIE_SECRET STRING
489     { cfg_parser->opt->cookie_secret = region_strdup(cfg_parser->opt->region, $2); }
490   | VAR_COOKIE_SECRET_FILE STRING
491     { cfg_parser->opt->cookie_secret_file = region_strdup(cfg_parser->opt->region, $2); }
492   | VAR_XFRD_TCP_MAX number
493     { cfg_parser->opt->xfrd_tcp_max = (int)$2; }
494   | VAR_XFRD_TCP_PIPELINE number
495     { cfg_parser->opt->xfrd_tcp_pipeline = (int)$2; }
496   | VAR_CPU_AFFINITY cpus
497     {
498       cfg_parser->opt->cpu_affinity = $2;
499     }
500   | service_cpu_affinity number
501     {
502       if($2 < 0) {
503         yyerror("expected a non-negative number");
504         YYABORT;
505       } else {
506         struct cpu_map_option *opt, *tail;
507 
508         opt = cfg_parser->opt->service_cpu_affinity;
509         while(opt && opt->service != $1) { opt = opt->next; }
510 
511         if(opt) {
512           opt->cpu = $2;
513         } else {
514           opt = region_alloc_zero(cfg_parser->opt->region, sizeof(*opt));
515           opt->service = (int)$1;
516           opt->cpu = (int)$2;
517 
518           tail = cfg_parser->opt->service_cpu_affinity;
519           if(tail) {
520             while(tail->next) { tail = tail->next; }
521             tail->next = opt;
522           } else {
523             cfg_parser->opt->service_cpu_affinity = opt;
524           }
525         }
526       }
527     }
528   ;
529 
530 socket_options:
531   | socket_options socket_option ;
532 
533 socket_option:
534     VAR_SERVERS STRING
535     {
536       char *tok, *ptr, *str;
537       struct range_option *servers = NULL;
538       long long first, last;
539 
540       /* user may specify "0 1", "0" "1", 0 1 or a combination thereof */
541       for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) {
542         struct range_option *opt =
543           region_alloc(cfg_parser->opt->region, sizeof(*opt));
544         first = last = 0;
545         if(!parse_range(tok, &first, &last)) {
546           yyerror("invalid server range '%s'", tok);
547           YYABORT;
548         }
549         assert(first >= 0);
550         assert(last >= 0);
551         opt->next = NULL;
552         opt->first = (int)first;
553         opt->last = (int)last;
554         if(servers) {
555           servers = servers->next = opt;
556         } else {
557           servers = cfg_parser->ip->servers = opt;
558         }
559       }
560     }
561   | VAR_BINDTODEVICE boolean
562     { cfg_parser->ip->dev = $2; }
563   | VAR_SETFIB number
564     { cfg_parser->ip->fib = $2; }
565   ;
566 
567 cpus:
568     { $$ = NULL; }
569   | cpus STRING
570     {
571       char *tok, *ptr, *str;
572       struct cpu_option *tail;
573       long long cpu;
574 
575       str = $2;
576       $$ = tail = $1;
577       if(tail) {
578         while(tail->next) { tail = tail->next; }
579       }
580 
581       /* Users may specify "0 1", "0" "1", 0 1 or a combination thereof. */
582       for(str = $2; (tok = strtok_r(str, " \t", &ptr)); str = NULL) {
583         struct cpu_option *opt =
584           region_alloc_zero(cfg_parser->opt->region, sizeof(*opt));
585         cpu = 0;
586         if(!parse_number(tok, &cpu) || cpu < 0) {
587           yyerror("expected a positive number");
588           YYABORT;
589         }
590         assert(cpu >=0);
591         opt->cpu = (int)cpu;
592         if(tail) {
593           tail->next = opt;
594           tail = opt;
595         } else {
596           $$ = tail = opt;
597         }
598       }
599     }
600   ;
601 
602 service_cpu_affinity:
603     VAR_XFRD_CPU_AFFINITY
604     { $$ = -1; }
605   | VAR_SERVER_CPU_AFFINITY
606     {
607       if($1 <= 0) {
608         yyerror("invalid server identifier");
609         YYABORT;
610       }
611       $$ = $1;
612     }
613   ;
614 
615 dnstap:
616     VAR_DNSTAP dnstap_block ;
617 
618 dnstap_block:
619     dnstap_block dnstap_option | ;
620 
621 dnstap_option:
622     VAR_DNSTAP_ENABLE boolean
623     { cfg_parser->opt->dnstap_enable = $2; }
624   | VAR_DNSTAP_SOCKET_PATH STRING
625     { cfg_parser->opt->dnstap_socket_path = region_strdup(cfg_parser->opt->region, $2); }
626   | VAR_DNSTAP_IP STRING
627     { cfg_parser->opt->dnstap_ip = region_strdup(cfg_parser->opt->region, $2); }
628   | VAR_DNSTAP_TLS boolean
629     { cfg_parser->opt->dnstap_tls = $2; }
630   | VAR_DNSTAP_TLS_SERVER_NAME STRING
631     { cfg_parser->opt->dnstap_tls_server_name = region_strdup(cfg_parser->opt->region, $2); }
632   | VAR_DNSTAP_TLS_CERT_BUNDLE STRING
633     { cfg_parser->opt->dnstap_tls_cert_bundle = region_strdup(cfg_parser->opt->region, $2); }
634   | VAR_DNSTAP_TLS_CLIENT_KEY_FILE STRING
635     { cfg_parser->opt->dnstap_tls_client_key_file = region_strdup(cfg_parser->opt->region, $2); }
636   | VAR_DNSTAP_TLS_CLIENT_CERT_FILE STRING
637     { cfg_parser->opt->dnstap_tls_client_cert_file = region_strdup(cfg_parser->opt->region, $2); }
638   | VAR_DNSTAP_SEND_IDENTITY boolean
639     { cfg_parser->opt->dnstap_send_identity = $2; }
640   | VAR_DNSTAP_SEND_VERSION boolean
641     { cfg_parser->opt->dnstap_send_version = $2; }
642   | VAR_DNSTAP_IDENTITY STRING
643     { cfg_parser->opt->dnstap_identity = region_strdup(cfg_parser->opt->region, $2); }
644   | VAR_DNSTAP_VERSION STRING
645     { cfg_parser->opt->dnstap_version = region_strdup(cfg_parser->opt->region, $2); }
646   | VAR_DNSTAP_LOG_AUTH_QUERY_MESSAGES boolean
647     { cfg_parser->opt->dnstap_log_auth_query_messages = $2; }
648   | VAR_DNSTAP_LOG_AUTH_RESPONSE_MESSAGES boolean
649     { cfg_parser->opt->dnstap_log_auth_response_messages = $2; }
650   ;
651 
652 remote_control:
653     VAR_REMOTE_CONTROL remote_control_block ;
654 
655 remote_control_block:
656     remote_control_block remote_control_option | ;
657 
658 remote_control_option:
659     VAR_CONTROL_ENABLE boolean
660     { cfg_parser->opt->control_enable = $2; }
661   | VAR_CONTROL_INTERFACE ip_address
662     {
663       struct ip_address_option *ip = cfg_parser->opt->control_interface;
664       if(ip == NULL) {
665         cfg_parser->opt->control_interface = $2;
666       } else {
667         while(ip->next != NULL) { ip = ip->next; }
668         ip->next = $2;
669       }
670     }
671   | VAR_CONTROL_PORT number
672     {
673       if($2 == 0) {
674         yyerror("control port number expected");
675       } else {
676         cfg_parser->opt->control_port = (int)$2;
677       }
678     }
679   | VAR_SERVER_KEY_FILE STRING
680     { cfg_parser->opt->server_key_file = region_strdup(cfg_parser->opt->region, $2); }
681   | VAR_SERVER_CERT_FILE STRING
682     { cfg_parser->opt->server_cert_file = region_strdup(cfg_parser->opt->region, $2); }
683   | VAR_CONTROL_KEY_FILE STRING
684     { cfg_parser->opt->control_key_file = region_strdup(cfg_parser->opt->region, $2); }
685   | VAR_CONTROL_CERT_FILE STRING
686     { cfg_parser->opt->control_cert_file = region_strdup(cfg_parser->opt->region, $2); }
687   ;
688 
689 tls_auth:
690     VAR_TLS_AUTH
691       {
692         tls_auth_options_type *tls_auth = tls_auth_options_create(cfg_parser->opt->region);
693         assert(cfg_parser->tls_auth == NULL);
694         cfg_parser->tls_auth = tls_auth;
695       }
696       tls_auth_block
697     {
698       struct tls_auth_options *tls_auth = cfg_parser->tls_auth;
699       if(tls_auth->name == NULL) {
700         yyerror("tls-auth has no name");
701       } else if(tls_auth->auth_domain_name == NULL) {
702         yyerror("tls-auth %s has no auth-domain-name", tls_auth->name);
703       } else if(tls_auth_options_find(cfg_parser->opt, tls_auth->name)) {
704         yyerror("duplicate tls-auth %s", tls_auth->name);
705       } else {
706       	tls_auth_options_insert(cfg_parser->opt, tls_auth);
707         cfg_parser->tls_auth = NULL;
708       }
709     } ;
710 
711 tls_auth_block:
712     tls_auth_block tls_auth_option | ;
713 
714 tls_auth_option:
715     VAR_NAME STRING
716     {
717       dname_type *dname;
718       dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2);
719       cfg_parser->tls_auth->name = region_strdup(cfg_parser->opt->region, $2);
720       if(dname == NULL) {
721         yyerror("bad tls-auth name %s", $2);
722       } else {
723         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
724       }
725     }
726   | VAR_TLS_AUTH_DOMAIN_NAME STRING
727     {
728       cfg_parser->tls_auth->auth_domain_name = region_strdup(cfg_parser->opt->region, $2);
729     }
730   | VAR_TLS_AUTH_CLIENT_CERT STRING
731     {
732 	    cfg_parser->tls_auth->client_cert = region_strdup(cfg_parser->opt->region, $2);
733     }
734   | VAR_TLS_AUTH_CLIENT_KEY STRING
735     {
736 	    cfg_parser->tls_auth->client_key = region_strdup(cfg_parser->opt->region, $2);
737     }
738   | VAR_TLS_AUTH_CLIENT_KEY_PW STRING
739     {
740 	    cfg_parser->tls_auth->client_key_pw = region_strdup(cfg_parser->opt->region, $2);
741     }
742   ;
743 
744 key:
745     VAR_KEY
746       {
747         key_options_type *key = key_options_create(cfg_parser->opt->region);
748         key->algorithm = region_strdup(cfg_parser->opt->region, "sha256");
749         assert(cfg_parser->key == NULL);
750         cfg_parser->key = key;
751       }
752       key_block
753     {
754       struct key_options *key = cfg_parser->key;
755       if(key->name == NULL) {
756         yyerror("tsig key has no name");
757       } else if(key->algorithm == NULL) {
758         yyerror("tsig key %s has no algorithm", key->name);
759       } else if(key->secret == NULL) {
760         yyerror("tsig key %s has no secret blob", key->name);
761       } else if(key_options_find(cfg_parser->opt, key->name)) {
762         yyerror("duplicate tsig key %s", key->name);
763       } else {
764         key_options_insert(cfg_parser->opt, key);
765         cfg_parser->key = NULL;
766       }
767     } ;
768 
769 key_block:
770     key_block key_option | ;
771 
772 key_option:
773     VAR_NAME STRING
774     {
775       dname_type *dname;
776 
777       dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2);
778       cfg_parser->key->name = region_strdup(cfg_parser->opt->region, $2);
779       if(dname == NULL) {
780         yyerror("bad tsig key name %s", $2);
781       } else {
782         region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname));
783       }
784     }
785   | VAR_ALGORITHM STRING
786     {
787       if(tsig_get_algorithm_by_name($2) == NULL) {
788         yyerror("bad tsig key algorithm %s", $2);
789       } else {
790         cfg_parser->key->algorithm = region_strdup(cfg_parser->opt->region, $2);
791       }
792     }
793   | VAR_SECRET STRING
794     {
795       uint8_t data[16384];
796       int size;
797 
798       cfg_parser->key->secret = region_strdup(cfg_parser->opt->region, $2);
799       size = b64_pton($2, data, sizeof(data));
800       if(size == -1) {
801         yyerror("cannot base64 decode tsig secret %s",
802           cfg_parser->key->name?
803           cfg_parser->key->name:"");
804       } else if(size != 0) {
805         memset(data, 0xdd, size); /* wipe secret */
806       }
807     } ;
808 
809 
810 zone:
811     VAR_ZONE
812       {
813         assert(cfg_parser->pattern == NULL);
814         assert(cfg_parser->zone == NULL);
815         cfg_parser->zone = zone_options_create(cfg_parser->opt->region);
816         cfg_parser->zone->part_of_config = 1;
817         cfg_parser->zone->pattern = cfg_parser->pattern =
818           pattern_options_create(cfg_parser->opt->region);
819         cfg_parser->zone->pattern->implicit = 1;
820       }
821     zone_block
822     {
823       assert(cfg_parser->zone != NULL);
824       if(cfg_parser->zone->name == NULL) {
825         yyerror("zone has no name");
826       } else if(!nsd_options_insert_zone(cfg_parser->opt, cfg_parser->zone)) {
827         yyerror("duplicate zone %s", cfg_parser->zone->name);
828       } else if(!nsd_options_insert_pattern(cfg_parser->opt, cfg_parser->zone->pattern)) {
829         yyerror("duplicate pattern %s", cfg_parser->zone->pattern->pname);
830       }
831       cfg_parser->pattern = NULL;
832       cfg_parser->zone = NULL;
833     } ;
834 
835 zone_block:
836     zone_block zone_option | ;
837 
838 zone_option:
839     VAR_NAME STRING
840     {
841       const char *marker = PATTERN_IMPLICIT_MARKER;
842       char *pname = region_alloc(cfg_parser->opt->region, strlen($2) + strlen(marker) + 1);
843       memmove(pname, marker, strlen(marker));
844       memmove(pname + strlen(marker), $2, strlen($2) + 1);
845       cfg_parser->zone->pattern->pname = pname;
846       cfg_parser->zone->name = region_strdup(cfg_parser->opt->region, $2);
847       if(pattern_options_find(cfg_parser->opt, pname)) {
848         yyerror("zone %s cannot be created because implicit pattern %s "
849                     "already exists", $2, pname);
850       }
851     }
852   | pattern_or_zone_option ;
853 
854 pattern:
855     VAR_PATTERN
856       {
857         assert(cfg_parser->pattern == NULL);
858         cfg_parser->pattern = pattern_options_create(cfg_parser->opt->region);
859       }
860       pattern_block
861     {
862       pattern_options_type *pattern = cfg_parser->pattern;
863       if(pattern->pname == NULL) {
864         yyerror("pattern has no name");
865       } else if(!nsd_options_insert_pattern(cfg_parser->opt, pattern)) {
866         yyerror("duplicate pattern %s", pattern->pname);
867       }
868       cfg_parser->pattern = NULL;
869     } ;
870 
871 pattern_block:
872     pattern_block pattern_option | ;
873 
874 pattern_option:
875     VAR_NAME STRING
876     {
877       if(strchr($2, ' ')) {
878         yyerror("space is not allowed in pattern name: '%s'", $2);
879       }
880       cfg_parser->pattern->pname = region_strdup(cfg_parser->opt->region, $2);
881     }
882   | pattern_or_zone_option ;
883 
884 pattern_or_zone_option:
885     VAR_RRL_WHITELIST STRING
886     {
887 #ifdef RATELIMIT
888       cfg_parser->pattern->rrl_whitelist |= rrlstr2type($2);
889 #endif
890     }
891   | VAR_ZONEFILE STRING
892     { cfg_parser->pattern->zonefile = region_strdup(cfg_parser->opt->region, $2); }
893   | VAR_ZONESTATS STRING
894     { cfg_parser->pattern->zonestats = region_strdup(cfg_parser->opt->region, $2); }
895   | VAR_SIZE_LIMIT_XFR number
896     {
897       if($2 > 0) {
898         cfg_parser->pattern->size_limit_xfr = (int)$2;
899       } else {
900         yyerror("expected a number greater than zero");
901       }
902     }
903   | VAR_MULTI_MASTER_CHECK boolean
904     { cfg_parser->pattern->multi_master_check = (int)$2; }
905   | VAR_INCLUDE_PATTERN STRING
906     { config_apply_pattern(cfg_parser->pattern, $2); }
907   | VAR_REQUEST_XFR STRING STRING
908     {
909       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
910       if(acl->blocked)
911         yyerror("blocked address used for request-xfr");
912       if(acl->rangetype != acl_range_single)
913         yyerror("address range used for request-xfr");
914       append_acl(&cfg_parser->pattern->request_xfr, acl);
915     }
916 	tlsauth_option
917 	{ }
918   | VAR_REQUEST_XFR VAR_AXFR STRING STRING
919     {
920       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4);
921       acl->use_axfr_only = 1;
922       if(acl->blocked)
923         yyerror("blocked address used for request-xfr");
924       if(acl->rangetype != acl_range_single)
925         yyerror("address range used for request-xfr");
926       append_acl(&cfg_parser->pattern->request_xfr, acl);
927     }
928 	tlsauth_option
929 	{ }
930   | VAR_REQUEST_XFR VAR_UDP STRING STRING
931     {
932       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $3, $4);
933       acl->allow_udp = 1;
934       if(acl->blocked)
935         yyerror("blocked address used for request-xfr");
936       if(acl->rangetype != acl_range_single)
937         yyerror("address range used for request-xfr");
938       append_acl(&cfg_parser->pattern->request_xfr, acl);
939     }
940   | VAR_ALLOW_NOTIFY STRING STRING
941     {
942       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
943       append_acl(&cfg_parser->pattern->allow_notify, acl);
944     }
945   | VAR_NOTIFY STRING STRING
946     {
947       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
948       if(acl->blocked)
949         yyerror("blocked address used for notify");
950       if(acl->rangetype != acl_range_single)
951         yyerror("address range used for notify");
952       append_acl(&cfg_parser->pattern->notify, acl);
953     }
954   | VAR_PROVIDE_XFR STRING STRING
955     {
956       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
957       append_acl(&cfg_parser->pattern->provide_xfr, acl);
958     }
959   | VAR_ALLOW_QUERY STRING STRING
960     {
961       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3);
962       append_acl(&cfg_parser->pattern->allow_query, acl);
963     }
964   | VAR_OUTGOING_INTERFACE STRING
965     {
966       acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, "NOKEY");
967       append_acl(&cfg_parser->pattern->outgoing_interface, acl);
968     }
969   | VAR_ALLOW_AXFR_FALLBACK boolean
970     {
971       cfg_parser->pattern->allow_axfr_fallback = $2;
972       cfg_parser->pattern->allow_axfr_fallback_is_default = 0;
973     }
974   | VAR_NOTIFY_RETRY number
975     {
976       cfg_parser->pattern->notify_retry = $2;
977       cfg_parser->pattern->notify_retry_is_default = 0;
978     }
979   | VAR_MAX_REFRESH_TIME number
980     {
981       cfg_parser->pattern->max_refresh_time = $2;
982       cfg_parser->pattern->max_refresh_time_is_default = 0;
983     }
984   | VAR_MIN_REFRESH_TIME number
985     {
986       cfg_parser->pattern->min_refresh_time = $2;
987       cfg_parser->pattern->min_refresh_time_is_default = 0;
988     }
989   | VAR_MAX_RETRY_TIME number
990     {
991       cfg_parser->pattern->max_retry_time = $2;
992       cfg_parser->pattern->max_retry_time_is_default = 0;
993     }
994   | VAR_MIN_RETRY_TIME number
995     {
996       cfg_parser->pattern->min_retry_time = $2;
997       cfg_parser->pattern->min_retry_time_is_default = 0;
998     }
999   | VAR_MIN_EXPIRE_TIME STRING
1000     {
1001       long long num;
1002       uint8_t expr;
1003 
1004       if (!parse_expire_expr($2, &num, &expr)) {
1005         yyerror("expected an expire time in seconds or \"refresh+retry+1\"");
1006         YYABORT; /* trigger a parser error */
1007       }
1008       cfg_parser->pattern->min_expire_time = num;
1009       cfg_parser->pattern->min_expire_time_expr = expr;
1010     }
1011   | VAR_STORE_IXFR boolean
1012     {
1013       cfg_parser->pattern->store_ixfr = $2;
1014       cfg_parser->pattern->store_ixfr_is_default = 0;
1015     }
1016   | VAR_IXFR_SIZE number
1017     {
1018       cfg_parser->pattern->ixfr_size = $2;
1019       cfg_parser->pattern->ixfr_size_is_default = 0;
1020     }
1021   | VAR_IXFR_NUMBER number
1022     {
1023       cfg_parser->pattern->ixfr_number = $2;
1024       cfg_parser->pattern->ixfr_number_is_default = 0;
1025     }
1026   | VAR_CREATE_IXFR boolean
1027     {
1028       cfg_parser->pattern->create_ixfr = $2;
1029       cfg_parser->pattern->create_ixfr_is_default = 0;
1030     }
1031   | VAR_VERIFY_ZONE boolean
1032     { cfg_parser->pattern->verify_zone = $2; }
1033   | VAR_VERIFIER command
1034     { cfg_parser->pattern->verifier = $2; }
1035   | VAR_VERIFIER_FEED_ZONE boolean
1036     { cfg_parser->pattern->verifier_feed_zone = $2; }
1037   | VAR_VERIFIER_TIMEOUT number
1038     { cfg_parser->pattern->verifier_timeout = $2; } ;
1039 
1040 verify:
1041     VAR_VERIFY verify_block ;
1042 
1043 verify_block:
1044     verify_block verify_option | ;
1045 
1046 verify_option:
1047     VAR_ENABLE boolean
1048     { cfg_parser->opt->verify_enable = $2; }
1049   | VAR_IP_ADDRESS ip_address
1050     {
1051       struct ip_address_option *ip = cfg_parser->opt->verify_ip_addresses;
1052       if(!ip) {
1053         cfg_parser->opt->verify_ip_addresses = $2;
1054       } else {
1055         while(ip->next) { ip = ip->next; }
1056         ip->next = $2;
1057       }
1058     }
1059   | VAR_PORT number
1060     {
1061       /* port number, stored as a string */
1062       char buf[16];
1063       (void)snprintf(buf, sizeof(buf), "%lld", $2);
1064       cfg_parser->opt->verify_port = region_strdup(cfg_parser->opt->region, buf);
1065     }
1066   | VAR_VERIFY_ZONES boolean
1067     { cfg_parser->opt->verify_zones = $2; }
1068   | VAR_VERIFIER command
1069     { cfg_parser->opt->verifier = $2; }
1070   | VAR_VERIFIER_COUNT number
1071     { cfg_parser->opt->verifier_count = (int)$2; }
1072   | VAR_VERIFIER_TIMEOUT number
1073     { cfg_parser->opt->verifier_timeout = (int)$2; }
1074   | VAR_VERIFIER_FEED_ZONE boolean
1075     { cfg_parser->opt->verifier_feed_zone = $2; } ;
1076 
1077 command:
1078     STRING arguments
1079     {
1080       char **argv;
1081       size_t argc = 1;
1082       for(struct component *i = $2; i; i = i->next) {
1083         argc++;
1084       }
1085       argv = region_alloc_zero(
1086         cfg_parser->opt->region, (argc + 1) * sizeof(char *));
1087       argc = 0;
1088       argv[argc++] = $1;
1089       for(struct component *j, *i = $2; i; i = j) {
1090         j = i->next;
1091         argv[argc++] = i->str;
1092         region_recycle(cfg_parser->opt->region, i, sizeof(*i));
1093       }
1094       $$ = argv;
1095     } ;
1096 
1097 arguments:
1098     { $$ = NULL; }
1099   | arguments STRING
1100     {
1101       struct component *comp = region_alloc_zero(
1102         cfg_parser->opt->region, sizeof(*comp));
1103       comp->str = region_strdup(cfg_parser->opt->region, $2);
1104       if($1) {
1105         struct component *tail = $1;
1106         while(tail->next) {
1107          tail = tail->next;
1108         }
1109         tail->next = comp;
1110         $$ = $1;
1111       } else {
1112         $$ = comp;
1113       }
1114     } ;
1115 
1116 ip_address:
1117     STRING
1118     {
1119       struct ip_address_option *ip = region_alloc_zero(
1120         cfg_parser->opt->region, sizeof(*ip));
1121       ip->address = region_strdup(cfg_parser->opt->region, $1);
1122       ip->fib = -1;
1123       $$ = ip;
1124     } ;
1125 
1126 number:
1127     STRING
1128     {
1129       if(!parse_number($1, &$$)) {
1130         yyerror("expected a number");
1131         YYABORT; /* trigger a parser error */
1132       }
1133     } ;
1134 
1135 boolean:
1136     STRING
1137     {
1138       if(!parse_boolean($1, &$$)) {
1139         yyerror("expected yes or no");
1140         YYABORT; /* trigger a parser error */
1141       }
1142     } ;
1143 
1144 tlsauth_option:
1145 	| STRING
1146 	{ char *tls_auth_name = region_strdup(cfg_parser->opt->region, $1);
1147 	  add_to_last_acl(&cfg_parser->pattern->request_xfr, tls_auth_name);} ;
1148 
1149 %%
1150 
1151 static void
1152 append_acl(struct acl_options **list, struct acl_options *acl)
1153 {
1154 	assert(list != NULL);
1155 
1156 	if(*list == NULL) {
1157 		*list = acl;
1158 	} else {
1159 		struct acl_options *tail = *list;
1160 		while(tail->next != NULL)
1161 			tail = tail->next;
1162 		tail->next = acl;
1163 	}
1164 }
1165 
1166 static void
add_to_last_acl(struct acl_options ** list,char * tls_auth_name)1167 add_to_last_acl(struct acl_options **list, char *tls_auth_name)
1168 {
1169 	struct acl_options *tail = *list;
1170 	assert(list != NULL);
1171 	assert(*list != NULL);
1172 	while(tail->next != NULL)
1173 		tail = tail->next;
1174 	tail->tls_auth_name = tls_auth_name;
1175 }
1176 
1177 static int
parse_boolean(const char * str,int * bln)1178 parse_boolean(const char *str, int *bln)
1179 {
1180 	if(strcmp(str, "yes") == 0) {
1181 		*bln = 1;
1182 	} else if(strcmp(str, "no") == 0) {
1183 		*bln = 0;
1184 	} else {
1185 		return 0;
1186 	}
1187 
1188 	return 1;
1189 }
1190 
1191 static int
parse_expire_expr(const char * str,long long * num,uint8_t * expr)1192 parse_expire_expr(const char *str, long long *num, uint8_t *expr)
1193 {
1194 	if(parse_number(str, num)) {
1195 		*expr = EXPIRE_TIME_HAS_VALUE;
1196 		return 1;
1197 	}
1198 	if(strcmp(str, REFRESHPLUSRETRYPLUS1_STR) == 0) {
1199 		*num = 0;
1200 		*expr = REFRESHPLUSRETRYPLUS1;
1201 		return 1;
1202 	}
1203 	return 0;
1204 }
1205 
1206 static int
parse_number(const char * str,long long * num)1207 parse_number(const char *str, long long *num)
1208 {
1209 	/* ensure string consists entirely of digits */
1210 	size_t pos = 0;
1211 	while(str[pos] >= '0' && str[pos] <= '9') {
1212 		pos++;
1213 	}
1214 
1215 	if(pos != 0 && str[pos] == '\0') {
1216 		*num = strtoll(str, NULL, 10);
1217 		return 1;
1218 	}
1219 
1220 	return 0;
1221 }
1222 
1223 static int
parse_range(const char * str,long long * low,long long * high)1224 parse_range(const char *str, long long *low, long long *high)
1225 {
1226 	const char *ptr = str;
1227 	long long num[2];
1228 
1229 	/* require range to begin with a number */
1230 	if(*ptr < '0' || *ptr > '9') {
1231 		return 0;
1232 	}
1233 
1234 	num[0] = strtoll(ptr, (char **)&ptr, 10);
1235 
1236 	/* require number to be followed by nothing at all or a dash */
1237 	if(*ptr == '\0') {
1238 		*low = num[0];
1239 		*high = num[0];
1240 		return 1;
1241 	} else if(*ptr != '-') {
1242 		return 0;
1243 	}
1244 
1245 	++ptr;
1246 	/* require dash to be followed by a number */
1247 	if(*ptr < '0' || *ptr > '9') {
1248 		return 0;
1249 	}
1250 
1251 	num[1] = strtoll(ptr, (char **)&ptr, 10);
1252 
1253 	/* require number to be followed by nothing at all */
1254 	if(*ptr == '\0') {
1255 		if(num[0] < num[1]) {
1256 			*low = num[0];
1257 			*high = num[1];
1258 		} else {
1259 			*low = num[1];
1260 			*high = num[0];
1261 		}
1262 		return 1;
1263 	}
1264 
1265 	return 0;
1266 }
1267