mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-04-20 05:02:11 +02:00
MINOR: acme: extend resolver-based DNS pre-check to dns-persist-01
Add challenge_type parameter to acme_rslv_start() to select the correct DNS lookup prefix: _validation-persist.<domain> for dns-persist-01 and _acme-challenge.<domain> for dns-01. Default cond_ready to ACME_RDY_DNS|ACME_RDY_DELAY for dns-persist-01. Extend ACME_CLI_WAIT to cover dns-persist-01 alongside dns-01. In ACME_RSLV_READY, check only TXT record existence for dns-persist-01 since the resolver cannot parse multiple strings within a single TXT entry.
This commit is contained in:
parent
0d3689959d
commit
39476040ec
@ -10,7 +10,7 @@
|
||||
#include <haproxy/acme-t.h>
|
||||
#include <haproxy/resolvers-t.h>
|
||||
|
||||
struct acme_rslv *acme_rslv_start(struct acme_auth *auth, unsigned int *dnstasks, char **errmsg);
|
||||
struct acme_rslv *acme_rslv_start(struct acme_auth *auth, unsigned int *dnstasks, const char *challenge_type, char **errmsg);
|
||||
void acme_rslv_free(struct acme_rslv *rslv);
|
||||
|
||||
#endif
|
||||
|
||||
48
src/acme.c
48
src/acme.c
@ -441,6 +441,11 @@ static int cfg_parse_acme_kws(char **args, int section_type, struct proxy *curpx
|
||||
cur_acme->cond_ready = ACME_RDY_CLI;
|
||||
}
|
||||
|
||||
/* dns-persist-01: wait then check for DNS propagation by default */
|
||||
if ((strcasecmp("dns-persist-01", args[1]) == 0) && (cur_acme->cond_ready == 0)) {
|
||||
cur_acme->cond_ready = ACME_RDY_DNS | ACME_RDY_DELAY;
|
||||
}
|
||||
|
||||
if ((strcasecmp("http-01", args[1]) == 0) && (cur_acme->cond_ready != 0)) {
|
||||
ha_alert("parsing [%s:%d]: keyword '%s' in '%s' section, \"http-01\" is not compatible with the \"challenge-ready\" option\n", file, linenum, args[0], cursection);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
@ -2451,7 +2456,8 @@ re:
|
||||
goto retry;
|
||||
}
|
||||
if ((ctx->next_auth = ctx->next_auth->next) == NULL) {
|
||||
if (strcasecmp(ctx->cfg->challenge, "dns-01") == 0 && ctx->cfg->cond_ready)
|
||||
if ((strcasecmp(ctx->cfg->challenge, "dns-01") == 0 ||
|
||||
strcasecmp(ctx->cfg->challenge, "dns-persist-01") == 0) && ctx->cfg->cond_ready)
|
||||
st = ACME_CLI_WAIT;
|
||||
else
|
||||
st = ACME_CHALLENGE;
|
||||
@ -2572,7 +2578,7 @@ re:
|
||||
|
||||
HA_ATOMIC_INC(&ctx->dnstasks);
|
||||
|
||||
auth->rslv = acme_rslv_start(auth, &ctx->dnstasks, &errmsg);
|
||||
auth->rslv = acme_rslv_start(auth, &ctx->dnstasks, ctx->cfg->challenge, &errmsg);
|
||||
if (!auth->rslv)
|
||||
goto abort;
|
||||
auth->rslv->acme_task = task;
|
||||
@ -2595,22 +2601,32 @@ re:
|
||||
for (auth = ctx->auths; auth != NULL; auth = auth->next) {
|
||||
if (auth->ready == ctx->cfg->cond_ready)
|
||||
continue;
|
||||
if (auth->rslv->result != RSLV_STATUS_VALID) {
|
||||
send_log(NULL, LOG_NOTICE, "acme: %s: dns-01: Couldn't get the TXT record for \"_acme-challenge.%.*s\", expected \"%.*s\" (status=%d)\n",
|
||||
ctx->store->path, (int)auth->dns.len, auth->dns.ptr,
|
||||
(int)auth->token.len, auth->token.ptr,
|
||||
/* for dns-01, verify the TXT record content matches the
|
||||
* expected token. for dns-persist-01, only check that
|
||||
* the record exists since the resolver cannot read
|
||||
* multiple strings within a single TXT entry */
|
||||
if (auth->rslv->result == RSLV_STATUS_VALID) {
|
||||
if (strcasecmp(ctx->cfg->challenge, "dns-01") == 0) {
|
||||
if (isteq(auth->rslv->txt, auth->token)) {
|
||||
auth->ready |= ACME_RDY_DNS;
|
||||
} else {
|
||||
send_log(NULL, LOG_NOTICE,
|
||||
"acme: %s: dns-01: TXT record mismatch for \"_acme-challenge.%.*s\": expected \"%.*s\", got \"%.*s\"\n",
|
||||
ctx->store->path, (int)auth->dns.len, auth->dns.ptr,
|
||||
(int)auth->token.len, auth->token.ptr,
|
||||
(int)auth->rslv->txt.len, auth->rslv->txt.ptr);
|
||||
all_ready = 0;
|
||||
}
|
||||
} else if (strcasecmp(ctx->cfg->challenge, "dns-persist-01") == 0) {
|
||||
auth->ready |= ACME_RDY_DNS;
|
||||
}
|
||||
} else {
|
||||
send_log(NULL, LOG_NOTICE, "acme: %s: %s: Couldn't get the TXT record for \"%s.%.*s\" (status=%d)\n",
|
||||
ctx->store->path, ctx->cfg->challenge,
|
||||
strcasecmp(ctx->cfg->challenge, "dns-persist-01") == 0 ? "_validation-persist" : "_acme-challenge",
|
||||
(int)auth->dns.len, auth->dns.ptr,
|
||||
auth->rslv->result);
|
||||
all_ready = 0;
|
||||
} else {
|
||||
if (isteq(auth->rslv->txt, auth->token)) {
|
||||
auth->ready |= ACME_RDY_DNS;
|
||||
} else {
|
||||
send_log(NULL, LOG_NOTICE, "acme: %s: dns-01: TXT record mismatch for \"_acme-challenge.%.*s\": expected \"%.*s\", got \"%.*s\"\n",
|
||||
ctx->store->path, (int)auth->dns.len, auth->dns.ptr,
|
||||
(int)auth->token.len, auth->token.ptr,
|
||||
(int)auth->rslv->txt.len, auth->rslv->txt.ptr);
|
||||
all_ready = 0;
|
||||
}
|
||||
}
|
||||
acme_rslv_free(auth->rslv);
|
||||
auth->rslv = NULL;
|
||||
|
||||
@ -90,12 +90,13 @@ void acme_rslv_free(struct acme_rslv *rslv)
|
||||
free(rslv);
|
||||
}
|
||||
|
||||
struct acme_rslv *acme_rslv_start(struct acme_auth *auth, unsigned int *dnstasks, char **errmsg)
|
||||
struct acme_rslv *acme_rslv_start(struct acme_auth *auth, unsigned int *dnstasks, const char *challenge_type, char **errmsg)
|
||||
{
|
||||
struct acme_rslv *rslv = NULL;
|
||||
struct resolvers *resolvers;
|
||||
char hostname[DNS_MAX_NAME_SIZE + 1];
|
||||
char dn[DNS_MAX_NAME_SIZE + 1];
|
||||
const char *prefix;
|
||||
int hostname_len;
|
||||
int dn_len;
|
||||
|
||||
@ -106,17 +107,22 @@ struct acme_rslv *acme_rslv_start(struct acme_auth *auth, unsigned int *dnstasks
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* dns-01 TXT record lives at _acme-challenge.<domain> */
|
||||
hostname_len = snprintf(hostname, sizeof(hostname), "_acme-challenge.%.*s",
|
||||
(int)auth->dns.len, auth->dns.ptr);
|
||||
/* dns-persist-01 TXT record lives at _validation-persist.<domain>,
|
||||
* dns-01 TXT record lives at _acme-challenge.<domain> */
|
||||
prefix = (strcasecmp(challenge_type, "dns-persist-01") == 0)
|
||||
? "_validation-persist"
|
||||
: "_acme-challenge";
|
||||
|
||||
hostname_len = snprintf(hostname, sizeof(hostname), "%s.%.*s",
|
||||
prefix, (int)auth->dns.len, auth->dns.ptr);
|
||||
if (hostname_len < 0 || hostname_len >= (int)sizeof(hostname)) {
|
||||
memprintf(errmsg, "hostname \"_acme-challenge.%.*s\" too long!\n", (int)auth->dns.len, auth->dns.ptr);
|
||||
memprintf(errmsg, "hostname \"%s.%.*s\" too long!\n", prefix, (int)auth->dns.len, auth->dns.ptr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dn_len = resolv_str_to_dn_label(hostname, hostname_len, dn, sizeof(dn));
|
||||
if (dn_len <= 0) {
|
||||
memprintf(errmsg, "couldn't convert hostname \"_acme-challenge.%.*s\" into dn label\n", (int)auth->dns.len, auth->dns.ptr);
|
||||
memprintf(errmsg, "couldn't convert hostname \"%s.%.*s\" into dn label\n", prefix, (int)auth->dns.len, auth->dns.ptr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user