[rt-commit] r182 - in /redwax-tool/trunk: ChangeLog redwax-tool.c redwax-tool.h redwax_keychain.c redwax_ldns.c redwax_openssl.c redwax_unbound.c redwax_unbound.h

rt-commit at redwax.eu rt-commit at redwax.eu
Mon Jun 3 16:10:34 CEST 2024


Author: minfrin at redwax.eu
Date: Mon Jun  3 16:10:32 2024
New Revision: 182

Log:
Add --filter-verify-tlsa to perform a DNS lookup
and subsequent verification of certificates against
a TLSA record.

Modified:
    redwax-tool/trunk/ChangeLog
    redwax-tool/trunk/redwax-tool.c
    redwax-tool/trunk/redwax-tool.h
    redwax-tool/trunk/redwax_keychain.c
    redwax-tool/trunk/redwax_ldns.c
    redwax-tool/trunk/redwax_openssl.c
    redwax-tool/trunk/redwax_unbound.c
    redwax-tool/trunk/redwax_unbound.h

Modified: redwax-tool/trunk/ChangeLog
==============================================================================
--- redwax-tool/trunk/ChangeLog	(original)
+++ redwax-tool/trunk/ChangeLog	Mon Jun  3 16:10:32 2024
@@ -1,5 +1,9 @@
 
 Changes with v0.9.5
+
+ *) Add --filter-verify-tlsa to perform a DNS lookup
+    and subsequent verification of certificates against
+    a TLSA record. [Graham Leggett]
 
  *) Add --filter-purpose option to allow search and
     verify to limit certificates by certificate

Modified: redwax-tool/trunk/redwax-tool.c
==============================================================================
--- redwax-tool/trunk/redwax-tool.c	(original)
+++ redwax-tool/trunk/redwax-tool.c	Mon Jun  3 16:10:32 2024
@@ -74,12 +74,18 @@
 
 APR_HOOK_STRUCT(
         APR_HOOK_LINK(initialise);
+        APR_HOOK_LINK(set_dns_server);
+        APR_HOOK_LINK(set_dns_trust_anchor);
         APR_HOOK_LINK(set_verify_param);
         APR_HOOK_LINK(complete_verify_param);
         APR_HOOK_LINK(set_verify_date);
         APR_HOOK_LINK(set_verify_expiry);
         APR_HOOK_LINK(set_purpose);
         APR_HOOK_LINK(complete_purpose);
+        APR_HOOK_LINK(set_tlsa);
+        APR_HOOK_LINK(process_tlsa);
+        APR_HOOK_LINK(set_smimea);
+        APR_HOOK_LINK(process_smimea);
         APR_HOOK_LINK(process_pem_in);
         APR_HOOK_LINK(process_trust_pem_in);
         APR_HOOK_LINK(complete_pkcs11_in);
@@ -120,10 +126,16 @@
         APR_HOOK_LINK(normalise_key);
         APR_HOOK_LINK(normalise_certificate);
         APR_HOOK_LINK(add_dns_metadata);
+        APR_HOOK_LINK(process_dns);
+        APR_HOOK_LINK(filter_poll);
 );
 
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, initialise,
         (redwax_tool_t * r), (r), OK, DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, set_dns_server,
+        (redwax_tool_t * r, const char *arg), (r, arg), OK, DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, set_dns_trust_anchor,
+        (redwax_tool_t * r, const char *arg), (r, arg), OK, DECLINED);
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, set_verify_param,
         (redwax_tool_t * r, const char *arg), (r, arg), OK, DECLINED);
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, complete_verify_param,
@@ -136,6 +148,14 @@
         (redwax_tool_t * r, const char *arg), (r, arg), OK, DECLINED);
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, complete_purpose,
         (redwax_tool_t * r, apr_hash_t *purposes), (r, purposes), OK, DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, set_tlsa,
+        (redwax_tool_t * r, const char *arg), (r, arg), OK, DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, process_tlsa,
+        (redwax_tool_t * r, redwax_dns_t *dns), (r, dns), DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, int, set_smimea,
+        (redwax_tool_t * r, const char *arg), (r, arg), OK, DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, process_smimea,
+        (redwax_tool_t * r, redwax_dns_t *dns), (r, dns), DECLINED);
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, process_pem_in,
         (redwax_tool_t * r, const char *arg, const char *secret), (r, arg, secret), DECLINED);
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, process_trust_pem_in,
@@ -211,6 +231,10 @@
         (redwax_tool_t * r, redwax_certificate_t *cert, int index), (r, cert, index), DECLINED);
 APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, apr_status_t, add_dns_metadata,
         (redwax_tool_t *r, redwax_metadata_t *m, const redwax_certificate_t *cert), (r, m, cert), OK, DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_FIRST(rt, REDWAX, int, process_dns,
+        (redwax_tool_t * r, redwax_dns_t *dns, redwax_rdata_t *rdata), (r, dns, rdata), DECLINED);
+APR_IMPLEMENT_EXTERNAL_HOOK_RUN_ALL(rt, REDWAX, apr_status_t, filter_poll,
+        (redwax_tool_t *r), (r), OK, DECLINED);
 
 #define REDWAX_TOOL_COMPLINE "COMP_LINE"
 #define REDWAX_TOOL_COMMANDLINE "COMMAND_LINE"
@@ -232,56 +256,60 @@
 #define REDWAX_TOOL_FILTER_DATE 267
 #define REDWAX_TOOL_FILTER_EXPIRY 268
 #define REDWAX_TOOL_FILTER_PURPOSE 269
-#define REDWAX_TOOL_CERT_OUT 270
-#define REDWAX_TOOL_NO_CERT_OUT 271
-#define REDWAX_TOOL_CHAIN_OUT 272
-#define REDWAX_TOOL_NO_CHAIN_OUT 273
-#define REDWAX_TOOL_ROOT_OUT 274
-#define REDWAX_TOOL_NO_ROOT_OUT 275
-#define REDWAX_TOOL_TRUST_OUT 276
-#define REDWAX_TOOL_NO_TRUST_OUT 277
-#define REDWAX_TOOL_CRL_OUT 278
-#define REDWAX_TOOL_NO_CRL_OUT 279
-#define REDWAX_TOOL_PARAM_OUT 280
-#define REDWAX_TOOL_NO_PARAM_OUT 281
-#define REDWAX_TOOL_KEY_IN 282
-#define REDWAX_TOOL_NO_KEY_IN 283
-#define REDWAX_TOOL_KEY_OUT 284
-#define REDWAX_TOOL_NO_KEY_OUT 285
-#define REDWAX_TOOL_AUTO_OUT 286
-#define REDWAX_TOOL_NO_AUTO_OUT 287
-#define REDWAX_TOOL_FILTER_VERIFY_PARAM 288
-#define REDWAX_TOOL_SECRET_SUFFIX_IN 289
-#define REDWAX_TOOL_SECRET_SUFFIX_OUT 290
-#define REDWAX_TOOL_SECRET_TOKEN_IN 291
-#define REDWAX_TOOL_SECRET_TOKEN_OUT 292
-#define REDWAX_TOOL_LABEL_OUT 293
-#define REDWAX_TOOL_NSS_OUT 294
-#define REDWAX_TOOL_NSS_SLOT_OUT 295
-#define REDWAX_TOOL_DER_OUT 296
-#define REDWAX_TOOL_PEM_OUT 297
-#define REDWAX_TOOL_PKCS12_OUT 298
-#define REDWAX_TOOL_PKCS11_OUT 299
-#define REDWAX_TOOL_PKCS11_MODULE_OUT 300
-#define REDWAX_TOOL_METADATA_OUT 301
-#define REDWAX_TOOL_METADATA_THRESHOLD 302
-#define REDWAX_TOOL_FORMAT_OUT 303
-#define REDWAX_TOOL_CALENDAR_OUT 304
-#define REDWAX_TOOL_CALENDAR_ALARM 305
-#define REDWAX_TOOL_REMINDER_OUT 306
-#define REDWAX_TOOL_JWKS_OUT 307
-#define REDWAX_TOOL_TEXT_OUT 308
-#define REDWAX_TOOL_NO_TEXT_OUT 309
-#define REDWAX_TOOL_SSH_PRIVATE_OUT 310
-#define REDWAX_TOOL_SSH_PUBLIC_OUT 311
-#define REDWAX_TOOL_SMIMEA_OUT 312
-#define REDWAX_TOOL_SSHFP_OUT 313
-#define REDWAX_TOOL_TLSA_OUT 314
-#define REDWAX_TOOL_USER_IN 315
-#define REDWAX_TOOL_USER_OUT 316
-#define REDWAX_TOOL_GROUP_IN 317
-#define REDWAX_TOOL_GROUP_OUT 318
-#define REDWAX_TOOL_ORDER_OUT 319
+#define REDWAX_TOOL_FILTER_VERIFY_PARAM 270
+#define REDWAX_TOOL_FILTER_VERIFY_TLSA 271
+#define REDWAX_TOOL_FILTER_VERIFY_SMIMEA 272
+#define REDWAX_TOOL_CERT_OUT 274
+#define REDWAX_TOOL_NO_CERT_OUT 275
+#define REDWAX_TOOL_CHAIN_OUT 276
+#define REDWAX_TOOL_NO_CHAIN_OUT 277
+#define REDWAX_TOOL_ROOT_OUT 278
+#define REDWAX_TOOL_NO_ROOT_OUT 279
+#define REDWAX_TOOL_TRUST_OUT 280
+#define REDWAX_TOOL_NO_TRUST_OUT 281
+#define REDWAX_TOOL_CRL_OUT 282
+#define REDWAX_TOOL_NO_CRL_OUT 283
+#define REDWAX_TOOL_PARAM_OUT 284
+#define REDWAX_TOOL_NO_PARAM_OUT 285
+#define REDWAX_TOOL_KEY_IN 286
+#define REDWAX_TOOL_NO_KEY_IN 287
+#define REDWAX_TOOL_KEY_OUT 288
+#define REDWAX_TOOL_NO_KEY_OUT 289
+#define REDWAX_TOOL_AUTO_OUT 290
+#define REDWAX_TOOL_NO_AUTO_OUT 291
+#define REDWAX_TOOL_SECRET_SUFFIX_IN 292
+#define REDWAX_TOOL_SECRET_SUFFIX_OUT 293
+#define REDWAX_TOOL_SECRET_TOKEN_IN 294
+#define REDWAX_TOOL_SECRET_TOKEN_OUT 295
+#define REDWAX_TOOL_LABEL_OUT 296
+#define REDWAX_TOOL_NSS_OUT 297
+#define REDWAX_TOOL_NSS_SLOT_OUT 298
+#define REDWAX_TOOL_DER_OUT 299
+#define REDWAX_TOOL_PEM_OUT 300
+#define REDWAX_TOOL_PKCS12_OUT 301
+#define REDWAX_TOOL_PKCS11_OUT 302
+#define REDWAX_TOOL_PKCS11_MODULE_OUT 303
+#define REDWAX_TOOL_METADATA_OUT 304
+#define REDWAX_TOOL_METADATA_THRESHOLD 305
+#define REDWAX_TOOL_FORMAT_OUT 306
+#define REDWAX_TOOL_CALENDAR_OUT 307
+#define REDWAX_TOOL_CALENDAR_ALARM 308
+#define REDWAX_TOOL_REMINDER_OUT 309
+#define REDWAX_TOOL_JWKS_OUT 310
+#define REDWAX_TOOL_TEXT_OUT 311
+#define REDWAX_TOOL_NO_TEXT_OUT 312
+#define REDWAX_TOOL_SSH_PRIVATE_OUT 313
+#define REDWAX_TOOL_SSH_PUBLIC_OUT 314
+#define REDWAX_TOOL_SMIMEA_OUT 315
+#define REDWAX_TOOL_SSHFP_OUT 316
+#define REDWAX_TOOL_TLSA_OUT 317
+#define REDWAX_TOOL_USER_IN 318
+#define REDWAX_TOOL_USER_OUT 319
+#define REDWAX_TOOL_GROUP_IN 320
+#define REDWAX_TOOL_GROUP_OUT 321
+#define REDWAX_TOOL_ORDER_OUT 322
+#define REDWAX_TOOL_DNS_SERVER 323
+#define REDWAX_TOOL_DNS_TRUST_ANCHOR 324
 
 #define REDWAX_EXIT_OK 0
 #define REDWAX_EXIT_INIT 1
@@ -307,13 +335,15 @@
         "  -q, --quiet\t\t\tBe quiet. Errors are suppressed." },
     { "debug", 'd', 0,
         "  -d, --debug\t\t\tBe loud. Print additional details of our progress." },
+    { "dns-server", REDWAX_TOOL_DNS_SERVER, 1, "  --dns-server=ip\t\tIf specified, supplies the IP address of the\n\t\t\t\tupstream DNS server. May be specified more\n\t\t\t\tthan once. If unspecified, will read from\n\t\t\t\t/etc/resolv.conf." },
+    { "dns-trust-anchor", REDWAX_TOOL_DNS_TRUST_ANCHOR, 1, "  --dns-trust-anchor=file\tSpecify the file containing the DNSSEC trust\n\t\t\t\tanchor. If unspecified, the key may be read\n\t\t\t\tfrom an OS specific default location." },
     { "secret-suffix-in", REDWAX_TOOL_SECRET_SUFFIX_IN, 1, "  --secret-suffix-in=suffix\tIf specified, secrets will be read from a file\n\t\t\t\twith the same name as the source file, and\n\t\t\t\tthe suffix specified. With value 'secret',\n\t\t\t\ta file 'key.pem' will have the secret loaded\n\t\t\t\tfrom 'key.secret' in the same directory." },
     { "secret-suffix-out", REDWAX_TOOL_SECRET_SUFFIX_OUT, 1, "  --secret-suffix-out=suffix\tIf specified, secrets will be read from a file\n\t\t\t\twith the same name as the target file, and\n\t\t\t\tthe suffix specified. With value 'secret',\n\t\t\t\ta file 'key.pem' will have the secret loaded\n\t\t\t\tfrom 'key.secret' in the same directory." },
     { "secret-token-in", REDWAX_TOOL_SECRET_TOKEN_IN, 1, "  --secret-token-in=file\tIf specified, secrets needed to read\n\t\t\t\tcertificates and keys from tokens will be read\n\t\t\t\tfrom a file one secret per line. Each secret\n\t\t\t\tis preceded by the name of the token and a\n\t\t\t\tcolon, as per the NSS pwdfile.txt file." },
     { "secret-token-out", REDWAX_TOOL_SECRET_TOKEN_OUT, 1, "  --secret-token-out=file\tIf specified, secrets needed to write\n\t\t\t\tcertificates and keys to tokens (PKCS11 and\n\t\t\t\tNSS) will be read from a file one secret per\n\t\t\t\tline. Each secret is preceded by the name of\n\t\t\t\tthe token and a colon, as per the NSS\n\t\t\t\tpwdfile.txt file." },
     { "label-out", REDWAX_TOOL_LABEL_OUT, 1, "  --label-out=label\t\tSet the name of the label to be applied to\n\t\t\t\tthe leaf certificates. If unspecified, the\n\t\t\t\tlabel is set to the subject of the certificate." },
     { "pem-in", REDWAX_TOOL_PEM_IN, 1, "  --pem-in=wildcard\t\tRead pem files from here. Use '-' for stdin." },
-    { "trust-pem-in", REDWAX_TOOL_TRUST_PEM_IN, 1, "  --trust-pem-in=wildcard\tRead pem files containing trusted certificates from here. Use '-' for stdin." },
+    { "trust-pem-in", REDWAX_TOOL_TRUST_PEM_IN, 1, "  --trust-pem-in=wildcard\tRead pem files containing trusted certificates\n\t\t\t\tfrom here. Use '-' for stdin." },
     { "pkcs12-in", REDWAX_TOOL_PKCS12_IN, 1, "  --pkcs12-in=file\t\tRead certificates, intermediate certificates,\n\t\t\t\troot certificates, crls, and keys from a PKCS12\n\t\t\t\tfile. Use '-' for stdin. Provide the secret\n\t\t\t\tusing --secret-suffix-in." },
     { "pkcs11-in", REDWAX_TOOL_PKCS11_IN, 1, "  --pkcs11-in=url\t\tRead certificates, intermediate certificates,\n\t\t\t\troot certificates, crls, and keys from a PKCS11\n\t\t\t\ttoken identified by the given url." },
     { "pkcs11-module-in", REDWAX_TOOL_PKCS11_MODULE_IN, 1, "  --pkcs11-module-in=mod\tSpecify the name of the PKCS11 module to be used,\n\t\t\t\toverriding system defaults. If relative, use the\n\t\t\t\tdefault PKCS11 module path, otherwise specify the\n\t\t\t\tabsolute path. Include the extension of the module." },
@@ -325,6 +355,12 @@
     { "filter-current", REDWAX_TOOL_FILTER_CURRENT, 0, "  --filter-current\t\tMatch the top ranking leaf certificate, and\n\t\t\t\tignore all other leaf certificates. The top\n\t\t\t\tcertificate is valid, and has the longest time\n\t\t\t\tto expiry." },
     { "filter-verify-params", REDWAX_TOOL_FILTER_VERIFY_PARAM, 1,
         "  --filter-verify-params=name\tSpecify the name of the set of parameters used\n\t\t\t\tfor verification. If unspecified, set to\n\t\t\t\t'default'." },
+    { "filter-verify-tlsa", REDWAX_TOOL_FILTER_VERIFY_TLSA, 1,
+        "  --filter-verify-tlsa=url\tPerform DANE verification on the server\n\t\t\t\tcertificate. The parameter is an URL, with a\n\t\t\t\thostname, optional scheme defaulting to tcp,\n\t\t\t\tand optional port defaulting to 443 (example:\n\t\t\t\ttcp://example.com:443). If unspecified, no\n\t\t\t\tDANE verification is performed." },
+#if 0
+    { "filter-verify-smimea", REDWAX_TOOL_FILTER_VERIFY_SMIMEA, 1,
+        "  --filter-verify-smimea=addr\tPerform DANE verification on the client\n\t\t\t\tcertificate. The parameter is an email address.\n\t\t\t\tIf unspecified, no DANE verification\n\t\t\t\tis performed." },
+#endif
     { "filter-date", REDWAX_TOOL_FILTER_DATE, 1, "  --filter-date=date\t\tSet the date to be used for certificate\n\t\t\t\tverification. If unset, it will default to the\n\t\t\t\tcurrent time. Date format is generalized time\n\t\t\t\tsyntax as defined in RFC 4517 section 3.3.13." },
     { "filter-expiry", REDWAX_TOOL_FILTER_EXPIRY, 1, "  --filter-expiry=[option]\tVerify certificate expiry. 'check' does expiry\n\t\t\t\tverification. 'ignore' allows expired\n\t\t\t\tcertificates. 'ignore-leaf' allows expired leaf\n\t\t\t\tcertificates. 'ignore-chain' allows expired\n\t\t\t\tchain certificates. Default is 'check'." },
     { "filter-purpose", REDWAX_TOOL_FILTER_PURPOSE, 1, "  --filter-purpose=purpose\tSet the purpose of the certificate to verify.\n\t\t\t\tIf unset, it will default to any purpose." },
@@ -1175,6 +1211,28 @@
     return APR_SUCCESS;
 }
 
+static apr_status_t redwax_set_dns_server(redwax_tool_t *r, const char *arg)
+{
+    apr_status_t status = rt_run_set_dns_server(r, arg);
+
+    if (status) {
+        r->rc = REDWAX_EXIT_FILTER;
+    }
+
+    return status;
+}
+
+static apr_status_t redwax_set_dns_trust_anchor(redwax_tool_t *r, const char *arg)
+{
+    apr_status_t status = rt_run_set_dns_trust_anchor(r, arg);
+
+    if (status) {
+        r->rc = REDWAX_EXIT_FILTER;
+    }
+
+    return status;
+}
+
 apr_status_t redwax_set_user(redwax_tool_t *r, const char *user)
 {
     struct passwd *pw;
@@ -2052,6 +2110,34 @@
     return APR_SUCCESS;
 }
 
+static apr_status_t redwax_filter_poll_cb(void *baton, apr_pollfd_t *descriptor)
+{
+    redwax_tool_t *r = (redwax_tool_t *) baton;
+    redwax_pollfd_t *ctx = (redwax_pollfd_t *) descriptor->client_data;
+
+    /* remove our event */
+    apr_pollcb_remove(r->poll, descriptor);
+
+    return ctx->cb(r, ctx->ctx, descriptor);
+}
+
+static apr_status_t redwax_filter_poll(redwax_tool_t *r)
+{
+    apr_status_t status = APR_SUCCESS;
+
+    while (r->poll_work) {
+
+        status = apr_pollcb_poll(r->poll, -1, redwax_filter_poll_cb, r);
+
+        if (APR_SUCCESS != status) {
+            break;
+        }
+
+    }
+
+    return status;
+}
+
 apr_status_t redwax_complete_filter_passthrough(redwax_tool_t *r,
         apr_hash_t *filters)
 {
@@ -2318,6 +2404,28 @@
     return status;
 }
 
+static apr_status_t redwax_set_tlsa(redwax_tool_t *r, const char *arg)
+{
+    apr_status_t status = rt_run_set_tlsa(r, arg);
+
+    if (status) {
+        r->rc = REDWAX_EXIT_OPTIONS;
+    }
+
+    return status;
+}
+
+static apr_status_t redwax_set_smimea(redwax_tool_t *r, const char *arg)
+{
+    apr_status_t status = rt_run_set_smimea(r, arg);
+
+    if (status) {
+        r->rc = REDWAX_EXIT_OPTIONS;
+    }
+
+    return status;
+}
+
 static apr_status_t redwax_set_purpose(redwax_tool_t *r, const char *arg)
 {
     apr_status_t status = rt_run_set_purpose(r, arg);
@@ -2537,6 +2645,7 @@
 
 void redwax_add_default_hooks()
 {
+    rt_hook_filter_poll(redwax_filter_poll, NULL, NULL, APR_HOOK_LAST);
     rt_hook_complete_filter(redwax_complete_filter_passthrough, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_process_filter(redwax_process_filter_passthrough, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_process_filter(redwax_process_filter_default, NULL, NULL,
@@ -2574,6 +2683,18 @@
             r->debug++;
             break;
         }
+        case REDWAX_TOOL_DNS_SERVER: {
+            if (redwax_set_dns_server(r, optarg)) {
+                return REDWAX_EXIT_AUTH;
+            }
+            break;
+        }
+        case REDWAX_TOOL_DNS_TRUST_ANCHOR: {
+            if (redwax_set_dns_trust_anchor(r, optarg)) {
+                return REDWAX_EXIT_AUTH;
+            }
+            break;
+        }
         }
 
     }
@@ -2699,9 +2820,28 @@
             }
             break;
         }
-        }
-
-    }
+        case REDWAX_TOOL_FILTER_VERIFY_TLSA: {
+            if (redwax_set_tlsa(r, optarg)) {
+                return REDWAX_EXIT_OPTIONS;
+            }
+            break;
+        }
+        case REDWAX_TOOL_FILTER_VERIFY_SMIMEA: {
+            if (redwax_set_smimea(r, optarg)) {
+                return REDWAX_EXIT_OPTIONS;
+            }
+            break;
+        }
+        }
+
+    }
+
+    /* filters poll */
+
+    if (rt_run_filter_poll(r)) {
+        return REDWAX_EXIT_OPTIONS;
+    }
+
 
     /* walk filters */
 
@@ -3116,6 +3256,10 @@
                 redwax_complete_order_out(r, optarg, state.isquoted);
                 break;
             }
+            case REDWAX_TOOL_DNS_TRUST_ANCHOR: {
+                redwax_complete_file(r, optarg, state.isquoted);
+                break;
+            }
             }
 
         }
@@ -3326,6 +3470,10 @@
         }
         case REDWAX_TOOL_ORDER_OUT: {
             redwax_complete_order_out(r, "", state.isquoted);
+            break;
+        }
+        case REDWAX_TOOL_DNS_TRUST_ANCHOR: {
+            redwax_complete_file(r, "", state.isquoted);
             break;
         }
         }
@@ -3433,6 +3581,8 @@
 
     apr_hook_sort_all();
 
+    r.per_module = redwax_create_module_config(r.pool);
+
 #if HAVE_LIBGEN_H
     r.base = basename(apr_pstrdup(r.pool, argv[0]));
 #endif
@@ -3472,10 +3622,16 @@
     r.hostnames = apr_hash_make(r.pool);
     r.ips = apr_hash_make(r.pool);
 
+    r.dns_requests = apr_array_make(r.pool, 10, sizeof(redwax_dns_t));
+
     r.pkcs11_in.pkcs11_modules = apr_array_make(r.pool, 10,
             sizeof(const char*));
     r.pkcs11_out.pkcs11_modules = apr_array_make(r.pool, 10,
             sizeof(const char*));
+
+    if (APR_SUCCESS != (status = apr_pollcb_create(&r.poll, 1, r.pool, APR_POLLSET_DEFAULT))) {
+        exit(REDWAX_EXIT_INIT);
+    }
 
     if (apr_gethostname(str, sizeof(str) - 1, r.pool) != APR_SUCCESS) {
         apr_file_printf(r.err, "%s: could not read the servername.\n", argv[0]);

Modified: redwax-tool/trunk/redwax-tool.h
==============================================================================
--- redwax-tool/trunk/redwax-tool.h	(original)
+++ redwax-tool/trunk/redwax-tool.h	Mon Jun  3 16:10:32 2024
@@ -26,6 +26,7 @@
 #include <apr_file_io.h>
 #include <apr_hash.h>
 #include <apr_hooks.h>
+#include <apr_poll.h>
 #include <apr_pools.h>
 #include <apr_tables.h>
 
@@ -120,6 +121,7 @@
     apr_array_header_t *crls_out;
     apr_array_header_t *keys_in;
     apr_array_header_t *keys_out;
+    apr_array_header_t *dns_requests;
     apr_hash_t *emails;
     apr_hash_t *hostnames;
     apr_hash_t *ips;
@@ -143,6 +145,8 @@
     const char *group_in;
     const char *group_out;
     const char *calendar_alarm;
+    const char *dane_basename;
+    apr_pollcb_t *poll;
     redwax_filter_t filter;
     redwax_nss_t nss_out;
     redwax_pkcs11_t pkcs11_in;
@@ -151,6 +155,7 @@
     redwax_format_e format;
     redwax_order_e order;
     redwax_expiry_e expiry;
+    int poll_work;
     int current;
     int cert_out;
     int chain_out;
@@ -334,6 +339,53 @@
     apr_size_t size;
 } redwax_offset_t;
 
+typedef struct redwax_dns_t redwax_dns_t;
+
+typedef apr_status_t(* redwax_dns_cb_t) (redwax_tool_t *r, redwax_dns_t *dns);
+
+typedef struct redwax_rdata_tlsa_t {
+    const char *usage_name;
+    const char *selector_name;
+    const char *mtype_name;
+    unsigned char usage;
+    unsigned char selector;
+    unsigned char mtype;
+    unsigned char *data;
+    int len;
+} redwax_rdata_tlsa_t;
+
+typedef struct redwax_rdata_t {
+    unsigned char *data;
+    int len;
+    union {
+        redwax_rdata_tlsa_t tlsa;
+    } rr;
+} redwax_rdata_t;
+
+typedef struct redwax_dns_t {
+    redwax_tool_t *r;
+    const char *basename;
+    const char *qname;
+    int rrtype;
+    int rrclass;
+    apr_array_header_t *rdata;
+    const char *canonname;
+    int havedata;
+    int nxdomain;
+    int secure;
+    int bogus;
+    const char *why_bogus;
+    redwax_dns_cb_t cb;
+    void *ctx;
+} redwax_dns_t;
+
+typedef apr_status_t(* redwax_pollfd_cb_t) (redwax_tool_t *r, void *ctx, apr_pollfd_t *descriptor);
+
+typedef struct redwax_pollfd_t {
+    redwax_pollfd_cb_t cb;
+    void *ctx;
+} redwax_pollfd_t;
+
 typedef enum redwax_token_escape_e {
     REDWAX_TOKEN_NOESCAPE = 0,
     REDWAX_TOKEN_WASESCAPE,
@@ -400,6 +452,14 @@
 #define MAXHOSTNAMELEN 256
 #endif
 
+#ifndef APR_WANT_READ
+#define APR_WANT_READ                  (APR_UTIL_START_STATUS + 115)
+#endif
+
+#ifndef APR_WANT_WRITE
+#define APR_WANT_WRITE                 (APR_UTIL_START_STATUS + 116)
+#endif
+
 /*
  * Comparisons.
  */
@@ -736,6 +796,38 @@
         (redwax_tool_t *r, const char *arg));
 
 /**
+ * Hook to set the tlsa.
+ *
+ * @param r The redwax-tool context.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, set_tlsa,
+        (redwax_tool_t *r, const char *arg));
+
+/**
+ * Hook to set the smimea.
+ *
+ * @param r The redwax-tool context.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, set_smimea,
+        (redwax_tool_t *r, const char *arg));
+
+/**
+ * Hook to set the DNS server address.
+ *
+ * @param r The redwax-tool context.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, set_dns_server,
+        (redwax_tool_t *r, const char *arg));
+
+/**
+ * Hook to set the DNS trust anchor.
+ *
+ * @param r The redwax-tool context.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, set_dns_trust_anchor,
+        (redwax_tool_t *r, const char *arg));
+
+/**
  * Hook to search for intermediate and root certificates.
  *
  * @param r The redwax-tool context.
@@ -797,4 +889,42 @@
 APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, add_dns_metadata,
         (redwax_tool_t *r, redwax_metadata_t *m, const redwax_certificate_t *cert));
 
+/**
+ * Hook to process DNS results.
+ *
+ * @param r The redwax-tool context.
+ * @param dns The dns result.
+ * @param rdata The dns record.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, process_dns,
+        (redwax_tool_t *r, redwax_dns_t *dns, redwax_rdata_t *rdata));
+
+/**
+ * Hook to process TLSA results.
+ *
+ * @param r The redwax-tool context.
+ * @param dns The dns result.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, process_tlsa,
+        (redwax_tool_t *r, redwax_dns_t *dns));
+
+/**
+ * Hook to process SMIMEA results.
+ *
+ * @param r The redwax-tool context.
+ * @param dns The dns result.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, process_smimea,
+        (redwax_tool_t *r, redwax_dns_t *dns));
+
+/**
+ * Hook to run the pre-filter poll.
+ *
+ * This is where DNS lookups and TLS connection attempts happen.
+ *
+ * @param r The redwax-tool context.
+ */
+APR_DECLARE_EXTERNAL_HOOK(rt, REDWAX, apr_status_t, filter_poll,
+        (redwax_tool_t *r));
+
 #endif

Modified: redwax-tool/trunk/redwax_keychain.c
==============================================================================
--- redwax-tool/trunk/redwax_keychain.c	(original)
+++ redwax-tool/trunk/redwax_keychain.c	Mon Jun  3 16:10:32 2024
@@ -578,7 +578,6 @@
 
     keychain_config_t *config;
 
-    r->per_module = redwax_create_module_config(r->pool);
     config = apr_pcalloc(r->pool, sizeof(keychain_config_t));
     redwax_set_module_config(r->per_module, &keychain_module, config);
 

Modified: redwax-tool/trunk/redwax_ldns.c
==============================================================================
--- redwax-tool/trunk/redwax_ldns.c	(original)
+++ redwax-tool/trunk/redwax_ldns.c	Mon Jun  3 16:10:32 2024
@@ -178,10 +178,103 @@
     return OK;
 }
 
+static apr_status_t redwax_ldns_process_dns(redwax_tool_t *r,
+        redwax_dns_t *dns, redwax_rdata_t *rdata)
+{
+
+    switch (dns->rrtype) {
+    case LDNS_RR_TYPE_TLSA: {
+
+        ldns_buffer buffer;
+
+        ldns_buffer_new_frm_data(&buffer, rdata->data, rdata->len);
+
+        if (!ldns_buffer_available(&buffer, 3)) {
+            redwax_print_error(r, "process-dns: TLSA record too short (<3)\n");
+            return APR_EGENERAL;
+        }
+        else {
+
+            rdata->rr.tlsa.usage = ldns_buffer_read_u8(&buffer);
+            rdata->rr.tlsa.selector = ldns_buffer_read_u8(&buffer);
+            rdata->rr.tlsa.mtype = ldns_buffer_read_u8(&buffer);
+
+            rdata->rr.tlsa.len = ldns_buffer_remaining(&buffer);
+            rdata->rr.tlsa.data = apr_palloc(r->pool, rdata->rr.tlsa.len);
+
+            ldns_buffer_read(&buffer, rdata->rr.tlsa.data, rdata->rr.tlsa.len);
+
+            switch (rdata->rr.tlsa.usage) {
+            case LDNS_TLSA_USAGE_CA_CONSTRAINT:
+                rdata->rr.tlsa.usage_name = "CA constraint";
+                break;
+            case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
+                rdata->rr.tlsa.usage_name = "Service certificate constraint";
+                break;
+            case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
+                rdata->rr.tlsa.usage_name = "Trust anchor assertion";
+                break;
+            case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
+                rdata->rr.tlsa.usage_name = "Domain issued certificate";
+                break;
+            case LDNS_TLSA_USAGE_PRIVCERT:
+                rdata->rr.tlsa.usage_name = "Private use";
+                break;
+            default:
+                rdata->rr.tlsa.usage_name = "Unassigned";
+                break;
+            }
+
+            switch (rdata->rr.tlsa.selector) {
+            case LDNS_TLSA_SELECTOR_FULL_CERTIFICATE:
+                rdata->rr.tlsa.selector_name = "CA constraint";
+                break;
+            case LDNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
+                rdata->rr.tlsa.selector_name = "Service certificate constraint";
+                break;
+            case LDNS_TLSA_SELECTOR_PRIVSEL:
+                rdata->rr.tlsa.selector_name = "Private use";
+                break;
+            default:
+                rdata->rr.tlsa.selector_name = "Unassigned";
+                break;
+            }
+
+            switch (rdata->rr.tlsa.mtype) {
+            case LDNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
+                rdata->rr.tlsa.mtype_name = "No hash used";
+                break;
+            case LDNS_TLSA_MATCHING_TYPE_SHA256:
+                rdata->rr.tlsa.mtype_name = "SHA-256";
+                break;
+            case LDNS_TLSA_MATCHING_TYPE_SHA512:
+                rdata->rr.tlsa.mtype_name = "SHA-512";
+                break;
+            case LDNS_TLSA_MATCHING_TYPE_PRIVMATCH:
+                rdata->rr.tlsa.mtype_name = "Private use";
+                break;
+            default:
+                rdata->rr.tlsa.mtype_name = "Unassigned";
+                break;
+            }
+
+        }
+
+        break;
+    }
+    default: {
+        redwax_print_error(r, "process-dns: unexpected record type: %d\n", dns->rrtype);
+        return APR_ENOTIMPL;
+    }
+    }
+    return APR_SUCCESS;
+}
+
 void redwax_add_default_ldns_hooks()
 {
     rt_hook_initialise(redwax_ldns_initialise, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_add_dns_metadata(redwax_ldns_add_tlsa_metadata, NULL, NULL, APR_HOOK_MIDDLE);
+    rt_hook_process_dns(redwax_ldns_process_dns, NULL, NULL, APR_HOOK_MIDDLE);
 }
 
 #else

Modified: redwax-tool/trunk/redwax_openssl.c
==============================================================================
--- redwax-tool/trunk/redwax_openssl.c	(original)
+++ redwax-tool/trunk/redwax_openssl.c	Mon Jun  3 16:10:32 2024
@@ -47,6 +47,7 @@
 #if HAVE_OPENSSL_CT_H
 #include <openssl/ct.h>
 #endif
+#include <openssl/ssl.h>
 
 #define REDWAX_OPENSSL_SEARCH "search"
 #define REDWAX_OPENSSL_VERIFY "verify"
@@ -60,6 +61,12 @@
 
 module openssl_module;
 
+typedef struct {
+    SSL_CTX *dane_ctx;
+    SSL *dane_ssl;
+} openssl_config_t;
+
+// move to config above
 static STACK_OF(X509) *cert_index;
 static STACK_OF(X509) *chain_index;
 static STACK_OF(X509) *trusted_index;
@@ -1069,8 +1076,42 @@
     return APR_SUCCESS;
 }
 
+static apr_status_t cleanup_SSL_CTX(void *dummy)
+{
+    if (dummy) {
+        SSL_CTX_free(dummy);
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t cleanup_SSL(void *dummy)
+{
+    if (dummy) {
+        SSL_free(dummy);
+    }
+
+    return APR_SUCCESS;
+}
+
 static apr_status_t redwax_openssl_initialise(redwax_tool_t *r)
 {
+    openssl_config_t *config;
+
+    config = apr_pcalloc(r->pool, sizeof(openssl_config_t));
+    redwax_set_module_config(r->per_module, &openssl_module, config);
+
+    config->dane_ctx = SSL_CTX_new(TLS_client_method());
+
+    SSL_CTX_dane_enable(config->dane_ctx);
+
+    config->dane_ssl = SSL_new(config->dane_ctx);
+
+    apr_pool_cleanup_register(r->pool, config->dane_ctx, cleanup_SSL_CTX,
+            apr_pool_cleanup_null);
+    apr_pool_cleanup_register(r->pool, config->dane_ssl, cleanup_SSL,
+            apr_pool_cleanup_null);
+
     cert_index = sk_X509_new_null();
     chain_index = sk_X509_new_null();
     trusted_index = sk_X509_new_null();
@@ -1819,6 +1860,95 @@
     }
 
     return 1;
+}
+
+static apr_status_t redwax_openssl_set_tlsa(redwax_tool_t *r, const char *arg)
+{
+    openssl_config_t *config = redwax_get_module_config(r->per_module, &openssl_module);
+
+    if (r->dane_basename) {
+
+        if (SSL_dane_enable(config->dane_ssl, r->dane_basename) <= 0) {
+
+            redwax_openssl_print_errors(r);
+            redwax_print_error(r,
+                    "Warning: Could not enable dane for '%s'\n",
+                    r->dane_basename);
+
+            return APR_EINVAL;
+        }
+
+    }
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t redwax_openssl_process_tlsa(redwax_tool_t *r, redwax_dns_t *dns)
+{
+    openssl_config_t *config = redwax_get_module_config(r->per_module, &openssl_module);
+
+    if (dns->bogus) {
+
+        redwax_print_error(r,
+                "filter-verify-tlsa: DNS TLSA response for '%s' failed "
+                "DNSSEC validation, ignoring: %s.\n", dns->qname, dns->why_bogus);
+
+        return APR_SUCCESS;
+    }
+
+    if (!dns->secure) {
+
+        redwax_print_error(r,
+                "filter-verify-tlsa: DNS TLSA response for '%s' is "
+                "not DNSSEC secured, ignoring.\n", dns->qname);
+
+        return APR_SUCCESS;
+    }
+
+    if (dns->nxdomain) {
+
+        redwax_print_error(r,
+                "filter-verify-tlsa: DNS TLSA record for '%s' does "
+                "not exist, ignoring.\n", dns->qname);
+
+        return APR_SUCCESS;
+    }
+
+    if (dns->rdata) {
+
+        int i;
+
+        for (i = 0; i < dns->rdata->nelts; i++)
+        {
+            const redwax_rdata_t *rdata = &APR_ARRAY_IDX(dns->rdata, i,
+                    const redwax_rdata_t);
+
+            if (SSL_dane_tlsa_add(config->dane_ssl, rdata->rr.tlsa.usage, rdata->rr.tlsa.selector, rdata->rr.tlsa.mtype,
+                    rdata->rr.tlsa.data, rdata->rr.tlsa.len) <= 0) {
+
+                redwax_openssl_print_errors(r);
+                redwax_print_error(r,
+                        "filter-verify-tlsa: DNS TLSA record for '%s' not "
+                        "accepted, ignoring.\n", dns->qname);
+
+            }
+            else {
+
+                redwax_print_error(r,
+                        "filter-verify-tlsa: DNS TLSA record for '%s' found "
+                        "(usage: %s[%d], selector: %s[%d], matching: %s[%d], digest: %d bytes)\n", dns->qname,
+                        rdata->rr.tlsa.usage_name, rdata->rr.tlsa.usage,
+                        rdata->rr.tlsa.selector_name, rdata->rr.tlsa.selector,
+                        rdata->rr.tlsa.mtype_name, rdata->rr.tlsa.mtype,
+                        rdata->rr.tlsa.len);
+
+            }
+
+        }
+
+    }
+
+    return APR_SUCCESS;
 }
 
 static apr_status_t redwax_openssl_process_filter_search(redwax_tool_t *r,
@@ -1983,6 +2113,8 @@
 static apr_status_t redwax_openssl_process_filter_verify(redwax_tool_t *r,
         const char *arg)
 {
+    openssl_config_t *config = redwax_get_module_config(r->per_module, &openssl_module);
+
     X509_STORE_CTX *ctx;
     X509_STORE *store;
     apr_hash_index_t *hi;
@@ -2109,6 +2241,10 @@
                  now_t = mktime(&now_tm);
 
                  X509_STORE_CTX_set_time(ctx, 0, now_t);
+             }
+
+             if (r->dane_basename) {
+                 X509_STORE_CTX_set0_dane(ctx, SSL_get0_dane(config->dane_ssl));
              }
 
              X509_STORE_CTX_set_verify_cb(ctx, &verify_cb);
@@ -6107,6 +6243,8 @@
     rt_hook_process_pem_in(redwax_openssl_process_pem_in, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_process_trust_pem_in(redwax_openssl_process_trust_pem_in, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_process_pkcs12_in(redwax_openssl_process_pkcs12_in, NULL, NULL, APR_HOOK_MIDDLE);
+    rt_hook_set_tlsa(redwax_openssl_set_tlsa, NULL, NULL, APR_HOOK_LAST);
+    rt_hook_process_tlsa(redwax_openssl_process_tlsa, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_complete_filter(redwax_openssl_complete_filter_verify, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_process_filter(redwax_openssl_process_filter_verify, NULL, NULL, APR_HOOK_MIDDLE);
     rt_hook_complete_filter(redwax_openssl_complete_filter_search, NULL, NULL, APR_HOOK_MIDDLE);

Modified: redwax-tool/trunk/redwax_unbound.c
==============================================================================
--- redwax-tool/trunk/redwax_unbound.c	(original)
+++ redwax-tool/trunk/redwax_unbound.c	Mon Jun  3 16:10:32 2024
@@ -25,21 +25,469 @@
 #include "config.h"
 #include "redwax-tool.h"
 
+#include "redwax_unbound.h"
 #include "redwax_util.h"
 
 #if HAVE_UNBOUND_H
 
+#include "apr_portable.h"
+#include "apr_uri.h"
+
+#include <netdb.h>
+
+#include <unbound.h>
+
 module unbound_module;
 
+typedef struct {
+    struct ub_ctx *ctx;
+    apr_pollfd_t socket_read;
+    redwax_pollfd_t read_ctx;
+    apr_pollfd_t socket_write;
+    redwax_pollfd_t write_ctx;
+    apr_status_t status;
+    int socket_read_work;
+    int dns_work;
+    int dns_server_set;
+    int dns_trust_anchor_set;
+} unbound_config_t;
+
+static apr_status_t cleanup_ub(void *dummy)
+{
+    struct ub_ctx *ctx = dummy;
+
+    ub_ctx_delete(ctx);
+
+    return APR_SUCCESS;
+}
+
 static apr_status_t redwax_unbound_initialise(redwax_tool_t *r)
 {
+    unbound_config_t *config;
+
+    config = apr_pcalloc(r->pool, sizeof(unbound_config_t));
+    redwax_set_module_config(r->per_module, &unbound_module, config);
+
+    /* create an unbound context */
+    config->ctx = ub_ctx_create();
+    if(!config->ctx) {
+        redwax_print_error(r,
+                "Could not create unbound context\n");
+        return APR_EINIT;
+    }
+
+    apr_pool_cleanup_register(r->pool, config->ctx, cleanup_ub,
+            apr_pool_cleanup_null);
 
     return OK;
 }
 
+static apr_status_t redwax_unbound_set_dns_server(redwax_tool_t *r, const char *arg)
+{
+    unbound_config_t *config = redwax_get_module_config(r->per_module, &unbound_module);
+
+    int rv;
+
+    if ((rv = ub_ctx_set_fwd(config->ctx, arg)) != 0) {
+        redwax_print_error(r,
+                "Could not assign DNS server '%s': %s\n",
+                arg, ub_strerror(rv));
+        return APR_EINIT;
+    }
+
+    config->dns_server_set++;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t redwax_unbound_set_dns_trust_anchor(redwax_tool_t *r, const char *arg)
+{
+    unbound_config_t *config = redwax_get_module_config(r->per_module, &unbound_module);
+
+    int rv;
+
+    if ((rv = ub_ctx_add_ta_file(config->ctx, arg)) != 0) {
+        redwax_print_error(r,
+                "Could not read DNS trust anchor '%s': %s (%s)\n",
+                arg, ub_strerror(rv), strerror(errno));
+        return APR_EINIT;
+    }
+
+    config->dns_trust_anchor_set++;
+
+    return APR_SUCCESS;
+}
+
+static apr_status_t redwax_unbound_set_tlsa(redwax_tool_t *r, const char *arg)
+{
+    apr_uri_t uri;
+
+    apr_status_t status;
+
+    if (r->dane_basename) {
+        redwax_print_error(r,
+                "URI '%s': filter-verify-tlsa can only be specified once\n", arg);
+        return APR_EINVAL;
+    }
+
+    status = apr_uri_parse(r->pool, arg, &uri);
+    if (APR_SUCCESS != status) {
+        redwax_print_error(r,
+                "Could not parse URI '%s': %pm\n", arg, &status);
+        return status;
+    }
+
+    if (!uri.hostname) {
+        redwax_print_error(r,
+                "URI '%s': hostname missing\n", arg);
+        return APR_EINVAL;
+    }
+    else {
+        r->dane_basename = uri.hostname;
+    }
+
+    if (!strcmp(uri.scheme, "tcp") || !strcmp(uri.scheme, "udp")) {
+
+        if (uri.port) {
+
+            const char *tlsa = apr_psprintf(r->pool, "_%d._%s.%s", uri.port, uri.scheme, uri.hostname);
+
+            redwax_dns_t *dns = apr_array_push(r->dns_requests);
+
+            dns->r = r;
+            dns->basename = uri.hostname;
+            dns->qname = tlsa;
+            dns->rrtype = 52 /* TYPE TLSA */;
+            dns->rrclass = 1 /* CLASS IN (internet) */;
+            dns->cb = rt_run_process_tlsa;
+
+            return APR_SUCCESS;
+        }
+        else {
+            redwax_print_error(r,
+                    "URI '%s': port missing\n", arg);
+            return APR_EINVAL;
+        }
+    }
+
+    if (uri.scheme) {
+
+        int found = 0;
+
+        setservent(1);
+
+        struct servent *ent;
+
+        while ((ent = getservent())) {
+
+            if (!strcmp(uri.scheme, ent->s_name)) {
+
+                const char *tlsa = apr_psprintf(r->pool, "_%d._%s.%s",
+                        uri.port ? uri.port : ntohs(ent->s_port),
+                                ent->s_proto, uri.hostname);
+
+                redwax_dns_t *dns = apr_array_push(r->dns_requests);
+
+                dns->r = r;
+                dns->basename = uri.hostname;
+                dns->qname = tlsa;
+                dns->rrtype = 52 /* TYPE TLSA */;
+                dns->rrclass = 1 /* CLASS IN (internet) */;
+                dns->cb = rt_run_process_tlsa;
+
+                found = 1;
+            }
+
+        }
+
+        endservent();
+
+        if (!found) {
+            redwax_print_error(r,
+                    "URI '%s': protocol '%s' not found\n", arg, uri.scheme);
+            return APR_EINVAL;
+        }
+        else {
+            return APR_SUCCESS;
+        }
+
+    }
+
+    else {
+        redwax_print_error(r,
+                "URI '%s': scheme missing\n", arg);
+        return APR_EINVAL;
+    }
+
+}
+
+static apr_status_t redwax_unbound_set_smimea(redwax_tool_t *r, const char *arg)
+{
+
+    return APR_ENOTIMPL;
+}
+
+static apr_status_t redwax_unbound_filter_read_cb(redwax_tool_t *r, void *baton, apr_pollfd_t *descriptor)
+{
+    unbound_config_t *config = redwax_get_module_config(r->per_module, &unbound_module);
+
+    apr_status_t status = APR_SUCCESS;
+    int rv;
+
+    /* ack readcb work */
+    r->poll_work--;
+
+    /* ack socket read work */
+    config->socket_read_work--;
+
+    rv = ub_process(config->ctx);
+
+    if (rv) {
+        redwax_print_error(r,
+                "Could not process DNS: %s (%s)\n",
+                ub_strerror(rv), strerror(errno));
+        return APR_EGENERAL;
+    }
+
+    if (config->status) {
+        return config->status;
+    }
+
+    if (config->dns_work) {
+
+        status = apr_pollcb_add(r->poll, &config->socket_read);
+
+        if (APR_SUCCESS != status) {
+            redwax_print_error(r,
+                    "Could not add read descriptor to poll: %pm\n", &status);
+            return status;
+        }
+
+        /* req readcb work */
+        r->poll_work++;
+
+        /* req socket read work */
+        config->socket_read_work++;
+    }
+
+    return status;
+}
+
+void redwax_unbound_filter_result_cb(void *ctx, int rv, struct ub_result* result)
+{
+    redwax_dns_t *dns = ctx;
+
+    redwax_tool_t *r = dns->r;
+
+    unbound_config_t *config = redwax_get_module_config(r->per_module, &unbound_module);
+
+    /* ack dns lookup work */
+    config->dns_work--;
+
+    if (rv) {
+        redwax_print_error(r,
+                "Could not resolve: %s\n",
+                ub_strerror(rv));
+        return;
+    }
+
+    dns->canonname = result->canonname;
+    dns->havedata = result->havedata;
+    dns->nxdomain = result->nxdomain;
+    dns->secure = result->secure;
+    dns->bogus = result->bogus;
+    dns->why_bogus = result->why_bogus;
+
+    if (result->data) {
+
+        int i, count;
+
+        for (count = 0; result->data[count]; count++);
+
+        dns->rdata = apr_array_make(r->pool, count, sizeof(redwax_rdata_t));
+
+        for (i = 0; i < count; i++) {
+
+            redwax_rdata_t *rdata = apr_array_push(dns->rdata);
+
+            rdata->data = (unsigned char *)result->data[i];
+            rdata->len = result->len[i];
+
+            rt_run_process_dns(r, dns, rdata);
+
+        }
+
+    }
+
+    config->status = dns->cb(r, dns);
+
+    ub_resolve_free(result);
+}
+
+static apr_status_t redwax_unbound_filter_write_cb(redwax_tool_t *r, void *baton, apr_pollfd_t *descriptor)
+{
+    unbound_config_t *config = redwax_get_module_config(r->per_module, &unbound_module);
+
+    redwax_dns_t *dns = apr_array_pop(r->dns_requests);
+
+    apr_status_t status = APR_SUCCESS;
+    int rv;
+
+    /* ack writecb work */
+    r->poll_work--;
+
+    rv = ub_resolve_async(config->ctx, dns->qname,
+            dns->rrtype,
+            dns->rrclass,
+            (void *)dns, redwax_unbound_filter_result_cb, NULL);
+
+    if (rv) {
+        redwax_print_error(r,
+                "Could not resolve '%s': %s (%s)\n",
+                dns->qname, ub_strerror(rv), strerror(errno));
+        return APR_EGENERAL;
+    }
+
+    /* req dns lookup work */
+    config->dns_work++;
+
+    if (!config->socket_read_work) {
+
+        status = apr_pollcb_add(r->poll, &config->socket_read);
+
+        if (APR_SUCCESS != status) {
+            redwax_print_error(r,
+                    "Could not add read descriptor to poll: %pm\n", &status);
+            return status;
+        }
+
+        /* req readcb work */
+        r->poll_work++;
+
+        /* req socket read work */
+        config->socket_read_work++;
+
+    }
+
+    if (r->dns_requests->nelts) {
+
+        status = apr_pollcb_add(r->poll, &config->socket_write);
+
+        if (APR_SUCCESS != status) {
+            redwax_print_error(r,
+                    "Could not add write descriptor to poll: %pm\n", &status);
+            return status;
+        }
+
+        /* req writecb work */
+        r->poll_work++;
+
+    }
+
+    return status;
+}
+
+static apr_status_t redwax_unbound_filter_poll(redwax_tool_t *r)
+{
+    unbound_config_t *config;
+    apr_socket_t *s = NULL;
+
+    apr_os_sock_t fd;
+    apr_status_t status;
+
+    if (!r->dns_requests->nelts) {
+        return OK;
+    }
+
+    config = redwax_get_module_config(r->per_module, &unbound_module);
+
+    /*
+     * Apply defaults if no explicit values are set.
+     */
+
+    /* read /etc/resolv.conf for DNS proxy settings (from DHCP) */
+    if (!config->dns_server_set) {
+
+        int rv;
+
+        if ((rv = ub_ctx_resolvconf(config->ctx, "/etc/resolv.conf"))) {
+            redwax_print_error(r,
+                    "Could not read /etc/resolv.conf: %s (%s)\n",
+                    ub_strerror(rv), strerror(errno));
+            return APR_EINIT;
+        }
+    }
+
+    /* read public keys for DNSSEC verification */
+    if (!config->dns_trust_anchor_set) {
+
+        int rv;
+
+        if ((rv = ub_ctx_add_ta_file(config->ctx, REDWAX_DEFAULT_ROOT_KEY))) {
+            redwax_print_error(r,
+                    "Could not read " REDWAX_DEFAULT_ROOT_KEY ": %s (%s)\n",
+                    ub_strerror(rv), strerror(errno));
+            return APR_EINIT;
+        }
+    }
+
+    fd = ub_fd(config->ctx);
+
+    if (-1 == fd) {
+        redwax_print_error(r,
+                "Could not obtain unbound fd: %s\n",
+                strerror(errno));
+        return APR_EGENERAL;
+    }
+
+    status = apr_os_sock_put(&s, &fd, r->pool);
+
+    if (APR_SUCCESS != status) {
+        redwax_print_error(r,
+                "Could not convert unbound fd: %pm\n", &status);
+        return status;
+    }
+
+    /* set up the read callback */
+    config->read_ctx.cb = redwax_unbound_filter_read_cb;
+
+    /* set up read descriptor */
+    config->socket_read.desc_type = APR_POLL_SOCKET;
+    config->socket_read.reqevents = APR_POLLIN;
+    config->socket_read.desc.s = s;
+    config->socket_read.client_data = &config->read_ctx;
+
+    /* set up the write callback */
+    config->write_ctx.cb = redwax_unbound_filter_write_cb;
+
+    /* set up write descriptor */
+    config->socket_write.desc_type = APR_POLL_SOCKET;
+    config->socket_write.reqevents = APR_POLLOUT;
+    config->socket_write.desc.s = s;
+    config->socket_write.client_data = &config->write_ctx;
+
+    status = apr_pollcb_add(r->poll, &config->socket_write);
+
+    if (APR_SUCCESS != status) {
+        redwax_print_error(r,
+                "Could not add descriptor to poll: %pm\n", &status);
+        return status;
+    }
+
+    /* req writecb work */
+    r->poll_work++;
+
+    return APR_SUCCESS;
+}
+
 void redwax_add_default_unbound_hooks()
 {
     rt_hook_initialise(redwax_unbound_initialise, NULL, NULL, APR_HOOK_MIDDLE);
+    rt_hook_set_dns_server(redwax_unbound_set_dns_server, NULL, NULL, APR_HOOK_MIDDLE);
+    rt_hook_set_dns_trust_anchor(redwax_unbound_set_dns_trust_anchor, NULL, NULL, APR_HOOK_MIDDLE);
+    rt_hook_set_tlsa(redwax_unbound_set_tlsa, NULL, NULL, APR_HOOK_MIDDLE);
+    rt_hook_set_smimea(redwax_unbound_set_smimea, NULL, NULL, APR_HOOK_MIDDLE);
+    rt_hook_filter_poll(redwax_unbound_filter_poll, NULL, NULL, APR_HOOK_MIDDLE);
 }
 
 #else

Modified: redwax-tool/trunk/redwax_unbound.h
==============================================================================
--- redwax-tool/trunk/redwax_unbound.h	(original)
+++ redwax-tool/trunk/redwax_unbound.h	Mon Jun  3 16:10:32 2024
@@ -25,6 +25,12 @@
 
 #include "config.h"
 
+#if 0
+#define REDWAX_DEFAULT_ROOT_KEY "/var/lib/unbound/root.key"
+#endif
+
+#define REDWAX_DEFAULT_ROOT_KEY "/opt/local/etc/unbound/root.key"
+
 void redwax_add_default_unbound_hooks();
 
 #endif /* REDWAX_UNBOUND_H_ */



More information about the rt-commit mailing list