PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/bind9/lib/isccfg/namedconf.c

https://bitbucket.org/freebsd/freebsd-head/
C | 2741 lines | 2107 code | 353 blank | 281 comment | 168 complexity | 34ffe94fa630a73157ebddc734461e61 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
  1. /*
  2. * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC")
  3. * Copyright (C) 2002, 2003 Internet Software Consortium.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11. * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15. * PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /* $Id$ */
  18. /*! \file */
  19. #include <config.h>
  20. #include <string.h>
  21. #include <isc/lex.h>
  22. #include <isc/mem.h>
  23. #include <isc/result.h>
  24. #include <isc/string.h>
  25. #include <isc/util.h>
  26. #include <isccfg/cfg.h>
  27. #include <isccfg/grammar.h>
  28. #include <isccfg/log.h>
  29. #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
  30. /*% Check a return value. */
  31. #define CHECK(op) \
  32. do { result = (op); \
  33. if (result != ISC_R_SUCCESS) goto cleanup; \
  34. } while (0)
  35. /*% Clean up a configuration object if non-NULL. */
  36. #define CLEANUP_OBJ(obj) \
  37. do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
  38. /*%
  39. * Forward declarations of static functions.
  40. */
  41. static isc_result_t
  42. parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
  43. const cfg_type_t *othertype, cfg_obj_t **ret);
  44. static isc_result_t
  45. parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
  46. static isc_result_t
  47. parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
  48. cfg_obj_t **ret);
  49. static isc_result_t
  50. parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
  51. cfg_obj_t **ret);
  52. static void
  53. print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj);
  54. static void
  55. doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type);
  56. static void
  57. print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj);
  58. static void
  59. doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
  60. static void
  61. doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type);
  62. static cfg_type_t cfg_type_acl;
  63. static cfg_type_t cfg_type_addrmatchelt;
  64. static cfg_type_t cfg_type_bracketed_aml;
  65. static cfg_type_t cfg_type_bracketed_namesockaddrkeylist;
  66. static cfg_type_t cfg_type_bracketed_sockaddrlist;
  67. static cfg_type_t cfg_type_bracketed_sockaddrnameportlist;
  68. static cfg_type_t cfg_type_controls;
  69. static cfg_type_t cfg_type_controls_sockaddr;
  70. static cfg_type_t cfg_type_destinationlist;
  71. static cfg_type_t cfg_type_dialuptype;
  72. static cfg_type_t cfg_type_ixfrdifftype;
  73. static cfg_type_t cfg_type_key;
  74. static cfg_type_t cfg_type_logfile;
  75. static cfg_type_t cfg_type_logging;
  76. static cfg_type_t cfg_type_logseverity;
  77. static cfg_type_t cfg_type_lwres;
  78. static cfg_type_t cfg_type_masterselement;
  79. static cfg_type_t cfg_type_nameportiplist;
  80. static cfg_type_t cfg_type_negated;
  81. static cfg_type_t cfg_type_notifytype;
  82. static cfg_type_t cfg_type_optional_allow;
  83. static cfg_type_t cfg_type_optional_class;
  84. static cfg_type_t cfg_type_optional_facility;
  85. static cfg_type_t cfg_type_optional_keyref;
  86. static cfg_type_t cfg_type_optional_port;
  87. static cfg_type_t cfg_type_options;
  88. static cfg_type_t cfg_type_portiplist;
  89. static cfg_type_t cfg_type_querysource4;
  90. static cfg_type_t cfg_type_querysource6;
  91. static cfg_type_t cfg_type_querysource;
  92. static cfg_type_t cfg_type_server;
  93. static cfg_type_t cfg_type_server_key_kludge;
  94. static cfg_type_t cfg_type_size;
  95. static cfg_type_t cfg_type_sizenodefault;
  96. static cfg_type_t cfg_type_sockaddr4wild;
  97. static cfg_type_t cfg_type_sockaddr6wild;
  98. static cfg_type_t cfg_type_statschannels;
  99. static cfg_type_t cfg_type_view;
  100. static cfg_type_t cfg_type_viewopts;
  101. static cfg_type_t cfg_type_zone;
  102. static cfg_type_t cfg_type_zoneopts;
  103. static cfg_type_t cfg_type_dynamically_loadable_zones;
  104. static cfg_type_t cfg_type_dynamically_loadable_zones_opts;
  105. static cfg_type_t cfg_type_v4_aaaa;
  106. /*
  107. * Clauses that can be found in a 'dynamically loadable zones' statement
  108. */
  109. static cfg_clausedef_t
  110. dynamically_loadable_zones_clauses[] = {
  111. { "database", &cfg_type_astring, 0 },
  112. { NULL, NULL, 0 }
  113. };
  114. /*
  115. * A dynamically loadable zones statement.
  116. */
  117. static cfg_tuplefielddef_t dynamically_loadable_zones_fields[] = {
  118. { "name", &cfg_type_astring, 0 },
  119. { "options", &cfg_type_dynamically_loadable_zones_opts, 0 },
  120. { NULL, NULL, 0 }
  121. };
  122. static cfg_type_t cfg_type_dynamically_loadable_zones = {
  123. "dlz", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  124. &cfg_rep_tuple,
  125. dynamically_loadable_zones_fields
  126. };
  127. /*% tkey-dhkey */
  128. static cfg_tuplefielddef_t tkey_dhkey_fields[] = {
  129. { "name", &cfg_type_qstring, 0 },
  130. { "keyid", &cfg_type_uint32, 0 },
  131. { NULL, NULL, 0 }
  132. };
  133. static cfg_type_t cfg_type_tkey_dhkey = {
  134. "tkey-dhkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
  135. tkey_dhkey_fields
  136. };
  137. /*% listen-on */
  138. static cfg_tuplefielddef_t listenon_fields[] = {
  139. { "port", &cfg_type_optional_port, 0 },
  140. { "acl", &cfg_type_bracketed_aml, 0 },
  141. { NULL, NULL, 0 }
  142. };
  143. static cfg_type_t cfg_type_listenon = {
  144. "listenon", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, listenon_fields };
  145. /*% acl */
  146. static cfg_tuplefielddef_t acl_fields[] = {
  147. { "name", &cfg_type_astring, 0 },
  148. { "value", &cfg_type_bracketed_aml, 0 },
  149. { NULL, NULL, 0 }
  150. };
  151. static cfg_type_t cfg_type_acl = {
  152. "acl", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, acl_fields };
  153. /*% masters */
  154. static cfg_tuplefielddef_t masters_fields[] = {
  155. { "name", &cfg_type_astring, 0 },
  156. { "port", &cfg_type_optional_port, 0 },
  157. { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
  158. { NULL, NULL, 0 }
  159. };
  160. static cfg_type_t cfg_type_masters = {
  161. "masters", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, masters_fields };
  162. /*%
  163. * "sockaddrkeylist", a list of socket addresses with optional keys
  164. * and an optional default port, as used in the masters option.
  165. * E.g.,
  166. * "port 1234 { mymasters; 10.0.0.1 key foo; 1::2 port 69; }"
  167. */
  168. static cfg_tuplefielddef_t namesockaddrkey_fields[] = {
  169. { "masterselement", &cfg_type_masterselement, 0 },
  170. { "key", &cfg_type_optional_keyref, 0 },
  171. { NULL, NULL, 0 },
  172. };
  173. static cfg_type_t cfg_type_namesockaddrkey = {
  174. "namesockaddrkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
  175. namesockaddrkey_fields
  176. };
  177. static cfg_type_t cfg_type_bracketed_namesockaddrkeylist = {
  178. "bracketed_namesockaddrkeylist", cfg_parse_bracketed_list,
  179. cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_namesockaddrkey
  180. };
  181. static cfg_tuplefielddef_t namesockaddrkeylist_fields[] = {
  182. { "port", &cfg_type_optional_port, 0 },
  183. { "addresses", &cfg_type_bracketed_namesockaddrkeylist, 0 },
  184. { NULL, NULL, 0 }
  185. };
  186. static cfg_type_t cfg_type_namesockaddrkeylist = {
  187. "sockaddrkeylist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
  188. namesockaddrkeylist_fields
  189. };
  190. /*%
  191. * A list of socket addresses with an optional default port,
  192. * as used in the also-notify option. E.g.,
  193. * "port 1234 { 10.0.0.1; 1::2 port 69; }"
  194. */
  195. static cfg_tuplefielddef_t portiplist_fields[] = {
  196. { "port", &cfg_type_optional_port, 0 },
  197. { "addresses", &cfg_type_bracketed_sockaddrlist, 0 },
  198. { NULL, NULL, 0 }
  199. };
  200. static cfg_type_t cfg_type_portiplist = {
  201. "portiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
  202. portiplist_fields
  203. };
  204. /*%
  205. * A public key, as in the "pubkey" statement.
  206. */
  207. static cfg_tuplefielddef_t pubkey_fields[] = {
  208. { "flags", &cfg_type_uint32, 0 },
  209. { "protocol", &cfg_type_uint32, 0 },
  210. { "algorithm", &cfg_type_uint32, 0 },
  211. { "key", &cfg_type_qstring, 0 },
  212. { NULL, NULL, 0 }
  213. };
  214. static cfg_type_t cfg_type_pubkey = {
  215. "pubkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  216. &cfg_rep_tuple, pubkey_fields };
  217. /*%
  218. * A list of RR types, used in grant statements.
  219. * Note that the old parser allows quotes around the RR type names.
  220. */
  221. static cfg_type_t cfg_type_rrtypelist = {
  222. "rrtypelist", cfg_parse_spacelist, cfg_print_spacelist,
  223. cfg_doc_terminal, &cfg_rep_list, &cfg_type_astring
  224. };
  225. static const char *mode_enums[] = { "grant", "deny", NULL };
  226. static cfg_type_t cfg_type_mode = {
  227. "mode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
  228. &cfg_rep_string, &mode_enums
  229. };
  230. static isc_result_t
  231. parse_matchtype(cfg_parser_t *pctx, const cfg_type_t *type,
  232. cfg_obj_t **ret) {
  233. isc_result_t result;
  234. CHECK(cfg_peektoken(pctx, 0));
  235. if (pctx->token.type == isc_tokentype_string &&
  236. strcasecmp(TOKEN_STRING(pctx), "zonesub") == 0) {
  237. pctx->flags |= CFG_PCTX_SKIP;
  238. }
  239. return (cfg_parse_enum(pctx, type, ret));
  240. cleanup:
  241. return (result);
  242. }
  243. static isc_result_t
  244. parse_matchname(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  245. isc_result_t result;
  246. cfg_obj_t *obj = NULL;
  247. if ((pctx->flags & CFG_PCTX_SKIP) != 0) {
  248. pctx->flags &= ~CFG_PCTX_SKIP;
  249. CHECK(cfg_parse_void(pctx, NULL, &obj));
  250. } else
  251. result = cfg_parse_astring(pctx, type, &obj);
  252. *ret = obj;
  253. cleanup:
  254. return (result);
  255. }
  256. static void
  257. doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) {
  258. cfg_print_chars(pctx, "[ ", 2);
  259. cfg_doc_obj(pctx, type->of);
  260. cfg_print_chars(pctx, " ]", 2);
  261. }
  262. static const char *matchtype_enums[] = {
  263. "name", "subdomain", "wildcard", "self", "selfsub", "selfwild",
  264. "krb5-self", "ms-self", "krb5-subdomain", "ms-subdomain",
  265. "tcp-self", "6to4-self", "zonesub", "external", NULL };
  266. static cfg_type_t cfg_type_matchtype = {
  267. "matchtype", parse_matchtype, cfg_print_ustring,
  268. cfg_doc_enum, &cfg_rep_string, &matchtype_enums
  269. };
  270. static cfg_type_t cfg_type_matchname = {
  271. "optional_matchname", parse_matchname, cfg_print_ustring,
  272. &doc_matchname, &cfg_rep_tuple, &cfg_type_ustring
  273. };
  274. /*%
  275. * A grant statement, used in the update policy.
  276. */
  277. static cfg_tuplefielddef_t grant_fields[] = {
  278. { "mode", &cfg_type_mode, 0 },
  279. { "identity", &cfg_type_astring, 0 }, /* domain name */
  280. { "matchtype", &cfg_type_matchtype, 0 },
  281. { "name", &cfg_type_matchname, 0 }, /* domain name */
  282. { "types", &cfg_type_rrtypelist, 0 },
  283. { NULL, NULL, 0 }
  284. };
  285. static cfg_type_t cfg_type_grant = {
  286. "grant", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  287. &cfg_rep_tuple, grant_fields
  288. };
  289. static cfg_type_t cfg_type_updatepolicy = {
  290. "update_policy", parse_updatepolicy, print_updatepolicy,
  291. doc_updatepolicy, &cfg_rep_list, &cfg_type_grant
  292. };
  293. static isc_result_t
  294. parse_updatepolicy(cfg_parser_t *pctx, const cfg_type_t *type,
  295. cfg_obj_t **ret) {
  296. isc_result_t result;
  297. CHECK(cfg_gettoken(pctx, 0));
  298. if (pctx->token.type == isc_tokentype_special &&
  299. pctx->token.value.as_char == '{') {
  300. cfg_ungettoken(pctx);
  301. return (cfg_parse_bracketed_list(pctx, type, ret));
  302. }
  303. if (pctx->token.type == isc_tokentype_string &&
  304. strcasecmp(TOKEN_STRING(pctx), "local") == 0) {
  305. cfg_obj_t *obj = NULL;
  306. CHECK(cfg_create_obj(pctx, &cfg_type_ustring, &obj));
  307. obj->value.string.length = strlen("local");
  308. obj->value.string.base = isc_mem_get(pctx->mctx,
  309. obj->value.string.length + 1);
  310. if (obj->value.string.base == NULL) {
  311. isc_mem_put(pctx->mctx, obj, sizeof(*obj));
  312. return (ISC_R_NOMEMORY);
  313. }
  314. memcpy(obj->value.string.base, "local", 5);
  315. obj->value.string.base[5] = '\0';
  316. *ret = obj;
  317. return (ISC_R_SUCCESS);
  318. }
  319. cfg_ungettoken(pctx);
  320. return (ISC_R_UNEXPECTEDTOKEN);
  321. cleanup:
  322. return (result);
  323. }
  324. static void
  325. print_updatepolicy(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  326. if (cfg_obj_isstring(obj))
  327. cfg_print_ustring(pctx, obj);
  328. else
  329. cfg_print_bracketed_list(pctx, obj);
  330. }
  331. static void
  332. doc_updatepolicy(cfg_printer_t *pctx, const cfg_type_t *type) {
  333. cfg_print_cstr(pctx, "( local | { ");
  334. cfg_doc_obj(pctx, type->of);
  335. cfg_print_cstr(pctx, "; ... }");
  336. }
  337. /*%
  338. * A view statement.
  339. */
  340. static cfg_tuplefielddef_t view_fields[] = {
  341. { "name", &cfg_type_astring, 0 },
  342. { "class", &cfg_type_optional_class, 0 },
  343. { "options", &cfg_type_viewopts, 0 },
  344. { NULL, NULL, 0 }
  345. };
  346. static cfg_type_t cfg_type_view = {
  347. "view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  348. &cfg_rep_tuple, view_fields
  349. };
  350. /*%
  351. * A zone statement.
  352. */
  353. static cfg_tuplefielddef_t zone_fields[] = {
  354. { "name", &cfg_type_astring, 0 },
  355. { "class", &cfg_type_optional_class, 0 },
  356. { "options", &cfg_type_zoneopts, 0 },
  357. { NULL, NULL, 0 }
  358. };
  359. static cfg_type_t cfg_type_zone = {
  360. "zone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  361. &cfg_rep_tuple, zone_fields
  362. };
  363. /*%
  364. * A "category" clause in the "logging" statement.
  365. */
  366. static cfg_tuplefielddef_t category_fields[] = {
  367. { "name", &cfg_type_astring, 0 },
  368. { "destinations", &cfg_type_destinationlist,0 },
  369. { NULL, NULL, 0 }
  370. };
  371. static cfg_type_t cfg_type_category = {
  372. "category", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  373. &cfg_rep_tuple, category_fields
  374. };
  375. /*%
  376. * A dnssec key, as used in the "trusted-keys" statement.
  377. */
  378. static cfg_tuplefielddef_t dnsseckey_fields[] = {
  379. { "name", &cfg_type_astring, 0 },
  380. { "flags", &cfg_type_uint32, 0 },
  381. { "protocol", &cfg_type_uint32, 0 },
  382. { "algorithm", &cfg_type_uint32, 0 },
  383. { "key", &cfg_type_qstring, 0 },
  384. { NULL, NULL, 0 }
  385. };
  386. static cfg_type_t cfg_type_dnsseckey = {
  387. "dnsseckey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  388. &cfg_rep_tuple, dnsseckey_fields
  389. };
  390. /*%
  391. * A managed key initialization specifier, as used in the
  392. * "managed-keys" statement.
  393. */
  394. static cfg_tuplefielddef_t managedkey_fields[] = {
  395. { "name", &cfg_type_astring, 0 },
  396. { "init", &cfg_type_ustring, 0 }, /* must be literal "initial-key" */
  397. { "flags", &cfg_type_uint32, 0 },
  398. { "protocol", &cfg_type_uint32, 0 },
  399. { "algorithm", &cfg_type_uint32, 0 },
  400. { "key", &cfg_type_qstring, 0 },
  401. { NULL, NULL, 0 }
  402. };
  403. static cfg_type_t cfg_type_managedkey = {
  404. "managedkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  405. &cfg_rep_tuple, managedkey_fields
  406. };
  407. static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };
  408. static cfg_type_t cfg_type_optional_wild_class = {
  409. "optional_wild_class", parse_optional_keyvalue, print_keyvalue,
  410. doc_optional_keyvalue, &cfg_rep_string, &wild_class_kw
  411. };
  412. static keyword_type_t wild_type_kw = { "type", &cfg_type_ustring };
  413. static cfg_type_t cfg_type_optional_wild_type = {
  414. "optional_wild_type", parse_optional_keyvalue,
  415. print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_type_kw
  416. };
  417. static keyword_type_t wild_name_kw = { "name", &cfg_type_qstring };
  418. static cfg_type_t cfg_type_optional_wild_name = {
  419. "optional_wild_name", parse_optional_keyvalue,
  420. print_keyvalue, doc_optional_keyvalue, &cfg_rep_string, &wild_name_kw
  421. };
  422. /*%
  423. * An rrset ordering element.
  424. */
  425. static cfg_tuplefielddef_t rrsetorderingelement_fields[] = {
  426. { "class", &cfg_type_optional_wild_class, 0 },
  427. { "type", &cfg_type_optional_wild_type, 0 },
  428. { "name", &cfg_type_optional_wild_name, 0 },
  429. { "order", &cfg_type_ustring, 0 }, /* must be literal "order" */
  430. { "ordering", &cfg_type_ustring, 0 },
  431. { NULL, NULL, 0 }
  432. };
  433. static cfg_type_t cfg_type_rrsetorderingelement = {
  434. "rrsetorderingelement", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
  435. rrsetorderingelement_fields
  436. };
  437. /*%
  438. * A global or view "check-names" option. Note that the zone
  439. * "check-names" option has a different syntax.
  440. */
  441. static const char *checktype_enums[] = { "master", "slave", "response", NULL };
  442. static cfg_type_t cfg_type_checktype = {
  443. "checktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
  444. &cfg_rep_string, &checktype_enums
  445. };
  446. static const char *checkmode_enums[] = { "fail", "warn", "ignore", NULL };
  447. static cfg_type_t cfg_type_checkmode = {
  448. "checkmode", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
  449. &cfg_rep_string, &checkmode_enums
  450. };
  451. static cfg_tuplefielddef_t checknames_fields[] = {
  452. { "type", &cfg_type_checktype, 0 },
  453. { "mode", &cfg_type_checkmode, 0 },
  454. { NULL, NULL, 0 }
  455. };
  456. static cfg_type_t cfg_type_checknames = {
  457. "checknames", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
  458. checknames_fields
  459. };
  460. static cfg_type_t cfg_type_bracketed_sockaddrlist = {
  461. "bracketed_sockaddrlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
  462. &cfg_rep_list, &cfg_type_sockaddr
  463. };
  464. static const char *autodnssec_enums[] = { "allow", "maintain", "off", NULL };
  465. static cfg_type_t cfg_type_autodnssec = {
  466. "autodnssec", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
  467. &cfg_rep_string, &autodnssec_enums
  468. };
  469. static cfg_type_t cfg_type_rrsetorder = {
  470. "rrsetorder", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
  471. &cfg_rep_list, &cfg_type_rrsetorderingelement
  472. };
  473. static keyword_type_t port_kw = { "port", &cfg_type_uint32 };
  474. static cfg_type_t cfg_type_optional_port = {
  475. "optional_port", parse_optional_keyvalue, print_keyvalue,
  476. doc_optional_keyvalue, &cfg_rep_uint32, &port_kw
  477. };
  478. /*% A list of keys, as in the "key" clause of the controls statement. */
  479. static cfg_type_t cfg_type_keylist = {
  480. "keylist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
  481. cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring
  482. };
  483. /*% A list of dnssec keys, as in "trusted-keys" */
  484. static cfg_type_t cfg_type_dnsseckeys = {
  485. "dnsseckeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
  486. cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_dnsseckey
  487. };
  488. /*%
  489. * A list of managed key entries, as in "trusted-keys". Currently
  490. * (9.7.0) this has a format similar to dnssec keys, except the keyname
  491. * is followed by the keyword "initial-key". In future releases, this
  492. * keyword may take other values indicating different methods for the
  493. * key to be initialized.
  494. */
  495. static cfg_type_t cfg_type_managedkeys = {
  496. "managedkeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
  497. cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_managedkey
  498. };
  499. static const char *forwardtype_enums[] = { "first", "only", NULL };
  500. static cfg_type_t cfg_type_forwardtype = {
  501. "forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
  502. &forwardtype_enums
  503. };
  504. static const char *zonetype_enums[] = {
  505. "master", "slave", "stub", "static-stub", "hint", "forward",
  506. "delegation-only", NULL };
  507. static cfg_type_t cfg_type_zonetype = {
  508. "zonetype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
  509. &cfg_rep_string, &zonetype_enums
  510. };
  511. static const char *loglevel_enums[] = {
  512. "critical", "error", "warning", "notice", "info", "dynamic", NULL };
  513. static cfg_type_t cfg_type_loglevel = {
  514. "loglevel", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
  515. &loglevel_enums
  516. };
  517. static const char *transferformat_enums[] = {
  518. "many-answers", "one-answer", NULL };
  519. static cfg_type_t cfg_type_transferformat = {
  520. "transferformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, &cfg_rep_string,
  521. &transferformat_enums
  522. };
  523. /*%
  524. * The special keyword "none", as used in the pid-file option.
  525. */
  526. static void
  527. print_none(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  528. UNUSED(obj);
  529. cfg_print_cstr(pctx, "none");
  530. }
  531. static cfg_type_t cfg_type_none = {
  532. "none", NULL, print_none, NULL, &cfg_rep_void, NULL
  533. };
  534. /*%
  535. * A quoted string or the special keyword "none". Used in the pid-file option.
  536. */
  537. static isc_result_t
  538. parse_qstringornone(cfg_parser_t *pctx, const cfg_type_t *type,
  539. cfg_obj_t **ret)
  540. {
  541. isc_result_t result;
  542. CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
  543. if (pctx->token.type == isc_tokentype_string &&
  544. strcasecmp(TOKEN_STRING(pctx), "none") == 0)
  545. return (cfg_create_obj(pctx, &cfg_type_none, ret));
  546. cfg_ungettoken(pctx);
  547. return (cfg_parse_qstring(pctx, type, ret));
  548. cleanup:
  549. return (result);
  550. }
  551. static void
  552. doc_qstringornone(cfg_printer_t *pctx, const cfg_type_t *type) {
  553. UNUSED(type);
  554. cfg_print_cstr(pctx, "( <quoted_string> | none )");
  555. }
  556. static cfg_type_t cfg_type_qstringornone = {
  557. "qstringornone", parse_qstringornone, NULL, doc_qstringornone,
  558. NULL, NULL
  559. };
  560. /*%
  561. * A boolean ("yes" or "no"), or the special keyword "auto".
  562. * Used in the dnssec-validation option.
  563. */
  564. static void
  565. print_auto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  566. UNUSED(obj);
  567. cfg_print_cstr(pctx, "auto");
  568. }
  569. static cfg_type_t cfg_type_auto = {
  570. "auto", NULL, print_auto, NULL, &cfg_rep_void, NULL
  571. };
  572. static isc_result_t
  573. parse_boolorauto(cfg_parser_t *pctx, const cfg_type_t *type,
  574. cfg_obj_t **ret)
  575. {
  576. isc_result_t result;
  577. CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
  578. if (pctx->token.type == isc_tokentype_string &&
  579. strcasecmp(TOKEN_STRING(pctx), "auto") == 0)
  580. return (cfg_create_obj(pctx, &cfg_type_auto, ret));
  581. cfg_ungettoken(pctx);
  582. return (cfg_parse_boolean(pctx, type, ret));
  583. cleanup:
  584. return (result);
  585. }
  586. static void
  587. print_boolorauto(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  588. if (obj->type->rep == &cfg_rep_void)
  589. cfg_print_chars(pctx, "auto", 4);
  590. else if (obj->value.boolean)
  591. cfg_print_chars(pctx, "yes", 3);
  592. else
  593. cfg_print_chars(pctx, "no", 2);
  594. }
  595. static void
  596. doc_boolorauto(cfg_printer_t *pctx, const cfg_type_t *type) {
  597. UNUSED(type);
  598. cfg_print_cstr(pctx, "( yes | no | auto )");
  599. }
  600. static cfg_type_t cfg_type_boolorauto = {
  601. "boolorauto", parse_boolorauto, print_boolorauto,
  602. doc_boolorauto, NULL, NULL
  603. };
  604. /*%
  605. * keyword hostname
  606. */
  607. static void
  608. print_hostname(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  609. UNUSED(obj);
  610. cfg_print_cstr(pctx, "hostname");
  611. }
  612. static cfg_type_t cfg_type_hostname = {
  613. "hostname", NULL, print_hostname, NULL, &cfg_rep_boolean, NULL
  614. };
  615. /*%
  616. * "server-id" argument.
  617. */
  618. static isc_result_t
  619. parse_serverid(cfg_parser_t *pctx, const cfg_type_t *type,
  620. cfg_obj_t **ret)
  621. {
  622. isc_result_t result;
  623. CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
  624. if (pctx->token.type == isc_tokentype_string &&
  625. strcasecmp(TOKEN_STRING(pctx), "none") == 0)
  626. return (cfg_create_obj(pctx, &cfg_type_none, ret));
  627. if (pctx->token.type == isc_tokentype_string &&
  628. strcasecmp(TOKEN_STRING(pctx), "hostname") == 0) {
  629. return (cfg_create_obj(pctx, &cfg_type_hostname, ret));
  630. }
  631. cfg_ungettoken(pctx);
  632. return (cfg_parse_qstring(pctx, type, ret));
  633. cleanup:
  634. return (result);
  635. }
  636. static void
  637. doc_serverid(cfg_printer_t *pctx, const cfg_type_t *type) {
  638. UNUSED(type);
  639. cfg_print_cstr(pctx, "( <quoted_string> | none | hostname )");
  640. }
  641. static cfg_type_t cfg_type_serverid = {
  642. "serverid", parse_serverid, NULL, doc_serverid, NULL, NULL };
  643. /*%
  644. * Port list.
  645. */
  646. static cfg_tuplefielddef_t porttuple_fields[] = {
  647. { "loport", &cfg_type_uint32, 0 },
  648. { "hiport", &cfg_type_uint32, 0 },
  649. { NULL, NULL, 0 }
  650. };
  651. static cfg_type_t cfg_type_porttuple = {
  652. "porttuple", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  653. &cfg_rep_tuple, porttuple_fields
  654. };
  655. static isc_result_t
  656. parse_port(cfg_parser_t *pctx, cfg_obj_t **ret) {
  657. isc_result_t result;
  658. CHECK(cfg_parse_uint32(pctx, NULL, ret));
  659. if ((*ret)->value.uint32 > 0xffff) {
  660. cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid port");
  661. cfg_obj_destroy(pctx, ret);
  662. result = ISC_R_RANGE;
  663. }
  664. cleanup:
  665. return (result);
  666. }
  667. static isc_result_t
  668. parse_portrange(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  669. isc_result_t result;
  670. cfg_obj_t *obj = NULL;
  671. UNUSED(type);
  672. CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
  673. if (pctx->token.type == isc_tokentype_number)
  674. CHECK(parse_port(pctx, ret));
  675. else {
  676. CHECK(cfg_gettoken(pctx, 0));
  677. if (pctx->token.type != isc_tokentype_string ||
  678. strcasecmp(TOKEN_STRING(pctx), "range") != 0) {
  679. cfg_parser_error(pctx, CFG_LOG_NEAR,
  680. "expected integer or 'range'");
  681. return (ISC_R_UNEXPECTEDTOKEN);
  682. }
  683. CHECK(cfg_create_tuple(pctx, &cfg_type_porttuple, &obj));
  684. CHECK(parse_port(pctx, &obj->value.tuple[0]));
  685. CHECK(parse_port(pctx, &obj->value.tuple[1]));
  686. if (obj->value.tuple[0]->value.uint32 >
  687. obj->value.tuple[1]->value.uint32) {
  688. cfg_parser_error(pctx, CFG_LOG_NOPREP,
  689. "low port '%u' must not be larger "
  690. "than high port",
  691. obj->value.tuple[0]->value.uint32);
  692. result = ISC_R_RANGE;
  693. goto cleanup;
  694. }
  695. *ret = obj;
  696. obj = NULL;
  697. }
  698. cleanup:
  699. if (obj != NULL)
  700. cfg_obj_destroy(pctx, &obj);
  701. return (result);
  702. }
  703. static cfg_type_t cfg_type_portrange = {
  704. "portrange", parse_portrange, NULL, cfg_doc_terminal,
  705. NULL, NULL
  706. };
  707. static cfg_type_t cfg_type_bracketed_portlist = {
  708. "bracketed_sockaddrlist", cfg_parse_bracketed_list,
  709. cfg_print_bracketed_list, cfg_doc_bracketed_list,
  710. &cfg_rep_list, &cfg_type_portrange
  711. };
  712. /*%
  713. * Clauses that can be found within the top level of the named.conf
  714. * file only.
  715. */
  716. static cfg_clausedef_t
  717. namedconf_clauses[] = {
  718. { "options", &cfg_type_options, 0 },
  719. { "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
  720. { "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
  721. { "masters", &cfg_type_masters, CFG_CLAUSEFLAG_MULTI },
  722. { "logging", &cfg_type_logging, 0 },
  723. { "view", &cfg_type_view, CFG_CLAUSEFLAG_MULTI },
  724. { "lwres", &cfg_type_lwres, CFG_CLAUSEFLAG_MULTI },
  725. { "statistics-channels", &cfg_type_statschannels,
  726. CFG_CLAUSEFLAG_MULTI },
  727. { NULL, NULL, 0 }
  728. };
  729. /*%
  730. * Clauses that can occur at the top level or in the view
  731. * statement, but not in the options block.
  732. */
  733. static cfg_clausedef_t
  734. namedconf_or_view_clauses[] = {
  735. { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
  736. { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
  737. /* only 1 DLZ per view allowed */
  738. { "dlz", &cfg_type_dynamically_loadable_zones, 0 },
  739. { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI },
  740. { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
  741. { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
  742. { NULL, NULL, 0 }
  743. };
  744. /*%
  745. * Clauses that can occur in the bind.keys file.
  746. */
  747. static cfg_clausedef_t
  748. bindkeys_clauses[] = {
  749. { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI },
  750. { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI },
  751. { NULL, NULL, 0 }
  752. };
  753. /*%
  754. * Clauses that can be found within the 'options' statement.
  755. */
  756. static cfg_clausedef_t
  757. options_clauses[] = {
  758. { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
  759. { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
  760. { "bindkeys-file", &cfg_type_qstring, 0 },
  761. { "blackhole", &cfg_type_bracketed_aml, 0 },
  762. { "coresize", &cfg_type_size, 0 },
  763. { "datasize", &cfg_type_size, 0 },
  764. { "session-keyfile", &cfg_type_qstringornone, 0 },
  765. { "session-keyname", &cfg_type_astring, 0 },
  766. { "session-keyalg", &cfg_type_astring, 0 },
  767. { "deallocate-on-exit", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
  768. { "directory", &cfg_type_qstring, CFG_CLAUSEFLAG_CALLBACK },
  769. { "dump-file", &cfg_type_qstring, 0 },
  770. { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
  771. { "files", &cfg_type_size, 0 },
  772. { "flush-zones-on-shutdown", &cfg_type_boolean, 0 },
  773. { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
  774. { "heartbeat-interval", &cfg_type_uint32, 0 },
  775. { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP },
  776. { "host-statistics-max", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
  777. { "hostname", &cfg_type_qstringornone, 0 },
  778. { "interface-interval", &cfg_type_uint32, 0 },
  779. { "listen-on", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
  780. { "listen-on-v6", &cfg_type_listenon, CFG_CLAUSEFLAG_MULTI },
  781. { "managed-keys-directory", &cfg_type_qstring, 0 },
  782. { "match-mapped-addresses", &cfg_type_boolean, 0 },
  783. { "memstatistics-file", &cfg_type_qstring, 0 },
  784. { "memstatistics", &cfg_type_boolean, 0 },
  785. { "multiple-cnames", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
  786. { "named-xfer", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
  787. { "pid-file", &cfg_type_qstringornone, 0 },
  788. { "port", &cfg_type_uint32, 0 },
  789. { "querylog", &cfg_type_boolean, 0 },
  790. { "recursing-file", &cfg_type_qstring, 0 },
  791. { "random-device", &cfg_type_qstring, 0 },
  792. { "recursive-clients", &cfg_type_uint32, 0 },
  793. { "reserved-sockets", &cfg_type_uint32, 0 },
  794. { "secroots-file", &cfg_type_qstring, 0 },
  795. { "serial-queries", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
  796. { "serial-query-rate", &cfg_type_uint32, 0 },
  797. { "server-id", &cfg_type_serverid, 0 },
  798. { "stacksize", &cfg_type_size, 0 },
  799. { "statistics-file", &cfg_type_qstring, 0 },
  800. { "statistics-interval", &cfg_type_uint32, CFG_CLAUSEFLAG_NYI },
  801. { "tcp-clients", &cfg_type_uint32, 0 },
  802. { "tcp-listen-queue", &cfg_type_uint32, 0 },
  803. { "tkey-dhkey", &cfg_type_tkey_dhkey, 0 },
  804. { "tkey-gssapi-credential", &cfg_type_qstring, 0 },
  805. { "tkey-gssapi-keytab", &cfg_type_qstring, 0 },
  806. { "tkey-domain", &cfg_type_qstring, 0 },
  807. { "transfers-per-ns", &cfg_type_uint32, 0 },
  808. { "transfers-in", &cfg_type_uint32, 0 },
  809. { "transfers-out", &cfg_type_uint32, 0 },
  810. { "treat-cr-as-space", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
  811. { "use-id-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
  812. { "use-ixfr", &cfg_type_boolean, 0 },
  813. { "use-v4-udp-ports", &cfg_type_bracketed_portlist, 0 },
  814. { "use-v6-udp-ports", &cfg_type_bracketed_portlist, 0 },
  815. { "version", &cfg_type_qstringornone, 0 },
  816. { NULL, NULL, 0 }
  817. };
  818. static cfg_type_t cfg_type_namelist = {
  819. "namelist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
  820. cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_qstring };
  821. static keyword_type_t exclude_kw = { "exclude", &cfg_type_namelist };
  822. static cfg_type_t cfg_type_optional_exclude = {
  823. "optional_exclude", parse_optional_keyvalue, print_keyvalue,
  824. doc_optional_keyvalue, &cfg_rep_list, &exclude_kw };
  825. static keyword_type_t exceptionnames_kw = { "except-from", &cfg_type_namelist };
  826. static cfg_type_t cfg_type_optional_exceptionnames = {
  827. "optional_allow", parse_optional_keyvalue, print_keyvalue,
  828. doc_optional_keyvalue, &cfg_rep_list, &exceptionnames_kw };
  829. static cfg_tuplefielddef_t denyaddresses_fields[] = {
  830. { "acl", &cfg_type_bracketed_aml, 0 },
  831. { "except-from", &cfg_type_optional_exceptionnames, 0 },
  832. { NULL, NULL, 0 }
  833. };
  834. static cfg_type_t cfg_type_denyaddresses = {
  835. "denyaddresses", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  836. &cfg_rep_tuple, denyaddresses_fields
  837. };
  838. static cfg_tuplefielddef_t denyaliases_fields[] = {
  839. { "name", &cfg_type_namelist, 0 },
  840. { "except-from", &cfg_type_optional_exceptionnames, 0 },
  841. { NULL, NULL, 0 }
  842. };
  843. static cfg_type_t cfg_type_denyaliases = {
  844. "denyaliases", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  845. &cfg_rep_tuple, denyaliases_fields
  846. };
  847. static cfg_type_t cfg_type_algorithmlist = {
  848. "algorithmlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
  849. cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
  850. static cfg_tuplefielddef_t disablealgorithm_fields[] = {
  851. { "name", &cfg_type_astring, 0 },
  852. { "algorithms", &cfg_type_algorithmlist, 0 },
  853. { NULL, NULL, 0 }
  854. };
  855. static cfg_type_t cfg_type_disablealgorithm = {
  856. "disablealgorithm", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  857. &cfg_rep_tuple, disablealgorithm_fields
  858. };
  859. static cfg_tuplefielddef_t mustbesecure_fields[] = {
  860. { "name", &cfg_type_astring, 0 },
  861. { "value", &cfg_type_boolean, 0 },
  862. { NULL, NULL, 0 }
  863. };
  864. static cfg_type_t cfg_type_mustbesecure = {
  865. "mustbesecure", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  866. &cfg_rep_tuple, mustbesecure_fields
  867. };
  868. static const char *masterformat_enums[] = { "text", "raw", NULL };
  869. static cfg_type_t cfg_type_masterformat = {
  870. "masterformat", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
  871. &cfg_rep_string, &masterformat_enums
  872. };
  873. /*
  874. * response-policy {
  875. * zone <string> [ policy (given|disabled|passthru|
  876. * nxdomain|nodata|cname <domain> ) ];
  877. * };
  878. *
  879. * this is a chimera of doc_optional_keyvalue() and cfg_doc_enum()
  880. */
  881. static void
  882. doc_rpz_policies(cfg_printer_t *pctx, const cfg_type_t *type) {
  883. const keyword_type_t *kw;
  884. const char * const *p;
  885. kw = type->of;
  886. cfg_print_chars(pctx, "[ ", 2);
  887. cfg_print_cstr(pctx, kw->name);
  888. cfg_print_chars(pctx, " ", 1);
  889. cfg_print_chars(pctx, "( ", 2);
  890. for (p = kw->type->of; *p != NULL; p++) {
  891. cfg_print_cstr(pctx, *p);
  892. if (p[1] != NULL)
  893. cfg_print_chars(pctx, " | ", 3);
  894. }
  895. }
  896. /*
  897. * print_qstring() from parser.c
  898. */
  899. static void
  900. print_rpz_cname(cfg_printer_t *pctx, const cfg_obj_t *obj)
  901. {
  902. cfg_print_chars(pctx, "\"", 1);
  903. cfg_print_ustring(pctx, obj);
  904. cfg_print_chars(pctx, "\"", 1);
  905. }
  906. static void
  907. doc_rpz_cname(cfg_printer_t *pctx, const cfg_type_t *type) {
  908. cfg_doc_terminal(pctx, type);
  909. cfg_print_chars(pctx, " ) ]", 4);
  910. }
  911. static isc_result_t
  912. parse_rpz(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  913. isc_result_t result;
  914. cfg_obj_t *obj = NULL;
  915. const cfg_tuplefielddef_t *fields = type->of;
  916. CHECK(cfg_create_tuple(pctx, type, &obj));
  917. CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
  918. CHECK(cfg_parse_obj(pctx, fields[1].type, &obj->value.tuple[1]));
  919. /*
  920. * parse cname domain only after "policy cname"
  921. */
  922. if (cfg_obj_isvoid(obj->value.tuple[1]) ||
  923. strcasecmp("cname", cfg_obj_asstring(obj->value.tuple[1]))) {
  924. CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2]));
  925. } else {
  926. CHECK(cfg_parse_obj(pctx, fields[2].type, &obj->value.tuple[2]));
  927. }
  928. *ret = obj;
  929. return (ISC_R_SUCCESS);
  930. cleanup:
  931. CLEANUP_OBJ(obj);
  932. return (result);
  933. }
  934. static const char *rpz_policies[] = {
  935. "given", "disabled", "passthru", "no-op", "nxdomain", "nodata",
  936. "cname", NULL
  937. };
  938. static cfg_type_t cfg_type_rpz_policylist = {
  939. "policies", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
  940. &cfg_rep_string, &rpz_policies
  941. };
  942. static keyword_type_t rpz_policies_kw = {
  943. "policy", &cfg_type_rpz_policylist
  944. };
  945. static cfg_type_t cfg_type_rpz_policy = {
  946. "optional_policy", parse_optional_keyvalue, print_keyvalue,
  947. doc_rpz_policies, &cfg_rep_string, &rpz_policies_kw
  948. };
  949. static cfg_type_t cfg_type_cname = {
  950. "domain", cfg_parse_astring, print_rpz_cname, doc_rpz_cname,
  951. &cfg_rep_string, NULL
  952. };
  953. static cfg_tuplefielddef_t rpzone_fields[] = {
  954. { "name", &cfg_type_astring, 0 },
  955. { "policy", &cfg_type_rpz_policy, 0 },
  956. { "cname", &cfg_type_cname, 0 },
  957. { NULL, NULL, 0 }
  958. };
  959. static cfg_type_t cfg_type_rpzone = {
  960. "rpzone", parse_rpz, cfg_print_tuple, cfg_doc_tuple,
  961. &cfg_rep_tuple, rpzone_fields
  962. };
  963. static cfg_clausedef_t rpz_clauses[] = {
  964. { "zone", &cfg_type_rpzone, CFG_CLAUSEFLAG_MULTI },
  965. { NULL, NULL, 0 }
  966. };
  967. static cfg_clausedef_t *rpz_clausesets[] = {
  968. rpz_clauses,
  969. NULL
  970. };
  971. static cfg_type_t cfg_type_rpz = {
  972. "rpz", cfg_parse_map, cfg_print_map, cfg_doc_map,
  973. &cfg_rep_map, rpz_clausesets
  974. };
  975. /*%
  976. * dnssec-lookaside
  977. */
  978. static void
  979. print_lookaside(cfg_printer_t *pctx, const cfg_obj_t *obj)
  980. {
  981. const cfg_obj_t *domain = obj->value.tuple[0];
  982. if (domain->value.string.length == 4 &&
  983. strncmp(domain->value.string.base, "auto", 4) == 0)
  984. cfg_print_cstr(pctx, "auto");
  985. else
  986. cfg_print_tuple(pctx, obj);
  987. }
  988. static void
  989. doc_lookaside(cfg_printer_t *pctx, const cfg_type_t *type) {
  990. UNUSED(type);
  991. cfg_print_cstr(pctx, "( <string> trust-anchor <string> | auto | no )");
  992. }
  993. static keyword_type_t trustanchor_kw = { "trust-anchor", &cfg_type_astring };
  994. static cfg_type_t cfg_type_optional_trustanchor = {
  995. "optional_trustanchor", parse_optional_keyvalue, print_keyvalue,
  996. doc_keyvalue, &cfg_rep_string, &trustanchor_kw
  997. };
  998. static cfg_tuplefielddef_t lookaside_fields[] = {
  999. { "domain", &cfg_type_astring, 0 },
  1000. { "trust-anchor", &cfg_type_optional_trustanchor, 0 },
  1001. { NULL, NULL, 0 }
  1002. };
  1003. static cfg_type_t cfg_type_lookaside = {
  1004. "lookaside", cfg_parse_tuple, print_lookaside, doc_lookaside,
  1005. &cfg_rep_tuple, lookaside_fields
  1006. };
  1007. /*
  1008. * DNS64.
  1009. */
  1010. static cfg_clausedef_t
  1011. dns64_clauses[] = {
  1012. { "clients", &cfg_type_bracketed_aml, 0 },
  1013. { "mapped", &cfg_type_bracketed_aml, 0 },
  1014. { "exclude", &cfg_type_bracketed_aml, 0 },
  1015. { "suffix", &cfg_type_netaddr6, 0 },
  1016. { "recursive-only", &cfg_type_boolean, 0 },
  1017. { "break-dnssec", &cfg_type_boolean, 0 },
  1018. { NULL, NULL, 0 },
  1019. };
  1020. static cfg_clausedef_t *
  1021. dns64_clausesets[] = {
  1022. dns64_clauses,
  1023. NULL
  1024. };
  1025. static cfg_type_t cfg_type_dns64 = {
  1026. "dns64", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map,
  1027. &cfg_rep_map, dns64_clausesets
  1028. };
  1029. /*%
  1030. * Clauses that can be found within the 'view' statement,
  1031. * with defaults in the 'options' statement.
  1032. */
  1033. static cfg_clausedef_t
  1034. view_clauses[] = {
  1035. { "acache-cleaning-interval", &cfg_type_uint32, 0 },
  1036. { "acache-enable", &cfg_type_boolean, 0 },
  1037. { "additional-from-auth", &cfg_type_boolean, 0 },
  1038. { "additional-from-cache", &cfg_type_boolean, 0 },
  1039. { "allow-new-zones", &cfg_type_boolean, 0 },
  1040. { "allow-query-cache", &cfg_type_bracketed_aml, 0 },
  1041. { "allow-query-cache-on", &cfg_type_bracketed_aml, 0 },
  1042. { "allow-recursion", &cfg_type_bracketed_aml, 0 },
  1043. { "allow-recursion-on", &cfg_type_bracketed_aml, 0 },
  1044. { "allow-v6-synthesis", &cfg_type_bracketed_aml,
  1045. CFG_CLAUSEFLAG_OBSOLETE },
  1046. { "attach-cache", &cfg_type_astring, 0 },
  1047. { "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
  1048. { "cache-file", &cfg_type_qstring, 0 },
  1049. { "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
  1050. { "cleaning-interval", &cfg_type_uint32, 0 },
  1051. { "clients-per-query", &cfg_type_uint32, 0 },
  1052. { "deny-answer-addresses", &cfg_type_denyaddresses, 0 },
  1053. { "deny-answer-aliases", &cfg_type_denyaliases, 0 },
  1054. { "disable-algorithms", &cfg_type_disablealgorithm,
  1055. CFG_CLAUSEFLAG_MULTI },
  1056. { "disable-empty-zone", &cfg_type_astring, CFG_CLAUSEFLAG_MULTI },
  1057. { "dns64", &cfg_type_dns64, CFG_CLAUSEFLAG_MULTI },
  1058. { "dns64-server", &cfg_type_astring, 0 },
  1059. { "dns64-contact", &cfg_type_astring, 0 },
  1060. { "dnssec-accept-expired", &cfg_type_boolean, 0 },
  1061. { "dnssec-enable", &cfg_type_boolean, 0 },
  1062. { "dnssec-lookaside", &cfg_type_lookaside, CFG_CLAUSEFLAG_MULTI },
  1063. { "dnssec-must-be-secure", &cfg_type_mustbesecure,
  1064. CFG_CLAUSEFLAG_MULTI },
  1065. { "dnssec-validation", &cfg_type_boolorauto, 0 },
  1066. { "dual-stack-servers", &cfg_type_nameportiplist, 0 },
  1067. { "edns-udp-size", &cfg_type_uint32, 0 },
  1068. { "empty-contact", &cfg_type_astring, 0 },
  1069. { "empty-server", &cfg_type_astring, 0 },
  1070. { "empty-zones-enable", &cfg_type_boolean, 0 },
  1071. { "fetch-glue", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
  1072. { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 },
  1073. { "lame-ttl", &cfg_type_uint32, 0 },
  1074. { "max-acache-size", &cfg_type_sizenodefault, 0 },
  1075. { "max-cache-size", &cfg_type_sizenodefault, 0 },
  1076. { "max-cache-ttl", &cfg_type_uint32, 0 },
  1077. { "max-clients-per-query", &cfg_type_uint32, 0 },
  1078. { "max-ncache-ttl", &cfg_type_uint32, 0 },
  1079. { "max-udp-size", &cfg_type_uint32, 0 },
  1080. { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP },
  1081. { "minimal-responses", &cfg_type_boolean, 0 },
  1082. { "preferred-glue", &cfg_type_astring, 0 },
  1083. { "provide-ixfr", &cfg_type_boolean, 0 },
  1084. /*
  1085. * Note that the query-source option syntax is different
  1086. * from the other -source options.
  1087. */
  1088. { "query-source", &cfg_type_querysource4, 0 },
  1089. { "query-source-v6", &cfg_type_querysource6, 0 },
  1090. { "queryport-pool-ports", &cfg_type_uint32, CFG_CLAUSEFLAG_OBSOLETE },
  1091. { "queryport-pool-updateinterval", &cfg_type_uint32,
  1092. CFG_CLAUSEFLAG_OBSOLETE },
  1093. { "recursion", &cfg_type_boolean, 0 },
  1094. { "request-ixfr", &cfg_type_boolean, 0 },
  1095. { "request-nsid", &cfg_type_boolean, 0 },
  1096. { "resolver-query-timeout", &cfg_type_uint32, 0 },
  1097. { "rfc2308-type1", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
  1098. { "root-delegation-only", &cfg_type_optional_exclude, 0 },
  1099. { "rrset-order", &cfg_type_rrsetorder, 0 },
  1100. { "sortlist", &cfg_type_bracketed_aml, 0 },
  1101. { "suppress-initial-notify", &cfg_type_boolean, CFG_CLAUSEFLAG_NYI },
  1102. { "topology", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_NOTIMP },
  1103. { "transfer-format", &cfg_type_transferformat, 0 },
  1104. { "use-queryport-pool", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
  1105. { "zero-no-soa-ttl-cache", &cfg_type_boolean, 0 },
  1106. #ifdef ALLOW_FILTER_AAAA_ON_V4
  1107. { "filter-aaaa", &cfg_type_bracketed_aml, 0 },
  1108. { "filter-aaaa-on-v4", &cfg_type_v4_aaaa, 0 },
  1109. #else
  1110. { "filter-aaaa", &cfg_type_bracketed_aml,
  1111. CFG_CLAUSEFLAG_NOTCONFIGURED },
  1112. { "filter-aaaa-on-v4", &cfg_type_v4_aaaa,
  1113. CFG_CLAUSEFLAG_NOTCONFIGURED },
  1114. #endif
  1115. { "response-policy", &cfg_type_rpz, 0 },
  1116. { NULL, NULL, 0 }
  1117. };
  1118. /*%
  1119. * Clauses that can be found within the 'view' statement only.
  1120. */
  1121. static cfg_clausedef_t
  1122. view_only_clauses[] = {
  1123. { "match-clients", &cfg_type_bracketed_aml, 0 },
  1124. { "match-destinations", &cfg_type_bracketed_aml, 0 },
  1125. { "match-recursive-only", &cfg_type_boolean, 0 },
  1126. { NULL, NULL, 0 }
  1127. };
  1128. /*%
  1129. * Sig-validity-interval.
  1130. */
  1131. static isc_result_t
  1132. parse_optional_uint32(cfg_parser_t *pctx, const cfg_type_t *type,
  1133. cfg_obj_t **ret)
  1134. {
  1135. isc_result_t result;
  1136. UNUSED(type);
  1137. CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
  1138. if (pctx->token.type == isc_tokentype_number) {
  1139. CHECK(cfg_parse_obj(pctx, &cfg_type_uint32, ret));
  1140. } else {
  1141. CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
  1142. }
  1143. cleanup:
  1144. return (result);
  1145. }
  1146. static void
  1147. doc_optional_uint32(cfg_printer_t *pctx, const cfg_type_t *type) {
  1148. UNUSED(type);
  1149. cfg_print_cstr(pctx, "[ <integer> ]");
  1150. }
  1151. static cfg_type_t cfg_type_optional_uint32 = {
  1152. "optional_uint32", parse_optional_uint32, NULL, doc_optional_uint32,
  1153. NULL, NULL };
  1154. static cfg_tuplefielddef_t validityinterval_fields[] = {
  1155. { "validity", &cfg_type_uint32, 0 },
  1156. { "re-sign", &cfg_type_optional_uint32, 0 },
  1157. { NULL, NULL, 0 }
  1158. };
  1159. static cfg_type_t cfg_type_validityinterval = {
  1160. "validityinterval", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  1161. &cfg_rep_tuple, validityinterval_fields
  1162. };
  1163. /*%
  1164. * Clauses that can be found in a 'zone' statement,
  1165. * with defaults in the 'view' or 'options' statement.
  1166. */
  1167. static cfg_clausedef_t
  1168. zone_clauses[] = {
  1169. { "allow-notify", &cfg_type_bracketed_aml, 0 },
  1170. { "allow-query", &cfg_type_bracketed_aml, 0 },
  1171. { "allow-query-on", &cfg_type_bracketed_aml, 0 },
  1172. { "allow-transfer", &cfg_type_bracketed_aml, 0 },
  1173. { "allow-update", &cfg_type_bracketed_aml, 0 },
  1174. { "allow-update-forwarding", &cfg_type_bracketed_aml, 0 },
  1175. { "also-notify", &cfg_type_portiplist, 0 },
  1176. { "alt-transfer-source", &cfg_type_sockaddr4wild, 0 },
  1177. { "alt-transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
  1178. { "auto-dnssec", &cfg_type_autodnssec, 0 },
  1179. { "check-dup-records", &cfg_type_checkmode, 0 },
  1180. { "check-integrity", &cfg_type_boolean, 0 },
  1181. { "check-mx", &cfg_type_checkmode, 0 },
  1182. { "check-mx-cname", &cfg_type_checkmode, 0 },
  1183. { "check-sibling", &cfg_type_boolean, 0 },
  1184. { "check-srv-cname", &cfg_type_checkmode, 0 },
  1185. { "check-wildcard", &cfg_type_boolean, 0 },
  1186. { "dialup", &cfg_type_dialuptype, 0 },
  1187. { "dnssec-dnskey-kskonly", &cfg_type_boolean, 0 },
  1188. { "dnssec-secure-to-insecure", &cfg_type_boolean, 0 },
  1189. { "forward", &cfg_type_forwardtype, 0 },
  1190. { "forwarders", &cfg_type_portiplist, 0 },
  1191. { "key-directory", &cfg_type_qstring, 0 },
  1192. { "maintain-ixfr-base", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
  1193. { "masterfile-format", &cfg_type_masterformat, 0 },
  1194. { "max-ixfr-log-size", &cfg_type_size, CFG_CLAUSEFLAG_OBSOLETE },
  1195. { "max-journal-size", &cfg_type_sizenodefault, 0 },
  1196. { "max-refresh-time", &cfg_type_uint32, 0 },
  1197. { "max-retry-time", &cfg_type_uint32, 0 },
  1198. { "max-transfer-idle-in", &cfg_type_uint32, 0 },
  1199. { "max-transfer-idle-out", &cfg_type_uint32, 0 },
  1200. { "max-transfer-time-in", &cfg_type_uint32, 0 },
  1201. { "max-transfer-time-out", &cfg_type_uint32, 0 },
  1202. { "min-refresh-time", &cfg_type_uint32, 0 },
  1203. { "min-retry-time", &cfg_type_uint32, 0 },
  1204. { "multi-master", &cfg_type_boolean, 0 },
  1205. { "notify", &cfg_type_notifytype, 0 },
  1206. { "notify-delay", &cfg_type_uint32, 0 },
  1207. { "notify-source", &cfg_type_sockaddr4wild, 0 },
  1208. { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
  1209. { "notify-to-soa", &cfg_type_boolean, 0 },
  1210. { "nsec3-test-zone", &cfg_type_boolean, CFG_CLAUSEFLAG_TESTONLY },
  1211. { "sig-signing-nodes", &cfg_type_uint32, 0 },
  1212. { "sig-signing-signatures", &cfg_type_uint32, 0 },
  1213. { "sig-signing-type", &cfg_type_uint32, 0 },
  1214. { "sig-validity-interval", &cfg_type_validityinterval, 0 },
  1215. { "transfer-source", &cfg_type_sockaddr4wild, 0 },
  1216. { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
  1217. { "try-tcp-refresh", &cfg_type_boolean, 0 },
  1218. { "update-check-ksk", &cfg_type_boolean, 0 },
  1219. { "use-alt-transfer-source", &cfg_type_boolean, 0 },
  1220. { "zero-no-soa-ttl", &cfg_type_boolean, 0 },
  1221. { "zone-statistics", &cfg_type_boolean, 0 },
  1222. { NULL, NULL, 0 }
  1223. };
  1224. /*%
  1225. * Clauses that can be found in a 'zone' statement
  1226. * only.
  1227. */
  1228. static cfg_clausedef_t
  1229. zone_only_clauses[] = {
  1230. { "type", &cfg_type_zonetype, 0 },
  1231. { "file", &cfg_type_qstring, 0 },
  1232. { "journal", &cfg_type_qstring, 0 },
  1233. { "ixfr-base", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
  1234. { "ixfr-tmp-file", &cfg_type_qstring, CFG_CLAUSEFLAG_OBSOLETE },
  1235. { "masters", &cfg_type_namesockaddrkeylist, 0 },
  1236. { "pubkey", &cfg_type_pubkey,
  1237. CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
  1238. { "update-policy", &cfg_type_updatepolicy, 0 },
  1239. { "database", &cfg_type_astring, 0 },
  1240. { "delegation-only", &cfg_type_boolean, 0 },
  1241. /*
  1242. * Note that the format of the check-names option is different between
  1243. * the zone options and the global/view options. Ugh.
  1244. */
  1245. { "check-names", &cfg_type_checkmode, 0 },
  1246. { "ixfr-from-differences", &cfg_type_boolean, 0 },
  1247. { "server-addresses", &cfg_type_bracketed_sockaddrlist, 0 },
  1248. { "server-names", &cfg_type_namelist, 0 },
  1249. { NULL, NULL, 0 }
  1250. };
  1251. /*% The top-level named.conf syntax. */
  1252. static cfg_clausedef_t *
  1253. namedconf_clausesets[] = {
  1254. namedconf_clauses,
  1255. namedconf_or_view_clauses,
  1256. NULL
  1257. };
  1258. LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_namedconf = {
  1259. "namedconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
  1260. &cfg_rep_map, namedconf_clausesets
  1261. };
  1262. /*% The bind.keys syntax (trusted-keys/managed-keys only). */
  1263. static cfg_clausedef_t *
  1264. bindkeys_clausesets[] = {
  1265. bindkeys_clauses,
  1266. NULL
  1267. };
  1268. LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bindkeys = {
  1269. "bindkeys", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
  1270. &cfg_rep_map, bindkeys_clausesets
  1271. };
  1272. /*% The new-zone-file syntax (for zones added by 'rndc addzone') */
  1273. static cfg_clausedef_t
  1274. newzones_clauses[] = {
  1275. { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI },
  1276. { NULL, NULL, 0 }
  1277. };
  1278. static cfg_clausedef_t *
  1279. newzones_clausesets[] = {
  1280. newzones_clauses,
  1281. NULL
  1282. };
  1283. LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_newzones = {
  1284. "newzones", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
  1285. &cfg_rep_map, newzones_clausesets
  1286. };
  1287. /*% The "options" statement syntax. */
  1288. static cfg_clausedef_t *
  1289. options_clausesets[] = {
  1290. options_clauses,
  1291. view_clauses,
  1292. zone_clauses,
  1293. NULL
  1294. };
  1295. static cfg_type_t cfg_type_options = {
  1296. "options", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, options_clausesets };
  1297. /*% The "view" statement syntax. */
  1298. static cfg_clausedef_t *
  1299. view_clausesets[] = {
  1300. view_only_clauses,
  1301. namedconf_or_view_clauses,
  1302. view_clauses,
  1303. zone_clauses,
  1304. dynamically_loadable_zones_clauses,
  1305. NULL
  1306. };
  1307. static cfg_type_t cfg_type_viewopts = {
  1308. "view", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, view_clausesets };
  1309. /*% The "zone" statement syntax. */
  1310. static cfg_clausedef_t *
  1311. zone_clausesets[] = {
  1312. zone_only_clauses,
  1313. zone_clauses,
  1314. NULL
  1315. };
  1316. static cfg_type_t cfg_type_zoneopts = {
  1317. "zoneopts", cfg_parse_map, cfg_print_map,
  1318. cfg_doc_map, &cfg_rep_map, zone_clausesets };
  1319. /*% The "dynamically loadable zones" statement syntax. */
  1320. static cfg_clausedef_t *
  1321. dynamically_loadable_zones_clausesets[] = {
  1322. dynamically_loadable_zones_clauses,
  1323. NULL
  1324. };
  1325. static cfg_type_t cfg_type_dynamically_loadable_zones_opts = {
  1326. "dynamically_loadable_zones_opts", cfg_parse_map,
  1327. cfg_print_map, cfg_doc_map, &cfg_rep_map,
  1328. dynamically_loadable_zones_clausesets
  1329. };
  1330. /*%
  1331. * Clauses that can be found within the 'key' statement.
  1332. */
  1333. static cfg_clausedef_t
  1334. key_clauses[] = {
  1335. { "algorithm", &cfg_type_astring, 0 },
  1336. { "secret", &cfg_type_astring, 0 },
  1337. { NULL, NULL, 0 }
  1338. };
  1339. static cfg_clausedef_t *
  1340. key_clausesets[] = {
  1341. key_clauses,
  1342. NULL
  1343. };
  1344. static cfg_type_t cfg_type_key = {
  1345. "key", cfg_parse_named_map, cfg_print_map,
  1346. cfg_doc_map, &cfg_rep_map, key_clausesets
  1347. };
  1348. /*%
  1349. * Clauses that can be found in a 'server' statement.
  1350. */
  1351. static cfg_clausedef_t
  1352. server_clauses[] = {
  1353. { "bogus", &cfg_type_boolean, 0 },
  1354. { "provide-ixfr", &cfg_type_boolean, 0 },
  1355. { "request-ixfr", &cfg_type_boolean, 0 },
  1356. { "support-ixfr", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
  1357. { "transfers", &cfg_type_uint32, 0 },
  1358. { "transfer-format", &cfg_type_transferformat, 0 },
  1359. { "keys", &cfg_type_server_key_kludge, 0 },
  1360. { "edns", &cfg_type_boolean, 0 },
  1361. { "edns-udp-size", &cfg_type_uint32, 0 },
  1362. { "max-udp-size", &cfg_type_uint32, 0 },
  1363. { "notify-source", &cfg_type_sockaddr4wild, 0 },
  1364. { "notify-source-v6", &cfg_type_sockaddr6wild, 0 },
  1365. { "query-source", &cfg_type_querysource4, 0 },
  1366. { "query-source-v6", &cfg_type_querysource6, 0 },
  1367. { "transfer-source", &cfg_type_sockaddr4wild, 0 },
  1368. { "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
  1369. { NULL, NULL, 0 }
  1370. };
  1371. static cfg_clausedef_t *
  1372. server_clausesets[] = {
  1373. server_clauses,
  1374. NULL
  1375. };
  1376. static cfg_type_t cfg_type_server = {
  1377. "server", cfg_parse_netprefix_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
  1378. server_clausesets
  1379. };
  1380. /*%
  1381. * Clauses that can be found in a 'channel' clause in the
  1382. * 'logging' statement.
  1383. *
  1384. * These have some additional constraints that need to be
  1385. * checked after parsing:
  1386. * - There must exactly one of file/syslog/null/stderr
  1387. *
  1388. */
  1389. static cfg_clausedef_t
  1390. channel_clauses[] = {
  1391. /* Destinations. We no longer require these to be first. */
  1392. { "file", &cfg_type_logfile, 0 },
  1393. { "syslog", &cfg_type_optional_facility, 0 },
  1394. { "null", &cfg_type_void, 0 },
  1395. { "stderr", &cfg_type_void, 0 },
  1396. /* Options. We now accept these for the null channel, too. */
  1397. { "severity", &cfg_type_logseverity, 0 },
  1398. { "print-time", &cfg_type_boolean, 0 },
  1399. { "print-severity", &cfg_type_boolean, 0 },
  1400. { "print-category", &cfg_type_boolean, 0 },
  1401. { NULL, NULL, 0 }
  1402. };
  1403. static cfg_clausedef_t *
  1404. channel_clausesets[] = {
  1405. channel_clauses,
  1406. NULL
  1407. };
  1408. static cfg_type_t cfg_type_channel = {
  1409. "channel", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
  1410. &cfg_rep_map, channel_clausesets
  1411. };
  1412. /*% A list of log destination, used in the "category" clause. */
  1413. static cfg_type_t cfg_type_destinationlist = {
  1414. "destinationlist", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list,
  1415. &cfg_rep_list, &cfg_type_astring };
  1416. /*%
  1417. * Clauses that can be found in a 'logging' statement.
  1418. */
  1419. static cfg_clausedef_t
  1420. logging_clauses[] = {
  1421. { "channel", &cfg_type_channel, CFG_CLAUSEFLAG_MULTI },
  1422. { "category", &cfg_type_category, CFG_CLAUSEFLAG_MULTI },
  1423. { NULL, NULL, 0 }
  1424. };
  1425. static cfg_clausedef_t *
  1426. logging_clausesets[] = {
  1427. logging_clauses,
  1428. NULL
  1429. };
  1430. static cfg_type_t cfg_type_logging = {
  1431. "logging", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, logging_clausesets };
  1432. /*%
  1433. * For parsing an 'addzone' statement
  1434. */
  1435. static cfg_tuplefielddef_t addzone_fields[] = {
  1436. { "name", &cfg_type_astring, 0 },
  1437. { "class", &cfg_type_optional_class, 0 },
  1438. { "view", &cfg_type_optional_class, 0 },
  1439. { "options", &cfg_type_zoneopts, 0 },
  1440. { NULL, NULL, 0 }
  1441. };
  1442. static cfg_type_t cfg_type_addzone = {
  1443. "addzone", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple, addzone_fields };
  1444. static cfg_clausedef_t
  1445. addzoneconf_clauses[] = {
  1446. { "addzone", &cfg_type_addzone, 0 },
  1447. { NULL, NULL, 0 }
  1448. };
  1449. static cfg_clausedef_t *
  1450. addzoneconf_clausesets[] = {
  1451. addzoneconf_clauses,
  1452. NULL
  1453. };
  1454. LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_addzoneconf = {
  1455. "addzoneconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
  1456. &cfg_rep_map, addzoneconf_clausesets
  1457. };
  1458. static isc_result_t
  1459. parse_unitstring(char *str, isc_resourcevalue_t *valuep) {
  1460. char *endp;
  1461. unsigned int len;
  1462. isc_uint64_t value;
  1463. isc_uint64_t unit;
  1464. value = isc_string_touint64(str, &endp, 10);
  1465. if (*endp == 0) {
  1466. *valuep = value;
  1467. return (ISC_R_SUCCESS);
  1468. }
  1469. len = strlen(str);
  1470. if (len < 2 || endp[1] != '\0')
  1471. return (ISC_R_FAILURE);
  1472. switch (str[len - 1]) {
  1473. case 'k':
  1474. case 'K':
  1475. unit = 1024;
  1476. break;
  1477. case 'm':
  1478. case 'M':
  1479. unit = 1024 * 1024;
  1480. break;
  1481. case 'g':
  1482. case 'G':
  1483. unit = 1024 * 1024 * 1024;
  1484. break;
  1485. default:
  1486. return (ISC_R_FAILURE);
  1487. }
  1488. if (value > ISC_UINT64_MAX / unit)
  1489. return (ISC_R_FAILURE);
  1490. *valuep = value * unit;
  1491. return (ISC_R_SUCCESS);
  1492. }
  1493. static isc_result_t
  1494. parse_sizeval(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1495. isc_result_t result;
  1496. cfg_obj_t *obj = NULL;
  1497. isc_uint64_t val;
  1498. UNUSED(type);
  1499. CHECK(cfg_gettoken(pctx, 0));
  1500. if (pctx->token.type != isc_tokentype_string) {
  1501. result = ISC_R_UNEXPECTEDTOKEN;
  1502. goto cleanup;
  1503. }
  1504. CHECK(parse_unitstring(TOKEN_STRING(pctx), &val));
  1505. CHECK(cfg_create_obj(pctx, &cfg_type_uint64, &obj));
  1506. obj->value.uint64 = val;
  1507. *ret = obj;
  1508. return (ISC_R_SUCCESS);
  1509. cleanup:
  1510. cfg_parser_error(pctx, CFG_LOG_NEAR, "expected integer and optional unit");
  1511. return (result);
  1512. }
  1513. /*%
  1514. * A size value (number + optional unit).
  1515. */
  1516. static cfg_type_t cfg_type_sizeval = {
  1517. "sizeval", parse_sizeval, cfg_print_uint64, cfg_doc_terminal,
  1518. &cfg_rep_uint64, NULL };
  1519. /*%
  1520. * A size, "unlimited", or "default".
  1521. */
  1522. static isc_result_t
  1523. parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1524. return (parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret));
  1525. }
  1526. static const char *size_enums[] = { "unlimited", "default", NULL };
  1527. static cfg_type_t cfg_type_size = {
  1528. "size", parse_size, cfg_print_ustring, cfg_doc_terminal,
  1529. &cfg_rep_string, size_enums
  1530. };
  1531. /*%
  1532. * A size or "unlimited", but not "default".
  1533. */
  1534. static const char *sizenodefault_enums[] = { "unlimited", NULL };
  1535. static cfg_type_t cfg_type_sizenodefault = {
  1536. "size_no_default", parse_size, cfg_print_ustring, cfg_doc_terminal,
  1537. &cfg_rep_string, sizenodefault_enums
  1538. };
  1539. /*%
  1540. * optional_keyvalue
  1541. */
  1542. static isc_result_t
  1543. parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type,
  1544. isc_boolean_t optional, cfg_obj_t **ret)
  1545. {
  1546. isc_result_t result;
  1547. cfg_obj_t *obj = NULL;
  1548. const keyword_type_t *kw = type->of;
  1549. CHECK(cfg_peektoken(pctx, 0));
  1550. if (pctx->token.type == isc_tokentype_string &&
  1551. strcasecmp(TOKEN_STRING(pctx), kw->name) == 0) {
  1552. CHECK(cfg_gettoken(pctx, 0));
  1553. CHECK(kw->type->parse(pctx, kw->type, &obj));
  1554. obj->type = type; /* XXX kludge */
  1555. } else {
  1556. if (optional) {
  1557. CHECK(cfg_parse_void(pctx, NULL, &obj));
  1558. } else {
  1559. cfg_parser_error(pctx, CFG_LOG_NEAR, "expected '%s'",
  1560. kw->name);
  1561. result = ISC_R_UNEXPECTEDTOKEN;
  1562. goto cleanup;
  1563. }
  1564. }
  1565. *ret = obj;
  1566. cleanup:
  1567. return (result);
  1568. }
  1569. static isc_result_t
  1570. parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype,
  1571. const cfg_type_t *othertype, cfg_obj_t **ret)
  1572. {
  1573. isc_result_t result;
  1574. CHECK(cfg_peektoken(pctx, 0));
  1575. if (pctx->token.type == isc_tokentype_string &&
  1576. cfg_is_enum(TOKEN_STRING(pctx), enumtype->of)) {
  1577. CHECK(cfg_parse_enum(pctx, enumtype, ret));
  1578. } else {
  1579. CHECK(cfg_parse_obj(pctx, othertype, ret));
  1580. }
  1581. cleanup:
  1582. return (result);
  1583. }
  1584. static void
  1585. doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *type) {
  1586. cfg_doc_terminal(pctx, type);
  1587. #if 0 /* XXX */
  1588. cfg_print_chars(pctx, "( ", 2);...
  1589. #endif
  1590. }
  1591. static isc_result_t
  1592. parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1593. return (parse_maybe_optional_keyvalue(pctx, type, ISC_FALSE, ret));
  1594. }
  1595. static isc_result_t
  1596. parse_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1597. return (parse_maybe_optional_keyvalue(pctx, type, ISC_TRUE, ret));
  1598. }
  1599. static void
  1600. print_keyvalue(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  1601. const keyword_type_t *kw = obj->type->of;
  1602. cfg_print_cstr(pctx, kw->name);
  1603. cfg_print_chars(pctx, " ", 1);
  1604. kw->type->print(pctx, obj);
  1605. }
  1606. static void
  1607. doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
  1608. const keyword_type_t *kw = type->of;
  1609. cfg_print_cstr(pctx, kw->name);
  1610. cfg_print_chars(pctx, " ", 1);
  1611. cfg_doc_obj(pctx, kw->type);
  1612. }
  1613. static void
  1614. doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type) {
  1615. const keyword_type_t *kw = type->of;
  1616. cfg_print_chars(pctx, "[ ", 2);
  1617. cfg_print_cstr(pctx, kw->name);
  1618. cfg_print_chars(pctx, " ", 1);
  1619. cfg_doc_obj(pctx, kw->type);
  1620. cfg_print_chars(pctx, " ]", 2);
  1621. }
  1622. static const char *dialup_enums[] = {
  1623. "notify", "notify-passive", "refresh", "passive", NULL };
  1624. static isc_result_t
  1625. parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1626. return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
  1627. }
  1628. static cfg_type_t cfg_type_dialuptype = {
  1629. "dialuptype", parse_dialup_type, cfg_print_ustring, doc_enum_or_other,
  1630. &cfg_rep_string, dialup_enums
  1631. };
  1632. static const char *notify_enums[] = { "explicit", "master-only", NULL };
  1633. static isc_result_t
  1634. parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1635. return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
  1636. }
  1637. static cfg_type_t cfg_type_notifytype = {
  1638. "notifytype", parse_notify_type, cfg_print_ustring, doc_enum_or_other,
  1639. &cfg_rep_string, notify_enums,
  1640. };
  1641. static const char *ixfrdiff_enums[] = { "master", "slave", NULL };
  1642. static isc_result_t
  1643. parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1644. return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
  1645. }
  1646. static cfg_type_t cfg_type_ixfrdifftype = {
  1647. "ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring, doc_enum_or_other,
  1648. &cfg_rep_string, ixfrdiff_enums,
  1649. };
  1650. static const char *v4_aaaa_enums[] = { "break-dnssec", NULL };
  1651. static isc_result_t
  1652. parse_v4_aaaa(cfg_parser_t *pctx, const cfg_type_t *type,
  1653. cfg_obj_t **ret) {
  1654. return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret));
  1655. }
  1656. static cfg_type_t cfg_type_v4_aaaa = {
  1657. "v4_aaaa", parse_v4_aaaa, cfg_print_ustring,
  1658. doc_enum_or_other, &cfg_rep_string, v4_aaaa_enums,
  1659. };
  1660. static keyword_type_t key_kw = { "key", &cfg_type_astring };
  1661. LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = {
  1662. "keyref", parse_keyvalue, print_keyvalue, doc_keyvalue,
  1663. &cfg_rep_string, &key_kw
  1664. };
  1665. static cfg_type_t cfg_type_optional_keyref = {
  1666. "optional_keyref", parse_optional_keyvalue, print_keyvalue,
  1667. doc_optional_keyvalue, &cfg_rep_string, &key_kw
  1668. };
  1669. /*%
  1670. * A "controls" statement is represented as a map with the multivalued
  1671. * "inet" and "unix" clauses.
  1672. */
  1673. static keyword_type_t controls_allow_kw = {
  1674. "allow", &cfg_type_bracketed_aml };
  1675. static cfg_type_t cfg_type_controls_allow = {
  1676. "controls_allow", parse_keyvalue,
  1677. print_keyvalue, doc_keyvalue,
  1678. &cfg_rep_list, &controls_allow_kw
  1679. };
  1680. static keyword_type_t controls_keys_kw = {
  1681. "keys", &cfg_type_keylist };
  1682. static cfg_type_t cfg_type_controls_keys = {
  1683. "controls_keys", parse_optional_keyvalue,
  1684. print_keyvalue, doc_optional_keyvalue,
  1685. &cfg_rep_list, &controls_keys_kw
  1686. };
  1687. static cfg_tuplefielddef_t inetcontrol_fields[] = {
  1688. { "address", &cfg_type_controls_sockaddr, 0 },
  1689. { "allow", &cfg_type_controls_allow, 0 },
  1690. { "keys", &cfg_type_controls_keys, 0 },
  1691. { NULL, NULL, 0 }
  1692. };
  1693. static cfg_type_t cfg_type_inetcontrol = {
  1694. "inetcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
  1695. inetcontrol_fields
  1696. };
  1697. static keyword_type_t controls_perm_kw = {
  1698. "perm", &cfg_type_uint32 };
  1699. static cfg_type_t cfg_type_controls_perm = {
  1700. "controls_perm", parse_keyvalue,
  1701. print_keyvalue, doc_keyvalue,
  1702. &cfg_rep_uint32, &controls_perm_kw
  1703. };
  1704. static keyword_type_t controls_owner_kw = {
  1705. "owner", &cfg_type_uint32 };
  1706. static cfg_type_t cfg_type_controls_owner = {
  1707. "controls_owner", parse_keyvalue,
  1708. print_keyvalue, doc_keyvalue,
  1709. &cfg_rep_uint32, &controls_owner_kw
  1710. };
  1711. static keyword_type_t controls_group_kw = {
  1712. "group", &cfg_type_uint32 };
  1713. static cfg_type_t cfg_type_controls_group = {
  1714. "controls_allow", parse_keyvalue,
  1715. print_keyvalue, doc_keyvalue,
  1716. &cfg_rep_uint32, &controls_group_kw
  1717. };
  1718. static cfg_tuplefielddef_t unixcontrol_fields[] = {
  1719. { "path", &cfg_type_qstring, 0 },
  1720. { "perm", &cfg_type_controls_perm, 0 },
  1721. { "owner", &cfg_type_controls_owner, 0 },
  1722. { "group", &cfg_type_controls_group, 0 },
  1723. { "keys", &cfg_type_controls_keys, 0 },
  1724. { NULL, NULL, 0 }
  1725. };
  1726. static cfg_type_t cfg_type_unixcontrol = {
  1727. "unixcontrol", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
  1728. unixcontrol_fields
  1729. };
  1730. static cfg_clausedef_t
  1731. controls_clauses[] = {
  1732. { "inet", &cfg_type_inetcontrol, CFG_CLAUSEFLAG_MULTI },
  1733. { "unix", &cfg_type_unixcontrol, CFG_CLAUSEFLAG_MULTI },
  1734. { NULL, NULL, 0 }
  1735. };
  1736. static cfg_clausedef_t *
  1737. controls_clausesets[] = {
  1738. controls_clauses,
  1739. NULL
  1740. };
  1741. static cfg_type_t cfg_type_controls = {
  1742. "controls", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map, &controls_clausesets
  1743. };
  1744. /*%
  1745. * A "statistics-channels" statement is represented as a map with the
  1746. * multivalued "inet" clauses.
  1747. */
  1748. static void
  1749. doc_optional_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
  1750. const keyword_type_t *kw = type->of;
  1751. cfg_print_chars(pctx, "[ ", 2);
  1752. cfg_print_cstr(pctx, kw->name);
  1753. cfg_print_chars(pctx, " ", 1);
  1754. cfg_doc_obj(pctx, kw->type);
  1755. cfg_print_chars(pctx, " ]", 2);
  1756. }
  1757. static cfg_type_t cfg_type_optional_allow = {
  1758. "optional_allow", parse_optional_keyvalue, print_keyvalue,
  1759. doc_optional_bracketed_list, &cfg_rep_list, &controls_allow_kw
  1760. };
  1761. static cfg_tuplefielddef_t statserver_fields[] = {
  1762. { "address", &cfg_type_controls_sockaddr, 0 }, /* reuse controls def */
  1763. { "allow", &cfg_type_optional_allow, 0 },
  1764. { NULL, NULL, 0 }
  1765. };
  1766. static cfg_type_t cfg_type_statschannel = {
  1767. "statschannel", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  1768. &cfg_rep_tuple, statserver_fields
  1769. };
  1770. static cfg_clausedef_t
  1771. statservers_clauses[] = {
  1772. { "inet", &cfg_type_statschannel, CFG_CLAUSEFLAG_MULTI },
  1773. { NULL, NULL, 0 }
  1774. };
  1775. static cfg_clausedef_t *
  1776. statservers_clausesets[] = {
  1777. statservers_clauses,
  1778. NULL
  1779. };
  1780. static cfg_type_t cfg_type_statschannels = {
  1781. "statistics-channels", cfg_parse_map, cfg_print_map, cfg_doc_map,
  1782. &cfg_rep_map, &statservers_clausesets
  1783. };
  1784. /*%
  1785. * An optional class, as used in view and zone statements.
  1786. */
  1787. static isc_result_t
  1788. parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1789. isc_result_t result;
  1790. UNUSED(type);
  1791. CHECK(cfg_peektoken(pctx, 0));
  1792. if (pctx->token.type == isc_tokentype_string)
  1793. CHECK(cfg_parse_obj(pctx, &cfg_type_ustring, ret));
  1794. else
  1795. CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
  1796. cleanup:
  1797. return (result);
  1798. }
  1799. static cfg_type_t cfg_type_optional_class = {
  1800. "optional_class", parse_optional_class, NULL, cfg_doc_terminal,
  1801. NULL, NULL
  1802. };
  1803. static isc_result_t
  1804. parse_querysource(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1805. isc_result_t result;
  1806. cfg_obj_t *obj = NULL;
  1807. isc_netaddr_t netaddr;
  1808. in_port_t port;
  1809. unsigned int have_address = 0;
  1810. unsigned int have_port = 0;
  1811. const unsigned int *flagp = type->of;
  1812. if ((*flagp & CFG_ADDR_V4OK) != 0)
  1813. isc_netaddr_any(&netaddr);
  1814. else if ((*flagp & CFG_ADDR_V6OK) != 0)
  1815. isc_netaddr_any6(&netaddr);
  1816. else
  1817. INSIST(0);
  1818. port = 0;
  1819. for (;;) {
  1820. CHECK(cfg_peektoken(pctx, 0));
  1821. if (pctx->token.type == isc_tokentype_string) {
  1822. if (strcasecmp(TOKEN_STRING(pctx),
  1823. "address") == 0)
  1824. {
  1825. /* read "address" */
  1826. CHECK(cfg_gettoken(pctx, 0));
  1827. CHECK(cfg_parse_rawaddr(pctx, *flagp,
  1828. &netaddr));
  1829. have_address++;
  1830. } else if (strcasecmp(TOKEN_STRING(pctx), "port") == 0)
  1831. {
  1832. /* read "port" */
  1833. CHECK(cfg_gettoken(pctx, 0));
  1834. CHECK(cfg_parse_rawport(pctx,
  1835. CFG_ADDR_WILDOK,
  1836. &port));
  1837. have_port++;
  1838. } else if (have_port == 0 && have_address == 0) {
  1839. return (cfg_parse_sockaddr(pctx, type, ret));
  1840. } else {
  1841. cfg_parser_error(pctx, CFG_LOG_NEAR,
  1842. "expected 'address' or 'port'");
  1843. return (ISC_R_UNEXPECTEDTOKEN);
  1844. }
  1845. } else
  1846. break;
  1847. }
  1848. if (have_address > 1 || have_port > 1 ||
  1849. have_address + have_port == 0) {
  1850. cfg_parser_error(pctx, 0, "expected one address and/or port");
  1851. return (ISC_R_UNEXPECTEDTOKEN);
  1852. }
  1853. CHECK(cfg_create_obj(pctx, &cfg_type_querysource, &obj));
  1854. isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
  1855. *ret = obj;
  1856. return (ISC_R_SUCCESS);
  1857. cleanup:
  1858. cfg_parser_error(pctx, CFG_LOG_NEAR, "invalid query source");
  1859. CLEANUP_OBJ(obj);
  1860. return (result);
  1861. }
  1862. static void
  1863. print_querysource(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  1864. isc_netaddr_t na;
  1865. isc_netaddr_fromsockaddr(&na, &obj->value.sockaddr);
  1866. cfg_print_cstr(pctx, "address ");
  1867. cfg_print_rawaddr(pctx, &na);
  1868. cfg_print_cstr(pctx, " port ");
  1869. cfg_print_rawuint(pctx, isc_sockaddr_getport(&obj->value.sockaddr));
  1870. }
  1871. static unsigned int sockaddr4wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V4OK;
  1872. static unsigned int sockaddr6wild_flags = CFG_ADDR_WILDOK | CFG_ADDR_V6OK;
  1873. static cfg_type_t cfg_type_querysource4 = {
  1874. "querysource4", parse_querysource, NULL, cfg_doc_terminal,
  1875. NULL, &sockaddr4wild_flags
  1876. };
  1877. static cfg_type_t cfg_type_querysource6 = {
  1878. "querysource6", parse_querysource, NULL, cfg_doc_terminal,
  1879. NULL, &sockaddr6wild_flags
  1880. };
  1881. static cfg_type_t cfg_type_querysource = {
  1882. "querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL
  1883. };
  1884. /*% addrmatchelt */
  1885. static isc_result_t
  1886. parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1887. isc_result_t result;
  1888. UNUSED(type);
  1889. CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
  1890. if (pctx->token.type == isc_tokentype_string ||
  1891. pctx->token.type == isc_tokentype_qstring) {
  1892. if (pctx->token.type == isc_tokentype_string &&
  1893. (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) {
  1894. CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret));
  1895. } else {
  1896. if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK |
  1897. CFG_ADDR_V4PREFIXOK |
  1898. CFG_ADDR_V6OK))
  1899. {
  1900. CHECK(cfg_parse_netprefix(pctx, NULL, ret));
  1901. } else {
  1902. CHECK(cfg_parse_astring(pctx, NULL, ret));
  1903. }
  1904. }
  1905. } else if (pctx->token.type == isc_tokentype_special) {
  1906. if (pctx->token.value.as_char == '{') {
  1907. /* Nested match list. */
  1908. CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_aml, ret));
  1909. } else if (pctx->token.value.as_char == '!') {
  1910. CHECK(cfg_gettoken(pctx, 0)); /* read "!" */
  1911. CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret));
  1912. } else {
  1913. goto bad;
  1914. }
  1915. } else {
  1916. bad:
  1917. cfg_parser_error(pctx, CFG_LOG_NEAR,
  1918. "expected IP match list element");
  1919. return (ISC_R_UNEXPECTEDTOKEN);
  1920. }
  1921. cleanup:
  1922. return (result);
  1923. }
  1924. /*%
  1925. * A negated address match list element (like "! 10.0.0.1").
  1926. * Somewhat sneakily, the caller is expected to parse the
  1927. * "!", but not to print it.
  1928. */
  1929. static cfg_tuplefielddef_t negated_fields[] = {
  1930. { "value", &cfg_type_addrmatchelt, 0 },
  1931. { NULL, NULL, 0 }
  1932. };
  1933. static void
  1934. print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  1935. cfg_print_chars(pctx, "!", 1);
  1936. cfg_print_tuple(pctx, obj);
  1937. }
  1938. static cfg_type_t cfg_type_negated = {
  1939. "negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple,
  1940. &negated_fields
  1941. };
  1942. /*% An address match list element */
  1943. static cfg_type_t cfg_type_addrmatchelt = {
  1944. "address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal,
  1945. NULL, NULL
  1946. };
  1947. /*% A bracketed address match list */
  1948. static cfg_type_t cfg_type_bracketed_aml = {
  1949. "bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list,
  1950. cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt
  1951. };
  1952. /*%
  1953. * The socket address syntax in the "controls" statement is silly.
  1954. * It allows both socket address families, but also allows "*",
  1955. * whis is gratuitously interpreted as the IPv4 wildcard address.
  1956. */
  1957. static unsigned int controls_sockaddr_flags =
  1958. CFG_ADDR_V4OK | CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
  1959. static cfg_type_t cfg_type_controls_sockaddr = {
  1960. "controls_sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr,
  1961. cfg_doc_sockaddr, &cfg_rep_sockaddr, &controls_sockaddr_flags
  1962. };
  1963. /*%
  1964. * Handle the special kludge syntax of the "keys" clause in the "server"
  1965. * statement, which takes a single key with or without braces and semicolon.
  1966. */
  1967. static isc_result_t
  1968. parse_server_key_kludge(cfg_parser_t *pctx, const cfg_type_t *type,
  1969. cfg_obj_t **ret)
  1970. {
  1971. isc_result_t result;
  1972. isc_boolean_t braces = ISC_FALSE;
  1973. UNUSED(type);
  1974. /* Allow opening brace. */
  1975. CHECK(cfg_peektoken(pctx, 0));
  1976. if (pctx->token.type == isc_tokentype_special &&
  1977. pctx->token.value.as_char == '{') {
  1978. CHECK(cfg_gettoken(pctx, 0));
  1979. braces = ISC_TRUE;
  1980. }
  1981. CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
  1982. if (braces) {
  1983. /* Skip semicolon if present. */
  1984. CHECK(cfg_peektoken(pctx, 0));
  1985. if (pctx->token.type == isc_tokentype_special &&
  1986. pctx->token.value.as_char == ';')
  1987. CHECK(cfg_gettoken(pctx, 0));
  1988. CHECK(cfg_parse_special(pctx, '}'));
  1989. }
  1990. cleanup:
  1991. return (result);
  1992. }
  1993. static cfg_type_t cfg_type_server_key_kludge = {
  1994. "server_key", parse_server_key_kludge, NULL, cfg_doc_terminal,
  1995. NULL, NULL
  1996. };
  1997. /*%
  1998. * An optional logging facility.
  1999. */
  2000. static isc_result_t
  2001. parse_optional_facility(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
  2002. {
  2003. isc_result_t result;
  2004. UNUSED(type);
  2005. CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
  2006. if (pctx->token.type == isc_tokentype_string ||
  2007. pctx->token.type == isc_tokentype_qstring) {
  2008. CHECK(cfg_parse_obj(pctx, &cfg_type_astring, ret));
  2009. } else {
  2010. CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret));
  2011. }
  2012. cleanup:
  2013. return (result);
  2014. }
  2015. static cfg_type_t cfg_type_optional_facility = {
  2016. "optional_facility", parse_optional_facility, NULL, cfg_doc_terminal,
  2017. NULL, NULL };
  2018. /*%
  2019. * A log severity. Return as a string, except "debug N",
  2020. * which is returned as a keyword object.
  2021. */
  2022. static keyword_type_t debug_kw = { "debug", &cfg_type_uint32 };
  2023. static cfg_type_t cfg_type_debuglevel = {
  2024. "debuglevel", parse_keyvalue,
  2025. print_keyvalue, doc_keyvalue,
  2026. &cfg_rep_uint32, &debug_kw
  2027. };
  2028. static isc_result_t
  2029. parse_logseverity(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  2030. isc_result_t result;
  2031. UNUSED(type);
  2032. CHECK(cfg_peektoken(pctx, 0));
  2033. if (pctx->token.type == isc_tokentype_string &&
  2034. strcasecmp(TOKEN_STRING(pctx), "debug") == 0) {
  2035. CHECK(cfg_gettoken(pctx, 0)); /* read "debug" */
  2036. CHECK(cfg_peektoken(pctx, ISC_LEXOPT_NUMBER));
  2037. if (pctx->token.type == isc_tokentype_number) {
  2038. CHECK(cfg_parse_uint32(pctx, NULL, ret));
  2039. } else {
  2040. /*
  2041. * The debug level is optional and defaults to 1.
  2042. * This makes little sense, but we support it for
  2043. * compatibility with BIND 8.
  2044. */
  2045. CHECK(cfg_create_obj(pctx, &cfg_type_uint32, ret));
  2046. (*ret)->value.uint32 = 1;
  2047. }
  2048. (*ret)->type = &cfg_type_debuglevel; /* XXX kludge */
  2049. } else {
  2050. CHECK(cfg_parse_obj(pctx, &cfg_type_loglevel, ret));
  2051. }
  2052. cleanup:
  2053. return (result);
  2054. }
  2055. static cfg_type_t cfg_type_logseverity = {
  2056. "log_severity", parse_logseverity, NULL, cfg_doc_terminal,
  2057. NULL, NULL };
  2058. /*%
  2059. * The "file" clause of the "channel" statement.
  2060. * This is yet another special case.
  2061. */
  2062. static const char *logversions_enums[] = { "unlimited", NULL };
  2063. static isc_result_t
  2064. parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  2065. return (parse_enum_or_other(pctx, type, &cfg_type_uint32, ret));
  2066. }
  2067. static cfg_type_t cfg_type_logversions = {
  2068. "logversions", parse_logversions, cfg_print_ustring, cfg_doc_terminal,
  2069. &cfg_rep_string, logversions_enums
  2070. };
  2071. static cfg_tuplefielddef_t logfile_fields[] = {
  2072. { "file", &cfg_type_qstring, 0 },
  2073. { "versions", &cfg_type_logversions, 0 },
  2074. { "size", &cfg_type_size, 0 },
  2075. { NULL, NULL, 0 }
  2076. };
  2077. static isc_result_t
  2078. parse_logfile(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  2079. isc_result_t result;
  2080. cfg_obj_t *obj = NULL;
  2081. const cfg_tuplefielddef_t *fields = type->of;
  2082. CHECK(cfg_create_tuple(pctx, type, &obj));
  2083. /* Parse the mandatory "file" field */
  2084. CHECK(cfg_parse_obj(pctx, fields[0].type, &obj->value.tuple[0]));
  2085. /* Parse "versions" and "size" fields in any order. */
  2086. for (;;) {
  2087. CHECK(cfg_peektoken(pctx, 0));
  2088. if (pctx->token.type == isc_tokentype_string) {
  2089. CHECK(cfg_gettoken(pctx, 0));
  2090. if (strcasecmp(TOKEN_STRING(pctx),
  2091. "versions") == 0 &&
  2092. obj->value.tuple[1] == NULL) {
  2093. CHECK(cfg_parse_obj(pctx, fields[1].type,
  2094. &obj->value.tuple[1]));
  2095. } else if (strcasecmp(TOKEN_STRING(pctx),
  2096. "size") == 0 &&
  2097. obj->value.tuple[2] == NULL) {
  2098. CHECK(cfg_parse_obj(pctx, fields[2].type,
  2099. &obj->value.tuple[2]));
  2100. } else {
  2101. break;
  2102. }
  2103. } else {
  2104. break;
  2105. }
  2106. }
  2107. /* Create void objects for missing optional values. */
  2108. if (obj->value.tuple[1] == NULL)
  2109. CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1]));
  2110. if (obj->value.tuple[2] == NULL)
  2111. CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[2]));
  2112. *ret = obj;
  2113. return (ISC_R_SUCCESS);
  2114. cleanup:
  2115. CLEANUP_OBJ(obj);
  2116. return (result);
  2117. }
  2118. static void
  2119. print_logfile(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  2120. cfg_print_obj(pctx, obj->value.tuple[0]); /* file */
  2121. if (obj->value.tuple[1]->type->print != cfg_print_void) {
  2122. cfg_print_cstr(pctx, " versions ");
  2123. cfg_print_obj(pctx, obj->value.tuple[1]);
  2124. }
  2125. if (obj->value.tuple[2]->type->print != cfg_print_void) {
  2126. cfg_print_cstr(pctx, " size ");
  2127. cfg_print_obj(pctx, obj->value.tuple[2]);
  2128. }
  2129. }
  2130. static void
  2131. doc_logfile(cfg_printer_t *pctx, const cfg_type_t *type) {
  2132. UNUSED(type);
  2133. cfg_print_cstr(pctx, "<quoted_string>");
  2134. cfg_print_chars(pctx, " ", 1);
  2135. cfg_print_cstr(pctx, "[ versions ( \"unlimited\" | <integer> ) ]");
  2136. cfg_print_chars(pctx, " ", 1);
  2137. cfg_print_cstr(pctx, "[ size <size> ]");
  2138. }
  2139. static cfg_type_t cfg_type_logfile = {
  2140. "log_file", parse_logfile, print_logfile, doc_logfile,
  2141. &cfg_rep_tuple, logfile_fields
  2142. };
  2143. /*% An IPv4 address with optional port, "*" accepted as wildcard. */
  2144. static cfg_type_t cfg_type_sockaddr4wild = {
  2145. "sockaddr4wild", cfg_parse_sockaddr, cfg_print_sockaddr,
  2146. cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr4wild_flags
  2147. };
  2148. /*% An IPv6 address with optional port, "*" accepted as wildcard. */
  2149. static cfg_type_t cfg_type_sockaddr6wild = {
  2150. "v6addrportwild", cfg_parse_sockaddr, cfg_print_sockaddr,
  2151. cfg_doc_sockaddr, &cfg_rep_sockaddr, &sockaddr6wild_flags
  2152. };
  2153. /*%
  2154. * lwres
  2155. */
  2156. static cfg_tuplefielddef_t lwres_view_fields[] = {
  2157. { "name", &cfg_type_astring, 0 },
  2158. { "class", &cfg_type_optional_class, 0 },
  2159. { NULL, NULL, 0 }
  2160. };
  2161. static cfg_type_t cfg_type_lwres_view = {
  2162. "lwres_view", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, &cfg_rep_tuple,
  2163. lwres_view_fields
  2164. };
  2165. static cfg_type_t cfg_type_lwres_searchlist = {
  2166. "lwres_searchlist", cfg_parse_bracketed_list, cfg_print_bracketed_list,
  2167. cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_astring };
  2168. static cfg_clausedef_t
  2169. lwres_clauses[] = {
  2170. { "listen-on", &cfg_type_portiplist, 0 },
  2171. { "view", &cfg_type_lwres_view, 0 },
  2172. { "search", &cfg_type_lwres_searchlist, 0 },
  2173. { "ndots", &cfg_type_uint32, 0 },
  2174. { NULL, NULL, 0 }
  2175. };
  2176. static cfg_clausedef_t *
  2177. lwres_clausesets[] = {
  2178. lwres_clauses,
  2179. NULL
  2180. };
  2181. static cfg_type_t cfg_type_lwres = {
  2182. "lwres", cfg_parse_map, cfg_print_map, cfg_doc_map, &cfg_rep_map,
  2183. lwres_clausesets
  2184. };
  2185. /*%
  2186. * rndc
  2187. */
  2188. static cfg_clausedef_t
  2189. rndcconf_options_clauses[] = {
  2190. { "default-key", &cfg_type_astring, 0 },
  2191. { "default-port", &cfg_type_uint32, 0 },
  2192. { "default-server", &cfg_type_astring, 0 },
  2193. { "default-source-address", &cfg_type_netaddr4wild, 0 },
  2194. { "default-source-address-v6", &cfg_type_netaddr6wild, 0 },
  2195. { NULL, NULL, 0 }
  2196. };
  2197. static cfg_clausedef_t *
  2198. rndcconf_options_clausesets[] = {
  2199. rndcconf_options_clauses,
  2200. NULL
  2201. };
  2202. static cfg_type_t cfg_type_rndcconf_options = {
  2203. "rndcconf_options", cfg_parse_map, cfg_print_map, cfg_doc_map,
  2204. &cfg_rep_map, rndcconf_options_clausesets
  2205. };
  2206. static cfg_clausedef_t
  2207. rndcconf_server_clauses[] = {
  2208. { "key", &cfg_type_astring, 0 },
  2209. { "port", &cfg_type_uint32, 0 },
  2210. { "source-address", &cfg_type_netaddr4wild, 0 },
  2211. { "source-address-v6", &cfg_type_netaddr6wild, 0 },
  2212. { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
  2213. { NULL, NULL, 0 }
  2214. };
  2215. static cfg_clausedef_t *
  2216. rndcconf_server_clausesets[] = {
  2217. rndcconf_server_clauses,
  2218. NULL
  2219. };
  2220. static cfg_type_t cfg_type_rndcconf_server = {
  2221. "rndcconf_server", cfg_parse_named_map, cfg_print_map, cfg_doc_map,
  2222. &cfg_rep_map, rndcconf_server_clausesets
  2223. };
  2224. static cfg_clausedef_t
  2225. rndcconf_clauses[] = {
  2226. { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI },
  2227. { "server", &cfg_type_rndcconf_server, CFG_CLAUSEFLAG_MULTI },
  2228. { "options", &cfg_type_rndcconf_options, 0 },
  2229. { NULL, NULL, 0 }
  2230. };
  2231. static cfg_clausedef_t *
  2232. rndcconf_clausesets[] = {
  2233. rndcconf_clauses,
  2234. NULL
  2235. };
  2236. LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndcconf = {
  2237. "rndcconf", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
  2238. &cfg_rep_map, rndcconf_clausesets
  2239. };
  2240. static cfg_clausedef_t
  2241. rndckey_clauses[] = {
  2242. { "key", &cfg_type_key, 0 },
  2243. { NULL, NULL, 0 }
  2244. };
  2245. static cfg_clausedef_t *
  2246. rndckey_clausesets[] = {
  2247. rndckey_clauses,
  2248. NULL
  2249. };
  2250. LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_rndckey = {
  2251. "rndckey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
  2252. &cfg_rep_map, rndckey_clausesets
  2253. };
  2254. /*
  2255. * session.key has exactly the same syntax as rndc.key, but it's defined
  2256. * separately for clarity (and so we can extend it someday, if needed).
  2257. */
  2258. LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_sessionkey = {
  2259. "sessionkey", cfg_parse_mapbody, cfg_print_mapbody, cfg_doc_mapbody,
  2260. &cfg_rep_map, rndckey_clausesets
  2261. };
  2262. static cfg_tuplefielddef_t nameport_fields[] = {
  2263. { "name", &cfg_type_astring, 0 },
  2264. { "port", &cfg_type_optional_port, 0 },
  2265. { NULL, NULL, 0 }
  2266. };
  2267. static cfg_type_t cfg_type_nameport = {
  2268. "nameport", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  2269. &cfg_rep_tuple, nameport_fields
  2270. };
  2271. static void
  2272. doc_sockaddrnameport(cfg_printer_t *pctx, const cfg_type_t *type) {
  2273. UNUSED(type);
  2274. cfg_print_chars(pctx, "( ", 2);
  2275. cfg_print_cstr(pctx, "<quoted_string>");
  2276. cfg_print_chars(pctx, " ", 1);
  2277. cfg_print_cstr(pctx, "[ port <integer> ]");
  2278. cfg_print_chars(pctx, " | ", 3);
  2279. cfg_print_cstr(pctx, "<ipv4_address>");
  2280. cfg_print_chars(pctx, " ", 1);
  2281. cfg_print_cstr(pctx, "[ port <integer> ]");
  2282. cfg_print_chars(pctx, " | ", 3);
  2283. cfg_print_cstr(pctx, "<ipv6_address>");
  2284. cfg_print_chars(pctx, " ", 1);
  2285. cfg_print_cstr(pctx, "[ port <integer> ]");
  2286. cfg_print_chars(pctx, " )", 2);
  2287. }
  2288. static isc_result_t
  2289. parse_sockaddrnameport(cfg_parser_t *pctx, const cfg_type_t *type,
  2290. cfg_obj_t **ret)
  2291. {
  2292. isc_result_t result;
  2293. cfg_obj_t *obj = NULL;
  2294. UNUSED(type);
  2295. CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
  2296. if (pctx->token.type == isc_tokentype_string ||
  2297. pctx->token.type == isc_tokentype_qstring) {
  2298. if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
  2299. CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret));
  2300. else {
  2301. const cfg_tuplefielddef_t *fields =
  2302. cfg_type_nameport.of;
  2303. CHECK(cfg_create_tuple(pctx, &cfg_type_nameport,
  2304. &obj));
  2305. CHECK(cfg_parse_obj(pctx, fields[0].type,
  2306. &obj->value.tuple[0]));
  2307. CHECK(cfg_parse_obj(pctx, fields[1].type,
  2308. &obj->value.tuple[1]));
  2309. *ret = obj;
  2310. obj = NULL;
  2311. }
  2312. } else {
  2313. cfg_parser_error(pctx, CFG_LOG_NEAR,
  2314. "expected IP address or hostname");
  2315. return (ISC_R_UNEXPECTEDTOKEN);
  2316. }
  2317. cleanup:
  2318. CLEANUP_OBJ(obj);
  2319. return (result);
  2320. }
  2321. static cfg_type_t cfg_type_sockaddrnameport = {
  2322. "sockaddrnameport_element", parse_sockaddrnameport, NULL,
  2323. doc_sockaddrnameport, NULL, NULL
  2324. };
  2325. static cfg_type_t cfg_type_bracketed_sockaddrnameportlist = {
  2326. "bracketed_sockaddrnameportlist", cfg_parse_bracketed_list,
  2327. cfg_print_bracketed_list, cfg_doc_bracketed_list,
  2328. &cfg_rep_list, &cfg_type_sockaddrnameport
  2329. };
  2330. /*%
  2331. * A list of socket addresses or name with an optional default port,
  2332. * as used in the dual-stack-servers option. E.g.,
  2333. * "port 1234 { dual-stack-servers.net; 10.0.0.1; 1::2 port 69; }"
  2334. */
  2335. static cfg_tuplefielddef_t nameportiplist_fields[] = {
  2336. { "port", &cfg_type_optional_port, 0 },
  2337. { "addresses", &cfg_type_bracketed_sockaddrnameportlist, 0 },
  2338. { NULL, NULL, 0 }
  2339. };
  2340. static cfg_type_t cfg_type_nameportiplist = {
  2341. "nameportiplist", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
  2342. &cfg_rep_tuple, nameportiplist_fields
  2343. };
  2344. /*%
  2345. * masters element.
  2346. */
  2347. static void
  2348. doc_masterselement(cfg_printer_t *pctx, const cfg_type_t *type) {
  2349. UNUSED(type);
  2350. cfg_print_chars(pctx, "( ", 2);
  2351. cfg_print_cstr(pctx, "<masters>");
  2352. cfg_print_chars(pctx, " | ", 3);
  2353. cfg_print_cstr(pctx, "<ipv4_address>");
  2354. cfg_print_chars(pctx, " ", 1);
  2355. cfg_print_cstr(pctx, "[ port <integer> ]");
  2356. cfg_print_chars(pctx, " | ", 3);
  2357. cfg_print_cstr(pctx, "<ipv6_address>");
  2358. cfg_print_chars(pctx, " ", 1);
  2359. cfg_print_cstr(pctx, "[ port <integer> ]");
  2360. cfg_print_chars(pctx, " )", 2);
  2361. }
  2362. static isc_result_t
  2363. parse_masterselement(cfg_parser_t *pctx, const cfg_type_t *type,
  2364. cfg_obj_t **ret)
  2365. {
  2366. isc_result_t result;
  2367. cfg_obj_t *obj = NULL;
  2368. UNUSED(type);
  2369. CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING));
  2370. if (pctx->token.type == isc_tokentype_string ||
  2371. pctx->token.type == isc_tokentype_qstring) {
  2372. if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V6OK))
  2373. CHECK(cfg_parse_sockaddr(pctx, &cfg_type_sockaddr, ret));
  2374. else
  2375. CHECK(cfg_parse_astring(pctx, &cfg_type_astring, ret));
  2376. } else {
  2377. cfg_parser_error(pctx, CFG_LOG_NEAR,
  2378. "expected IP address or masters name");
  2379. return (ISC_R_UNEXPECTEDTOKEN);
  2380. }
  2381. cleanup:
  2382. CLEANUP_OBJ(obj);
  2383. return (result);
  2384. }
  2385. static cfg_type_t cfg_type_masterselement = {
  2386. "masters_element", parse_masterselement, NULL,
  2387. doc_masterselement, NULL, NULL
  2388. };