From 377b3406060dc6224096f572d666263ca388ae99 Mon Sep 17 00:00:00 2001 From: purplerain Date: Sat, 13 Apr 2024 04:04:37 +0000 Subject: [PATCH] sync with OpenBSD -current --- gnu/usr.bin/cvs/configure | 5 +- gnu/usr.bin/cvs/configure.in | 3 +- lib/libcrypto/evp/bio_enc.c | 131 +- lib/libcrypto/evp/evp_local.h | 7 +- lib/libcrypto/evp/pmeth_fn.c | 42 +- lib/libcrypto/evp/pmeth_gn.c | 40 +- lib/libcurses/tinfo/read_entry.c | 10 +- share/man/man4/uchcom.4 | 12 +- share/man/man4/ucom.4 | 6 +- share/man/man4/usb.4 | 6 +- sys/dev/pci/if_bnxt.c | 4 +- sys/dev/pci/if_igc.c | 4 +- sys/dev/pci/if_ixl.c | 6 +- sys/dev/pci/if_mcx.c | 5 +- sys/dev/pci/if_ngbe.c | 4 +- sys/dev/pci/ixgbe.h | 4 +- sys/dev/usb/if_mtw.c | 4 +- sys/dev/usb/uchcom.c | 277 +++- sys/dev/usb/usbdevs | 3 +- sys/dev/usb/usbdevs.h | 5 +- sys/dev/usb/usbdevs_data.h | 8 +- sys/kern/kern_sysctl.c | 8 +- sys/net/pf.c | 20 +- sys/netinet/in_pcb.c | 24 +- sys/netinet/raw_ip.c | 21 +- sys/netinet/tcp_input.c | 24 +- sys/netinet/tcp_subr.c | 29 +- sys/netinet/tcp_usrreq.c | 31 +- sys/netinet/tcp_var.h | 4 +- sys/netinet/udp_usrreq.c | 16 +- sys/netinet6/in6_pcb.c | 9 +- usr.sbin/nsd/Makefile.in | 63 +- usr.sbin/nsd/acx_nlnetlabs.m4 | 145 +- usr.sbin/nsd/buffer.h | 102 ++ usr.sbin/nsd/config.h.in | 4 + usr.sbin/nsd/configlexer.lex | 6 +- usr.sbin/nsd/configparser.y | 65 +- usr.sbin/nsd/configure | 39 +- usr.sbin/nsd/configure.ac | 12 +- usr.sbin/nsd/difffile.c | 30 +- usr.sbin/nsd/difffile.h | 5 + usr.sbin/nsd/dname.c | 8 +- usr.sbin/nsd/dname.h | 14 + usr.sbin/nsd/doc/ChangeLog | 88 +- usr.sbin/nsd/doc/README | 10 +- usr.sbin/nsd/doc/RELNOTES | 61 + usr.sbin/nsd/namedb.h | 9 + usr.sbin/nsd/nsd-checkconf.8.in | 2 +- usr.sbin/nsd/nsd-checkconf.c | 30 +- usr.sbin/nsd/nsd-checkzone.8.in | 2 +- usr.sbin/nsd/nsd-control.8.in | 47 +- usr.sbin/nsd/nsd-control.c | 8 +- usr.sbin/nsd/nsd-mem.c | 2 +- usr.sbin/nsd/nsd.8.in | 4 +- usr.sbin/nsd/nsd.c | 2 +- usr.sbin/nsd/nsd.conf.5.in | 212 +-- usr.sbin/nsd/nsd.conf.sample.in | 36 +- usr.sbin/nsd/options.c | 293 +++- usr.sbin/nsd/options.h | 60 +- usr.sbin/nsd/query.c | 12 + usr.sbin/nsd/remote.c | 187 ++- usr.sbin/nsd/server.c | 199 ++- usr.sbin/nsd/util.c | 8 + usr.sbin/nsd/util.h | 9 + usr.sbin/nsd/xfrd-catalog-zones.c | 1285 +++++++++++++++++ usr.sbin/nsd/xfrd-catalog-zones.h | 128 ++ usr.sbin/nsd/xfrd-disk.c | 8 +- usr.sbin/nsd/xfrd-tcp.c | 2 +- usr.sbin/nsd/xfrd.c | 182 ++- usr.sbin/nsd/xfrd.h | 6 + usr.sbin/rpki-client/rrdp_notification.c | 4 +- usr.sbin/snmpd/snmpd.c | 17 +- usr.sbin/unbound/Makefile.in | 4 +- usr.sbin/unbound/README.md | 6 +- usr.sbin/unbound/cachedb/cachedb.c | 11 +- usr.sbin/unbound/cachedb/redis.c | 68 +- usr.sbin/unbound/config.guess | 17 +- usr.sbin/unbound/config.sub | 176 ++- usr.sbin/unbound/configure | 654 +++------ usr.sbin/unbound/configure.ac | 21 +- usr.sbin/unbound/daemon/remote.c | 35 +- usr.sbin/unbound/daemon/worker.c | 8 + usr.sbin/unbound/dns64/dns64.c | 97 +- usr.sbin/unbound/dnstap/dnstap.m4 | 2 +- usr.sbin/unbound/dnstap/dtstream.c | 8 +- .../unbound/dnstap/unbound-dnstap-socket.c | 12 +- usr.sbin/unbound/doc/Changelog | 149 +- usr.sbin/unbound/doc/README | 2 +- usr.sbin/unbound/doc/example.conf.in | 11 +- usr.sbin/unbound/doc/libunbound.3.in | 4 +- usr.sbin/unbound/doc/unbound-anchor.8.in | 2 +- usr.sbin/unbound/doc/unbound-checkconf.8.in | 2 +- usr.sbin/unbound/doc/unbound-control.8.in | 2 +- usr.sbin/unbound/doc/unbound-host.1.in | 2 +- usr.sbin/unbound/doc/unbound.8.in | 4 +- usr.sbin/unbound/doc/unbound.conf.5.in | 32 +- usr.sbin/unbound/dynlibmod/dynlibmod.c | 3 +- usr.sbin/unbound/edns-subnet/subnetmod.c | 30 +- usr.sbin/unbound/edns-subnet/subnetmod.h | 7 + usr.sbin/unbound/ipset/ipset.c | 4 +- usr.sbin/unbound/iterator/iter_priv.c | 26 +- usr.sbin/unbound/iterator/iter_resptype.c | 25 +- usr.sbin/unbound/iterator/iter_resptype.h | 4 +- usr.sbin/unbound/iterator/iter_scrub.c | 67 +- usr.sbin/unbound/iterator/iter_scrub.h | 5 +- usr.sbin/unbound/iterator/iterator.c | 74 +- usr.sbin/unbound/iterator/iterator.h | 7 + usr.sbin/unbound/libunbound/libworker.c | 4 + usr.sbin/unbound/services/authzone.c | 11 +- usr.sbin/unbound/services/listen_dnsport.c | 8 +- usr.sbin/unbound/services/mesh.c | 9 +- usr.sbin/unbound/services/outside_network.c | 2 +- usr.sbin/unbound/services/rpz.c | 10 +- usr.sbin/unbound/sldns/str2wire.c | 21 +- usr.sbin/unbound/sldns/wire2str.c | 82 ++ usr.sbin/unbound/sldns/wire2str.h | 13 + usr.sbin/unbound/smallapp/unbound-checkconf.c | 17 + usr.sbin/unbound/testcode/dohclient.c | 6 +- usr.sbin/unbound/testcode/fake_event.c | 2 +- usr.sbin/unbound/testcode/streamtcp.1 | 11 + usr.sbin/unbound/testcode/streamtcp.c | 76 +- usr.sbin/unbound/testcode/unitauth.c | 128 ++ usr.sbin/unbound/util/config_file.c | 10 + usr.sbin/unbound/util/config_file.h | 6 + usr.sbin/unbound/util/configlexer.lex | 3 + usr.sbin/unbound/util/configparser.y | 45 +- usr.sbin/unbound/util/data/msgencode.c | 4 +- usr.sbin/unbound/util/data/msgparse.c | 25 + usr.sbin/unbound/util/data/msgparse.h | 18 + usr.sbin/unbound/util/fptr_wlist.c | 2 + usr.sbin/unbound/util/log.c | 2 +- usr.sbin/unbound/util/module.c | 18 + usr.sbin/unbound/util/module.h | 10 + usr.sbin/unbound/util/net_help.c | 105 ++ usr.sbin/unbound/util/net_help.h | 18 + usr.sbin/unbound/util/netevent.c | 102 +- usr.sbin/unbound/util/proxy_protocol.c | 174 ++- usr.sbin/unbound/util/proxy_protocol.h | 66 +- usr.sbin/unbound/util/rfc_1982.c | 1 + usr.sbin/unbound/util/siphash.c | 5 + usr.sbin/unbound/validator/val_anchor.c | 21 + usr.sbin/unbound/validator/val_anchor.h | 8 + usr.sbin/unbound/validator/validator.c | 11 + 143 files changed, 5314 insertions(+), 1499 deletions(-) create mode 100644 usr.sbin/nsd/xfrd-catalog-zones.c create mode 100644 usr.sbin/nsd/xfrd-catalog-zones.h diff --git a/gnu/usr.bin/cvs/configure b/gnu/usr.bin/cvs/configure index b4cf62234..722f0dc92 100644 --- a/gnu/usr.bin/cvs/configure +++ b/gnu/usr.bin/cvs/configure @@ -4512,7 +4512,7 @@ trap 'rm -fr `echo "Makefile \ vms/Makefile \ windows-NT/Makefile \ windows-NT/SCC/Makefile \ - zlib/Makefile config.h src/options.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 + config.h src/options.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then diff --git a/gnu/usr.bin/cvs/configure.in b/gnu/usr.bin/cvs/configure.in index 6329cbf44..1352d3837 100644 --- a/gnu/usr.bin/cvs/configure.in +++ b/gnu/usr.bin/cvs/configure.in @@ -427,8 +427,7 @@ AC_OUTPUT([Makefile \ tools/Makefile \ vms/Makefile \ windows-NT/Makefile \ - windows-NT/SCC/Makefile \ - zlib/Makefile], + windows-NT/SCC/Makefile], [chmod -f +x \ contrib/clmerge \ contrib/cln_hist \ diff --git a/lib/libcrypto/evp/bio_enc.c b/lib/libcrypto/evp/bio_enc.c index 62712830a..30baf9351 100644 --- a/lib/libcrypto/evp/bio_enc.c +++ b/lib/libcrypto/evp/bio_enc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bio_enc.c,v 1.32 2024/04/09 13:52:41 beck Exp $ */ +/* $OpenBSD: bio_enc.c,v 1.33 2024/04/12 11:10:34 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -105,7 +105,7 @@ static const BIO_METHOD methods_enc = { const BIO_METHOD * BIO_f_cipher(void) { - return (&methods_enc); + return &methods_enc; } LCRYPTO_ALIAS(BIO_f_cipher); @@ -120,7 +120,7 @@ bio_enc_ctx_free(BIO_ENC_CTX *ctx) } static int -enc_new(BIO *bi) +enc_new(BIO *bio) { BIO_ENC_CTX *ctx; int ret = 0; @@ -133,7 +133,7 @@ enc_new(BIO *bi) ctx->cont = 1; ctx->ok = 1; - bi->ptr = ctx; + bio->ptr = ctx; ctx = NULL; ret = 1; @@ -145,29 +145,29 @@ enc_new(BIO *bi) } static int -enc_free(BIO *a) +enc_free(BIO *bio) { - if (a == NULL) + if (bio == NULL) return 0; - bio_enc_ctx_free(a->ptr); - explicit_bzero(a, sizeof(*a)); + bio_enc_ctx_free(bio->ptr); + explicit_bzero(bio, sizeof(*bio)); return 1; } static int -enc_read(BIO *b, char *out, int outl) +enc_read(BIO *bio, char *out, int outl) { - int ret = 0, i; BIO_ENC_CTX *ctx; + int ret = 0, i; if (out == NULL) - return (0); - ctx = (BIO_ENC_CTX *)b->ptr; + return 0; + ctx = bio->ptr; - if ((ctx == NULL) || (b->next_bio == NULL)) - return (0); + if (ctx == NULL || bio->next_bio == NULL) + return 0; /* First check if there are bytes decoded/encoded */ if (ctx->buf_len > 0) { @@ -194,11 +194,12 @@ enc_read(BIO *b, char *out, int outl) /* read in at IV offset, read the EVP_Cipher * documentation about why */ - i = BIO_read(b->next_bio, &(ctx->buf[BUF_OFFSET]), ENC_BLOCK_SIZE); + i = BIO_read(bio->next_bio, &ctx->buf[BUF_OFFSET], + ENC_BLOCK_SIZE); if (i <= 0) { /* Should be continue next time we are called? */ - if (!BIO_should_retry(b->next_bio)) { + if (!BIO_should_retry(bio->next_bio)) { ctx->cont = i; i = EVP_CipherFinal_ex(ctx->cipher_ctx, (unsigned char *)ctx->buf, @@ -212,7 +213,7 @@ enc_read(BIO *b, char *out, int outl) } else { EVP_CipherUpdate(ctx->cipher_ctx, (unsigned char *)ctx->buf, &ctx->buf_len, - (unsigned char *)&(ctx->buf[BUF_OFFSET]), i); + (unsigned char *)&ctx->buf[BUF_OFFSET], i); ctx->cont = 1; /* Note: it is possible for EVP_CipherUpdate to * decrypt zero bytes because this is or looks like @@ -237,39 +238,39 @@ enc_read(BIO *b, char *out, int outl) out += i; } - BIO_clear_retry_flags(b); - BIO_copy_next_retry(b); - return ((ret == 0) ? ctx->cont : ret); + BIO_clear_retry_flags(bio); + BIO_copy_next_retry(bio); + return ret == 0 ? ctx->cont : ret; } static int -enc_write(BIO *b, const char *in, int inl) +enc_write(BIO *bio, const char *in, int inl) { - int ret = 0, n, i; BIO_ENC_CTX *ctx; + int ret = 0, n, i; - ctx = (BIO_ENC_CTX *)b->ptr; + ctx = bio->ptr; ret = inl; - BIO_clear_retry_flags(b); + BIO_clear_retry_flags(bio); n = ctx->buf_len - ctx->buf_off; while (n > 0) { - i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); + i = BIO_write(bio->next_bio, &(ctx->buf[ctx->buf_off]), n); if (i <= 0) { - BIO_copy_next_retry(b); - return (i); + BIO_copy_next_retry(bio); + return i; } ctx->buf_off += i; n -= i; } /* at this point all pending data has been written */ - if ((in == NULL) || (inl <= 0)) - return (0); + if (in == NULL || inl <= 0) + return 0; ctx->buf_off = 0; while (inl > 0) { - n = (inl > ENC_BLOCK_SIZE) ? ENC_BLOCK_SIZE : inl; + n = inl > ENC_BLOCK_SIZE ? ENC_BLOCK_SIZE : inl; EVP_CipherUpdate(ctx->cipher_ctx, (unsigned char *)ctx->buf, &ctx->buf_len, (unsigned char *)in, n); @@ -279,10 +280,10 @@ enc_write(BIO *b, const char *in, int inl) ctx->buf_off = 0; n = ctx->buf_len; while (n > 0) { - i = BIO_write(b->next_bio, &(ctx->buf[ctx->buf_off]), n); + i = BIO_write(bio->next_bio, &ctx->buf[ctx->buf_off], n); if (i <= 0) { - BIO_copy_next_retry(b); - return (ret == inl) ? i : ret - inl; + BIO_copy_next_retry(bio); + return ret == inl ? i : ret - inl; } n -= i; ctx->buf_off += i; @@ -290,20 +291,21 @@ enc_write(BIO *b, const char *in, int inl) ctx->buf_len = 0; ctx->buf_off = 0; } - BIO_copy_next_retry(b); - return (ret); + BIO_copy_next_retry(bio); + + return ret; } static long -enc_ctrl(BIO *b, int cmd, long num, void *ptr) +enc_ctrl(BIO *bio, int cmd, long num, void *ptr) { BIO *dbio; BIO_ENC_CTX *ctx, *dctx; - long ret = 1; - int i; EVP_CIPHER_CTX **c_ctx; + int i; + long ret = 1; - ctx = b->ptr; + ctx = bio->ptr; switch (cmd) { case BIO_CTRL_RESET: @@ -311,29 +313,29 @@ enc_ctrl(BIO *b, int cmd, long num, void *ptr) ctx->finished = 0; EVP_CipherInit_ex(ctx->cipher_ctx, NULL, NULL, NULL, NULL, ctx->cipher_ctx->encrypt); - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); break; case BIO_CTRL_EOF: /* More to read */ if (ctx->cont <= 0) ret = 1; else - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); break; case BIO_CTRL_WPENDING: ret = ctx->buf_len - ctx->buf_off; if (ret <= 0) - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); break; case BIO_CTRL_PENDING: /* More to read in buffer */ ret = ctx->buf_len - ctx->buf_off; if (ret <= 0) - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); break; case BIO_CTRL_FLUSH: /* do a final write */ again: while (ctx->buf_len != ctx->buf_off) { - i = enc_write(b, NULL, 0); + i = enc_write(bio, NULL, 0); if (i < 0) return i; } @@ -343,7 +345,7 @@ enc_ctrl(BIO *b, int cmd, long num, void *ptr) ctx->buf_off = 0; ret = EVP_CipherFinal_ex(ctx->cipher_ctx, (unsigned char *)ctx->buf, - &(ctx->buf_len)); + &ctx->buf_len); ctx->ok = (int)ret; if (ret <= 0) break; @@ -353,20 +355,20 @@ enc_ctrl(BIO *b, int cmd, long num, void *ptr) } /* Finally flush the underlying BIO */ - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); break; case BIO_C_GET_CIPHER_STATUS: ret = (long)ctx->ok; break; case BIO_C_DO_STATE_MACHINE: - BIO_clear_retry_flags(b); - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - BIO_copy_next_retry(b); + BIO_clear_retry_flags(bio); + ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); + BIO_copy_next_retry(bio); break; case BIO_C_GET_CIPHER_CTX: c_ctx = ptr; *c_ctx = ctx->cipher_ctx; - b->init = 1; + bio->init = 1; break; case BIO_CTRL_DUP: dbio = ptr; @@ -376,7 +378,7 @@ enc_ctrl(BIO *b, int cmd, long num, void *ptr) dbio->init = 1; break; default: - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + ret = BIO_ctrl(bio->next_bio, cmd, num, ptr); break; } @@ -384,46 +386,47 @@ enc_ctrl(BIO *b, int cmd, long num, void *ptr) } static long -enc_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +enc_callback_ctrl(BIO *bio, int cmd, BIO_info_cb *fp) { long ret = 1; - if (b->next_bio == NULL) - return (0); + if (bio->next_bio == NULL) + return 0; + switch (cmd) { default: - ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + ret = BIO_callback_ctrl(bio->next_bio, cmd, fp); break; } - return (ret); + + return ret; } int -BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k, +BIO_set_cipher(BIO *bio, const EVP_CIPHER *c, const unsigned char *k, const unsigned char *i, int e) { BIO_ENC_CTX *ctx; long (*cb)(BIO *, int, const char *, int, long, long); - if (b == NULL) + if (bio == NULL) return 0; - if ((ctx = BIO_get_data(b)) == NULL) + if ((ctx = BIO_get_data(bio)) == NULL) return 0; - if ((cb = BIO_get_callback(b)) != NULL) { - if (cb(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 0L) - <= 0) + if ((cb = BIO_get_callback(bio)) != NULL) { + if (cb(bio, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 0L) <= 0) return 0; } - BIO_set_init(b, 1); + BIO_set_init(bio, 1); if (!EVP_CipherInit_ex(ctx->cipher_ctx, c, NULL, k, i, e)) return 0; if (cb != NULL) - return cb(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 1L); + return cb(bio, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 1L); return 1; } diff --git a/lib/libcrypto/evp/evp_local.h b/lib/libcrypto/evp/evp_local.h index b1c0c9b14..9631992a2 100644 --- a/lib/libcrypto/evp/evp_local.h +++ b/lib/libcrypto/evp/evp_local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: evp_local.h,v 1.21 2024/03/26 01:41:06 tb Exp $ */ +/* $OpenBSD: evp_local.h,v 1.22 2024/04/12 09:41:39 tb Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2000. */ @@ -283,10 +283,8 @@ struct evp_pkey_method_st { int (*copy)(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src); void (*cleanup)(EVP_PKEY_CTX *ctx); - int (*paramgen_init)(EVP_PKEY_CTX *ctx); int (*paramgen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey); - int (*keygen_init)(EVP_PKEY_CTX *ctx); int (*keygen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey); int (*sign_init)(EVP_PKEY_CTX *ctx); @@ -298,7 +296,6 @@ struct evp_pkey_method_st { const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen); - int (*verify_recover_init)(EVP_PKEY_CTX *ctx); int (*verify_recover)(EVP_PKEY_CTX *ctx, unsigned char *rout, size_t *routlen, const unsigned char *sig, size_t siglen); @@ -307,11 +304,9 @@ struct evp_pkey_method_st { int (*signctx)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, EVP_MD_CTX *mctx); - int (*encrypt_init)(EVP_PKEY_CTX *ctx); int (*encrypt)(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen); - int (*decrypt_init)(EVP_PKEY_CTX *ctx); int (*decrypt)(EVP_PKEY_CTX *ctx, unsigned char *out, size_t *outlen, const unsigned char *in, size_t inlen); diff --git a/lib/libcrypto/evp/pmeth_fn.c b/lib/libcrypto/evp/pmeth_fn.c index f8ed555fd..308c434f0 100644 --- a/lib/libcrypto/evp/pmeth_fn.c +++ b/lib/libcrypto/evp/pmeth_fn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmeth_fn.c,v 1.10 2024/04/09 13:52:41 beck Exp $ */ +/* $OpenBSD: pmeth_fn.c,v 1.11 2024/04/12 09:41:39 tb Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2006. */ @@ -155,19 +155,15 @@ LCRYPTO_ALIAS(EVP_PKEY_verify); int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx) { - int ret; - - if (!ctx || !ctx->pmeth || !ctx->pmeth->verify_recover) { + if (ctx == NULL || ctx->pmeth == NULL || + ctx->pmeth->verify_recover == NULL) { EVPerror(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } + ctx->operation = EVP_PKEY_OP_VERIFYRECOVER; - if (!ctx->pmeth->verify_recover_init) - return 1; - ret = ctx->pmeth->verify_recover_init(ctx); - if (ret <= 0) - ctx->operation = EVP_PKEY_OP_UNDEFINED; - return ret; + + return 1; } LCRYPTO_ALIAS(EVP_PKEY_verify_recover_init); @@ -191,19 +187,14 @@ LCRYPTO_ALIAS(EVP_PKEY_verify_recover); int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) { - int ret; - - if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) { + if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) { EVPerror(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } + ctx->operation = EVP_PKEY_OP_ENCRYPT; - if (!ctx->pmeth->encrypt_init) - return 1; - ret = ctx->pmeth->encrypt_init(ctx); - if (ret <= 0) - ctx->operation = EVP_PKEY_OP_UNDEFINED; - return ret; + + return 1; } LCRYPTO_ALIAS(EVP_PKEY_encrypt_init); @@ -227,19 +218,14 @@ LCRYPTO_ALIAS(EVP_PKEY_encrypt); int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx) { - int ret; - - if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) { + if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->decrypt == NULL) { EVPerror(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } + ctx->operation = EVP_PKEY_OP_DECRYPT; - if (!ctx->pmeth->decrypt_init) - return 1; - ret = ctx->pmeth->decrypt_init(ctx); - if (ret <= 0) - ctx->operation = EVP_PKEY_OP_UNDEFINED; - return ret; + + return 1; } LCRYPTO_ALIAS(EVP_PKEY_decrypt_init); diff --git a/lib/libcrypto/evp/pmeth_gn.c b/lib/libcrypto/evp/pmeth_gn.c index 2711ba1a9..b8b51ced3 100644 --- a/lib/libcrypto/evp/pmeth_gn.c +++ b/lib/libcrypto/evp/pmeth_gn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmeth_gn.c,v 1.16 2024/04/09 13:52:41 beck Exp $ */ +/* $OpenBSD: pmeth_gn.c,v 1.18 2024/04/12 09:41:39 tb Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2006. */ @@ -71,19 +71,14 @@ int EVP_PKEY_paramgen_init(EVP_PKEY_CTX *ctx) { - int ret; - - if (!ctx || !ctx->pmeth || !ctx->pmeth->paramgen) { + if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->paramgen == NULL) { EVPerror(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } + ctx->operation = EVP_PKEY_OP_PARAMGEN; - if (!ctx->pmeth->paramgen_init) - return 1; - ret = ctx->pmeth->paramgen_init(ctx); - if (ret <= 0) - ctx->operation = EVP_PKEY_OP_UNDEFINED; - return ret; + + return 1; } LCRYPTO_ALIAS(EVP_PKEY_paramgen_init); @@ -120,19 +115,14 @@ LCRYPTO_ALIAS(EVP_PKEY_paramgen); int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx) { - int ret; - - if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) { + if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->keygen == NULL) { EVPerror(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } + ctx->operation = EVP_PKEY_OP_KEYGEN; - if (!ctx->pmeth->keygen_init) - return 1; - ret = ctx->pmeth->keygen_init(ctx); - if (ret <= 0) - ctx->operation = EVP_PKEY_OP_UNDEFINED; - return ret; + + return 1; } LCRYPTO_ALIAS(EVP_PKEY_keygen_init); @@ -141,7 +131,7 @@ EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey) { int ret; - if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) { + if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->keygen == NULL) { EVPerror(EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); return -2; } @@ -150,17 +140,19 @@ EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey) return -1; } - if (!ppkey) + if (ppkey == NULL) return -1; - if (!*ppkey) + if (*ppkey == NULL) *ppkey = EVP_PKEY_new(); + if (*ppkey == NULL) + return -1; - ret = ctx->pmeth->keygen(ctx, *ppkey); - if (ret <= 0) { + if ((ret = ctx->pmeth->keygen(ctx, *ppkey)) <= 0) { EVP_PKEY_free(*ppkey); *ppkey = NULL; } + return ret; } LCRYPTO_ALIAS(EVP_PKEY_keygen); diff --git a/lib/libcurses/tinfo/read_entry.c b/lib/libcurses/tinfo/read_entry.c index 641b8df95..cfc4fded8 100644 --- a/lib/libcurses/tinfo/read_entry.c +++ b/lib/libcurses/tinfo/read_entry.c @@ -1,4 +1,4 @@ -/* $OpenBSD: read_entry.c,v 1.18 2023/10/17 09:52:09 nicm Exp $ */ +/* $OpenBSD: read_entry.c,v 1.19 2024/04/12 14:10:28 millert Exp $ */ /**************************************************************************** * Copyright 2018-2022,2023 Thomas E. Dickey * @@ -44,7 +44,7 @@ #include -MODULE_ID("$Id: read_entry.c,v 1.18 2023/10/17 09:52:09 nicm Exp $") +MODULE_ID("$Id: read_entry.c,v 1.19 2024/04/12 14:10:28 millert Exp $") #define MyNumber(n) (short) LOW_MSB(n) @@ -864,9 +864,10 @@ _nc_read_tic_entry(char *filename, } #if NCURSES_USE_TERMCAP if (code != TGETENT_YES) { + const char *source = _nc_get_source(); code = _nc_read_termcap_entry(name, tp); _nc_SPRINTF(filename, _nc_SLIMIT(PATH_MAX) - "%.*s", PATH_MAX - 1, _nc_get_source()); + "%.*s", PATH_MAX - 1, source ? source : ""); } #endif returnDB(code); @@ -912,9 +913,10 @@ _nc_read_entry2(const char *const name, char *const filename, TERMTYPE2 *const t } #elif NCURSES_USE_TERMCAP if (code != TGETENT_YES) { + const char *source = _nc_get_source(); code = _nc_read_termcap_entry(name, tp); _nc_SPRINTF(filename, _nc_SLIMIT(PATH_MAX) - "%.*s", PATH_MAX - 1, _nc_get_source()); + "%.*s", PATH_MAX - 1, source ? source : ""); } #endif } diff --git a/share/man/man4/uchcom.4 b/share/man/man4/uchcom.4 index 3ef2eece9..5aa552b44 100644 --- a/share/man/man4/uchcom.4 +++ b/share/man/man4/uchcom.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: uchcom.4,v 1.2 2013/07/16 16:05:49 schwarze Exp $ +.\" $OpenBSD: uchcom.4,v 1.3 2024/04/12 00:43:32 kevlo Exp $ .\" .\" Copyright (c) 2007 Jonathan Gray .\" @@ -14,19 +14,23 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: July 16 2013 $ +.Dd $Mdocdate: April 12 2024 $ .Dt UCHCOM 4 .Os .Sh NAME .Nm uchcom -.Nd WinChipHead CH341/340 based USB serial adapter +.Nd WinChipHead CH343/341/340 based USB serial adapter .Sh SYNOPSIS .Cd "uchcom* at uhub?" .Cd "ucom* at uchcom?" .Sh DESCRIPTION The .Nm -driver supports WinChipHead CH341/340 serial devices. +driver supports WinChipHead CH343/341/340 serial devices. +.Pp +The CH341/340 devices only support a variety of baud rates +up to 921600. +CH343 devices support any baud rate up to 6 Mbps. .Sh SEE ALSO .Xr tty 4 , .Xr ucom 4 , diff --git a/share/man/man4/ucom.4 b/share/man/man4/ucom.4 index aaa447962..260986fe7 100644 --- a/share/man/man4/ucom.4 +++ b/share/man/man4/ucom.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ucom.4,v 1.33 2019/06/07 16:06:59 jcs Exp $ +.\" $OpenBSD: ucom.4,v 1.34 2024/04/12 00:43:32 kevlo Exp $ .\" $NetBSD: ucom.4,v 1.3 2000/04/14 14:55:18 augustss Exp $ .\" .\" Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -28,7 +28,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: June 7 2019 $ +.Dd $Mdocdate: April 12 2024 $ .Dt UCOM 4 .Os .Sh NAME @@ -38,7 +38,7 @@ .Cd "ucom* at moscom?" # MosChip Semiconductor MCS7703 .Cd "ucom* at uark?" # Arkmicro Technologies .Cd "ucom* at ubsa?" # Belkin -.Cd "ucom* at uchcom?" # WinChipHead CH341/340 +.Cd "ucom* at uchcom?" # WinChipHead CH343/341/340 .Cd "ucom* at ucycom?" # Cypress .Cd "ucom* at uftdi?" # FTDI .Cd "ucom* at uipaq?" # iPAQ diff --git a/share/man/man4/usb.4 b/share/man/man4/usb.4 index 1d95449fd..57ebda4a0 100644 --- a/share/man/man4/usb.4 +++ b/share/man/man4/usb.4 @@ -1,4 +1,4 @@ -.\" $OpenBSD: usb.4,v 1.217 2024/01/04 08:41:59 kevlo Exp $ +.\" $OpenBSD: usb.4,v 1.218 2024/04/12 00:43:32 kevlo Exp $ .\" $NetBSD: usb.4,v 1.15 1999/07/29 14:20:32 augustss Exp $ .\" .\" Copyright (c) 1999 The NetBSD Foundation, Inc. @@ -28,7 +28,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: January 4 2024 $ +.Dd $Mdocdate: April 12 2024 $ .Dt USB 4 .Os .Sh NAME @@ -179,7 +179,7 @@ Arkmicro Technologies ARK3116 based USB serial adapter .It Xr ubsa 4 Belkin USB serial adapter .It Xr uchcom 4 -WinChipHead CH341/340 based USB serial adapter +WinChipHead CH343/341/340 based USB serial adapter .It Xr ucom 4 USB tty support .It Xr ucrcom 4 diff --git a/sys/dev/pci/if_bnxt.c b/sys/dev/pci/if_bnxt.c index 09192af6c..7177f4684 100644 --- a/sys/dev/pci/if_bnxt.c +++ b/sys/dev/pci/if_bnxt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bnxt.c,v 1.47 2024/02/14 22:41:48 bluhm Exp $ */ +/* $OpenBSD: if_bnxt.c,v 1.48 2024/04/12 19:27:43 jan Exp $ */ /*- * Broadcom NetXtreme-C/E network driver. * @@ -76,8 +76,6 @@ #endif #include -#include -#include #include #include #include diff --git a/sys/dev/pci/if_igc.c b/sys/dev/pci/if_igc.c index db6416b37..0019074d1 100644 --- a/sys/dev/pci/if_igc.c +++ b/sys/dev/pci/if_igc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_igc.c,v 1.19 2024/03/25 20:25:13 mbuhl Exp $ */ +/* $OpenBSD: if_igc.c,v 1.20 2024/04/12 19:27:43 jan Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause * @@ -48,8 +48,6 @@ #include #include -#include -#include #if NBPFILTER > 0 #include diff --git a/sys/dev/pci/if_ixl.c b/sys/dev/pci/if_ixl.c index d8d714dcf..edb10ff4b 100644 --- a/sys/dev/pci/if_ixl.c +++ b/sys/dev/pci/if_ixl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ixl.c,v 1.97 2024/02/14 22:41:48 bluhm Exp $ */ +/* $OpenBSD: if_ixl.c,v 1.98 2024/04/12 19:27:43 jan Exp $ */ /* * Copyright (c) 2013-2015, Intel Corporation @@ -83,13 +83,11 @@ #endif #include -#include -#include +#include #include #include #include #include -#include #include #include diff --git a/sys/dev/pci/if_mcx.c b/sys/dev/pci/if_mcx.c index f17ca130e..9528f48f5 100644 --- a/sys/dev/pci/if_mcx.c +++ b/sys/dev/pci/if_mcx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mcx.c,v 1.113 2024/04/11 06:42:12 jmatthew Exp $ */ +/* $OpenBSD: if_mcx.c,v 1.114 2024/04/12 01:54:21 jsg Exp $ */ /* * Copyright (c) 2017 David Gwynne @@ -8108,13 +8108,14 @@ mcx_media_change(struct ifnet *ifp) } } + ext_media = 0; for (i = 0; i < nitems(mcx_ext_eth_cap_map); i++) { const struct mcx_eth_proto_capability *cap; cap = &mcx_ext_eth_cap_map[i]; if (cap->cap_media == IFM_SUBTYPE(sc->sc_media.ifm_media)) { - media = (1 << i); + ext_media = (1 << i); break; } } diff --git a/sys/dev/pci/if_ngbe.c b/sys/dev/pci/if_ngbe.c index fe2873b32..e09328d54 100644 --- a/sys/dev/pci/if_ngbe.c +++ b/sys/dev/pci/if_ngbe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ngbe.c,v 1.2 2023/11/10 15:51:20 bluhm Exp $ */ +/* $OpenBSD: if_ngbe.c,v 1.3 2024/04/12 19:27:43 jan Exp $ */ /* * Copyright (c) 2015-2017 Beijing WangXun Technology Co., Ltd. @@ -37,8 +37,6 @@ #include #include -#include -#include #if NBPFILTER > 0 #include diff --git a/sys/dev/pci/ixgbe.h b/sys/dev/pci/ixgbe.h index 5fbfba93d..2851b2858 100644 --- a/sys/dev/pci/ixgbe.h +++ b/sys/dev/pci/ixgbe.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ixgbe.h,v 1.34 2023/05/18 08:22:37 jan Exp $ */ +/* $OpenBSD: ixgbe.h,v 1.35 2024/04/12 19:27:43 jan Exp $ */ /****************************************************************************** @@ -65,8 +65,6 @@ #include #include -#include -#include #include #include #include diff --git a/sys/dev/usb/if_mtw.c b/sys/dev/usb/if_mtw.c index 2a6d1e9f5..bdd6e53ac 100644 --- a/sys/dev/usb/if_mtw.c +++ b/sys/dev/usb/if_mtw.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_mtw.c,v 1.8 2023/03/08 04:43:08 guenther Exp $ */ +/* $OpenBSD: if_mtw.c,v 1.9 2024/04/12 09:56:39 jsg Exp $ */ /* * Copyright (c) 2008-2010 Damien Bergamini * Copyright (c) 2013-2014 Kevin Lo @@ -2549,7 +2549,7 @@ mt7601_set_chan(struct mtw_softc *sc, u_int chan) int i; /* find the settings for this channel */ - for (i = 0; mt7601_rf_chan[i].chan != chan; i++) + for (i = 0; mt7601_rf_chan[i].chan != chan; i++); mtw_rf_write(sc, 0, 17, mt7601_rf_chan[i].r17); mtw_rf_write(sc, 0, 18, mt7601_rf_chan[i].r18); diff --git a/sys/dev/usb/uchcom.c b/sys/dev/usb/uchcom.c index d67c27756..94c451c03 100644 --- a/sys/dev/usb/uchcom.c +++ b/sys/dev/usb/uchcom.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uchcom.c,v 1.33 2022/04/09 20:07:44 naddy Exp $ */ +/* $OpenBSD: uchcom.c,v 1.34 2024/04/12 00:43:32 kevlo Exp $ */ /* $NetBSD: uchcom.c,v 1.1 2007/09/03 17:57:37 tshiozak Exp $ */ /* @@ -31,7 +31,7 @@ */ /* - * driver for WinChipHead CH341/340, the worst USB-serial chip in the world. + * driver for WinChipHead CH343/341/340. */ #include @@ -41,8 +41,11 @@ #include #include +#include + #include #include +#include #include #include #include @@ -55,16 +58,20 @@ int uchcomdebug = 0; #endif #define DPRINTF(x) DPRINTFN(0, x) -#define UCHCOM_IFACE_INDEX 0 +#define UCHCOM_IFACE_INDEX 0 +#define UCHCOM_SECOND_IFACE_INDEX 1 #define UCHCOM_REV_CH340 0x0250 +#define UCHCOM_REV_CH343 0x0440 #define UCHCOM_INPUT_BUF_SIZE 8 -#define UCHCOM_REQ_GET_VERSION 0x5F -#define UCHCOM_REQ_READ_REG 0x95 -#define UCHCOM_REQ_WRITE_REG 0x9A -#define UCHCOM_REQ_RESET 0xA1 -#define UCHCOM_REQ_SET_DTRRTS 0xA4 +#define UCHCOM_REQ_GET_VERSION 0x5F +#define UCHCOM_REQ_READ_REG 0x95 +#define UCHCOM_REQ_WRITE_REG 0x9A +#define UCHCOM_REQ_RESET 0xA1 +#define UCHCOM_REQ_SET_DTRRTS 0xA4 +#define UCHCOM_REQ_CH343_WRITE_REG 0xA8 +#define UCHCOM_REQ_SET_BAUDRATE UCHCOM_REQ_RESET #define UCHCOM_REG_STAT1 0x06 #define UCHCOM_REG_STAT2 0x07 @@ -88,6 +95,8 @@ int uchcomdebug = 0; #define UCHCOM_RTS_MASK 0x40 #define UCHCOM_BREAK_MASK 0x01 +#define UCHCOM_ABREAK_MASK 0x10 +#define UCHCOM_CH343_BREAK_MASK 0x80 #define UCHCOM_LCR_CS5 0x00 #define UCHCOM_LCR_CS6 0x01 @@ -106,6 +115,9 @@ int uchcomdebug = 0; #define UCHCOM_INTR_STAT2 0x03 #define UCHCOM_INTR_LEAST 4 +#define UCHCOM_T 0x08 +#define UCHCOM_CL 0x04 +#define UCHCOM_CT 0x80 /* * XXX - these magic numbers come from Linux (drivers/usb/serial/ch341.c). * The manufacturer was unresponsive when asked for documentation. @@ -115,12 +127,15 @@ int uchcomdebug = 0; #define UCHCOMOBUFSIZE 256 +#define UCHCOM_TYPE_CH343 1 + struct uchcom_softc { struct device sc_dev; struct usbd_device *sc_udev; struct device *sc_subdev; - struct usbd_interface *sc_iface; + struct usbd_interface *sc_intr_iface; + struct usbd_interface *sc_data_iface; /* */ int sc_intr_endpoint; struct usbd_pipe *sc_intr_pipe; @@ -129,6 +144,7 @@ struct uchcom_softc /* */ int sc_release; uint8_t sc_version; + int sc_type; int sc_dtr; int sc_rts; u_char sc_lsr; @@ -178,8 +194,6 @@ int uchcom_open(void *, int); void uchcom_close(void *, int); void uchcom_intr(struct usbd_xfer *, void *, usbd_status); -int uchcom_find_ifaces(struct uchcom_softc *, - struct usbd_interface **); int uchcom_find_endpoints(struct uchcom_softc *, struct uchcom_endpoints *); void uchcom_close_intr_pipe(struct uchcom_softc *); @@ -202,9 +216,14 @@ void uchcom_convert_status(struct uchcom_softc *, uint8_t); int uchcom_update_status(struct uchcom_softc *); int uchcom_set_dtrrts(struct uchcom_softc *, int, int); int uchcom_set_break(struct uchcom_softc *, int); +int uchcom_set_break_ch343(struct uchcom_softc *, int); +void uchcom_calc_baudrate_ch343(uint32_t, uint8_t *, uint8_t *); int uchcom_calc_divider_settings(struct uchcom_divider *, uint32_t); +int uchcom_set_dte_rate_ch343(struct uchcom_softc *, uint32_t, + uint16_t); int uchcom_set_dte_rate(struct uchcom_softc *, uint32_t); -int uchcom_set_line_control(struct uchcom_softc *, tcflag_t); +uint16_t uchcom_set_line_control(struct uchcom_softc *, tcflag_t, + uint16_t *); int uchcom_clear_chip(struct uchcom_softc *); int uchcom_reset_chip(struct uchcom_softc *); int uchcom_setup_comm(struct uchcom_softc *); @@ -229,7 +248,8 @@ const struct ucom_methods uchcom_methods = { static const struct usb_devno uchcom_devs[] = { { USB_VENDOR_WCH, USB_PRODUCT_WCH_CH341 }, { USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH340 }, - { USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341A } + { USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341A }, + { USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH343 } }; struct cfdriver uchcom_cd = { @@ -262,26 +282,22 @@ uchcom_attach(struct device *parent, struct device *self, void *aux) struct uchcom_softc *sc = (struct uchcom_softc *)self; struct usb_attach_arg *uaa = aux; struct ucom_attach_args uca; - struct usbd_device *dev = uaa->device; struct uchcom_endpoints endpoints; - sc->sc_udev = dev; + sc->sc_udev = uaa->device; + sc->sc_intr_iface = uaa->iface; sc->sc_dtr = sc->sc_rts = -1; sc->sc_release = uaa->release; DPRINTF(("\n\nuchcom attach: sc=%p\n", sc)); - switch (sc->sc_release) { - case UCHCOM_REV_CH340: + if (sc->sc_release >= UCHCOM_REV_CH343) { + printf("%s: CH343\n", sc->sc_dev.dv_xname); + sc->sc_type = UCHCOM_TYPE_CH343; + } else if (sc->sc_release == UCHCOM_REV_CH340) printf("%s: CH340\n", sc->sc_dev.dv_xname); - break; - default: + else printf("%s: CH341\n", sc->sc_dev.dv_xname); - break; - } - - if (uchcom_find_ifaces(sc, &sc->sc_iface)) - goto failed; if (uchcom_find_endpoints(sc, &endpoints)) goto failed; @@ -297,8 +313,8 @@ uchcom_attach(struct device *parent, struct device *self, void *aux) uca.obufsize = UCHCOMOBUFSIZE; uca.ibufsizepad = endpoints.ep_bulkin_size; uca.opkthdrlen = 0; - uca.device = dev; - uca.iface = sc->sc_iface; + uca.device = sc->sc_udev; + uca.iface = sc->sc_data_iface; uca.methods = &uchcom_methods; uca.arg = sc; uca.info = NULL; @@ -329,34 +345,30 @@ uchcom_detach(struct device *self, int flags) return rv; } -int -uchcom_find_ifaces(struct uchcom_softc *sc, struct usbd_interface **riface) -{ - usbd_status err; - - err = usbd_device2interface_handle(sc->sc_udev, UCHCOM_IFACE_INDEX, - riface); - if (err) { - printf("\n%s: failed to get interface: %s\n", - sc->sc_dev.dv_xname, usbd_errstr(err)); - return -1; - } - - return 0; -} - int uchcom_find_endpoints(struct uchcom_softc *sc, struct uchcom_endpoints *endpoints) { int i, bin=-1, bout=-1, intr=-1, binsize=0, isize=0; + usb_config_descriptor_t *cdesc; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; + usbd_status err; + uint8_t ifaceno; - id = usbd_get_interface_descriptor(sc->sc_iface); + /* Get the config descriptor. */ + cdesc = usbd_get_config_descriptor(sc->sc_udev); + + if (cdesc == NULL) { + printf("%s: failed to get configuration descriptor\n", + sc->sc_dev.dv_xname); + return -1; + } + + id = usbd_get_interface_descriptor(sc->sc_intr_iface); for (i = 0; i < id->bNumEndpoints; i++) { - ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i); + ed = usbd_interface2endpoint_descriptor(sc->sc_intr_iface, i); if (ed == NULL) { printf("%s: no endpoint descriptor for %d\n", sc->sc_dev.dv_xname, i); @@ -367,12 +379,36 @@ uchcom_find_endpoints(struct uchcom_softc *sc, UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { intr = ed->bEndpointAddress; isize = UGETW(ed->wMaxPacketSize); - } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && - UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { + } + } + + ifaceno = (cdesc->bNumInterfaces == 2) ? + UCHCOM_SECOND_IFACE_INDEX : UCHCOM_IFACE_INDEX; + + err = usbd_device2interface_handle(sc->sc_udev, ifaceno, + &sc->sc_data_iface); + if (err) { + printf("\n%s: failed to get second interface, err=%s\n", + sc->sc_dev.dv_xname, usbd_errstr(err)); + return -1; + } + + id = usbd_get_interface_descriptor(sc->sc_data_iface); + + for (i = 0; i < id->bNumEndpoints; i++) { + ed = usbd_interface2endpoint_descriptor(sc->sc_data_iface, i); + if (ed == NULL) { + printf("%s: no endpoint descriptor for %d\n", + sc->sc_dev.dv_xname, i); + return -1; + } + + if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { bin = ed->bEndpointAddress; binsize = UGETW(ed->wMaxPacketSize); } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && - UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { + UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { bout = ed->bEndpointAddress; } } @@ -400,6 +436,8 @@ uchcom_find_endpoints(struct uchcom_softc *sc, DPRINTF(("%s: bulkin=%d, bulkout=%d, intr=%d, isize=%d\n", sc->sc_dev.dv_xname, bin, bout, intr, isize)); + usbd_claim_iface(sc->sc_udev, ifaceno); + endpoints->ep_intr = intr; endpoints->ep_intr_size = isize; endpoints->ep_bulkin = bin; @@ -453,8 +491,9 @@ uchcom_write_reg(struct uchcom_softc *sc, DPRINTF(("uchcom: write reg 0x%02X<-0x%02X, 0x%02X<-0x%02X\n", (unsigned)reg1, (unsigned)val1, (unsigned)reg2, (unsigned)val2)); - return uchcom_generic_control_out( - sc, UCHCOM_REQ_WRITE_REG, + return uchcom_generic_control_out(sc, + (sc->sc_type != UCHCOM_TYPE_CH343) ? + UCHCOM_REQ_WRITE_REG : UCHCOM_REQ_CH343_WRITE_REG, reg1|((uint16_t)reg2<<8), val1|((uint16_t)val2<<8)); } @@ -615,6 +654,46 @@ uchcom_set_break(struct uchcom_softc *sc, int onoff) return 0; } +int +uchcom_set_break_ch343(struct uchcom_softc *sc, int onoff) +{ + usbd_status err; + uint8_t brk = UCHCOM_CH343_BREAK_MASK; + + if (!onoff) + brk |= UCHCOM_ABREAK_MASK; + + err = uchcom_write_reg(sc, brk, 0, 0, 0); + if (err) + return EIO; + + return 0; +} + +void +uchcom_calc_baudrate_ch343(uint32_t rate, uint8_t *divisor, uint8_t *factor) +{ + uint32_t clk = 12000000; + + if (rate >= 256000) + *divisor = 7; + else if (rate > 23529) { + clk /= 2; + *divisor = 3; + } else if (rate > 2941) { + clk /= 16; + *divisor = 2; + } else if (rate > 367) { + clk /= 128; + *divisor = 1; + } else { + clk = 11719; + *divisor = 0; + } + + *factor = 256 - clk / rate; +} + int uchcom_calc_divider_settings(struct uchcom_divider *dp, uint32_t rate) { @@ -654,6 +733,26 @@ found: return 0; } +int +uchcom_set_dte_rate_ch343(struct uchcom_softc *sc, uint32_t rate, uint16_t val) +{ + usbd_status err; + uint16_t idx; + uint8_t factor, div; + + uchcom_calc_baudrate_ch343(rate, &div, &factor); + idx = (factor << 8) | div; + + err = uchcom_generic_control_out(sc, UCHCOM_REQ_SET_BAUDRATE, val, idx); + if (err) { + printf("%s: cannot set DTE rate: %s\n", + sc->sc_dev.dv_xname, usbd_errstr(err)); + return EIO; + } + + return 0; +} + int uchcom_set_dte_rate(struct uchcom_softc *sc, uint32_t rate) { @@ -677,8 +776,8 @@ uchcom_set_dte_rate(struct uchcom_softc *sc, uint32_t rate) return 0; } -int -uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag) +uint16_t +uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag, uint16_t *val) { usbd_status err; uint8_t lcr = 0, lcr2 = 0; @@ -703,12 +802,14 @@ uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag) return 0; } - err = uchcom_read_reg(sc, UCHCOM_REG_LCR, &lcr, - UCHCOM_REG_LCR2, &lcr2); - if (err) { - printf("%s: cannot get LCR: %s\n", - sc->sc_dev.dv_xname, usbd_errstr(err)); - return EIO; + if (sc->sc_type != UCHCOM_TYPE_CH343) { + err = uchcom_read_reg(sc, UCHCOM_REG_LCR, &lcr, UCHCOM_REG_LCR2, + &lcr2); + if (err) { + printf("%s: cannot get LCR: %s\n", + sc->sc_dev.dv_xname, usbd_errstr(err)); + return EIO; + } } lcr = UCHCOM_LCR_RXE | UCHCOM_LCR_TXE; @@ -738,12 +839,16 @@ uchcom_set_line_control(struct uchcom_softc *sc, tcflag_t cflag) lcr |= UCHCOM_LCR_STOPB; } - err = uchcom_write_reg(sc, UCHCOM_REG_LCR, lcr, UCHCOM_REG_LCR2, lcr2); - if (err) { - printf("%s: cannot set LCR: %s\n", - sc->sc_dev.dv_xname, usbd_errstr(err)); - return EIO; - } + if (sc->sc_type != UCHCOM_TYPE_CH343) { + err = uchcom_write_reg(sc, UCHCOM_REG_LCR, lcr, UCHCOM_REG_LCR2, + lcr2); + if (err) { + printf("%s: cannot set LCR: %s\n", + sc->sc_dev.dv_xname, usbd_errstr(err)); + return EIO; + } + } else + *val = UCHCOM_T | UCHCOM_CL | UCHCOM_CT | lcr << 8; return 0; } @@ -790,10 +895,6 @@ uchcom_setup_comm(struct uchcom_softc *sc) { int ret; - ret = uchcom_update_version(sc); - if (ret) - return ret; - ret = uchcom_clear_chip(sc); if (ret) return ret; @@ -802,7 +903,7 @@ uchcom_setup_comm(struct uchcom_softc *sc) if (ret) return ret; - ret = uchcom_set_line_control(sc, CS8); + ret = uchcom_set_line_control(sc, CS8, 0); if (ret) return ret; @@ -818,11 +919,6 @@ uchcom_setup_comm(struct uchcom_softc *sc) if (ret) return ret; - sc->sc_dtr = sc->sc_rts = 1; - ret = uchcom_set_dtrrts(sc, sc->sc_dtr, sc->sc_rts); - if (ret) - return ret; - return 0; } @@ -833,7 +929,7 @@ uchcom_setup_intr_pipe(struct uchcom_softc *sc) if (sc->sc_intr_endpoint != -1 && sc->sc_intr_pipe == NULL) { sc->sc_intr_buf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); - err = usbd_open_pipe_intr(sc->sc_iface, + err = usbd_open_pipe_intr(sc->sc_intr_iface, sc->sc_intr_endpoint, USBD_SHORT_XFER_OK, &sc->sc_intr_pipe, sc, @@ -899,7 +995,10 @@ uchcom_set(void *arg, int portno, int reg, int onoff) uchcom_set_dtrrts(sc, sc->sc_dtr, sc->sc_rts); break; case UCOM_SET_BREAK: - uchcom_set_break(sc, onoff); + if (sc->sc_type == UCHCOM_TYPE_CH343) + uchcom_set_break_ch343(sc, onoff); + else + uchcom_set_break(sc, onoff); break; } } @@ -908,16 +1007,20 @@ int uchcom_param(void *arg, int portno, struct termios *t) { struct uchcom_softc *sc = arg; + uint16_t val = 0; int ret; if (usbd_is_dying(sc->sc_udev)) return 0; - ret = uchcom_set_line_control(sc, t->c_cflag); + ret = uchcom_set_line_control(sc, t->c_cflag, &val); if (ret) return ret; - ret = uchcom_set_dte_rate(sc, t->c_ospeed); + if (sc->sc_type == UCHCOM_TYPE_CH343) + ret = uchcom_set_dte_rate_ch343(sc, t->c_ospeed, val); + else + ret = uchcom_set_dte_rate(sc, t->c_ospeed); if (ret) return ret; @@ -937,7 +1040,19 @@ uchcom_open(void *arg, int portno) if (ret) return ret; - ret = uchcom_setup_comm(sc); + ret = uchcom_update_version(sc); + if (ret) + return ret; + + if (sc->sc_type == UCHCOM_TYPE_CH343) + ret = uchcom_update_status(sc); + else + ret = uchcom_setup_comm(sc); + if (ret) + return ret; + + sc->sc_dtr = sc->sc_rts = 1; + ret = uchcom_set_dtrrts(sc, sc->sc_dtr, sc->sc_rts); if (ret) return ret; @@ -961,6 +1076,7 @@ uchcom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) { struct uchcom_softc *sc = priv; u_char *buf = sc->sc_intr_buf; + uint32_t intrstat; if (usbd_is_dying(sc->sc_udev)) return; @@ -982,6 +1098,9 @@ uchcom_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) (unsigned)buf[4], (unsigned)buf[5], (unsigned)buf[6], (unsigned)buf[7])); - uchcom_convert_status(sc, buf[UCHCOM_INTR_STAT1]); + intrstat = (sc->sc_type == UCHCOM_TYPE_CH343) ? + xfer->actlen - 1 : UCHCOM_INTR_STAT1; + + uchcom_convert_status(sc, buf[intrstat]); ucom_status_change((struct ucom_softc *) sc->sc_subdev); } diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index 188fba35a..8edc5a80e 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -1,4 +1,4 @@ -$OpenBSD: usbdevs,v 1.760 2023/11/27 20:03:50 miod Exp $ +$OpenBSD: usbdevs,v 1.761 2024/04/12 00:43:32 kevlo Exp $ /* $NetBSD: usbdevs,v 1.322 2003/05/10 17:47:14 hamajima Exp $ */ /* @@ -4652,6 +4652,7 @@ product WAVESENSE JAZZ 0xaaaa Jazz blood glucose meter /* WCH/QinHeng Electronics */ product WCH CH341 0x5523 CH341 serial/parallel product WCH2 CH341A 0x5523 CH341A serial/parallel +product WCH2 CH343 0x55d3 CH343 serial/parallel product WCH2 CH340 0x7523 CH340 serial/parallel product WCH2 TEMPER 0xe025 TEMPer sensor diff --git a/sys/dev/usb/usbdevs.h b/sys/dev/usb/usbdevs.h index 9a7e68f21..dc8ccc6c4 100644 --- a/sys/dev/usb/usbdevs.h +++ b/sys/dev/usb/usbdevs.h @@ -1,10 +1,10 @@ -/* $OpenBSD: usbdevs.h,v 1.772 2023/11/27 20:04:07 miod Exp $ */ +/* $OpenBSD: usbdevs.h,v 1.773 2024/04/12 00:44:07 kevlo Exp $ */ /* * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. * * generated from: - * OpenBSD: usbdevs,v 1.760 2023/11/27 20:03:50 miod Exp + * OpenBSD: usbdevs,v 1.761 2024/04/12 00:43:32 kevlo Exp */ /* $NetBSD: usbdevs,v 1.322 2003/05/10 17:47:14 hamajima Exp $ */ @@ -4659,6 +4659,7 @@ /* WCH/QinHeng Electronics */ #define USB_PRODUCT_WCH_CH341 0x5523 /* CH341 serial/parallel */ #define USB_PRODUCT_WCH2_CH341A 0x5523 /* CH341A serial/parallel */ +#define USB_PRODUCT_WCH2_CH343 0x55d3 /* CH343 serial/parallel */ #define USB_PRODUCT_WCH2_CH340 0x7523 /* CH340 serial/parallel */ #define USB_PRODUCT_WCH2_TEMPER 0xe025 /* TEMPer sensor */ diff --git a/sys/dev/usb/usbdevs_data.h b/sys/dev/usb/usbdevs_data.h index 3cf210c7e..4bc928785 100644 --- a/sys/dev/usb/usbdevs_data.h +++ b/sys/dev/usb/usbdevs_data.h @@ -1,10 +1,10 @@ -/* $OpenBSD: usbdevs_data.h,v 1.766 2023/11/27 20:04:07 miod Exp $ */ +/* $OpenBSD: usbdevs_data.h,v 1.767 2024/04/12 00:44:07 kevlo Exp $ */ /* * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. * * generated from: - * OpenBSD: usbdevs,v 1.760 2023/11/27 20:03:50 miod Exp + * OpenBSD: usbdevs,v 1.761 2024/04/12 00:43:32 kevlo Exp */ /* $NetBSD: usbdevs,v 1.322 2003/05/10 17:47:14 hamajima Exp $ */ @@ -11933,6 +11933,10 @@ const struct usb_known_product usb_known_products[] = { USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH341A, "CH341A serial/parallel", }, + { + USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH343, + "CH343 serial/parallel", + }, { USB_VENDOR_WCH2, USB_PRODUCT_WCH2_CH340, "CH340 serial/parallel", diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 16a9989e4..a9a65e649 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sysctl.c,v 1.426 2024/03/29 06:50:06 miod Exp $ */ +/* $OpenBSD: kern_sysctl.c,v 1.427 2024/04/12 16:07:09 bluhm Exp $ */ /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ /*- @@ -1482,6 +1482,12 @@ sysctl_file(int *name, u_int namelen, char *where, size_t *sizep, TAILQ_FOREACH(inp, &tcbtable.inpt_queue, inp_queue) FILLSO(inp->inp_socket); mtx_leave(&tcbtable.inpt_mtx); +#ifdef INET6 + mtx_enter(&tcb6table.inpt_mtx); + TAILQ_FOREACH(inp, &tcb6table.inpt_queue, inp_queue) + FILLSO(inp->inp_socket); + mtx_leave(&tcb6table.inpt_mtx); +#endif mtx_enter(&udbtable.inpt_mtx); TAILQ_FOREACH(inp, &udbtable.inpt_queue, inp_queue) FILLSO(inp->inp_socket); diff --git a/sys/net/pf.c b/sys/net/pf.c index f8e6f20bf..e0e31b754 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.1193 2024/01/10 16:44:30 bluhm Exp $ */ +/* $OpenBSD: pf.c,v 1.1194 2024/04/12 16:07:09 bluhm Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -3788,7 +3788,7 @@ pf_socket_lookup(struct pf_pdesc *pd) { struct pf_addr *saddr, *daddr; u_int16_t sport, dport; - struct inpcbtable *tb; + struct inpcbtable *table; struct inpcb *inp; pd->lookup.uid = -1; @@ -3800,14 +3800,14 @@ pf_socket_lookup(struct pf_pdesc *pd) dport = pd->hdr.tcp.th_dport; PF_ASSERT_LOCKED(); NET_ASSERT_LOCKED(); - tb = &tcbtable; + table = &tcbtable; break; case IPPROTO_UDP: sport = pd->hdr.udp.uh_sport; dport = pd->hdr.udp.uh_dport; PF_ASSERT_LOCKED(); NET_ASSERT_LOCKED(); - tb = &udbtable; + table = &udbtable; break; default: return (-1); @@ -3830,10 +3830,10 @@ pf_socket_lookup(struct pf_pdesc *pd) * Fails when rtable is changed while evaluating the ruleset * The socket looked up will not match the one hit in the end. */ - inp = in_pcblookup(tb, saddr->v4, sport, daddr->v4, dport, + inp = in_pcblookup(table, saddr->v4, sport, daddr->v4, dport, pd->rdomain); if (inp == NULL) { - inp = in_pcblookup_listen(tb, daddr->v4, dport, + inp = in_pcblookup_listen(table, daddr->v4, dport, NULL, pd->rdomain); if (inp == NULL) return (-1); @@ -3842,11 +3842,13 @@ pf_socket_lookup(struct pf_pdesc *pd) #ifdef INET6 case AF_INET6: if (pd->virtual_proto == IPPROTO_UDP) - tb = &udb6table; - inp = in6_pcblookup(tb, &saddr->v6, sport, &daddr->v6, + table = &udb6table; + if (pd->virtual_proto == IPPROTO_TCP) + table = &tcb6table; + inp = in6_pcblookup(table, &saddr->v6, sport, &daddr->v6, dport, pd->rdomain); if (inp == NULL) { - inp = in6_pcblookup_listen(tb, &daddr->v6, dport, + inp = in6_pcblookup_listen(table, &daddr->v6, dport, NULL, pd->rdomain); if (inp == NULL) return (-1); diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index b937c783d..7a79b6b4c 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.299 2024/03/31 15:53:12 bluhm Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.300 2024/04/12 16:07:09 bluhm Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -743,10 +743,8 @@ in_pcbnotifyall(struct inpcbtable *table, const struct sockaddr_in *dst, rw_enter_write(&table->inpt_notify); mtx_enter(&table->inpt_mtx); TAILQ_FOREACH(inp, &table->inpt_queue, inp_queue) { -#ifdef INET6 - if (ISSET(inp->inp_flags, INP_IPV6)) - continue; -#endif + KASSERT(!ISSET(inp->inp_flags, INP_IPV6)); + if (inp->inp_faddr.s_addr != dst->sin_addr.s_addr || rtable_l2(inp->inp_rtableid) != rdomain) { continue; @@ -852,8 +850,7 @@ in_pcblookup_local_lock(struct inpcbtable *table, const void *laddrp, wildcard = 0; #ifdef INET6 if (ISSET(flags, INPLOOKUP_IPV6)) { - if (!ISSET(inp->inp_flags, INP_IPV6)) - continue; + KASSERT(ISSET(inp->inp_flags, INP_IPV6)); if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) wildcard++; @@ -869,10 +866,7 @@ in_pcblookup_local_lock(struct inpcbtable *table, const void *laddrp, } else #endif /* INET6 */ { -#ifdef INET6 - if (ISSET(inp->inp_flags, INP_IPV6)) - continue; -#endif /* INET6 */ + KASSERT(!ISSET(inp->inp_flags, INP_IPV6)); if (inp->inp_faddr.s_addr != INADDR_ANY) wildcard++; @@ -1032,7 +1026,7 @@ in_pcbhash_insert(struct inpcb *inp) &inp->inp_faddr6, inp->inp_fport, &inp->inp_laddr6, inp->inp_lport); else -#endif /* INET6 */ +#endif hash = in_pcbhash(table, rtable_l2(inp->inp_rtableid), &inp->inp_faddr, inp->inp_fport, &inp->inp_laddr, inp->inp_lport); @@ -1052,10 +1046,8 @@ in_pcbhash_lookup(struct inpcbtable *table, uint64_t hash, u_int rdomain, head = &table->inpt_hashtbl[hash & table->inpt_mask]; LIST_FOREACH(inp, head, inp_hash) { -#ifdef INET6 - if (ISSET(inp->inp_flags, INP_IPV6)) - continue; -#endif + KASSERT(!ISSET(inp->inp_flags, INP_IPV6)); + if (inp->inp_fport == fport && inp->inp_lport == lport && inp->inp_faddr.s_addr == faddr->s_addr && inp->inp_laddr.s_addr == laddr->s_addr && diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 219e2898f..ea57cc31a 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -1,4 +1,4 @@ -/* $OpenBSD: raw_ip.c,v 1.157 2024/03/05 09:45:13 bluhm Exp $ */ +/* $OpenBSD: raw_ip.c,v 1.158 2024/04/12 12:25:58 bluhm Exp $ */ /* $NetBSD: raw_ip.c,v 1.25 1996/02/18 18:58:33 christos Exp $ */ /* @@ -172,7 +172,13 @@ rip_input(struct mbuf **mp, int *offp, int proto, int af) TAILQ_FOREACH(inp, &rawcbtable.inpt_queue, inp_queue) { KASSERT(!ISSET(inp->inp_flags, INP_IPV6)); - if (inp->inp_socket->so_rcv.sb_state & SS_CANTRCVMORE) + /* + * Packet must not be inserted after disconnected wakeup + * call. To avoid race, check again when holding receive + * buffer mutex. + */ + if (ISSET(READ_ONCE(inp->inp_socket->so_rcv.sb_state), + SS_CANTRCVMORE)) continue; if (rtable_l2(inp->inp_rtableid) != rtable_l2(m->m_pkthdr.ph_rtableid)) @@ -219,21 +225,24 @@ rip_input(struct mbuf **mp, int *offp, int proto, int af) n = m_copym(m, 0, M_COPYALL, M_NOWAIT); if (n != NULL) { struct socket *so = inp->inp_socket; - int ret; + int ret = 0; if (inp->inp_flags & INP_CONTROLOPTS || so->so_options & SO_TIMESTAMP) ip_savecontrol(inp, &opts, ip, n); mtx_enter(&so->so_rcv.sb_mtx); - ret = sbappendaddr(so, &so->so_rcv, - sintosa(&ripsrc), n, opts); + if (!ISSET(inp->inp_socket->so_rcv.sb_state, + SS_CANTRCVMORE)) { + ret = sbappendaddr(so, &so->so_rcv, + sintosa(&ripsrc), n, opts); + } mtx_leave(&so->so_rcv.sb_mtx); if (ret == 0) { - /* should notify about lost packet */ m_freem(n); m_freem(opts); + ipstat_inc(ips_noproto); } else sorwakeup(so); } diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 7bd9e07e3..9320e2401 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_input.c,v 1.402 2024/04/10 22:10:03 bluhm Exp $ */ +/* $OpenBSD: tcp_input.c,v 1.403 2024/04/12 16:07:09 bluhm Exp $ */ /* $NetBSD: tcp_input.c,v 1.23 1996/02/13 23:43:44 christos Exp $ */ /* @@ -140,7 +140,8 @@ struct timeval tcp_ackdrop_ppslim_last; #ifdef INET6 #define ND6_HINT(tp) \ do { \ - if (tp && tp->t_inpcb && (tp->t_inpcb->inp_flags & INP_IPV6) && \ + if (tp && tp->t_inpcb && \ + ISSET(tp->t_inpcb->inp_flags, INP_IPV6) && \ rtisvalid(tp->t_inpcb->inp_route.ro_rt)) { \ nd6_nud_hint(tp->t_inpcb->inp_route.ro_rt); \ } \ @@ -540,7 +541,7 @@ findpcb: switch (af) { #ifdef INET6 case AF_INET6: - inp = in6_pcblookup(&tcbtable, &ip6->ip6_src, + inp = in6_pcblookup(&tcb6table, &ip6->ip6_src, th->th_sport, &ip6->ip6_dst, th->th_dport, m->m_pkthdr.ph_rtableid); break; @@ -557,10 +558,10 @@ findpcb: switch (af) { #ifdef INET6 case AF_INET6: - inp = in6_pcblookup_listen(&tcbtable, &ip6->ip6_dst, + inp = in6_pcblookup_listen(&tcb6table, &ip6->ip6_dst, th->th_dport, m, m->m_pkthdr.ph_rtableid); break; -#endif /* INET6 */ +#endif case AF_INET: inp = in_pcblookup_listen(&tcbtable, ip->ip_dst, th->th_dport, m, m->m_pkthdr.ph_rtableid); @@ -3543,17 +3544,16 @@ syn_cache_get(struct sockaddr *src, struct sockaddr *dst, struct tcphdr *th, sizeof(oldinp->inp_seclevel)); #endif /* IPSEC */ #ifdef INET6 - /* - * inp still has the OLD in_pcb stuff, set the - * v6-related flags on the new guy, too. - */ - inp->inp_flags |= (oldinp->inp_flags & INP_IPV6); - if (inp->inp_flags & INP_IPV6) { + if (ISSET(inp->inp_flags, INP_IPV6)) { + KASSERT(ISSET(oldinp->inp_flags, INP_IPV6)); + inp->inp_ipv6.ip6_hlim = oldinp->inp_ipv6.ip6_hlim; inp->inp_hops = oldinp->inp_hops; } else -#endif /* INET6 */ +#endif { + KASSERT(!ISSET(oldinp->inp_flags, INP_IPV6)); + inp->inp_ip.ip_ttl = oldinp->inp_ip.ip_ttl; inp->inp_options = ip_srcroute(m); if (inp->inp_options == NULL) { diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index e8256d042..61cd51830 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_subr.c,v 1.199 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: tcp_subr.c,v 1.200 2024/04/12 16:07:09 bluhm Exp $ */ /* $NetBSD: tcp_subr.c,v 1.22 1996/02/13 23:44:00 christos Exp $ */ /* @@ -159,6 +159,9 @@ tcp_init(void) "sackhl", NULL); pool_sethardlimit(&sackhl_pool, tcp_sackhole_limit, NULL, 0); in_pcbinit(&tcbtable, TCB_INITIAL_HASH_SIZE); +#ifdef INET6 + in_pcbinit(&tcb6table, TCB_INITIAL_HASH_SIZE); +#endif tcpcounters = counters_alloc(tcps_ncounters); arc4random_buf(tcp_secret, sizeof(tcp_secret)); @@ -461,21 +464,15 @@ tcp_newtcpcb(struct inpcb *inp, int wait) tp->t_pmtud_mss_acked = 0; #ifdef INET6 - /* we disallow IPv4 mapped address completely. */ - if ((inp->inp_flags & INP_IPV6) == 0) - tp->pf = PF_INET; - else + if (ISSET(inp->inp_flags, INP_IPV6)) { tp->pf = PF_INET6; -#else - tp->pf = PF_INET; -#endif - -#ifdef INET6 - if (inp->inp_flags & INP_IPV6) inp->inp_ipv6.ip6_hlim = ip6_defhlim; - else -#endif /* INET6 */ + } else +#endif + { + tp->pf = PF_INET; inp->inp_ip.ip_ttl = ip_defttl; + } inp->inp_ppcb = (caddr_t)tp; return (tp); @@ -675,7 +672,7 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d) * corresponding to the address in the ICMPv6 message * payload. */ - inp = in6_pcblookup(&tcbtable, &sa6->sin6_addr, + inp = in6_pcblookup(&tcb6table, &sa6->sin6_addr, th.th_dport, &sa6_src->sin6_addr, th.th_sport, rdomain); if (cmd == PRC_MSGSIZE) { /* @@ -703,7 +700,7 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *d) rdomain); in_pcbunref(inp); } else { - in6_pcbnotify(&tcbtable, sa6, 0, + in6_pcbnotify(&tcb6table, sa6, 0, sa6_src, 0, rdomain, cmd, NULL, notify); } } @@ -845,7 +842,7 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, u_int rdomain, void *v) void tcp6_mtudisc_callback(struct sockaddr_in6 *sin6, u_int rdomain) { - in6_pcbnotify(&tcbtable, sin6, 0, + in6_pcbnotify(&tcb6table, sin6, 0, &sa6_any, 0, rdomain, PRC_MSGSIZE, NULL, tcp_mtudisc); } #endif /* INET6 */ diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 48c694a0f..7704890af 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_usrreq.c,v 1.230 2024/02/11 01:27:45 bluhm Exp $ */ +/* $OpenBSD: tcp_usrreq.c,v 1.231 2024/04/12 16:07:09 bluhm Exp $ */ /* $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */ /* @@ -171,6 +171,9 @@ const struct sysctl_bounded_args tcpctl_vars[] = { }; struct inpcbtable tcbtable; +#ifdef INET6 +struct inpcbtable tcb6table; +#endif int tcp_fill_info(struct tcpcb *, struct socket *, struct mbuf *); int tcp_ident(void *, size_t *, void *, size_t, int); @@ -317,7 +320,7 @@ tcp_ctloutput(int op, struct socket *so, int level, int optname, if (ISSET(inp->inp_flags, INP_IPV6)) error = ip6_ctloutput(op, so, level, optname, m); else -#endif /* INET6 */ +#endif error = ip_ctloutput(op, so, level, optname, m); return (error); } @@ -452,6 +455,7 @@ tcp_ctloutput(int op, struct socket *so, int level, int optname, int tcp_attach(struct socket *so, int proto, int wait) { + struct inpcbtable *table; struct tcpcb *tp; struct inpcb *inp; int error; @@ -467,7 +471,13 @@ tcp_attach(struct socket *so, int proto, int wait) } NET_ASSERT_LOCKED(); - error = in_pcballoc(so, &tcbtable, wait); +#ifdef INET6 + if (so->so_proto->pr_domain->dom_family == PF_INET6) + table = &tcb6table; + else +#endif + table = &tcbtable; + error = in_pcballoc(so, table, wait); if (error) return (error); inp = sotoinpcb(so); @@ -482,14 +492,11 @@ tcp_attach(struct socket *so, int proto, int wait) } tp->t_state = TCPS_CLOSED; #ifdef INET6 - /* we disallow IPv4 mapped address completely. */ - if (inp->inp_flags & INP_IPV6) + if (ISSET(inp->inp_flags, INP_IPV6)) tp->pf = PF_INET6; else - tp->pf = PF_INET; -#else - tp->pf = PF_INET; #endif + tp->pf = PF_INET; if ((so->so_options & SO_LINGER) && so->so_linger == 0) so->so_linger = TCP_LINGERTIME; @@ -619,7 +626,7 @@ tcp_connect(struct socket *so, struct mbuf *nam) } #ifdef INET6 - if (inp->inp_flags & INP_IPV6) { + if (ISSET(inp->inp_flags, INP_IPV6)) { struct sockaddr_in6 *sin6; if ((error = in6_nam2sin6(nam, &sin6))) @@ -630,7 +637,7 @@ tcp_connect(struct socket *so, struct mbuf *nam) goto out; } } else -#endif /* INET6 */ +#endif { struct sockaddr_in *sin; @@ -1148,7 +1155,7 @@ tcp_ident(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int dodrop) switch (tir.faddr.ss_family) { #ifdef INET6 case AF_INET6: - inp = in6_pcblookup(&tcbtable, &f6, + inp = in6_pcblookup(&tcb6table, &f6, fin6->sin6_port, &l6, lin6->sin6_port, tir.rdomain); break; #endif @@ -1175,7 +1182,7 @@ tcp_ident(void *oldp, size_t *oldlenp, void *newp, size_t newlen, int dodrop) switch (tir.faddr.ss_family) { #ifdef INET6 case AF_INET6: - inp = in6_pcblookup_listen(&tcbtable, + inp = in6_pcblookup_listen(&tcb6table, &l6, lin6->sin6_port, NULL, tir.rdomain); break; #endif diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index f96f39eef..3d75cf84c 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tcp_var.h,v 1.176 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: tcp_var.h,v 1.177 2024/04/12 16:07:09 bluhm Exp $ */ /* $NetBSD: tcp_var.h,v 1.17 1996/02/13 23:44:24 christos Exp $ */ /* @@ -676,7 +676,7 @@ extern const struct pr_usrreqs tcp6_usrreqs; #endif extern struct pool tcpcb_pool; -extern struct inpcbtable tcbtable; /* head of queue of active tcpcb's */ +extern struct inpcbtable tcbtable, tcb6table; /* queue of active tcpcb's */ extern int tcp_do_rfc1323; /* enabled/disabled? */ extern int tcptv_keep_init; /* [N] time to keep alive initial SYN packet */ extern int tcp_mssdflt; /* default maximum segment size */ diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 65f6a745d..0a9c1afb5 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udp_usrreq.c,v 1.318 2024/02/11 18:14:26 mvs Exp $ */ +/* $OpenBSD: udp_usrreq.c,v 1.319 2024/04/12 16:07:09 bluhm Exp $ */ /* $NetBSD: udp_usrreq.c,v 1.28 1996/03/16 23:54:03 christos Exp $ */ /* @@ -1117,10 +1117,10 @@ udp_attach(struct socket *so, int proto, int wait) if ((error = in_pcballoc(so, table, wait))) return error; #ifdef INET6 - if (sotoinpcb(so)->inp_flags & INP_IPV6) + if (ISSET(sotoinpcb(so)->inp_flags, INP_IPV6)) sotoinpcb(so)->inp_ipv6.ip6_hlim = ip6_defhlim; else -#endif /* INET6 */ +#endif sotoinpcb(so)->inp_ip.ip_ttl = ip_defttl; return 0; } @@ -1184,11 +1184,11 @@ udp_connect(struct socket *so, struct mbuf *addr) soassertlocked(so); #ifdef INET6 - if (inp->inp_flags & INP_IPV6) { + if (ISSET(inp->inp_flags, INP_IPV6)) { if (!IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) return (EISCONN); } else -#endif /* INET6 */ +#endif { if (inp->inp_faddr.s_addr != INADDR_ANY) return (EISCONN); @@ -1209,11 +1209,11 @@ udp_disconnect(struct socket *so) soassertlocked(so); #ifdef INET6 - if (inp->inp_flags & INP_IPV6) { + if (ISSET(inp->inp_flags, INP_IPV6)) { if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) return (ENOTCONN); } else -#endif /* INET6 */ +#endif { if (inp->inp_faddr.s_addr == INADDR_ANY) return (ENOTCONN); @@ -1251,7 +1251,7 @@ udp_send(struct socket *so, struct mbuf *m, struct mbuf *addr, mtod(addr, struct sockaddr *)); else #ifdef INET6 - if (inp->inp_flags & INP_IPV6) + if (ISSET(inp->inp_flags, INP_IPV6)) session = pipex_l2tp_userland_lookup_session_ipv6( m, inp->inp_faddr6); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index edace547c..0e6ab9fb5 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_pcb.c,v 1.143 2024/03/31 15:53:12 bluhm Exp $ */ +/* $OpenBSD: in6_pcb.c,v 1.144 2024/04/12 16:07:09 bluhm Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -479,8 +479,7 @@ in6_pcbnotify(struct inpcbtable *table, const struct sockaddr_in6 *dst, rw_enter_write(&table->inpt_notify); mtx_enter(&table->inpt_mtx); TAILQ_FOREACH(inp, &table->inpt_queue, inp_queue) { - if (!ISSET(inp->inp_flags, INP_IPV6)) - continue; + KASSERT(ISSET(inp->inp_flags, INP_IPV6)); /* * Under the following condition, notify of redirects @@ -580,8 +579,8 @@ in6_pcbhash_lookup(struct inpcbtable *table, uint64_t hash, u_int rdomain, head = &table->inpt_hashtbl[hash & table->inpt_mask]; LIST_FOREACH(inp, head, inp_hash) { - if (!ISSET(inp->inp_flags, INP_IPV6)) - continue; + KASSERT(ISSET(inp->inp_flags, INP_IPV6)); + if (inp->inp_fport == fport && inp->inp_lport == lport && IN6_ARE_ADDR_EQUAL(&inp->inp_faddr6, faddr) && IN6_ARE_ADDR_EQUAL(&inp->inp_laddr6, laddr) && diff --git a/usr.sbin/nsd/Makefile.in b/usr.sbin/nsd/Makefile.in index 4f7f32f5f..6b716a42a 100644 --- a/usr.sbin/nsd/Makefile.in +++ b/usr.sbin/nsd/Makefile.in @@ -18,10 +18,8 @@ datarootdir = @datarootdir@ # NSD specific pathnames configdir = @configdir@ piddir = @piddir@ -dbdir = @dbdir@ pidfile = @pidfile@ logfile = @logfile@ -dbfile = @dbfile@ xfrdir = @xfrdir@ xfrdfile = @xfrdfile@ zonelistfile = @zonelistfile@ @@ -66,7 +64,6 @@ EDIT = $(SED) \ -e 's,@chrootdir\@,$(chrootdir),g' \ -e 's,@pidfile\@,$(pidfile),g' \ -e 's,@logfile\@,$(logfile),g' \ - -e 's,@dbfile\@,$(dbfile),g' \ -e 's,@xfrdir\@,$(xfrdir),g' \ -e 's,@xfrdfile\@,$(xfrdfile),g' \ -e 's,@zonelistfile\@,$(zonelistfile),g' \ @@ -80,7 +77,7 @@ TARGETS=nsd nsd-checkconf nsd-checkzone nsd-control nsd.conf.sample nsd-control- MANUALS=nsd.8 nsd-checkconf.8 nsd-checkzone.8 nsd-control.8 nsd.conf.5 COMMON_OBJ=answer.o axfr.o ixfr.o ixfrcreate.o buffer.o configlexer.o configparser.o dname.o dns.o edns.o iterated_hash.o lookup3.o namedb.o nsec3.o options.o packet.o query.o rbtree.o radtree.o rdata.o region-allocator.o rrl.o siphash.o tsig.o tsig-openssl.o udb.o util.o bitset.o popen3.o proxy_protocol.o -XFRD_OBJ=xfrd-disk.o xfrd-notify.o xfrd-tcp.o xfrd.o remote.o $(DNSTAP_OBJ) +XFRD_OBJ=xfrd-catalog-zones.o xfrd-disk.o xfrd-notify.o xfrd-tcp.o xfrd.o remote.o $(DNSTAP_OBJ) NSD_OBJ=$(COMMON_OBJ) $(XFRD_OBJ) difffile.o ipc.o mini_event.o netio.o nsd.o server.o dbaccess.o dbcreate.o zlexer.o zonec.o zparser.o verify.o ALL_OBJ=$(NSD_OBJ) nsd-checkconf.o nsd-checkzone.o nsd-control.o nsd-mem.o xfr-inspect.o NSD_CHECKCONF_OBJ=$(COMMON_OBJ) nsd-checkconf.o @@ -129,7 +126,8 @@ orig-install: all $(INSTALL) -d $(DESTDIR)$(configdir) if test -n "$(piddir)"; then $(INSTALL) -d $(DESTDIR)$(piddir); fi $(INSTALL) -d $(DESTDIR)$(xfrdir) - $(INSTALL) -d $(DESTDIR)$(dbdir) + $(INSTALL) -d `dirname $(DESTDIR)$(xfrdfile)` + $(INSTALL) -d `dirname $(DESTDIR)$(zonelistfile)` $(INSTALL) -d $(DESTDIR)$(mandir) $(INSTALL) -d $(DESTDIR)$(mandir)/man8 $(INSTALL) -d $(DESTDIR)$(mandir)/man5 @@ -152,7 +150,7 @@ uninstall: rm -f -- $(DESTDIR)$(mandir)/man8/nsd-checkconf.8 $(DESTDIR)$(mandir)/man8/nsd-checkzone.8 $(DESTDIR)$(mandir)/man8/nsd-control.8 rm -f -- $(DESTDIR)$(pidfile) @echo - @echo "You still need to remove $(DESTDIR)$(configdir), $(DESTDIR)$(piddir), $(DESTDIR)$(dbfile) directory by hand." + @echo "You still need to remove $(DESTDIR)$(configdir), $(DESTDIR)$(piddir), $(DESTDIR)$(xfrdfile), $(DESTDIR)$(zonelistfile) directory by hand." test: @@ -435,15 +433,15 @@ configparser.o: configparser.c config.h $(srcdir)/options.h \ $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h configparser.h dbaccess.o: $(srcdir)/dbaccess.c config.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/options.h $(srcdir)/rdata.h \ - $(srcdir)/udb.h $(srcdir)/zonec.h $(srcdir)/nsec3.h $(srcdir)/difffile.h $(srcdir)/nsd.h $(srcdir)/edns.h \ - $(srcdir)/bitset.h $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/ixfrcreate.h + $(srcdir)/udb.h $(srcdir)/zonec.h $(srcdir)/nsec3.h $(srcdir)/difffile.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/ixfr.h $(srcdir)/query.h \ + $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/ixfrcreate.h dbcreate.o: $(srcdir)/dbcreate.c config.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h \ - $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/udb.h \ - $(srcdir)/options.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/packet.h $(srcdir)/tsig.h + $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/udb.h $(srcdir)/options.h $(srcdir)/nsd.h \ + $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/ixfr.h $(srcdir)/query.h $(srcdir)/packet.h $(srcdir)/tsig.h difffile.o: $(srcdir)/difffile.c config.h $(srcdir)/difffile.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \ - $(srcdir)/options.h $(srcdir)/udb.h $(srcdir)/xfrd-disk.h $(srcdir)/packet.h $(srcdir)/rdata.h \ - $(srcdir)/nsec3.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/tsig.h $(srcdir)/ixfr.h $(srcdir)/zonec.h + $(srcdir)/options.h $(srcdir)/udb.h $(srcdir)/xfrd-disk.h $(srcdir)/packet.h $(srcdir)/rdata.h $(srcdir)/nsec3.h $(srcdir)/nsd.h $(srcdir)/edns.h \ + $(srcdir)/bitset.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/tsig.h $(srcdir)/ixfr.h $(srcdir)/zonec.h $(srcdir)/xfrd-catalog-zones.h $(srcdir)/xfrd.h dname.o: $(srcdir)/dname.c config.h $(srcdir)/dns.h $(srcdir)/dname.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h \ $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h @@ -472,8 +470,7 @@ netio.o: $(srcdir)/netio.c config.h $(srcdir)/netio.h $(srcdir)/region-allocator $(srcdir)/util.h nsd.o: $(srcdir)/nsd.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/tsig.h $(srcdir)/dname.h \ - $(srcdir)/remote.h $(srcdir)/xfrd-disk.h $(srcdir)/dnstap/dnstap_collector.h $(srcdir)/util/proxy_protocol.h \ - config.h + $(srcdir)/remote.h $(srcdir)/xfrd-disk.h $(srcdir)/ipc.h $(srcdir)/netio.h $(srcdir)/util/proxy_protocol.h config.h nsd-checkconf.o: $(srcdir)/nsd-checkconf.c config.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/options.h $(srcdir)/rbtree.h $(srcdir)/rrl.h $(srcdir)/query.h \ $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h @@ -486,15 +483,15 @@ nsd-control.o: $(srcdir)/nsd-control.c config.h $(srcdir)/util.h $(srcdir)/tsig. $(srcdir)/dns.h $(srcdir)/radtree.h nsd-mem.o: $(srcdir)/nsd-mem.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/tsig.h $(srcdir)/dname.h $(srcdir)/options.h $(srcdir)/rbtree.h \ - $(srcdir)/namedb.h $(srcdir)/radtree.h + $(srcdir)/namedb.h $(srcdir)/radtree.h $(srcdir)/difffile.h $(srcdir)/udb.h nsec3.o: $(srcdir)/nsec3.c config.h $(srcdir)/nsec3.h $(srcdir)/iterated_hash.h \ $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \ $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/answer.h $(srcdir)/packet.h $(srcdir)/query.h $(srcdir)/tsig.h \ - $(srcdir)/udb.h $(srcdir)/options.h + $(srcdir)/options.h options.o: $(srcdir)/options.c config.h $(srcdir)/options.h \ $(srcdir)/region-allocator.h $(srcdir)/rbtree.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h \ $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/ixfr.h $(srcdir)/difffile.h \ - $(srcdir)/udb.h $(srcdir)/rrl.h configparser.h + $(srcdir)/udb.h $(srcdir)/rrl.h $(srcdir)/xfrd.h configparser.h packet.o: $(srcdir)/packet.c config.h $(srcdir)/packet.h $(srcdir)/dns.h $(srcdir)/namedb.h \ $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/query.h \ $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/tsig.h $(srcdir)/rdata.h @@ -511,8 +508,8 @@ region-allocator.o: $(srcdir)/region-allocator.c config.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h remote.o: $(srcdir)/remote.c config.h $(srcdir)/remote.h $(srcdir)/util.h $(srcdir)/xfrd.h \ $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/dns.h $(srcdir)/radtree.h \ - $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/xfrd-notify.h $(srcdir)/xfrd-tcp.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h \ - $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h $(srcdir)/netio.h + $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/xfrd-catalog-zones.h $(srcdir)/xfrd-notify.h $(srcdir)/xfrd-tcp.h $(srcdir)/nsd.h \ + $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h $(srcdir)/netio.h rrl.o: $(srcdir)/rrl.c config.h $(srcdir)/rrl.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/lookup3.h $(srcdir)/options.h @@ -520,15 +517,14 @@ server.o: $(srcdir)/server.c config.h $(srcdir)/axfr.h $(srcdir)/nsd.h $(srcdir) $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/query.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/packet.h $(srcdir)/tsig.h $(srcdir)/netio.h $(srcdir)/xfrd.h $(srcdir)/options.h $(srcdir)/xfrd-tcp.h \ $(srcdir)/xfrd-disk.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/nsec3.h $(srcdir)/ipc.h $(srcdir)/remote.h $(srcdir)/lookup3.h $(srcdir)/rrl.h \ - $(srcdir)/ixfr.h $(srcdir)/dnstap/dnstap_collector.h $(srcdir)/verify.h $(srcdir)/util/proxy_protocol.h config.h + $(srcdir)/ixfr.h $(srcdir)/verify.h $(srcdir)/util/proxy_protocol.h config.h siphash.o: $(srcdir)/siphash.c tsig.o: $(srcdir)/tsig.c config.h $(srcdir)/tsig.h $(srcdir)/buffer.h \ $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/tsig-openssl.h $(srcdir)/dns.h $(srcdir)/packet.h $(srcdir)/namedb.h \ $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/query.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h tsig-openssl.o: $(srcdir)/tsig-openssl.c config.h $(srcdir)/tsig-openssl.h \ $(srcdir)/region-allocator.h $(srcdir)/tsig.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dname.h -udb.o: $(srcdir)/udb.c config.h $(srcdir)/udb.h $(srcdir)/lookup3.h $(srcdir)/util.h \ - $(srcdir)/radtree.h +udb.o: $(srcdir)/udb.c config.h $(srcdir)/udb.h $(srcdir)/lookup3.h $(srcdir)/util.h util.o: $(srcdir)/util.c config.h $(srcdir)/util.h $(srcdir)/region-allocator.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/zonec.h $(srcdir)/nsd.h $(srcdir)/edns.h \ $(srcdir)/bitset.h @@ -537,9 +533,13 @@ verify.o: $(srcdir)/verify.c config.h $(srcdir)/region-allocator.h $(srcdir)/nam $(srcdir)/options.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/verify.h $(srcdir)/popen3.h xfrd.o: $(srcdir)/xfrd.c config.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h \ $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h \ - $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd-disk.h $(srcdir)/xfrd-notify.h $(srcdir)/netio.h $(srcdir)/nsd.h \ - $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/rdata.h $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h $(srcdir)/remote.h $(srcdir)/rrl.h \ - $(srcdir)/query.h $(srcdir)/dnstap/dnstap_collector.h + $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd-disk.h $(srcdir)/xfrd-notify.h \ + $(srcdir)/xfrd-catalog-zones.h $(srcdir)/netio.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h $(srcdir)/rdata.h \ + $(srcdir)/difffile.h $(srcdir)/udb.h $(srcdir)/ipc.h $(srcdir)/remote.h $(srcdir)/rrl.h $(srcdir)/query.h +xfrd-catalog-zones.o: $(srcdir)/xfrd-catalog-zones.c config.h \ + $(srcdir)/difffile.h $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h \ + $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/udb.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h $(srcdir)/packet.h \ + $(srcdir)/xfrd-catalog-zones.h $(srcdir)/xfrd.h $(srcdir)/tsig.h $(srcdir)/xfrd-notify.h xfrd-disk.o: $(srcdir)/xfrd-disk.c config.h $(srcdir)/xfrd-disk.h $(srcdir)/xfrd.h \ $(srcdir)/rbtree.h $(srcdir)/region-allocator.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h \ $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h @@ -549,20 +549,20 @@ xfrd-notify.o: $(srcdir)/xfrd-notify.c config.h $(srcdir)/xfrd-notify.h \ xfrd-tcp.o: $(srcdir)/xfrd-tcp.c config.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/bitset.h $(srcdir)/xfrd-tcp.h $(srcdir)/xfrd.h $(srcdir)/rbtree.h \ $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/options.h $(srcdir)/tsig.h $(srcdir)/packet.h $(srcdir)/xfrd-disk.h -xfr-inspect.o: $(srcdir)/xfr-inspect.c config.h $(srcdir)/udb.h \ - $(srcdir)/dns.h $(srcdir)/util.h $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/packet.h $(srcdir)/namedb.h \ - $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h $(srcdir)/difffile.h $(srcdir)/options.h +xfr-inspect.o: $(srcdir)/xfr-inspect.c config.h $(srcdir)/util.h $(srcdir)/buffer.h \ + $(srcdir)/region-allocator.h $(srcdir)/packet.h $(srcdir)/dns.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/radtree.h $(srcdir)/rbtree.h \ + $(srcdir)/rdata.h $(srcdir)/difffile.h $(srcdir)/options.h $(srcdir)/udb.h zlexer.o: zlexer.c config.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h zparser.h zonec.o: $(srcdir)/zonec.c config.h $(srcdir)/zonec.h $(srcdir)/namedb.h $(srcdir)/dname.h \ $(srcdir)/buffer.h $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/rdata.h \ zparser.h $(srcdir)/options.h $(srcdir)/nsec3.h zparser.o: zparser.c config.h $(srcdir)/dname.h $(srcdir)/buffer.h \ - $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/zonec.h + $(srcdir)/region-allocator.h $(srcdir)/util.h $(srcdir)/namedb.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/rbtree.h $(srcdir)/zonec.h \ + zparser.h b64_ntop.o: $(srcdir)/compat/b64_ntop.c config.h b64_pton.o: $(srcdir)/compat/b64_pton.c config.h basename.o: $(srcdir)/compat/basename.c -cpuset.o: $(srcdir)/compat/cpuset.c config.h explicit_bzero.o: $(srcdir)/compat/explicit_bzero.c config.h fake-rfc2553.o: $(srcdir)/compat/fake-rfc2553.c $(srcdir)/compat/fake-rfc2553.h config.h inet_aton.o: $(srcdir)/compat/inet_aton.c config.h @@ -599,8 +599,7 @@ cutest_iter.o: $(srcdir)/tpkg/cutest/cutest_iter.c config.h $(srcdir)/nsd.h \ cutest_namedb.o: $(srcdir)/tpkg/cutest/cutest_namedb.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/options.h $(srcdir)/region-allocator.h \ $(srcdir)/rbtree.h $(srcdir)/namedb.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/dns.h $(srcdir)/radtree.h $(srcdir)/nsec3.h $(srcdir)/udb.h \ - $(srcdir)/udb.h $(srcdir)/difffile.h $(srcdir)/namedb.h $(srcdir)/options.h $(srcdir)/zonec.h $(srcdir)/nsd.h \ - $(srcdir)/edns.h $(srcdir)/bitset.h + $(srcdir)/difffile.h $(srcdir)/namedb.h $(srcdir)/options.h $(srcdir)/udb.h $(srcdir)/zonec.h $(srcdir)/nsd.h $(srcdir)/edns.h $(srcdir)/bitset.h cutest_options.o: $(srcdir)/tpkg/cutest/cutest_options.c config.h \ $(srcdir)/tpkg/cutest/cutest.h $(srcdir)/region-allocator.h $(srcdir)/options.h $(srcdir)/region-allocator.h \ $(srcdir)/rbtree.h $(srcdir)/util.h $(srcdir)/dname.h $(srcdir)/buffer.h $(srcdir)/util.h $(srcdir)/nsd.h $(srcdir)/dns.h $(srcdir)/edns.h $(srcdir)/bitset.h diff --git a/usr.sbin/nsd/acx_nlnetlabs.m4 b/usr.sbin/nsd/acx_nlnetlabs.m4 index 54d32907b..6a01dc5a4 100644 --- a/usr.sbin/nsd/acx_nlnetlabs.m4 +++ b/usr.sbin/nsd/acx_nlnetlabs.m4 @@ -1,8 +1,11 @@ # acx_nlnetlabs.m4 - common macros for configure checks -# Copyright 2009, Wouter Wijngaards, NLnet Labs. +# Copyright 2009, Wouter Wijngaards, NLnet Labs. # BSD licensed. # -# Version 46 +# Version 48 +# 2024-01-16 fix to add -l:libssp.a to -lcrypto link check. +# and check for getaddrinfo with only header. +# 2024-01-15 fix to add crypt32 to -lcrypto link check when checking for gdi32. # 2023-05-04 fix to remove unused whitespace. # 2023-01-26 fix -Wstrict-prototypes. # 2022-09-01 fix checking if nonblocking sockets work on OpenBSD. @@ -121,7 +124,7 @@ dnl Escape backslashes as \\, for C:\ paths, for the C preprocessor defines. dnl for example, ACX_ESCAPE_BACKSLASH($from_var, to_var) -dnl $1: the text to change. +dnl $1: the text to change. dnl $2: the result. AC_DEFUN([ACX_ESCAPE_BACKSLASH], [$2="`echo $1 | sed -e 's/\\\\/\\\\\\\\/g'`" ]) @@ -129,7 +132,7 @@ AC_DEFUN([ACX_ESCAPE_BACKSLASH], [$2="`echo $1 | sed -e 's/\\\\/\\\\\\\\/g'`" dnl Calculate comma separated windows-resource numbers from package version. dnl Picks the first three(,0) or four numbers out of the name. dnl $1: variable for the result -AC_DEFUN([ACX_RSRC_VERSION], +AC_DEFUN([ACX_RSRC_VERSION], [$1=[`echo $PACKAGE_VERSION | sed -e 's/^[^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\).*$/\1,\2,\3,\4/' -e 's/^[^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9][^0-9]*\([0-9][0-9]*\)[^0-9]*$/\1,\2,\3,0/' `] ]) @@ -138,7 +141,7 @@ dnl Checks if the compiler will accept the flag. dnl $1: the flag without a - in front, so g to check -g. dnl $2: executed if yes dnl $3: executed if no -AC_DEFUN([ACX_CHECK_COMPILER_FLAG], +AC_DEFUN([ACX_CHECK_COMPILER_FLAG], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(whether $CC supports -$1) @@ -238,12 +241,12 @@ AC_MSG_CHECKING([$CC dependency flag]) echo 'void f(void){}' >conftest.c if test "`$CC -MM conftest.c 2>&1`" = "conftest.o: conftest.c"; then DEPFLAG="-MM" -else +else if test "`$CC -xM1 conftest.c 2>&1`" = "conftest.o: conftest.c"; then DEPFLAG="-xM1" else DEPFLAG="-MM" # dunno do something - fi + fi fi AC_MSG_RESULT($DEPFLAG) rm -f conftest.c @@ -453,7 +456,7 @@ AC_DEFUN([ACX_CHECK_FLTO], [ ]) dnl Check the printf-format attribute (if any) -dnl result in HAVE_ATTR_FORMAT. +dnl result in HAVE_ATTR_FORMAT. dnl Make sure you also include the AHX_CONFIG_FORMAT_ATTRIBUTE. AC_DEFUN([ACX_CHECK_FORMAT_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) @@ -487,7 +490,7 @@ AC_DEFUN([AHX_CONFIG_FORMAT_ATTRIBUTE], ]) dnl Check how to mark function arguments as unused. -dnl result in HAVE_ATTR_UNUSED. +dnl result in HAVE_ATTR_UNUSED. dnl Make sure you include AHX_CONFIG_UNUSED_ATTRIBUTE also. AC_DEFUN([ACX_CHECK_UNUSED_ATTRIBUTE], [AC_REQUIRE([AC_PROG_CC]) @@ -559,7 +562,7 @@ LT_INIT ]) dnl Detect if u_char type is defined, otherwise define it. -AC_DEFUN([ACX_TYPE_U_CHAR], +AC_DEFUN([ACX_TYPE_U_CHAR], [AC_CHECK_TYPE([u_char], , [AC_DEFINE([u_char], [unsigned char], [Define to 'unsigned char if not defined])], [ AC_INCLUDES_DEFAULT @@ -570,7 +573,7 @@ AC_INCLUDES_DEFAULT dnl Detect if rlim_t type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_RLIM_T], -[AC_CHECK_TYPE(rlim_t, , +[AC_CHECK_TYPE(rlim_t, , [AC_DEFINE([rlim_t], [unsigned long], [Define to 'int' if not defined])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_RESOURCE_H @@ -581,7 +584,7 @@ AC_INCLUDES_DEFAULT dnl Detect if socklen_t type is defined, otherwise define it. AC_DEFUN([ACX_TYPE_SOCKLEN_T], [ -AC_CHECK_TYPE(socklen_t, , +AC_CHECK_TYPE(socklen_t, , [AC_DEFINE([socklen_t], [int], [Define to 'int' if not defined])], [ AC_INCLUDES_DEFAULT #ifdef HAVE_SYS_SOCKET_H @@ -720,7 +723,7 @@ AC_DEFUN([ACX_SSL_CHECKS], [ [If you have EVP_sha256]) ],[ AC_MSG_RESULT(no) - # check if -lwsock32 or -lgdi32 are needed. + # check if -lwsock32 or -lgdi32 are needed. BAKLIBS="$LIBS" BAKSSLLIBS="$LIBSSL_LIBS" LIBS="$LIBS -lgdi32 -lws2_32" @@ -737,35 +740,68 @@ AC_DEFUN([ACX_SSL_CHECKS], [ AC_MSG_RESULT(no) LIBS="$BAKLIBS" LIBSSL_LIBS="$BAKSSLLIBS" - LIBS="$LIBS -ldl" - LIBSSL_LIBS="$LIBSSL_LIBS -ldl" - AC_MSG_CHECKING([if -lcrypto needs -ldl]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ - int EVP_sha256(void); - (void)EVP_sha256(); - ]])],[ - AC_DEFINE([HAVE_EVP_SHA256], 1, - [If you have EVP_sha256]) - AC_MSG_RESULT(yes) - ],[ - AC_MSG_RESULT(no) - LIBS="$BAKLIBS" - LIBSSL_LIBS="$BAKSSLLIBS" - LIBS="$LIBS -ldl -pthread" - LIBSSL_LIBS="$LIBSSL_LIBS -ldl -pthread" - AC_MSG_CHECKING([if -lcrypto needs -ldl -pthread]) - AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ - int EVP_sha256(void); - (void)EVP_sha256(); - ]])],[ - AC_DEFINE([HAVE_EVP_SHA256], 1, - [If you have EVP_sha256]) - AC_MSG_RESULT(yes) - ],[ - AC_MSG_RESULT(no) - AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required]) + + LIBS="$LIBS -lgdi32 -lws2_32 -lcrypt32" + LIBSSL_LIBS="$LIBSSL_LIBS -lgdi32 -lws2_32 -lcrypt32" + AC_MSG_CHECKING([if -lcrypto needs -lgdi32 -lws2_32 -lcrypt32]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ + int EVP_sha256(void); + (void)EVP_sha256(); + ]])],[ + AC_DEFINE([HAVE_EVP_SHA256], 1, + [If you have EVP_sha256]) + AC_MSG_RESULT(yes) + ],[ + AC_MSG_RESULT(no) + LIBS="$BAKLIBS" + LIBSSL_LIBS="$BAKSSLLIBS" + + LIBS="$LIBS -lgdi32 -lws2_32 -lcrypt32 -l:libssp.a" + LIBSSL_LIBS="$LIBSSL_LIBS -lgdi32 -lws2_32 -lcrypt32 -l:libssp.a" + AC_MSG_CHECKING([if -lcrypto needs -lgdi32 -lws2_32 -lcrypt32 -l:libssp.a]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ + int EVP_sha256(void); + (void)EVP_sha256(); + ]])],[ + AC_DEFINE([HAVE_EVP_SHA256], 1, + [If you have EVP_sha256]) + AC_MSG_RESULT(yes) + ],[ + AC_MSG_RESULT(no) + LIBS="$BAKLIBS" + LIBSSL_LIBS="$BAKSSLLIBS" + + LIBS="$LIBS -ldl" + LIBSSL_LIBS="$LIBSSL_LIBS -ldl" + AC_MSG_CHECKING([if -lcrypto needs -ldl]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ + int EVP_sha256(void); + (void)EVP_sha256(); + ]])],[ + AC_DEFINE([HAVE_EVP_SHA256], 1, + [If you have EVP_sha256]) + AC_MSG_RESULT(yes) + ],[ + AC_MSG_RESULT(no) + LIBS="$BAKLIBS" + LIBSSL_LIBS="$BAKSSLLIBS" + LIBS="$LIBS -ldl -pthread" + LIBSSL_LIBS="$LIBSSL_LIBS -ldl -pthread" + AC_MSG_CHECKING([if -lcrypto needs -ldl -pthread]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ + int EVP_sha256(void); + (void)EVP_sha256(); + ]])],[ + AC_DEFINE([HAVE_EVP_SHA256], 1, + [If you have EVP_sha256]) + AC_MSG_RESULT(yes) + ],[ + AC_MSG_RESULT(no) + AC_MSG_ERROR([OpenSSL found in $ssldir, but version 0.9.7 or higher is required]) + ]) + ]) ]) - ]) + ]) ]) ]) fi @@ -797,7 +833,7 @@ AC_ARG_WITH(ssl, AS_HELP_STRING([--with-ssl=pathname],[enable SSL (will check /u dnl Check for SSL, where ssl is optional (--without-ssl is allowed) dnl Adds --with-ssl option, searches for openssl and defines HAVE_SSL if found -dnl Setup of CPPFLAGS, CFLAGS. Adds -lcrypto to LIBS. +dnl Setup of CPPFLAGS, CFLAGS. Adds -lcrypto to LIBS. dnl Checks main header files of SSL. dnl AC_DEFUN([ACX_WITH_SSL_OPTIONAL], @@ -872,7 +908,7 @@ dnl see if on windows if test "$ac_cv_header_windows_h" = "yes"; then AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) USE_WINSOCK="1" - if echo $LIBS | grep 'lws2_32' >/dev/null; then + if echo "$LIBS" | grep 'lws2_32' >/dev/null; then : else LIBS="$LIBS -lws2_32" @@ -880,6 +916,24 @@ if test "$ac_cv_header_windows_h" = "yes"; then fi ], dnl no quick getaddrinfo, try mingw32 and winsock2 library. +dnl perhaps getaddrinfo needs only the include +AC_LINK_IFELSE( +[AC_LANG_PROGRAM( +[ +#ifdef HAVE_WS2TCPIP_H +#include +#endif +], +[ + (void)getaddrinfo(NULL, NULL, NULL, NULL); +] +)], +[ +ac_cv_func_getaddrinfo="yes" +AC_DEFINE(USE_WINSOCK, 1, [Whether the windows socket API is used]) +USE_WINSOCK="1" +], + ORIGLIBS="$LIBS" LIBS="$LIBS -lws2_32" AC_LINK_IFELSE( @@ -904,6 +958,7 @@ ac_cv_func_getaddrinfo="no" LIBS="$ORIGLIBS" ]) ) +) AC_MSG_RESULT($ac_cv_func_getaddrinfo) if test $ac_cv_func_getaddrinfo = yes; then @@ -1037,7 +1092,7 @@ int main(void) /* send and receive on the socket */ if((p=fork()) == 0) { for(i=0; i_position += count; } +static inline int +try_buffer_write_at(buffer_type *buffer, size_t at, const void *data, size_t count) +{ + if(!buffer_available_at(buffer, at, count)) + return 0; + memcpy(buffer->_data + at, data, count); + return 1; +} + +static inline int +try_buffer_write(buffer_type *buffer, const void *data, size_t count) +{ + if(!try_buffer_write_at(buffer, buffer->_position, data, count)) + return 0; + buffer->_position += count; + return 1; +} + static inline void buffer_write_string_at(buffer_type *buffer, size_t at, const char *str) { @@ -272,6 +290,18 @@ buffer_write_string(buffer_type *buffer, const char *str) buffer_write(buffer, str, strlen(str)); } +static inline int +try_buffer_write_string_at(buffer_type *buffer, size_t at, const char *str) +{ + return try_buffer_write_at(buffer, at, str, strlen(str)); +} + +static inline int +try_buffer_write_string(buffer_type *buffer, const char *str) +{ + return try_buffer_write(buffer, str, strlen(str)); +} + static inline void buffer_write_u8_at(buffer_type *buffer, size_t at, uint8_t data) { @@ -328,6 +358,78 @@ buffer_write_u64(buffer_type *buffer, uint64_t data) buffer->_position += sizeof(data); } +static inline int +try_buffer_write_u8_at(buffer_type *buffer, size_t at, uint8_t data) +{ + if(!buffer_available_at(buffer, at, sizeof(data))) + return 0; + buffer->_data[at] = data; + return 1; +} + +static inline int +try_buffer_write_u8(buffer_type *buffer, uint8_t data) +{ + if(!try_buffer_write_u8_at(buffer, buffer->_position, data)) + return 0; + buffer->_position += sizeof(data); + return 1; +} + +static inline int +try_buffer_write_u16_at(buffer_type *buffer, size_t at, uint16_t data) +{ + if(!buffer_available_at(buffer, at, sizeof(data))) + return 0; + write_uint16(buffer->_data + at, data); + return 1; +} + +static inline int +try_buffer_write_u16(buffer_type *buffer, uint16_t data) +{ + if(!try_buffer_write_u16_at(buffer, buffer->_position, data)) + return 0; + buffer->_position += sizeof(data); + return 1; +} + +static inline int +try_buffer_write_u32_at(buffer_type *buffer, size_t at, uint32_t data) +{ + if(!buffer_available_at(buffer, at, sizeof(data))) + return 0; + write_uint32(buffer->_data + at, data); + return 1; +} + +static inline int +try_buffer_write_u32(buffer_type *buffer, uint32_t data) +{ + if(!try_buffer_write_u32_at(buffer, buffer->_position, data)) + return 0; + buffer->_position += sizeof(data); + return 1; +} + +static inline int +try_buffer_write_u64_at(buffer_type *buffer, size_t at, uint64_t data) +{ + if(!buffer_available_at(buffer, at, sizeof(data))) + return 0; + write_uint64(buffer->_data + at, data); + return 1; +} + +static inline int +try_buffer_write_u64(buffer_type *buffer, uint64_t data) +{ + if(!try_buffer_write_u64_at(buffer, buffer->_position, data)) + return 0; + buffer->_position += sizeof(data); + return 1; +} + static inline void buffer_read_at(buffer_type *buffer, size_t at, void *data, size_t count) { diff --git a/usr.sbin/nsd/config.h.in b/usr.sbin/nsd/config.h.in index eda3cf95b..1a082157d 100644 --- a/usr.sbin/nsd/config.h.in +++ b/usr.sbin/nsd/config.h.in @@ -631,6 +631,10 @@ /* Define to 1 to enable dnstap support */ #undef USE_DNSTAP +/* Define this to show the role of processes in the logfile for debugging + purposes. */ +#undef USE_LOG_PROCESS_ROLE + /* Define if you want to use internal select based events */ #undef USE_MINI_EVENT diff --git a/usr.sbin/nsd/configlexer.lex b/usr.sbin/nsd/configlexer.lex index 44c674fa8..36d43b641 100644 --- a/usr.sbin/nsd/configlexer.lex +++ b/usr.sbin/nsd/configlexer.lex @@ -298,7 +298,8 @@ store-ixfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_STORE_IXFR;} ixfr-size{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IXFR_SIZE;} ixfr-number{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_IXFR_NUMBER;} create-ixfr{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CREATE_IXFR;} -multi-master-check{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_MASTER_CHECK;} +multi-master-check{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_PRIMARY_CHECK;} +multi-primary-check{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_MULTI_PRIMARY_CHECK;} tls-service-key{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_KEY;} tls-service-ocsp{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_OCSP;} tls-service-pem{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_TLS_SERVICE_PEM;} @@ -318,6 +319,9 @@ verifier{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER; } verifier-count{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER_COUNT; } verifier-feed-zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER_FEED_ZONE; } verifier-timeout{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_VERIFIER_TIMEOUT; } +catalog{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CATALOG; } +catalog-member-pattern{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CATALOG_MEMBER_PATTERN; } +catalog-producer-zone{COLON} { LEXOUT(("v(%s) ", yytext)); return VAR_CATALOG_PRODUCER_ZONE; } {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;} servers={UNQUOTEDLETTER}* { diff --git a/usr.sbin/nsd/configparser.y b/usr.sbin/nsd/configparser.y index ed412b2f4..8b9f9a945 100644 --- a/usr.sbin/nsd/configparser.y +++ b/usr.sbin/nsd/configparser.y @@ -33,6 +33,7 @@ extern config_parser_state_type *cfg_parser; static void append_acl(struct acl_options **list, struct acl_options *acl); static void add_to_last_acl(struct acl_options **list, char *ac); static int parse_boolean(const char *str, int *bln); +static int parse_catalog_role(const char *str, int *role); static int parse_expire_expr(const char *str, long long *num, uint8_t *expr); static int parse_number(const char *str, long long *num); static int parse_range(const char *str, long long *low, long long *high); @@ -53,6 +54,7 @@ struct component { struct cpu_option *cpu; char **strv; struct component *comp; + int role; } %token STRING @@ -63,6 +65,7 @@ struct component { %type cpus %type command %type arguments +%type catalog_role /* server */ %token VAR_SERVER @@ -194,7 +197,7 @@ struct component { %token VAR_MAX_RETRY_TIME %token VAR_MIN_RETRY_TIME %token VAR_MIN_EXPIRE_TIME -%token VAR_MULTI_MASTER_CHECK +%token VAR_MULTI_PRIMARY_CHECK %token VAR_SIZE_LIMIT_XFR %token VAR_ZONESTATS %token VAR_INCLUDE_PATTERN @@ -202,6 +205,9 @@ struct component { %token VAR_IXFR_SIZE %token VAR_IXFR_NUMBER %token VAR_CREATE_IXFR +%token VAR_CATALOG +%token VAR_CATALOG_MEMBER_PATTERN +%token VAR_CATALOG_PRODUCER_ZONE /* zone */ %token VAR_ZONE @@ -900,13 +906,15 @@ pattern_or_zone_option: yyerror("expected a number greater than zero"); } } - | VAR_MULTI_MASTER_CHECK boolean - { cfg_parser->pattern->multi_master_check = (int)$2; } + | VAR_MULTI_PRIMARY_CHECK boolean + { cfg_parser->pattern->multi_primary_check = (int)$2; } | VAR_INCLUDE_PATTERN STRING { config_apply_pattern(cfg_parser->pattern, $2); } | VAR_REQUEST_XFR STRING STRING { acl_options_type *acl = parse_acl_info(cfg_parser->opt->region, $2, $3); + if(cfg_parser->pattern->catalog_role == CATALOG_ROLE_PRODUCER) + yyerror("catalog producer zones cannot be secondary zones"); if(acl->blocked) yyerror("blocked address used for request-xfr"); if(acl->rangetype != acl_range_single) @@ -1035,7 +1043,32 @@ pattern_or_zone_option: | VAR_VERIFIER_FEED_ZONE boolean { cfg_parser->pattern->verifier_feed_zone = $2; } | VAR_VERIFIER_TIMEOUT number - { cfg_parser->pattern->verifier_timeout = $2; } ; + { cfg_parser->pattern->verifier_timeout = $2; } + | VAR_CATALOG catalog_role + { + if($2 == CATALOG_ROLE_PRODUCER && cfg_parser->pattern->request_xfr) + yyerror("catalog producer zones cannot be secondary zones"); + cfg_parser->pattern->catalog_role = $2; + cfg_parser->pattern->catalog_role_is_default = 0; + } + | VAR_CATALOG_MEMBER_PATTERN STRING + { + cfg_parser->pattern->catalog_member_pattern = region_strdup(cfg_parser->opt->region, $2); + } + | VAR_CATALOG_PRODUCER_ZONE STRING + { + dname_type *dname; + + if(cfg_parser->zone) { + yyerror("catalog-producer-zone option is for patterns only and cannot " + "be used in a zone clause"); + } else if(!(dname = (dname_type *)dname_parse(cfg_parser->opt->region, $2))) { + yyerror("bad catalog producer name %s", $2); + } else { + region_recycle(cfg_parser->opt->region, dname, dname_total_size(dname)); + cfg_parser->pattern->catalog_producer_zone = region_strdup(cfg_parser->opt->region, $2); + } + }; verify: VAR_VERIFY verify_block ; @@ -1146,6 +1179,15 @@ tlsauth_option: { char *tls_auth_name = region_strdup(cfg_parser->opt->region, $1); add_to_last_acl(&cfg_parser->pattern->request_xfr, tls_auth_name);} ; +catalog_role: + STRING + { + if(!parse_catalog_role($1, &$$)) { + yyerror("expected consumer or producer"); + YYABORT; /* trigger a parser error */ + } + } ; + %% static void @@ -1264,3 +1306,18 @@ parse_range(const char *str, long long *low, long long *high) return 0; } + +static int +parse_catalog_role(const char *str, int *role) +{ + if(strcasecmp(str, "consumer") == 0) { + *role = CATALOG_ROLE_CONSUMER; + } else if(strcmp(str, "producer") == 0) { + *role = CATALOG_ROLE_PRODUCER; + } else { + return 0; + } + return 1; +} + + diff --git a/usr.sbin/nsd/configure b/usr.sbin/nsd/configure index b6b378c7b..65cea5651 100644 --- a/usr.sbin/nsd/configure +++ b/usr.sbin/nsd/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for NSD 4.8.0. +# Generated by GNU Autoconf 2.69 for NSD 4.9.1. # # Report bugs to . # @@ -581,8 +581,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='NSD' PACKAGE_TARNAME='nsd' -PACKAGE_VERSION='4.8.0' -PACKAGE_STRING='NSD 4.8.0' +PACKAGE_VERSION='4.9.1' +PACKAGE_STRING='NSD 4.9.1' PACKAGE_BUGREPORT='https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl' PACKAGE_URL='' @@ -738,6 +738,7 @@ enable_ipv6 enable_bind8_stats enable_zone_stats enable_checking +enable_log_role enable_memclean enable_ratelimit enable_ratelimit_default_is_off @@ -1327,7 +1328,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures NSD 4.8.0 to adapt to many kinds of systems. +\`configure' configures NSD 4.9.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1389,7 +1390,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of NSD 4.8.0:";; + short | recursive ) echo "Configuration of NSD 4.9.1:";; esac cat <<\_ACEOF @@ -1413,6 +1414,8 @@ Optional Features: --enable-zone-stats Enable per-zone statistics gathering (needs --enable-bind8-stats) --enable-checking Enable internal runtime checks + --enable-log-role Shows the role of processes in the logfile (enable + this only for debugging purposes) --enable-memclean Cleanup memory (at exit) for eg. valgrind, memcheck --enable-ratelimit Enable rate limiting --enable-ratelimit-default-is-off @@ -1562,7 +1565,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -NSD configure 4.8.0 +NSD configure 4.9.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2271,7 +2274,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by NSD $as_me 4.8.0, which was +It was created by NSD $as_me 4.9.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -9020,6 +9023,24 @@ $as_echo "#define NDEBUG /**/" >>confdefs.h ;; esac +# Check whether --enable-log-role was given. +if test "${enable_log_role+set}" = set; then : + enableval=$enable_log_role; +fi + +case "$enable_log_role" in + yes) + +cat >>confdefs.h <<_ACEOF +#define USE_LOG_PROCESS_ROLE /**/ +_ACEOF + + ;; + no|*) + ;; +esac + + # Check whether --enable-memclean was given. if test "${enable_memclean+set}" = set; then : enableval=$enable_memclean; @@ -10890,7 +10911,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by NSD $as_me 4.8.0, which was +This file was extended by NSD $as_me 4.9.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -10952,7 +10973,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -NSD config.status 4.8.0 +NSD config.status 4.9.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/usr.sbin/nsd/configure.ac b/usr.sbin/nsd/configure.ac index 174d51124..56aa738f8 100644 --- a/usr.sbin/nsd/configure.ac +++ b/usr.sbin/nsd/configure.ac @@ -5,7 +5,7 @@ dnl sinclude(acx_nlnetlabs.m4) sinclude(dnstap/dnstap.m4) -AC_INIT([NSD],[4.8.0],[https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl]) +AC_INIT([NSD],[4.9.1],[https://github.com/NLnetLabs/nsd/issues or nsd-bugs@nlnetlabs.nl]) AC_CONFIG_HEADERS([config.h]) # @@ -1004,6 +1004,16 @@ case "$enable_checking" in ;; esac +AC_ARG_ENABLE(log-role, AS_HELP_STRING([--enable-log-role],[Shows the role of processes in the logfile (enable this only for debugging purposes)])) +case "$enable_log_role" in + yes) + AC_DEFINE_UNQUOTED([USE_LOG_PROCESS_ROLE], [], [Define this to show the role of processes in the logfile for debugging purposes.]) + ;; + no|*) + ;; +esac + + AC_ARG_ENABLE(memclean, AS_HELP_STRING([--enable-memclean],[Cleanup memory (at exit) for eg. valgrind, memcheck])) if test "$enable_memclean" = "yes"; then AC_DEFINE_UNQUOTED([MEMCLEAN], [1], [Define this to cleanup memory at exit (eg. for valgrind, etc.)]) fi diff --git a/usr.sbin/nsd/difffile.c b/usr.sbin/nsd/difffile.c index bd5a54960..792d7a8fc 100644 --- a/usr.sbin/nsd/difffile.c +++ b/usr.sbin/nsd/difffile.c @@ -24,6 +24,7 @@ #include "rrl.h" #include "ixfr.h" #include "zonec.h" +#include "xfrd-catalog-zones.h" static int write_64(FILE *out, uint64_t val) @@ -919,7 +920,7 @@ find_or_create_zone(namedb_type* db, const dname_type* zone_name, * by xfrd, who wrote the AXFR or IXFR to disk, so we only * need to add it to our config. * This process does not need linesize and offset zonelist */ - zopt = zone_list_zone_insert(opt, zstr, patname, 0, 0); + zopt = zone_list_zone_insert(opt, zstr, patname); if(!zopt) return 0; } @@ -1273,7 +1274,7 @@ check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial) return 0; } -static int +int apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in, struct nsd_options* ATTR_UNUSED(opt), udb_base* taskudb, udb_ptr* last_task, uint32_t xfrfilenr) @@ -1348,7 +1349,7 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in, if(check_for_bad_serial(nsd->db, zone_buf, old_serial)) { DEBUG(DEBUG_XFRD,1, (LOG_ERR, "skipping diff file commit with bad serial")); - return 1; + return -2; /* Success in "main" process, failure in "xfrd" */ } if(!zone->is_skipped) @@ -1372,7 +1373,7 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in, diff_update_commit( zone_buf, DIFF_CORRUPT, nsd, xfrfilenr); /* the udb is still dirty, it is bad */ - exit(1); + return -1; /* Fatal! */ } else if(ret == 2) { break; } @@ -1402,12 +1403,12 @@ apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in, if(softfail && taskudb && !is_axfr) { log_msg(LOG_ERR, "Failed to apply IXFR cleanly " "(deletes nonexistent RRs, adds existing RRs). " - "Zone %s contents is different from master, " + "Zone %s contents is different from primary, " "starting AXFR. Transfer %s", zone_buf, log_buf); /* add/del failures in IXFR, get an AXFR */ diff_update_commit( zone_buf, DIFF_INCONSISTENT, nsd, xfrfilenr); - exit(1); + return -1; /* Fatal! */ } if(ixfr_store) ixfr_store_finish(ixfr_store, nsd, log_buf); @@ -1598,6 +1599,7 @@ void task_new_check_zonefiles(udb_base* udb, udb_ptr* last, const dname_type* zone) { udb_ptr e; + xfrd_check_catalog_consumer_zonefiles(zone); DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task checkzonefiles")); if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) + (zone?dname_total_size(zone):0), zone)) { @@ -2111,13 +2113,23 @@ task_process_apply_xfr(struct nsd* nsd, udb_base* udb, udb_ptr *last_task, return; } /* read and apply zone transfer */ - if(!apply_ixfr_for_zone(nsd, zone, df, nsd->options, udb, - last_task, TASKLIST(task)->yesno)) { + switch(apply_ixfr_for_zone(nsd, zone, df, nsd->options, udb, last_task, + TASKLIST(task)->yesno)) { + case 1: /* Success */ + break; + + case 0: /* Failure */ /* soainfo_gone will be communicated from server_reload, unless preceding updates have been applied */ zone->is_skipped = 1; - } + break; + case -1:/* Fatal */ + exit(1); + break; + + default:break; + } fclose(df); } diff --git a/usr.sbin/nsd/difffile.h b/usr.sbin/nsd/difffile.h index ba777c8a5..4a88d4b1d 100644 --- a/usr.sbin/nsd/difffile.h +++ b/usr.sbin/nsd/difffile.h @@ -66,6 +66,11 @@ int add_RR(namedb_type* db, const dname_type* dname, buffer_type* packet, size_t rdatalen, zone_type *zone, int* softfail); +/* apply the xfr file identified by xfrfilenr to zone */ +int apply_ixfr_for_zone(struct nsd* nsd, zone_type* zone, FILE* in, + struct nsd_options* opt, udb_base* taskudb, udb_ptr* last_task, + uint32_t xfrfilenr); + enum soainfo_hint { soainfo_ok, soainfo_gone, diff --git a/usr.sbin/nsd/dname.c b/usr.sbin/nsd/dname.c index 487d2535a..eced1714e 100644 --- a/usr.sbin/nsd/dname.c +++ b/usr.sbin/nsd/dname.c @@ -392,6 +392,12 @@ const char * dname_to_string(const dname_type *dname, const dname_type *origin) { static char buf[MAXDOMAINLEN * 5]; + return dname_to_string_buf(dname, origin, buf); +} + +const char * +dname_to_string_buf(const dname_type *dname, const dname_type *origin, char buf[MAXDOMAINLEN * 5]) +{ size_t i; size_t labels_to_convert = dname->label_count - 1; int absolute = 1; @@ -399,7 +405,7 @@ dname_to_string(const dname_type *dname, const dname_type *origin) const uint8_t *src; if (dname->label_count == 1) { - strlcpy(buf, ".", sizeof(buf)); + strlcpy(buf, ".", MAXDOMAINLEN * 5); return buf; } diff --git a/usr.sbin/nsd/dname.h b/usr.sbin/nsd/dname.h index 0d5dc4ac8..e37cb2373 100644 --- a/usr.sbin/nsd/dname.h +++ b/usr.sbin/nsd/dname.h @@ -15,6 +15,7 @@ #include "buffer.h" #include "region-allocator.h" +#include "dns.h" /* for MAXDOMAINLEN */ #if defined(NAMEDB_UPPERCASE) || defined(USE_NAMEDB_UPPERCASE) #define DNAME_NORMALIZE toupper @@ -346,6 +347,19 @@ label_next(const uint8_t *label) const char *dname_to_string(const dname_type *dname, const dname_type *origin); +/* + * Convert DNAME to its string representation. The result if written + * to the provided buffer buf, which must be at least 5 times + * MAXDOMAINNAMELEN. + * + * If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname + * will be represented relative to ORIGIN. + * + * Pre: dname != NULL + */ +const char *dname_to_string_buf(const dname_type *dname, + const dname_type *origin, + char buf[MAXDOMAINLEN * 5]); /* * Create a dname containing the single label specified by STR diff --git a/usr.sbin/nsd/doc/ChangeLog b/usr.sbin/nsd/doc/ChangeLog index 3e50194b1..a04481d1b 100644 --- a/usr.sbin/nsd/doc/ChangeLog +++ b/usr.sbin/nsd/doc/ChangeLog @@ -1,5 +1,91 @@ +4 April 2024: Jeroen + - Use rooted temporary path in makedist.sh. + +3 April 2024: Jeroen + - Replace multiple strcat and strcpy by snprintf. + - Tag for 4.9.0. + +26 March 2024: Jeroen + - Test if debug is available in do-tests. + - Enforce timeout from NSD in ixfr_gone test. + - Update expressions in ixfr_and_restart test. + - Make algorithm explicit in control-repattern test. + - Switch algorithm to hmac-256 for testplan_mess test. + - Tag for 4.9.0rc1. + +25 March 2024: Jeroen + - Fix timing sensitivity in ixfr_outsync test. + +22 March 2024: Jeroen + - Set up doc/RELNOTES for upcoming release. + +26 February 2024: Willem + - Merge #316: Fix to reap defunct children by the reload process that + emerged when some serve child processes were still serving TCP + request while the others had already quit, while the reload process + was waiting for the signal from the backup/old main process that all + children exited. + - Fix (also from Merge #316) to reap exited children more frequently + from server main loop for processes that exited during reload, but + missed the initial reaping at start of the main loop because they + took somewhat longer to exit. + +16 February 2024: Wouter + - Fix compile with memclean for xfrd nsd.db close. + - In xfrd del secondary zone, the timer could perhaps have + event_added, and if so, it would not be event_del if a tcp connection + is active at the time. This could cause the libevent event lists + to fail. Also fix to make sure to set event_added for the + nsd-control ssl nonblocking handshake and check event_added there + too, for extra certainty. + +15 February 2024: Willem + - Merge #304: Support for Catalog zones version "2" as specified in + RFC 9432. Both the consumer as well as the producer role are + implemented, but only a single catalog consumer zone is allowed. + The "coo" property, only relevant with multiple catalog consumer, + is therefore not supported. The "group" property is supported. + Have a look at the nsd.conf man page for details on how to + configure and use catalog zones. + +12 February 2024: Willem + - Allow SOA apex queries to otherwise with allow-query protected zones + for clients matching a provide-xfr rule, because clients that are + allowed to transfer the zone need to be able to query SOA at the + apex preceding the actual transfer. + +6 February 2024: Wouter + - Fix #313: nsd 4.8 stats with implausible spikes. + +16 January 2024: Wouter + - Move acx_nlnetlabs.m4 to version 48, with ssp and getaddrinfo + include check. + +14 January 2024: Wouter + - Move acx_nlnetlabs.m4 to version 47, with crypt32 check. + +8 December 2023: Wouter + - Merge #309: More RFC 8499 compliance. + - Fix #310: NSD stats contain the terms "master" and "slave". + - Fix control-reconfig-xfrd test for zonestatus primary that is + printed by nsd-control zonestatus. + +7 December 2023: Wouter + - Merge #307 from anandb-ripencc: Many improvements to the nsd.conf + man page. + - Fix #308: Deprecate "multi-master-check" in favour of + "multi-primary-check". + +6 December 2023: Wouter + - Fix to sync the tests script file common.sh. + - Update test script file common.sh. + - Fix #306: Missing AC_SUBST(dbdir) breaks installation with 4.8.0. + - Fix for #306: Create directory for xfrd.state and zone.list files + in make install. + 29 November 2023: Wouter - - Tag for 4.8.0rc1. + - Tag for 4.8.0rc1. This became 4.8.0 release on 6 December 2023. + The repository continues with version 4.8.1 under development. 28 November 2023: Wouter - Set up doc/RELNOTES for upcoming release. diff --git a/usr.sbin/nsd/doc/README b/usr.sbin/nsd/doc/README index 1fd624012..1466efc09 100644 --- a/usr.sbin/nsd/doc/README +++ b/usr.sbin/nsd/doc/README @@ -21,7 +21,7 @@ 1.0 Introduction -This is NSD Name Server Daemon (NSD) version 4.8.0. +This is NSD Name Server Daemon (NSD) version 4.9.1. The NLnet Labs Name Server Daemon (NSD) is an authoritative RFC compliant DNS nameserver. It was first conceived to allow for more genetic @@ -57,7 +57,7 @@ and uses a simple configuration file 'nsd.conf'. 1.2 Quick build and install -Step 1: Unpack the source with gtar -xzvf nsd-4.8.0.tar.gz +Step 1: Unpack the source with gtar -xzvf nsd-4.9.1.tar.gz Step 2: Create user nsd or any other unprivileged user of your choice. In case of later make sure to use @@ -111,9 +111,9 @@ Step 11: If desired add 'nsd-control write' to your superuser crontab to Use your favorite combination of tar and gnu zip to unpack the source, for example -$ gtar -xzvf nsd-4.8.0.tar.gz +$ gtar -xzvf nsd-4.9.1.tar.gz -will unpack the source into the ./nsd-4.8.0 directory... +will unpack the source into the ./nsd-4.9.1 directory... 2.2 Configuring NSD @@ -920,4 +920,4 @@ larger and regular donations please contact us at users@NLnetLabs.nl. Also see http://www.nlnetlabs.nl/labs/contributors/. -$Id: README,v 1.7 2023/12/20 17:29:02 florian Exp $ +$Id: README,v 1.8 2024/04/12 15:53:34 florian Exp $ diff --git a/usr.sbin/nsd/doc/RELNOTES b/usr.sbin/nsd/doc/RELNOTES index e5e234d7e..d2c25ea55 100644 --- a/usr.sbin/nsd/doc/RELNOTES +++ b/usr.sbin/nsd/doc/RELNOTES @@ -1,5 +1,66 @@ NSD RELEASE NOTES +4.9.1 +================ +BUG FIXES: + - Use rooted temporary path in makedist.sh. + +4.9.0 +================ +FEATURES: + - Merge #315: Allow SOA apex queries to otherwise with allow-query + protected zones for clients matching a provide-xfr rule, because + clients that are allowed to transfer the zone need to be able to + query SOA at the apex preceding the actual transfer. + - Merge #304: Support for Catalog zones version "2" as specified in + RFC 9432. Both the consumer as well as the producer role are + implemented, but only a single catalog consumer zone is allowed. + The "coo" property, only relevant with multiple catalog consumer, + is therefore not supported. The "group" property is supported. + Have a look at the nsd.conf man page for details on how to + configure and use catalog zones. + +BUG FIXES: + - Fix to sync the tests script file common.sh. + - Update test script file common.sh. + - Fix #306: Missing AC_SUBST(dbdir) breaks installation with 4.8.0. + - Fix for #306: Create directory for xfrd.state and zone.list files + in make install. + - Merge #307 from anandb-ripencc: Many improvements to the nsd.conf + man page. + - Fix #308: Deprecate "multi-master-check" in favour of + "multi-primary-check". + - Merge #309: More RFC 8499 compliance. + - Fix control-reconfig-xfrd test for zonestatus primary that is + printed by nsd-control zonestatus. + - Move acx_nlnetlabs.m4 to version 47, with crypt32 check. + - Move acx_nlnetlabs.m4 to version 48, with ssp and getaddrinfo + include check. + - Fix #313: nsd 4.8 stats with implausible spikes. + - Fix compile with memclean for xfrd nsd.db close. + - In xfrd del secondary zone, the timer could perhaps have + event_added, and if so, it would not be event_del if a tcp connection + is active at the time. This could cause the libevent event lists + to fail. Also fix to make sure to set event_added for the + nsd-control ssl nonblocking handshake and check event_added there + too, for extra certainty. + - Merge #316: Fix to reap defunct children by the reload process that + emerged when some serve child processes were still serving TCP + request while the others had already quit, while the reload process + was waiting for the signal from the backup/old main process that all + children exited. + - Fix (also from Merge #316) to reap exited children more frequently + from server main loop for processes that exited during reload, but + missed the initial reaping at start of the main loop because they + took somewhat longer to exit. + - Fix timing sensitivity in ixfr_outsync test. + - Test if debug is available in do-tests. + - Enforce timeout from NSD in ixfr_gone test. + - Update expressions in ixfr_and_restart test. + - Make algorithm explicit in control-repattern test. + - Switch algorithm to hmac-256 for testplan_mess test. + - Replace multiple strcat and strcpy by snprintf. + 4.8.0 ================ FEATURES: diff --git a/usr.sbin/nsd/namedb.h b/usr.sbin/nsd/namedb.h index c99664389..175b033d9 100644 --- a/usr.sbin/nsd/namedb.h +++ b/usr.sbin/nsd/namedb.h @@ -318,6 +318,10 @@ static inline int domain_is_subdomain(domain_type* d1, domain_type* d2) /* easy printout, to static buffer of dname_to_string, fqdn. */ static inline const char* domain_to_string(domain_type* domain) { return dname_to_string(domain_dname(domain), NULL); } +/* easy printout, to given buffer of dname_to_string, fqdn. */ +static inline const char* domain_to_string_buf(domain_type* domain, char *buf) +{ return dname_to_string_buf(domain_dname(domain), NULL, buf); } + /* * The type covered by the signature in the specified RRSIG RR. @@ -391,6 +395,11 @@ void namedb_read_zonefile(struct nsd* nsd, struct zone* zone, struct udb_base* taskudb, struct udb_ptr* last_task); zone_type* namedb_zone_create(namedb_type* db, const dname_type* dname, struct zone_options* zopt); +static inline zone_type* +namedb_find_or_create_zone(namedb_type *db, const dname_type *dname, + struct zone_options* zopt) +{ zone_type* zone = namedb_find_zone(db, dname); + return zone ? zone : namedb_zone_create(db, dname, zopt); } void namedb_zone_delete(namedb_type* db, zone_type* zone); void namedb_write_zonefile(struct nsd* nsd, struct zone_options* zopt); void namedb_write_zonefiles(struct nsd* nsd, struct nsd_options* options); diff --git a/usr.sbin/nsd/nsd-checkconf.8.in b/usr.sbin/nsd/nsd-checkconf.8.in index 54275503d..bf96296e6 100644 --- a/usr.sbin/nsd/nsd-checkconf.8.in +++ b/usr.sbin/nsd/nsd-checkconf.8.in @@ -1,4 +1,4 @@ -.TH "nsd\-checkconf" "8" "Dec 6, 2023" "NLnet Labs" "nsd 4.8.0" +.TH "nsd\-checkconf" "8" "Apr 4, 2024" "NLnet Labs" "nsd 4.9.1" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" diff --git a/usr.sbin/nsd/nsd-checkconf.c b/usr.sbin/nsd/nsd-checkconf.c index 15c96cbf0..e0fcaaa0e 100644 --- a/usr.sbin/nsd/nsd-checkconf.c +++ b/usr.sbin/nsd/nsd-checkconf.c @@ -354,7 +354,7 @@ config_print_zone(nsd_options_type* opt, const char* k, int s, const char *o, #ifdef RATELIMIT ZONE_GET_RRL(rrl_whitelist, o, zone->pattern); #endif - ZONE_GET_BIN(multi_master_check, o, zone->pattern); + ZONE_GET_BIN(multi_primary_check, o, zone->pattern); ZONE_GET_BIN(store_ixfr, o, zone->pattern); ZONE_GET_INT(ixfr_size, o, zone->pattern); ZONE_GET_INT(ixfr_number, o, zone->pattern); @@ -391,7 +391,7 @@ config_print_zone(nsd_options_type* opt, const char* k, int s, const char *o, #ifdef RATELIMIT ZONE_GET_RRL(rrl_whitelist, o, p); #endif - ZONE_GET_BIN(multi_master_check, o, p); + ZONE_GET_BIN(multi_primary_check, o, p); ZONE_GET_BIN(store_ixfr, o, p); ZONE_GET_INT(ixfr_size, o, p); ZONE_GET_INT(ixfr_number, o, p); @@ -524,8 +524,8 @@ static void print_zone_content_elems(pattern_options_type* pat) print_acl("allow_query:", pat->allow_query); print_acl("allow-notify:", pat->allow_notify); print_acl("request-xfr:", pat->request_xfr); - if(pat->multi_master_check) - printf("\tmulti-master-check: %s\n", pat->multi_master_check?"yes":"no"); + if(pat->multi_primary_check) + printf("\tmulti-primary-check: %s\n", pat->multi_primary_check?"yes":"no"); if(!pat->notify_retry_is_default) printf("\tnotify-retry: %d\n", pat->notify_retry); print_acl("notify:", pat->notify); @@ -585,6 +585,20 @@ static void print_zone_content_elems(pattern_options_type* pat) if(pat->verifier_timeout != VERIFIER_TIMEOUT_INHERIT) { printf("\tverifier-timeout: %d\n", pat->verifier_timeout); } + + if(!pat->catalog_role_is_default) + switch(pat->catalog_role) { + case CATALOG_ROLE_CONSUMER: printf("\tcatalog: consumer\n"); + break; + case CATALOG_ROLE_PRODUCER: printf("\tcatalog: producer\n"); + break; + default : break; + } + + if(pat->catalog_member_pattern) + print_string_var("catalog-member-pattern:", pat->catalog_member_pattern); + if(pat->catalog_producer_zone) + print_string_var("catalog-producer-zone:", pat->catalog_producer_zone); } void @@ -806,9 +820,9 @@ additional_checks(nsd_options_type* opt, const char* filename) "is received?\n", filename, zone->name); errors ++; } - if(!zone_is_slave(zone) && (!zone->pattern->zonefile || - zone->pattern->zonefile[0] == 0)) { - fprintf(stderr, "%s: zone %s is a master zone but has " + if(!zone_is_slave(zone) && !zone_is_catalog_producer(zone) + && (!zone->pattern->zonefile || zone->pattern->zonefile[0] == 0)) { + fprintf(stderr, "%s: zone %s is a primary zone but has " "no zonefile. Where can the data come from?\n", filename, zone->name); errors ++; @@ -963,7 +977,7 @@ main(int argc, char* argv[]) /* read config file */ options = nsd_options_create(region_create(xalloc, free)); tsig_init(options->region); - if (!parse_options_file(options, configfile, NULL, NULL) || + if (!parse_options_file(options, configfile, NULL, NULL, NULL) || !additional_checks(options, configfile)) { exit(2); } diff --git a/usr.sbin/nsd/nsd-checkzone.8.in b/usr.sbin/nsd/nsd-checkzone.8.in index 555ea58e2..8b27253cf 100644 --- a/usr.sbin/nsd/nsd-checkzone.8.in +++ b/usr.sbin/nsd/nsd-checkzone.8.in @@ -1,4 +1,4 @@ -.TH "nsd\-checkzone" "8" "Dec 6, 2023" "NLnet Labs" "nsd 4.8.0" +.TH "nsd\-checkzone" "8" "Apr 4, 2024" "NLnet Labs" "nsd 4.9.1" .\" Copyright (c) 2014, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" diff --git a/usr.sbin/nsd/nsd-control.8.in b/usr.sbin/nsd/nsd-control.8.in index 9c02b3223..f64d192ea 100644 --- a/usr.sbin/nsd/nsd-control.8.in +++ b/usr.sbin/nsd/nsd-control.8.in @@ -1,4 +1,4 @@ -.TH "nsd\-control" "8" "Dec 6, 2023" "NLnet Labs" "nsd 4.8.0" +.TH "nsd\-control" "8" "Apr 4, 2024" "NLnet Labs" "nsd 4.9.1" .\" Copyright (c) 2011, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" @@ -16,7 +16,8 @@ .B nsd\-control performs remote administration on the \fInsd\fR(8) DNS server. It reads the configuration file, contacts the nsd server over SSL, sends the -command and displays the result. +command and displays the result. Commands that require a reload are queued +and the result indicates the command was accepted. .P The available options are: .TP @@ -80,7 +81,7 @@ Same as stats, but does not zero the counters. .B addzone Add a new zone to the running server. The zone is added to the zonelist file on disk, so it stays after a restart. The pattern name determines -the options for the new zone. For slave zones a zone transfer is +the options for the new zone. For secondary zones a zone transfer is immediately attempted. For zones with a zonefile, the zone file is attempted to be read in. .TP @@ -114,28 +115,28 @@ path are created if necessary. With argument that zone is written if it was modified, without argument, all modified zones are written. .TP .B notify [] -Send NOTIFY messages to slave servers. Sends to the IP addresses -configured in the 'notify:' lists for the master zones hosted on this -server. Usually NSD sends NOTIFY messages right away when a master zone +Send NOTIFY messages to secondary servers. Sends to the IP addresses +configured in the 'notify:' lists for the primary zones hosted on this +server. Usually NSD sends NOTIFY messages right away when a primary zone serial is updated. If a zone is given, notifies are sent for that zone. -These slave servers are supposed to initiate a zone transfer request -later (to this server or another master), this can be allowed via +These secondary servers are supposed to initiate a zone transfer request +later (to this server or another primary), this can be allowed via the 'provide\-xfr:' acl list configuration. With argument that zone is processed, without argument, all zones are processed. .TP .B transfer [] -Attempt to update slave zones that are hosted on this server by contacting -the masters. The masters are configured via 'request\-xfr:' lists. +Attempt to update secondary zones that are hosted on this server by contacting +the primaries. The primaries are configured via 'request\-xfr:' lists. If a zone is given, that zone is updated. Usually NSD receives a NOTIFY -from the masters (configured via 'allow\-notify:' acl list) that a new zone +from the primaries (configured via 'allow\-notify:' acl list) that a new zone serial has to be transferred. For zones with no content, NSD may have backed -off from asking often because the masters did not respond, but this command +off from asking often because the primaries did not respond, but this command will reset the backoff to its initial timeout, for frequent retries. With argument that zone is transferred, without argument, all zones are transferred. .TP .B force_transfer [] -Force update slave zones that are hosted on this server. Even if the -master hosts the same serial number of the zone, a full AXFR is performed +Force update secondary zones that are hosted on this server. Even if the +primary hosts the same serial number of the zone, a full AXFR is performed to fetch it. If you want to use IXFR and check that the serial number increases, use the 'transfer' command. With argument that zone is transferred, without argument, all zones are transferred. @@ -143,9 +144,9 @@ transferred, without argument, all zones are transferred. .B zonestatus [] Print state of the zone, the serial numbers and since when they have been acquired. Also prints the notify action (to which server), and -zone transfer (and from which master) if there is activity right now. -The state of the zone is printed as: 'master' (master zones), 'ok' (slave -zone is up\-to\-date), 'expired' (slave zone has expired), 'refreshing' (slave +zone transfer (and from which primary) if there is activity right now. +The state of the zone is printed as: 'primary' (primary zones), 'ok' (secondary +zone is up\-to\-date), 'expired' (secondary zone has expired), 'refreshing' (secondary zone has transfers active). The serial numbers printed are the 'served\-serial' (currently active), the 'commit\-serial' (is in reload), the 'notified\-serial' (got notify, busy fetching the data). The serial @@ -323,13 +324,13 @@ number of answers with TC flag set. .I num.dropped number of queries that were dropped because they failed sanity check. .TP -.I zone.master -number of master zones served. These are zones with no 'request\-xfr:' -entries. +.I zone.primary +number of primary zones served. These are zones with no 'request\-xfr:' +entries. Also output as 'zone.master' for backwards compatibility. .TP -.I zone.slave -number of slave zones served. These are zones with 'request\-xfr' -entries. +.I zone.secondary +number of secondary zones served. These are zones with 'request\-xfr' +entries. Also output as 'zone.slave' for backwards compatibility. .SH "FILES" .TP .I @nsdconfigfile@ diff --git a/usr.sbin/nsd/nsd-control.c b/usr.sbin/nsd/nsd-control.c index e42685aa4..528729fd2 100644 --- a/usr.sbin/nsd/nsd-control.c +++ b/usr.sbin/nsd/nsd-control.c @@ -124,9 +124,9 @@ usage() printf(" addzones add zone list on stdin {name space pattern newline}\n"); printf(" delzones remove zone list on stdin {name newline}\n"); printf(" write [] write changed zonefiles to disk\n"); - printf(" notify [] send NOTIFY messages to slave servers\n"); - printf(" transfer [] try to update slave zones to newer serial\n"); - printf(" force_transfer [] update slave zones with AXFR, no serial check\n"); + printf(" notify [] send NOTIFY messages to secondary servers\n"); + printf(" transfer [] try to update secondary zones to newer serial\n"); + printf(" force_transfer [] update secondary zones with AXFR, no serial check\n"); printf(" zonestatus [] print state, serial, activity\n"); printf(" serverpid get pid of server process\n"); printf(" verbosity change logging detail\n"); @@ -523,7 +523,7 @@ go(const char* cfgfile, char* svr, int argc, char* argv[]) exit(1); } tsig_init(opt->region); - if(!parse_options_file(opt, cfgfile, NULL, NULL)) { + if(!parse_options_file(opt, cfgfile, NULL, NULL, NULL)) { fprintf(stderr, "could not read config file\n"); exit(1); } diff --git a/usr.sbin/nsd/nsd-mem.c b/usr.sbin/nsd/nsd-mem.c index 9f7b6992a..cc8455218 100644 --- a/usr.sbin/nsd/nsd-mem.c +++ b/usr.sbin/nsd/nsd-mem.c @@ -274,7 +274,7 @@ main(int argc, char *argv[]) DEFAULT_CHUNK_SIZE, DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1)); tsig_init(nsd.options->region); - if(!parse_options_file(nsd.options, configfile, NULL, NULL)) { + if(!parse_options_file(nsd.options, configfile, NULL, NULL, NULL)) { error("could not read config: %s\n", configfile); } if(!parse_zone_list_file(nsd.options)) { diff --git a/usr.sbin/nsd/nsd.8.in b/usr.sbin/nsd/nsd.8.in index 4d286a014..d0ea7a2e6 100644 --- a/usr.sbin/nsd/nsd.8.in +++ b/usr.sbin/nsd/nsd.8.in @@ -1,9 +1,9 @@ -.TH "NSD" "8" "Dec 6, 2023" "NLnet Labs" "NSD 4.8.0" +.TH "NSD" "8" "Apr 4, 2024" "NLnet Labs" "NSD 4.9.1" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" .B nsd -\- Name Server Daemon (NSD) version 4.8.0. +\- Name Server Daemon (NSD) version 4.9.1. .SH "SYNOPSIS" .B nsd .RB [ \-4 ] diff --git a/usr.sbin/nsd/nsd.c b/usr.sbin/nsd/nsd.c index 80b4cb096..c3b99c037 100644 --- a/usr.sbin/nsd/nsd.c +++ b/usr.sbin/nsd/nsd.c @@ -1134,7 +1134,7 @@ main(int argc, char *argv[]) pp_init(&write_uint16, &write_uint32); /* Read options */ - if(!parse_options_file(nsd.options, configfile, NULL, NULL)) { + if(!parse_options_file(nsd.options, configfile, NULL, NULL, NULL)) { error("could not read config: %s\n", configfile); } if(!parse_zone_list_file(nsd.options)) { diff --git a/usr.sbin/nsd/nsd.conf.5.in b/usr.sbin/nsd/nsd.conf.5.in index 467203aa5..357b8df0a 100644 --- a/usr.sbin/nsd/nsd.conf.5.in +++ b/usr.sbin/nsd/nsd.conf.5.in @@ -1,4 +1,4 @@ -.TH "nsd.conf" "5" "Dec 6, 2023" "NLnet Labs" "nsd 4.8.0" +.TH "nsd.conf" "5" "Apr 4, 2024" "NLnet Labs" "nsd 4.9.1" .\" Copyright (c) 2001\-2008, NLnet Labs. All rights reserved. .\" See LICENSE for the license. .SH "NAME" @@ -7,18 +7,17 @@ .SH "SYNOPSIS" .B nsd.conf .SH "DESCRIPTION" -.B Nsd.conf -is used to configure nsd(8). The file format has attributes and -values. Some attributes have attributes inside them. The notation -is: attribute: value. +This file is used to configure nsd(8). It specifies options for the nsd +server, zone files, primaries and secondaries. +.PP +The file format has attributes and values. Some attributes have attributes +inside them. The notation is: +.PP +attribute: value .PP Comments start with # and last to the end of line. Empty lines are -ignored as is whitespace at the beginning of a line. Quotes can be used, -for names with spaces, eg. "file name.zone". -.PP -.B Nsd.conf -specifies options for the nsd server, zone files, primaries and -secondaries. +ignored, as is whitespace at the beginning of a line. Quotes must be used +for values with spaces in them, eg. "file name.zone". .SH "EXAMPLE" An example of a short nsd.conf file is below. .LP @@ -32,22 +31,19 @@ server: server-count: 1 # use this number of cpu cores .RE .RS 5 -database: "" # or use "@dbfile@" -.RE -.RS 5 -zonelistfile: "@zonelistfile@" -.RE -.RS 5 username: @user@ .RE .RS 5 -logfile: "@logfile@" +zonelistfile: @zonelistfile@ .RE .RS 5 -pidfile: "@pidfile@" +logfile: @logfile@ .RE .RS 5 -xfrdfile: "@xfrdfile@" +pidfile: @pidfile@ +.RE +.RS 5 +xfrdfile: @xfrdfile@ .RE .TP zone: @@ -60,13 +56,13 @@ zonefile: @configdir@/example.com.zone .TP zone: .RS 5 -# this server is master, 192.0.2.1 is the secondary. +# this server is the primary and 192.0.2.1 is the secondary. .RE .RS 5 -name: masterzone.com +name: primaryzone.com .RE .RS 5 -zonefile: @configdir@/masterzone.com.zone +zonefile: @configdir@/primaryzone.com.zone .RE .RS 5 notify: 192.0.2.1 NOKEY @@ -77,13 +73,13 @@ provide-xfr: 192.0.2.1 NOKEY .TP zone: .RS 5 -# this server is secondary, 192.0.2.2 is master. +# this server is the secondary and 192.0.2.2 is the primary. .RE .RS 5 -name: secondzone.com +name: secondaryzone.com .RE .RS 5 -zonefile: @configdir@/secondzone.com.zone +zonefile: @configdir@/secondaryzone.com.zone .RE .RS 5 allow-notify: 192.0.2.2 NOKEY @@ -92,7 +88,7 @@ allow-notify: 192.0.2.2 NOKEY request-xfr: 192.0.2.2 NOKEY .RE .LP -Then, use kill \-HUP to reload changes from master zone files. +Then, use kill \-HUP to reload changes from primary zone files. And use kill \-TERM to stop the server. .SH "FILE FORMAT" There must be whitespace between keywords. Attribute keywords end @@ -138,7 +134,7 @@ and '~' work, see \fBglob\fR(7). If no files match the pattern, this is not an error. .SS "Server Options" .LP -The global options (if not overridden from the NSD commandline) are +The global options (if not overridden from the NSD command-line) are taken from the .B server: clause. There may only be one @@ -148,7 +144,7 @@ clause. .B ip\-address:\fR [@port] [servers] [bindtodevice] [setfib] NSD will bind to the listed ip\-address. Can be given multiple times to bind multiple ip\-addresses. Optionally, a port number can be given. -If none are given NSD listens to the wildcard interface. Same as commandline option +If none are given NSD listens to the wildcard interface. Same as command-line option .BR \-a. .IP To limit which NSD server(s) listen on the given interface, specify one or @@ -195,10 +191,10 @@ Set the receive buffer size for query-servicing sockets. Set to 0 to use the de .TP .B debug\-mode:\fR Turns on debugging mode for nsd, does not fork a daemon process. -Default is no. Same as commandline option +Default is no. Same as command-line option .BR \-d. If set to yes it does not fork and stays in the foreground, which can -be helpful for commandline debugging, but is also used by certain +be helpful for command-line debugging, but is also used by certain server supervisor processes to ascertain that the server is running. .TP .B do\-ip4:\fR @@ -207,6 +203,9 @@ If yes, NSD listens to IPv4 connections. Default yes. .B do\-ip6:\fR If yes, NSD listens to IPv6 connections. Default yes. .TP +.B database:\fR +This option is ignored by NSD versions 4.8.0 and newer, because the database feature has been removed. +.TP .B zonelistfile:\fR By default .I @zonelistfile@ @@ -218,7 +217,7 @@ This file is used for the nsd\-control addzone and delzone commands. .B identity:\fR Returns the specified identity when asked for CH TXT ID.SERVER. Default is the name as returned by gethostname(3). Same as -commandline option +command-line option .BR \-i . See hide\-identity to set the server to not respond to such queries. .TP @@ -230,12 +229,12 @@ See hide\-version to set the server to not respond to such queries. .B nsid:\fR Add the specified nsid to the EDNS section of the answer when queried with an NSID EDNS enabled packet. As a sequence of hex characters or -with ascii_ prefix and then an ascii string. Same as commandline option +with ascii_ prefix and then an ascii string. Same as command-line option .BR \-I . .TP .B logfile:\fR Log messages to the logfile. The default is to log to stderr and -syslog (with facility LOG_DAEMON). Same as commandline option +syslog (with facility LOG_DAEMON). Same as command-line option .BR \-l . .TP .B log\-only\-syslog:\fR @@ -245,8 +244,8 @@ been opened, the server uses stderr. Stderr is also used if syslog is not available. Default is no. .TP .B server\-count:\fR -Start this many NSD servers. Default is 1. Same as commandline -option +Start this many NSD servers. Default is 1. Same as command-line +option .BR \-N . .TP .B cpu\-affinity:\fR ... @@ -267,7 +266,7 @@ enabled. .TP .B tcp\-count:\fR The maximum number of concurrent, active TCP connections by each server. -Default is 100. Same as commandline option +Default is 100. Same as command-line option .BR \-n . .TP .B tcp\-reject\-overflow:\fR @@ -324,19 +323,19 @@ Preferred EDNS buffer size for IPv6. Default 1232. .B pidfile:\fR Use the pid file instead of the platform specific default, usually .IR @pidfile@. -Same as commandline option +Same as command-line option .BR \-P . With "" there is no pidfile, for some startup management setups, where a pidfile is not useful to have. .TP .B port:\fR Answer queries on the specified port. Default is 53. Same as -commandline option +command-line option .BR \-p . .TP .B statistics:\fR If not present no statistics are dumped. Statistics are produced -every number seconds. Same as commandline option +every number seconds. Same as command-line option .BR \-s . .TP .B chroot:\fR @@ -346,20 +345,19 @@ inside the chroot, you have to prepend the \fBchroot\fR path. That way, you can switch the chroot option on and off without having to modify anything else in the configuration. Set the value to "" (the empty string) to disable the chroot. By default "\fI@chrootdir@\fR" is used. Same as -commandline option +command-line option .BR \-t . .TP .B username:\fR After binding the socket, drop user privileges and assume the -username. Can be username, id or id.gid. Same as commandline option +username. Can be username, id or id.gid. Same as command-line option .BR \-u . .TP .B zonesdir:\fR Change the working directory to the specified directory before accessing -zone files. Also, NSD will access \fBdatabase\fR, \fBzonelistfile\fR, -\fBlogfile\fR, \fBpidfile\fR, \fBxfrdfile\fR, \fBxfrdir\fR, -\fBserver-key-file\fR, \fBserver-cert-file\fR, \fBcontrol-key-file\fR and -\fBcontrol-cert-file\fR +zone files. Also, NSD will access \fBzonelistfile\fR, \fBlogfile\fR, +\fBpidfile\fR, \fBxfrdfile\fR, \fBxfrdir\fR, \fBserver-key-file\fR, +\fBserver-cert-file\fR, \fBcontrol-key-file\fR and \fBcontrol-cert-file\fR relative to this directory. Set the value to "" (the empty string) to disable the change of working directory. By default "\fI@zonesdir@\fR" is used. @@ -371,7 +369,7 @@ Ignored, for compatibility with NSD3 config files. The soa timeout and zone transfer daemon in NSD will save its state to this file. State is read back after a restart. The state file can be deleted without too much harm, but timestamps of zones will be gone. -If it is configured as "", the state file is not used, all slave zones +If it is configured as "", the state file is not used, all secondary zones are checked for updates upon startup. For more details see the section on zone expiry behavior of NSD. Default is .IR @xfrdfile@ . @@ -456,13 +454,9 @@ The default is yes. The nsd\-control reload command reloads zone files regardless of this option. .TP .B zonefiles\-write:\fR -Write changed secondary zones to their zonefile every N seconds. If the -zone (pattern) configuration has "" zonefile, it is not written. Zones that -have received zone transfer updates are written to their zonefile. -Default is 0 (disabled) when there is a database, and 3600 (1 hour) when -database is "". The database also commits zone transfer contents. -You can configure it away from the default by putting the config statement -for zonefiles\-write: after the database: statement in the config file. +Write updated secondary zones to their zonefile every N seconds. If the +zone or pattern's "zonefile" option is set to "" (empty string), no zonefile +is written. The default is 3600 (1 hour). .\" rrlstart .TP .B rrl\-size:\fR @@ -740,8 +734,10 @@ The zone options such as .BR verify\-zone , .BR verifier , .BR verifier\-feed\-zone , +.BR verifier\-timeout , +.BR catalog , and -.B verifier\-timeout +.B catalog\-member\-pattern can be given. They are applied to the patterns and zones that include this pattern. .SS "Zone Options" @@ -824,7 +820,7 @@ symbols. .RE .TP .B request\-xfr:\fR [AXFR|UDP] [tls\-auth\-name] -Access control list. The listed address (the master) is queried for +Access control list. The listed address (the primary) is queried for AXFR/IXFR on update. A port number can be added using a suffix of @number, for example 1.2.3.4@5300. The specified key is used during AXFR/IXFR. If tls-auth-name is included, the specified tls-auth clause will be used to @@ -833,9 +829,9 @@ perform authenticated XFR-over-TLS. .RS If the AXFR option is given, the server will not be contacted with IXFR queries but only AXFR requests will be made to the server. This -allows an NSD secondary to have a master server that runs NSD. If +allows an NSD secondary to have a primary server that runs NSD. If the AXFR option is left out then both IXFR and AXFR requests are -made to the master server. +made to the primary server. .P If the UDP option is given, the secondary will use UDP to transmit the IXFR requests. You should deploy TSIG when allowing UDP transport, to authenticate @@ -844,7 +840,7 @@ Kaminsky\-style attacks. If the UDP option is left out then IXFR will be transmitted using TCP. .P If a tls-auth-name is given then TLS (by default on port 853) will be used -for all zone transfers for the zone. If authentication of the master based on +for all zone transfers for the zone. If authentication of the primary based on the specified tls-auth authentication information fails, the XFR request will not be sent. Support for TLS 1.3 is required for XFR-over-TLS. .RE @@ -971,10 +967,13 @@ The RRL classification types are: nxdomain, error, referral, any, rrsig, wildcard, nodata, dnskey, positive, all. .\" rrlend .TP +.B multi\-primary\-check:\fR +Default no. If enabled, checks all primaries for the last version. It uses +the higher version of all the configured primaries. Useful if you have multiple +primaries that have different version numbers served. +.TP .B multi\-master\-check:\fR -Default no. If enabled, checks all masters for the last version. It uses -the higher version of all the configured masters. Useful if you have multiple -masters that have different version numbers served. +It is the same as multi\-primary\-check. .TP .B verify\-zone:\fR Enable or disable verification for this zone. Default is value\-zones @@ -990,10 +989,57 @@ Feed updated zone to verifier over standard input. Default is verifier\-feed\-zone configured in .B verify:\fR. .TP -.B verifier\-timeout: +.B verifier\-timeout:\fR Number of seconds before verifier is forcefully terminated. Specify 0 (zero) to not use a specific timeout. Default is verifier\-timeout from .B verify:\fR. +.TP +.B catalog:\fR +If set to \fIconsumer\fR, catalog zone processing is enabled for the zone. +Only a single zone may be configured as a catalog consumer zone. When more than +one catalog consumer zone is configured, none of them will be processed. +Member zones of the catalog will use the pattern specified by the group +property, or if a group property is missing or invalid, the pattern specified +by the \fBcatalog\-member\-pattern\fR option is used. Group properties are valid +if there is only a single value matching the name of a for member zones valid +pattern. +.IP +A zone with the option set to \fIproducer\fR, can be used to produce a +catalog zone. Member zones for catalog producer zones can be added with +"\fInsd\-control addzone \fR", where has a +\fBcatalog\-producer\-zone\fR option pointing to a catalog producer zone. +Members will get a group property with the pattern name as value. +Catalog producer zones must be primary zones and may not have a +\fBrequest\-xfr\fR option. Catalog producer zones will \fInot\fR read content +from zone files, but will reconstruct the zone on startup from the member zone +entries in @zonelistfile@, specified with the \fBzonelistfile\fR option. +.IP +The status of both catalog consumer and producer zones can be verified with +\fInsd\-control zonestatus\fR. It will show the number of member zones and, if +the catalog zone is invalid, the reason for it to be invalid is shown. +\fInsd\-control zonestatus\fR will also show the entry of a catalog member zone +in the catalog (consumer or producer) zone as \fBcatalog-member-id:\fR. +.IP +A catalog zone can either be catalog consumer zone or a catalog producer zone +but not both. Likewise, catalog member zones can be either a member of catalog +consumer zone or a catalog producer zone but not both. +.IP +Catalog zones contain a list of zones that are served. Use \fBallow\-query: +0.0.0.0/0 BLOCKED\fR and \fBallow\-query: ::0/0 BLOCKED\fR in a catalog zone +zone or pattern clause to prevent revealing the catalog. Also consider using +transfers over TLS to further protect the catalog against eavesdroppers. +.TP +.B catalog\-member\-pattern:\fR +If this option is provided for a catalog consumer zone, members of that catalog +that have a missing or an invalid group property will be added using pattern +. +.TP +.B catalog\-producer\-zone:\fR +This option can only be used in a pattern. Adding a zone using +"\fInsd\-control addzone \fR with a containing this +option, will cause a catalog member entry to be created in the catalog producer +zone . must exist and must be a valid catalog +producer zone. .SS "Key Declarations" The .B key: @@ -1109,17 +1155,17 @@ These are responses from NSD to clients. BIND9 is a name server implementation with its own configuration file format, named.conf(5). BIND9 types zones as 'Master' or 'Slave'. .SS "Slave zones" -For a slave zone, the master servers are listed. The master servers are +For a secondary zone, the primary servers are listed. The primary servers are queried for zone data, and are listened to for update notifications. In NSD these two properties need to be configured separately, by listing -the master address in allow\-notify and request\-xfr statements. +the primary address in allow\-notify and request\-xfr statements. .P In BIND9 you only need to provide allow\-notify elements for any extra sources of notifications (i.e. the operators), NSD needs to have -allow\-notify for both masters and operators. BIND9 allows +allow\-notify for both primaries and operators. BIND9 allows additional transfer sources, in NSD you list those as request\-xfr. .P -Here is an example of a slave zone in BIND9 syntax. +Here is an example of a secondary zone in BIND9 syntax. .P # Config file for example.org options { @@ -1147,13 +1193,13 @@ keys { tsig.example.org. ; }; .LP zone "example.org" { .RS 5 -type slave; +type secondary; .RE .RS 5 file "secondary/example.org.signed"; .RE .RS 5 -masters { 162.0.4.49; }; +primaries { 162.0.4.49; }; .RE }; .P @@ -1185,7 +1231,7 @@ name: "example.org" zonefile: "secondary/example.org.signed" .RE .RS 5 -# the master is allowed to notify and will provide zone data. +# the primary is allowed to notify and will provide zone data. .RE .RS 5 allow\-notify: 162.0.4.49 NOKEY @@ -1194,24 +1240,24 @@ allow\-notify: 162.0.4.49 NOKEY request\-xfr: 162.0.4.49 tsig.example.org. .RE .P -Notice that the master is listed twice, once to allow it to send notifies -to this slave server and once to tell the slave server where to look for +Notice that the primary is listed twice, once to allow it to send notifies +to this secondary server and once to tell the secondary server where to look for updates zone data. More allow\-notify and request\-xfr lines can be -added to specify more masters. +added to specify more primaries. .P It is possible to specify extra allow\-notify lines for addresses -that are also allowed to send notifications to this slave server. +that are also allowed to send notifications to this secondary server. .SS "Master zones" -For a master zone in BIND9, the slave servers are listed. These slave +For a primary zone in BIND9, the secondary servers are listed. These secondary servers are sent notifications of updated and are allowed to request transfer of the zone data. In NSD these two properties need to be configured separately. .P -Here is an example of a master zone in BIND9 syntax. +Here is an example of a primary zone in BIND9 syntax. .LP zone "example.nl" { .RS 5 -type master; +type primary; .RE .RS 5 file "example.nl"; @@ -1238,7 +1284,7 @@ provide\-xfr: ::0/0 NOKEY .RE .P .RS 5 -# to list a slave server you would in general give +# to list a secondary server you would in general give .RE .RS 5 # provide\-xfr: 1.2.3.4 tsig\-key.name. @@ -1256,11 +1302,6 @@ also function as a resolver or cache. The configuration options that BIND9 has for the resolver or caching thus have no equivalents for NSD. .SH "FILES" .TP -"@dbfile@" -default -.B NSD -database -.TP @nsdconfigfile@ default .B NSD @@ -1269,9 +1310,8 @@ configuration file \fInsd\fR(8), \fInsd\-checkconf\fR(8), \fInsd\-control\fR(8) .SH "AUTHORS" .B NSD -was written by NLnet Labs and RIPE NCC joint team. Please see +was written by a combined team from NLnet Labs and RIPE NCC. Please see the CREDITS file in the distribution for further details. .SH "BUGS" .B nsd.conf -is parsed by a primitive parser, error messages may not be to the -point. +is parsed by a primitive parser. Error messages may not be to the point. diff --git a/usr.sbin/nsd/nsd.conf.sample.in b/usr.sbin/nsd/nsd.conf.sample.in index 676825984..3ff4196e4 100644 --- a/usr.sbin/nsd/nsd.conf.sample.in +++ b/usr.sbin/nsd/nsd.conf.sample.in @@ -399,12 +399,12 @@ remote-control: # which is only offered for transfer to secondaries over TLS. #allow-query: 192.0.2.0/24 NOKEY - # If no master and slave access control elements are provided, + # If no primary and secondary access control elements are provided, # this zone will not be served to/from other servers. - # A master zone needs notify: and provide-xfr: lists. A slave + # A primary zone needs notify: and provide-xfr: lists. A secondary # may also allow zone transfer (for debug or other secondaries). - # notify these slaves when the master zone changes, address TSIG|NOKEY + # notify these secondaries when the primary zone changes, address TSIG|NOKEY # IP can be ipv4 and ipv6, with @port for a nondefault port number. #notify: 192.0.2.1 NOKEY # allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED @@ -425,9 +425,9 @@ remote-control: # provide-xfr: 0.0.0.0/0 NOKEY # provide-xfr: ::0/0 NOKEY - # A slave zone needs allow-notify: and request-xfr: lists. + # A secondary zone needs allow-notify: and request-xfr: lists. #allow-notify: 2001:db8::0/64 my_tsig_key_name - # By default, a slave will request a zone transfer with IXFR/TCP. + # By default, a secondary will request a zone transfer with IXFR/TCP. # If you want to make use of IXFR/UDP use: UDP addr tsigkey # for a master that only speaks AXFR (like NSD) use AXFR addr tsigkey # If you want to require use of XFR-over-TLS use: addr tsigkey tlsauthname @@ -451,9 +451,9 @@ remote-control: # retry values (limited to the bounds given with the above parameters), plus 1. #min-expire-time: 0 - # Slave server tries zone transfer to all masters and picks highest - # zone version available, for when masters have different versions. - #multi-master-check: no + # Secondary server tries zone transfer to all primaries and picks highest + # zone version available, for when primaries have different versions. + #multi-primary-check: no # limit the zone transfer size (in bytes), stops very large transfers # 0 is no limits enforced. @@ -467,7 +467,7 @@ remote-control: # from that pattern are inserted into this one (as if it were a # macro). The statement can be given in between other statements, # because the order of access control elements can make a difference - # (which master to request from first, which slave to notify first). + # (which master to request from first, which secondary to notify first). #include-pattern: "common-masters" # Verify zone before publishing. @@ -488,6 +488,24 @@ remote-control: # Default is verifier-timeout in verify. # verifier-timeout: 0 + # Turn this zone into a catalog consumer zone. + # The catalog-member-pattern option is the default pattern that + # will be used for members without or with invalid group property. + # catalog: consumer + # catalog-member-pattern: "example-pattern" + + # Turn this zone into a catalog producer zone. + # Member zones can be added using nsd-control addzone + # where is a pattern containing a catalog-producer-zone + # option pointing to this zone. + # catalog: producer + + # Use this pattern to add catalog producer members. "catalog1.invalid" + # needs to be a valid catalog producer zone; i.e. a primary zone + # without a request-xfr option and with and catalog option set to + # producer. + # catalog-producer-member: "catalog1.invalid" + # Fixed zone entries. Here you can config zones that cannot be deleted. # Zones that are dynamically added and deleted are put in the zonelist file. # diff --git a/usr.sbin/nsd/options.c b/usr.sbin/nsd/options.c index 2ce9720ce..f964dcb06 100644 --- a/usr.sbin/nsd/options.c +++ b/usr.sbin/nsd/options.c @@ -21,6 +21,7 @@ #include "difffile.h" #include "rrl.h" #include "bitset.h" +#include "xfrd.h" #include "configparser.h" config_parser_state_type* cfg_parser = 0; @@ -202,7 +203,8 @@ warn_if_directory(const char* filetype, FILE* f, const char* fname) int parse_options_file(struct nsd_options* opt, const char* file, - void (*err)(void*,const char*), void* err_arg) + void (*err)(void*,const char*), void* err_arg, + struct nsd_options* old_opts) { FILE *in = 0; struct pattern_options* pat; @@ -246,6 +248,10 @@ parse_options_file(struct nsd_options* opt, const char* file, RBTREE_FOR(pat, struct pattern_options*, opt->patterns) { + struct pattern_options* old_pat = + old_opts ? pattern_options_find(old_opts, pat->pname) + : NULL; + /* lookup keys for acls */ for(acl=pat->allow_notify; acl; acl=acl->next) { @@ -300,6 +306,43 @@ parse_options_file(struct nsd_options* opt, const char* file, c_error("key %s in pattern %s could not be found", acl->key_name, pat->pname); } + /* lookup zones for catalog-producer-zone options */ + if(pat->catalog_producer_zone) { + struct zone_options* zopt; + const dname_type *dname = dname_parse(opt->region, + pat->catalog_producer_zone); + if(dname == NULL) { + ; /* pass; already erred during parsing */ + + } else if (!(zopt = zone_options_find(opt, dname))) { + c_error("catalog producer zone %s in pattern " + "%s could not be found", + pat->catalog_producer_zone, + pat->pname); + + } else if (!zone_is_catalog_producer(zopt)) { + c_error("catalog-producer-zone %s in pattern " + "%s is not configered as a " + "catalog: producer", + pat->catalog_producer_zone, + pat->pname); + } + } + if( !old_opts /* Okay to add a cat producer member zone pat */ + || (!old_pat) /* But not to add, change or del an existing */ + || ( old_pat && !old_pat->catalog_producer_zone + && !pat->catalog_producer_zone) + || ( old_pat && old_pat->catalog_producer_zone + && pat->catalog_producer_zone + && strcmp( old_pat->catalog_producer_zone + , pat->catalog_producer_zone) == 0)){ + ; /* No existing catalog producer member zone added + * or changed. Everyting is fine: pass */ + } else { + c_error("catalog-producer-zone in pattern %s cannot " + "be removed or changed on a running NSD", + pat->pname); + } } if(cfg_parser->errors > 0) @@ -372,18 +415,26 @@ zone_list_free_insert(struct nsd_options* opt, int linesize, off_t off) opt->zonefree_number++; } -struct zone_options* -zone_list_zone_insert(struct nsd_options* opt, const char* nm, - const char* patnm, int linesize, off_t off) +static struct zone_options* +zone_list_member_zone_insert(struct nsd_options* opt, const char* nm, + const char* patnm, int linesize, off_t off, const char* mem_idnm, + new_member_id_type new_member_id) { struct pattern_options* pat = pattern_options_find(opt, patnm); + struct catalog_member_zone* cmz = NULL; struct zone_options* zone; + char member_id_str[MAXDOMAINLEN * 5 + 3] = "ERROR!"; + DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "zone_list_zone_insert(\"%s\", \"%s\"" + ", %d, \"%s\")", nm, patnm, linesize, + (mem_idnm ? mem_idnm : ""))); if(!pat) { log_msg(LOG_ERR, "pattern does not exist for zone %s " "pattern %s", nm, patnm); return NULL; } - zone = zone_options_create(opt->region); + zone = pat->catalog_producer_zone + ? &(cmz = catalog_member_zone_create(opt->region))->options + : zone_options_create(opt->region); zone->part_of_config = 0; zone->name = region_strdup(opt->region, nm); zone->linesize = linesize; @@ -396,9 +447,40 @@ zone_list_zone_insert(struct nsd_options* opt, const char* nm, region_recycle(opt->region, zone, sizeof(*zone)); return NULL; } + if(!mem_idnm) { + if(cmz && new_member_id) + new_member_id(cmz); + if(cmz && cmz->member_id) { + /* Assume all bytes of member_id are printable. + * plus 1 for space + */ + zone->linesize += label_length(dname_name(cmz->member_id)) + 1; + DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "new linesize: %d", + (int)zone->linesize)); + } + } else if(!cmz) + log_msg(LOG_ERR, "member ID '%s' given, but no catalog-producer-" + "zone value provided in zone '%s' or pattern '%s'", + mem_idnm, nm, patnm); + + else if(snprintf(member_id_str, sizeof(member_id_str), + "%s.zones.%s", mem_idnm, pat->catalog_producer_zone) >= + (int)sizeof(member_id_str)) + log_msg(LOG_ERR, "syntax error in member ID '%s.zones.%s' for " + "zone '%s'", mem_idnm, pat->catalog_producer_zone, nm); + + else if(!(cmz->member_id = dname_parse(opt->region, member_id_str))) + log_msg(LOG_ERR, "parse error in member ID '%s' for " + "zone '%s'", member_id_str, nm); return zone; } +struct zone_options* +zone_list_zone_insert(struct nsd_options* opt,const char* nm,const char* patnm) +{ + return zone_list_member_zone_insert(opt, nm, patnm, 0, 0, NULL, NULL); +} + int parse_zone_list_file(struct nsd_options* opt) { @@ -465,8 +547,42 @@ parse_zone_list_file(struct nsd_options* opt) /* store offset and line size for zone entry */ /* and create zone entry in zonetree */ - (void)zone_list_zone_insert(opt, nm, patnm, linesize, - ftello(opt->zonelist)-linesize); + (void)zone_list_member_zone_insert(opt, nm, patnm, + linesize, ftello(opt->zonelist)-linesize, + NULL, NULL); + + } else if(strncmp(buf, "cat ", 4) == 0) { + int linesize = strlen(buf); + /* parse the 'add' line */ + /* pick last space on the line, so that the domain + * name can have a space in it (but not the pattern)*/ + char* nm = buf + 4; + char* mem_idnm = strrchr(nm, ' '), *patnm; + if(!mem_idnm) { + /* parse error */ + log_msg(LOG_ERR, "parse error in %s: '%s'", + opt->zonelistfile, buf); + continue; + } + *mem_idnm++ = 0; + patnm = strrchr(nm, ' '); + if(!patnm) { + *--mem_idnm = ' '; + /* parse error */ + log_msg(LOG_ERR, "parse error in %s: '%s'", + opt->zonelistfile, buf); + continue; + } + *patnm++ = 0; + if(linesize && buf[linesize-1] == '\n') + buf[linesize-1] = 0; + + /* store offset and line size for zone entry */ + /* and create zone entry in zonetree */ + (void)zone_list_member_zone_insert(opt, nm, patnm, + linesize, ftello(opt->zonelist)-linesize, + mem_idnm, NULL); + } else if(strncmp(buf, "del ", 4) == 0) { /* store offset and line size for deleted entry */ int linesize = strlen(buf); @@ -485,26 +601,62 @@ parse_zone_list_file(struct nsd_options* opt) void zone_options_delete(struct nsd_options* opt, struct zone_options* zone) { + struct catalog_member_zone* member_zone = as_catalog_member_zone(zone); + rbtree_delete(opt->zone_options, zone->node.key); region_recycle(opt->region, (void*)zone->node.key, dname_total_size( (dname_type*)zone->node.key)); - region_recycle(opt->region, zone, sizeof(*zone)); + if(!member_zone) { + region_recycle(opt->region, zone, sizeof(*zone)); + return; + } + /* Because catalog member zones are in xfrd only deleted through + * catalog_del_consumer_member_zone() or through + * xfrd_del_catalog_producer_member(), which both clear the node, + * and because member zones in the main and serve processes are not + * indexed, *member_zone->node == *RBTREE_NULL. + * member_id is cleared too by those delete function, but there may be + * leftover member_id's from the initial zone.list processing, which + * made it to the main and serve processes. + */ + assert(!memcmp(&member_zone->node, RBTREE_NULL, sizeof(*RBTREE_NULL))); + if(member_zone->member_id) { + region_recycle(opt->region, (void*)member_zone->member_id, + dname_total_size(member_zone->member_id)); + } + region_recycle(opt->region, member_zone, sizeof(*member_zone)); } + /* add a new zone to the zonelist */ struct zone_options* -zone_list_add(struct nsd_options* opt, const char* zname, const char* pname) +zone_list_add_or_cat(struct nsd_options* opt, const char* zname, + const char* pname, new_member_id_type new_member_id) { int r; struct zonelist_free* e; struct zonelist_bucket* b; - int linesize = 6 + strlen(zname) + strlen(pname); + char zone_list_line[6 + 5 * MAXDOMAINLEN + 2024 + 65]; + struct catalog_member_zone* cmz; + /* create zone entry */ - struct zone_options* zone = zone_list_zone_insert(opt, zname, pname, - linesize, 0); + struct zone_options* zone = zone_list_member_zone_insert( + opt, zname, pname, 6 + strlen(zname) + strlen(pname), + 0, NULL, new_member_id); if(!zone) return NULL; + if(zone_is_catalog_producer_member(zone) + && (cmz = as_catalog_member_zone(zone)) + && cmz->member_id) { + snprintf(zone_list_line, sizeof(zone_list_line), + "cat %s %s %.*s\n", zname, pname, + (int)label_length(dname_name(cmz->member_id)), + (const char*)dname_name(cmz->member_id) + 1); + } else { + snprintf(zone_list_line, sizeof(zone_list_line), + "add %s %s\n", zname, pname); + } /* use free entry or append to file or create new file */ if(!opt->zonelist || opt->zonelist_off == 0) { /* create new file */ @@ -531,7 +683,7 @@ zone_list_add(struct nsd_options* opt, const char* zname, const char* pname) zone->off = ftello(opt->zonelist); if(zone->off == -1) log_msg(LOG_ERR, "ftello(%s): %s", opt->zonelistfile, strerror(errno)); - r = fprintf(opt->zonelist, "add %s %s\n", zname, pname); + r = fprintf(opt->zonelist, "%s", zone_list_line); if(r != zone->linesize) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", @@ -561,7 +713,7 @@ zone_list_add(struct nsd_options* opt, const char* zname, const char* pname) zone_options_delete(opt, zone); return NULL; } - r = fprintf(opt->zonelist, "add %s %s\n", zname, pname); + r = fprintf(opt->zonelist, "%s", zone_list_line); if(r != zone->linesize) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", @@ -572,7 +724,7 @@ zone_list_add(struct nsd_options* opt, const char* zname, const char* pname) zone_options_delete(opt, zone); return NULL; } - opt->zonelist_off += linesize; + opt->zonelist_off += zone->linesize; if(fflush(opt->zonelist) != 0) { log_msg(LOG_ERR, "fflush %s: %s", opt->zonelistfile, strerror(errno)); } @@ -587,7 +739,7 @@ zone_list_add(struct nsd_options* opt, const char* zname, const char* pname) zone_options_delete(opt, zone); return NULL; } - r = fprintf(opt->zonelist, "add %s %s\n", zname, pname); + r = fprintf(opt->zonelist, "%s", zone_list_line); if(r != zone->linesize) { if(r == -1) log_msg(LOG_ERR, "could not write to %s: %s", @@ -617,6 +769,11 @@ zone_list_add(struct nsd_options* opt, const char* zname, const char* pname) void zone_list_del(struct nsd_options* opt, struct zone_options* zone) { + if (zone_is_catalog_consumer_member(zone)) { + /* catalog consumer member zones are not in the zones.list file */ + zone_options_delete(opt, zone); + return; + } /* put its space onto the free entry */ if(fseeko(opt->zonelist, zone->off, SEEK_SET) == -1) { log_msg(LOG_ERR, "fseeko(%s): %s", opt->zonelistfile, strerror(errno)); @@ -691,10 +848,21 @@ zone_list_compact(struct nsd_options* opt) return; } RBTREE_FOR(zone, struct zone_options*, opt->zone_options) { + struct catalog_member_zone* cmz; + if(zone->part_of_config) continue; - r = fprintf(out, "add %s %s\n", zone->name, - zone->pattern->pname); + if(zone_is_catalog_producer_member(zone) + && (cmz = as_catalog_member_zone(zone)) + && cmz->member_id) { + r = fprintf(out, "cat %s %s %.*s\n", zone->name, + zone->pattern->pname, + (int)label_length(dname_name(cmz->member_id)), + (const char*)dname_name(cmz->member_id) + 1); + } else { + r = fprintf(out, "add %s %s\n", zone->name, + zone->pattern->pname); + } if(r < 0) { log_msg(LOG_ERR, "write %s failed: %s", outname, strerror(errno)); @@ -807,9 +975,26 @@ zone_options_create(region_type* region) zone->name = 0; zone->pattern = 0; zone->part_of_config = 0; + zone->is_catalog_member_zone = 0; return zone; } +struct catalog_member_zone* +catalog_member_zone_create(region_type* region) +{ + struct catalog_member_zone* member_zone; + member_zone = (struct catalog_member_zone*)region_alloc(region, + sizeof(struct catalog_member_zone)); + member_zone->options.node = *RBTREE_NULL; + member_zone->options.name = 0; + member_zone->options.pattern = 0; + member_zone->options.part_of_config = 0; + member_zone->options.is_catalog_member_zone = 1; + member_zone->member_id = NULL; + member_zone->node = *RBTREE_NULL; + return member_zone; +} + /* true is booleans are the same truth value */ #define booleq(x,y) ( ((x) && (y)) || (!(x) && !(y)) ) @@ -896,7 +1081,7 @@ pattern_options_create(region_type* region) #ifdef RATELIMIT p->rrl_whitelist = 0; #endif - p->multi_master_check = 0; + p->multi_primary_check = 0; p->store_ixfr = 0; p->store_ixfr_is_default = 1; p->ixfr_size = IXFR_SIZE_DEFAULT; @@ -912,7 +1097,10 @@ pattern_options_create(region_type* region) p->verifier_feed_zone_is_default = 1; p->verifier_timeout = VERIFIER_TIMEOUT_INHERIT; p->verifier_timeout_is_default = 1; - + p->catalog_role = CATALOG_ROLE_INHERIT; + p->catalog_role_is_default = 1; + p->catalog_member_pattern = NULL; + p->catalog_producer_zone = NULL; return p; } @@ -1099,7 +1287,7 @@ copy_pat_fixed(region_type* region, struct pattern_options* orig, #ifdef RATELIMIT orig->rrl_whitelist = p->rrl_whitelist; #endif - orig->multi_master_check = p->multi_master_check; + orig->multi_primary_check = p->multi_primary_check; orig->store_ixfr = p->store_ixfr; orig->store_ixfr_is_default = p->store_ixfr_is_default; orig->ixfr_size = p->ixfr_size; @@ -1114,6 +1302,16 @@ copy_pat_fixed(region_type* region, struct pattern_options* orig, orig->verifier_timeout_is_default = p->verifier_timeout_is_default; orig->verifier_feed_zone = p->verifier_feed_zone; orig->verifier_feed_zone_is_default = p->verifier_feed_zone_is_default; + orig->catalog_role = p->catalog_role; + orig->catalog_role_is_default = p->catalog_role_is_default; + if(p->catalog_member_pattern) + orig->catalog_member_pattern = + region_strdup(region, p->catalog_member_pattern); + else orig->catalog_member_pattern = NULL; + if(p->catalog_producer_zone) + orig->catalog_producer_zone = + region_strdup(region, p->catalog_producer_zone); + else orig->catalog_producer_zone = NULL; } void @@ -1227,7 +1425,7 @@ pattern_options_equal(struct pattern_options* p, struct pattern_options* q) #ifdef RATELIMIT if(p->rrl_whitelist != q->rrl_whitelist) return 0; #endif - if(!booleq(p->multi_master_check,q->multi_master_check)) return 0; + if(!booleq(p->multi_primary_check,q->multi_primary_check)) return 0; if(p->size_limit_xfr != q->size_limit_xfr) return 0; if(!booleq(p->store_ixfr,q->store_ixfr)) return 0; if(!booleq(p->store_ixfr_is_default,q->store_ixfr_is_default)) return 0; @@ -1248,6 +1446,19 @@ pattern_options_equal(struct pattern_options* p, struct pattern_options* q) if(p->verifier_timeout != q->verifier_timeout) return 0; if(!booleq(p->verifier_timeout_is_default, q->verifier_timeout_is_default)) return 0; + if(p->catalog_role != q->catalog_role) return 0; + if(!booleq(p->catalog_role_is_default, + q->catalog_role_is_default)) return 0; + if(!p->catalog_member_pattern && q->catalog_member_pattern) return 0; + else if(p->catalog_member_pattern && !q->catalog_member_pattern) return 0; + else if(p->catalog_member_pattern && q->catalog_member_pattern) { + if(strcmp(p->catalog_member_pattern, q->catalog_member_pattern) != 0) return 0; + } + if(!p->catalog_producer_zone && q->catalog_producer_zone) return 0; + else if(p->catalog_producer_zone && !q->catalog_producer_zone) return 0; + else if(p->catalog_producer_zone && q->catalog_producer_zone) { + if(strcmp(p->catalog_producer_zone, q->catalog_producer_zone) != 0) return 0; + } return 1; } @@ -1456,7 +1667,7 @@ pattern_options_marshal(struct buffer* b, struct pattern_options* p) marshal_u8(b, p->min_retry_time_is_default); marshal_u32(b, p->min_expire_time); marshal_u8(b, p->min_expire_time_expr); - marshal_u8(b, p->multi_master_check); + marshal_u8(b, p->multi_primary_check); marshal_u8(b, p->store_ixfr); marshal_u8(b, p->store_ixfr_is_default); marshal_u64(b, p->ixfr_size); @@ -1472,6 +1683,10 @@ pattern_options_marshal(struct buffer* b, struct pattern_options* p) marshal_u8(b, p->verifier_feed_zone_is_default); marshal_u32(b, p->verifier_timeout); marshal_u8(b, p->verifier_timeout_is_default); + marshal_u8(b, p->catalog_role); + marshal_u8(b, p->catalog_role_is_default); + marshal_str(b, p->catalog_member_pattern); + marshal_str(b, p->catalog_producer_zone); } struct pattern_options* @@ -1506,7 +1721,7 @@ pattern_options_unmarshal(region_type* r, struct buffer* b) p->min_retry_time_is_default = unmarshal_u8(b); p->min_expire_time = unmarshal_u32(b); p->min_expire_time_expr = unmarshal_u8(b); - p->multi_master_check = unmarshal_u8(b); + p->multi_primary_check = unmarshal_u8(b); p->store_ixfr = unmarshal_u8(b); p->store_ixfr_is_default = unmarshal_u8(b); p->ixfr_size = unmarshal_u64(b); @@ -1522,6 +1737,10 @@ pattern_options_unmarshal(region_type* r, struct buffer* b) p->verifier_feed_zone_is_default = unmarshal_u8(b); p->verifier_timeout = unmarshal_u32(b); p->verifier_timeout_is_default = unmarshal_u8(b); + p->catalog_role = unmarshal_u8(b); + p->catalog_role_is_default = unmarshal_u8(b); + p->catalog_member_pattern = unmarshal_str(r, b); + p->catalog_producer_zone = unmarshal_str(r, b); return p; } @@ -2334,6 +2553,18 @@ config_apply_pattern(struct pattern_options *dest, const char* name) c_error("could not find pattern %s", name); return; } + if(strncmp(dest->pname, PATTERN_IMPLICIT_MARKER, + strlen(PATTERN_IMPLICIT_MARKER)) == 0 + && pat->catalog_producer_zone) { + c_error("patterns with an catalog-producer-zone option are to " + "be used with \"nsd-control addzone\" only and cannot " + "be included from zone clauses in the config file"); + return; + } + if((dest->catalog_role == CATALOG_ROLE_PRODUCER && pat->request_xfr) + || ( pat->catalog_role == CATALOG_ROLE_PRODUCER && dest->request_xfr)){ + c_error("catalog producer zones cannot be secondary zones"); + } /* apply settings */ if(pat->zonefile) @@ -2397,8 +2628,8 @@ config_apply_pattern(struct pattern_options *dest, const char* name) copy_and_append_acls(&dest->provide_xfr, pat->provide_xfr); copy_and_append_acls(&dest->allow_query, pat->allow_query); copy_and_append_acls(&dest->outgoing_interface, pat->outgoing_interface); - if(pat->multi_master_check) - dest->multi_master_check = pat->multi_master_check; + if(pat->multi_primary_check) + dest->multi_primary_check = pat->multi_primary_check; if(!pat->verify_zone_is_default) { dest->verify_zone = pat->verify_zone; @@ -2435,6 +2666,16 @@ config_apply_pattern(struct pattern_options *dest, const char* name) } dest->verifier = vec; } + if(!pat->catalog_role_is_default) { + dest->catalog_role = pat->catalog_role; + dest->catalog_role_is_default = 0; + } + if(pat->catalog_member_pattern) + dest->catalog_member_pattern = region_strdup( + cfg_parser->opt->region, pat->catalog_member_pattern); + if(pat->catalog_producer_zone) + dest->catalog_producer_zone = region_strdup( + cfg_parser->opt->region, pat->catalog_producer_zone); } void diff --git a/usr.sbin/nsd/options.h b/usr.sbin/nsd/options.h index ea7dda9e0..9e95d5f6e 100644 --- a/usr.sbin/nsd/options.h +++ b/usr.sbin/nsd/options.h @@ -20,6 +20,7 @@ struct buffer; struct nsd; struct proxy_protocol_port_list; + typedef struct nsd_options nsd_options_type; typedef struct pattern_options pattern_options_type; typedef struct zone_options zone_options_type; @@ -35,6 +36,9 @@ typedef struct config_parser_state config_parser_state_type; #define VERIFY_ZONE_INHERIT (2) #define VERIFIER_FEED_ZONE_INHERIT (2) #define VERIFIER_TIMEOUT_INHERIT (-1) +#define CATALOG_ROLE_INHERIT (0) +#define CATALOG_ROLE_CONSUMER (1) +#define CATALOG_ROLE_PRODUCER (2) /* * Options global for nsd. @@ -292,7 +296,7 @@ struct pattern_options { */ uint8_t min_expire_time_expr; uint64_t size_limit_xfr; - uint8_t multi_master_check; + uint8_t multi_primary_check; uint8_t store_ixfr; uint8_t store_ixfr_is_default; uint64_t ixfr_size; @@ -308,6 +312,10 @@ struct pattern_options { uint8_t verifier_feed_zone_is_default; int32_t verifier_timeout; uint8_t verifier_timeout_is_default; + uint8_t catalog_role; + uint8_t catalog_role_is_default; + const char* catalog_member_pattern; + const char* catalog_producer_zone; } ATTR_PACKED; #define PATTERN_IMPLICIT_MARKER "_implicit_" @@ -328,9 +336,27 @@ struct zone_options { * a anonymous pattern created in-place */ struct pattern_options* pattern; /* zone is fixed into the main config, not in zonelist, cannot delete */ - uint8_t part_of_config; + unsigned part_of_config : 1; + unsigned is_catalog_member_zone: 1; } ATTR_PACKED; +/* + * Options for catalog member zones + * assert(options->is_catalog_member_zone == 1) + * when options->pattern->catalog_producer_zone is set, this is a + * producer member zone, otherwise a consumer member zone. + * A catalog member zone is either a member zone of a catalog producer zone + * or a catalog consumer zone. They are mutually exclusive. + */ +struct catalog_member_zone { + struct zone_options options; + const struct dname* member_id; + /* node in the associated catalog consumer or producer zone */ + rbnode_type node; +} ATTR_PACKED; + +typedef void (*new_member_id_type)(struct catalog_member_zone* zone); + union acl_addr_storage { #ifdef INET6 struct in_addr addr; @@ -459,9 +485,13 @@ int nsd_options_insert_pattern(struct nsd_options* opt, /* parses options file. Returns false on failure. callback, if nonNULL, * gets called with error strings, default prints. */ int parse_options_file(struct nsd_options* opt, const char* file, - void (*err)(void*,const char*), void* err_arg); + void (*err)(void*,const char*), void* err_arg, + struct nsd_options* old_opts); struct zone_options* zone_options_create(region_type* region); void zone_options_delete(struct nsd_options* opt, struct zone_options* zone); +struct catalog_member_zone* catalog_member_zone_create(region_type* region); +static inline struct catalog_member_zone* as_catalog_member_zone(struct zone_options* zopt) +{ return zopt && zopt->is_catalog_member_zone ? (struct catalog_member_zone*)zopt : NULL; } /* find a zone by apex domain name, or NULL if not found. */ struct zone_options* zone_options_find(struct nsd_options* opt, const struct dname* apex); @@ -488,12 +518,16 @@ void tls_auth_options_insert(struct nsd_options* opt, struct tls_auth_options* a struct tls_auth_options* tls_auth_options_find(struct nsd_options* opt, const char* name); /* read in zone list file. Returns false on failure */ int parse_zone_list_file(struct nsd_options* opt); +/* create (potential) catalog producer member entry and add to the zonelist */ +struct zone_options* zone_list_add_or_cat(struct nsd_options* opt, + const char* zname, const char* pname, new_member_id_type new_member_id); /* create zone entry and add to the zonelist file */ -struct zone_options* zone_list_add(struct nsd_options* opt, const char* zname, - const char* pname); +static inline struct zone_options* zone_list_add(struct nsd_options* opt, + const char* zname, const char* pname) +{ return zone_list_add_or_cat(opt, zname, pname, NULL); } /* create zonelist entry, do not insert in file (called by _add) */ struct zone_options* zone_list_zone_insert(struct nsd_options* opt, - const char* nm, const char* patnm, int linesize, off_t off); + const char* nm, const char* patnm); void zone_list_del(struct nsd_options* opt, struct zone_options* zone); void zone_list_compact(struct nsd_options* opt); void zone_list_close(struct nsd_options* opt); @@ -544,6 +578,20 @@ int acl_equal(struct acl_options* p, struct acl_options* q); /* see if a zone is a slave or a master zone */ int zone_is_slave(struct zone_options* opt); +/* see if a zone is a catalog consumer */ +static inline int zone_is_catalog_consumer(struct zone_options* opt) +{ return opt && opt->pattern + && opt->pattern->catalog_role == CATALOG_ROLE_CONSUMER; } +static inline int zone_is_catalog_producer(struct zone_options* opt) +{ return opt && opt->pattern + && opt->pattern->catalog_role == CATALOG_ROLE_PRODUCER; } +static inline int zone_is_catalog_member(struct zone_options* opt) +{ return opt && opt->is_catalog_member_zone; } +static inline const char* zone_is_catalog_producer_member(struct zone_options* opt) +{ return opt && opt->pattern && opt->pattern->catalog_producer_zone + ? opt->pattern->catalog_producer_zone : NULL; } +static inline int zone_is_catalog_consumer_member(struct zone_options* opt) +{ return zone_is_catalog_member(opt) && !zone_is_catalog_producer_member(opt); } /* create zonefile name, returns static pointer (perhaps to options data) */ const char* config_make_zonefile(struct zone_options* zone, struct nsd* nsd); diff --git a/usr.sbin/nsd/query.c b/usr.sbin/nsd/query.c index 3f92ffbaa..7881dbebf 100644 --- a/usr.sbin/nsd/query.c +++ b/usr.sbin/nsd/query.c @@ -1365,6 +1365,18 @@ answer_lookup_zone(struct nsd *nsd, struct query *q, answer_type *answer, why->ip_address_spec, why->nokey?"NOKEY": (why->blocked?"BLOCKED":why->key_name))); + } else if(q->qtype == TYPE_SOA + && 0 == dname_compare(q->qname, + (const dname_type*)q->zone->opts->node.key) + && -1 != acl_check_incoming( + q->zone->opts->pattern->provide_xfr, q,&why)) { + assert(why); + DEBUG(DEBUG_QUERY,1, (LOG_INFO, "SOA apex query %s " + "passed request-xfr acl %s %s", + dname_to_string(q->qname, NULL), + why->ip_address_spec, + why->nokey?"NOKEY": + (why->blocked?"BLOCKED":why->key_name))); } else { if (verbosity >= 2) { char address[128]; diff --git a/usr.sbin/nsd/remote.c b/usr.sbin/nsd/remote.c index ebc779747..1921b46d3 100644 --- a/usr.sbin/nsd/remote.c +++ b/usr.sbin/nsd/remote.c @@ -74,6 +74,7 @@ #include "remote.h" #include "util.h" #include "xfrd.h" +#include "xfrd-catalog-zones.h" #include "xfrd-notify.h" #include "xfrd-tcp.h" #include "nsd.h" @@ -101,8 +102,10 @@ #define REMOTE_CONTROL_TCP_TIMEOUT 120 /** repattern to master or slave */ -#define REPAT_SLAVE 1 -#define REPAT_MASTER 2 +#define REPAT_SLAVE 1 +#define REPAT_MASTER 2 +#define REPAT_CATALOG_CONSUMER 4 +#define REPAT_CATALOG_CONSUMER_DEINIT 8 /** if you want zero to be inhibited in stats output. * it omits zeroes for types that have no acronym and unused-rcodes */ @@ -665,7 +668,8 @@ remote_accept_callback(int fd, short event, void* arg) n->ssl = SSL_new(rc->ctx); if(!n->ssl) { log_crypto_err("could not SSL_new"); - event_del(&n->c); + if(n->event_added) + event_del(&n->c); free(n); goto close_exit; } @@ -673,7 +677,8 @@ remote_accept_callback(int fd, short event, void* arg) (void)SSL_set_mode(n->ssl, SSL_MODE_AUTO_RETRY); if(!SSL_set_fd(n->ssl, newfd)) { log_crypto_err("could not SSL_set_fd"); - event_del(&n->c); + if(n->event_added) + event_del(&n->c); SSL_free(n->ssl); free(n); goto close_exit; @@ -958,7 +963,7 @@ do_transfer(RES* ssl, xfrd_state_type* xfrd, char* arg) xfrd_handle_notify_and_start_xfr(zone, NULL); send_ok(ssl); } else { - (void)ssl_printf(ssl, "error zone not slave\n"); + (void)ssl_printf(ssl, "error zone not secondary\n"); } } else { RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { @@ -999,7 +1004,7 @@ do_force_transfer(RES* ssl, xfrd_state_type* xfrd, char* arg) force_transfer_zone(zone); send_ok(ssl); } else { - (void)ssl_printf(ssl, "error zone not slave\n"); + (void)ssl_printf(ssl, "error zone not secondary\n"); } } else { RBTREE_FOR(zone, xfrd_zone_type*, xfrd->zones) { @@ -1037,6 +1042,62 @@ print_zonestatus(RES* ssl, xfrd_state_type* xfrd, struct zone_options* zo) if(!ssl_printf(ssl, " pattern: %s\n", zo->pattern->pname)) return 0; } + if(zone_is_catalog_consumer(zo)) { + zone_type* zone = namedb_find_zone(xfrd->nsd->db, + (const dname_type*)zo->node.key); + struct xfrd_catalog_consumer_zone* consumer_zone = + (struct xfrd_catalog_consumer_zone*) + rbtree_search( xfrd->catalog_consumer_zones + , zo->node.key); + + if(!ssl_printf(ssl, " catalog: consumer")) + return 0; + if(zone && zone->soa_rrset && zone->soa_rrset->rrs + && zone->soa_rrset->rrs[0].rdata_count > 2 + && rdata_atom_size(zone->soa_rrset->rrs[0].rdatas[2]) == + sizeof(uint32_t)) { + if(!ssl_printf(ssl, " (serial: %u, # members: %zu)\n", + read_uint32(rdata_atom_data( + zone->soa_rrset->rrs[0].rdatas[2])), + consumer_zone + ? consumer_zone->member_ids.count : 0)) + return 0; + + } else if(!ssl_printf(ssl, "\n")) + return 0; + if(invalid_catalog_consumer_zone(zo)) { + if(!ssl_printf(ssl, " catalog-invalid: %s\n", + invalid_catalog_consumer_zone(zo))) + return 0; + } + } + if(zone_is_catalog_producer(zo)) { + struct xfrd_catalog_producer_zone* producer_zone = + (struct xfrd_catalog_producer_zone*) + rbtree_search( xfrd->catalog_producer_zones + , zo->node.key); + if(!ssl_printf(ssl, " catalog: producer")) + return 0; + if(producer_zone) { + if(!ssl_printf(ssl, " (serial: %u, # members: %zu)\n", + (unsigned)producer_zone->serial, + producer_zone->member_ids.count)) + return 0; + } else if(!ssl_printf(ssl, "\n")) + return 0; + if (zone_is_slave(zo)) { + if(!ssl_printf(ssl, " catalog-invalid: a catalog " + "producer cannot be a secondary zone")) + return 0; + } + } + if(zone_is_catalog_member(zo)) { + if(!ssl_printf(ssl, " catalog-member-id: %s\n", + as_catalog_member_zone(zo)->member_id + ? dname_to_string(as_catalog_member_zone(zo)->member_id, NULL) + : "ERROR member-id is missing!")) + return 0; + } if(nz) { if(nz->is_waiting) { if(!ssl_printf(ssl, " notify: \"waiting-for-fd\"\n")) @@ -1057,7 +1118,7 @@ print_zonestatus(RES* ssl, xfrd_state_type* xfrd, struct zone_options* zo) } } if(!xz) { - if(!ssl_printf(ssl, " state: master\n")) + if(!ssl_printf(ssl, " state: primary\n")) return 0; return 1; } @@ -1267,6 +1328,15 @@ perform_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg) dname = NULL; return 0; } + if(zone_is_catalog_consumer_member(zopt)) { + (void)ssl_printf(ssl, "Error: Zone is a catalog " + "consumer member zone with id %s\nRepattern in the " + "catalog with a group property.\n", dname_to_string( + as_catalog_member_zone(zopt)->member_id, NULL)); + region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); + dname = NULL; + return 0; + } /* found the zone, now delete it */ /* create deletion task */ /* this deletion task is processed before the addition task, @@ -1281,6 +1351,10 @@ perform_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg) xfrd_del_slave_zone(xfrd, dname); } xfrd_del_notify(xfrd, dname); + /* delete it in xfrd's catalog consumers list */ + if(zone_is_catalog_consumer(zopt)) { + xfrd_deinit_catalog_consumer_zone(xfrd, dname); + } /* delete from config */ zone_list_del(xfrd->nsd->options, zopt); } else { @@ -1290,7 +1364,8 @@ perform_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg) dname = NULL; /* add to zonelist and adds to config in memory */ - zopt = zone_list_add(xfrd->nsd->options, arg, arg2); + zopt = zone_list_add_or_cat(xfrd->nsd->options, arg, arg2, + xfrd_add_catalog_producer_member); if(!zopt) { /* also dname parse error here */ (void)ssl_printf(ssl, "error could not add zonelist entry\n"); @@ -1302,6 +1377,10 @@ perform_changezone(RES* ssl, xfrd_state_type* xfrd, char* arg) getzonestatid(xfrd->nsd->options, zopt)); zonestat_inc_ifneeded(xfrd); xfrd_set_reload_now(xfrd); + /* add to xfrd - catalog consumer zones */ + if (zone_is_catalog_consumer(zopt)) { + xfrd_init_catalog_consumer_zone(xfrd, zopt); + } /* add to xfrd - notify (for master and slaves) */ init_notify_send(xfrd->notify_zones, xfrd->region, zopt); /* add to xfrd - slave */ @@ -1353,7 +1432,8 @@ perform_addzone(RES* ssl, xfrd_state_type* xfrd, char* arg) dname = NULL; /* add to zonelist and adds to config in memory */ - zopt = zone_list_add(xfrd->nsd->options, arg, arg2); + zopt = zone_list_add_or_cat(xfrd->nsd->options, arg, arg2, + xfrd_add_catalog_producer_member); if(!zopt) { /* also dname parse error here */ (void)ssl_printf(ssl, "error could not add zonelist entry\n"); @@ -1365,6 +1445,10 @@ perform_addzone(RES* ssl, xfrd_state_type* xfrd, char* arg) getzonestatid(xfrd->nsd->options, zopt)); zonestat_inc_ifneeded(xfrd); xfrd_set_reload_now(xfrd); + /* add to xfrd - catalog consumer zones */ + if (zone_is_catalog_consumer(zopt)) { + xfrd_init_catalog_consumer_zone(xfrd, zopt); + } /* add to xfrd - notify (for master and slaves) */ init_notify_send(xfrd->notify_zones, xfrd->region, zopt); /* add to xfrd - slave */ @@ -1380,6 +1464,8 @@ perform_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg) { const dname_type* dname; struct zone_options* zopt; + /* dont recycle dname when it becomes part of a xfrd_producer_member */ + int recycle_dname = 1; dname = dname_parse(xfrd->region, arg); if(!dname) { @@ -1406,7 +1492,17 @@ perform_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg) "nsd.conf yourself and repattern\n"); return 0; } + if(zone_is_catalog_consumer_member(zopt) + && as_catalog_member_zone(zopt)->member_id) { + (void)ssl_printf(ssl, "Error: Zone is a catalog consumer " + "member zone with id %s\nRemove the member id from the " + "catalog to delete this zone.\n", dname_to_string( + as_catalog_member_zone(zopt)->member_id, NULL)); + region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); + dname = NULL; + return 0; + } /* create deletion task */ task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task, dname); @@ -1416,10 +1512,18 @@ perform_delzone(RES* ssl, xfrd_state_type* xfrd, char* arg) xfrd_del_slave_zone(xfrd, dname); } xfrd_del_notify(xfrd, dname); + /* delete it in xfrd's catalog consumers list */ + if(zone_is_catalog_consumer(zopt)) { + xfrd_deinit_catalog_consumer_zone(xfrd, dname); + } else { + recycle_dname = !xfrd_del_catalog_producer_member(xfrd, dname); + } /* delete from config */ zone_list_del(xfrd->nsd->options, zopt); - region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); + if(recycle_dname) + region_recycle(xfrd->region, + (void*)dname, dname_total_size(dname)); return 1; } @@ -1580,6 +1684,10 @@ remove_cfgzone(xfrd_state_type* xfrd, const char* pname) xfrd_del_slave_zone(xfrd, dname); } xfrd_del_notify(xfrd, dname); + /* delete it in xfrd's catalog consumers list */ + if(zone_is_catalog_consumer(zopt)) { + xfrd_deinit_catalog_consumer_zone(xfrd, dname); + } /* delete from zoneoptions */ zone_options_delete(xfrd->nsd->options, zopt); @@ -1614,6 +1722,10 @@ add_cfgzone(xfrd_state_type* xfrd, const char* pname) getzonestatid(xfrd->nsd->options, zopt)); /* zonestat_inc is done after the entire config file has been done */ xfrd_set_reload_now(xfrd); + /* add to xfrd - catalog consumer zones */ + if (zone_is_catalog_consumer(zopt)) { + xfrd_init_catalog_consumer_zone(xfrd, zopt); + } /* add to xfrd - notify (for master and slaves) */ init_notify_send(xfrd->notify_zones, xfrd->region, zopt); /* add to xfrd - slave */ @@ -1762,12 +1874,19 @@ repat_patterns(xfrd_state_type* xfrd, struct nsd_options* newopt) } else if (!p->request_xfr && origp->request_xfr) { newstate = REPAT_MASTER; } + if ( p->catalog_role == CATALOG_ROLE_CONSUMER + && origp->catalog_role != CATALOG_ROLE_CONSUMER) { + newstate |= REPAT_CATALOG_CONSUMER; + } else if (p->catalog_role != CATALOG_ROLE_CONSUMER + && origp->catalog_role == CATALOG_ROLE_CONSUMER) { + newstate |= REPAT_CATALOG_CONSUMER_DEINIT; + } add_pat(xfrd, p); if (p->implicit && newstate) { const dname_type* dname = parse_implicit_name(xfrd, p->pname); if (dname) { - if (newstate == REPAT_SLAVE) { + if (newstate & REPAT_SLAVE) { struct zone_options* zopt = zone_options_find( oldopt, dname); @@ -1775,10 +1894,22 @@ repat_patterns(xfrd_state_type* xfrd, struct nsd_options* newopt) xfrd_init_slave_zone( xfrd, zopt); } - } else if (newstate == REPAT_MASTER) { + } else if (newstate & REPAT_MASTER) { xfrd_del_slave_zone(xfrd, dname); } + if (newstate & REPAT_CATALOG_CONSUMER) { + struct zone_options* zopt = + zone_options_find( + oldopt, dname); + if (zopt) { + xfrd_init_catalog_consumer_zone( + xfrd, zopt); + } + } else if (newstate & REPAT_CATALOG_CONSUMER_DEINIT) { + xfrd_deinit_catalog_consumer_zone( + xfrd, dname); + } region_recycle(xfrd->region, (void*)dname, dname_total_size(dname)); @@ -1797,15 +1928,23 @@ repat_patterns(xfrd_state_type* xfrd, struct nsd_options* newopt) RBTREE_FOR(zone_opt, struct zone_options*, oldopt->zone_options) { struct pattern_options* oldp = zone_opt->pattern; if (!oldp->implicit) { - if (oldp->xfrd_flags == REPAT_SLAVE) { + if (oldp->xfrd_flags & REPAT_SLAVE) { /* xfrd needs stable reference so get * it from the oldopt(modified) tree */ xfrd_init_slave_zone(xfrd, zone_opt); - } else if (oldp->xfrd_flags == REPAT_MASTER) { + } else if (oldp->xfrd_flags & REPAT_MASTER) { xfrd_del_slave_zone(xfrd, (const dname_type*) zone_opt->node.key); } + if (oldp->xfrd_flags & REPAT_CATALOG_CONSUMER) { + xfrd_init_catalog_consumer_zone(xfrd, + zone_opt); + } else if (oldp->xfrd_flags & REPAT_CATALOG_CONSUMER_DEINIT) { + xfrd_deinit_catalog_consumer_zone(xfrd, + (const dname_type*) + zone_opt->node.key); + } oldp->xfrd_flags = 0; } } @@ -1883,7 +2022,8 @@ do_repattern(RES* ssl, xfrd_state_type* xfrd) (void)ssl_printf(ssl, "reconfig start, read %s\n", cfgfile); opt = nsd_options_create(region); - if(!parse_options_file(opt, cfgfile, &print_ssl_cfg_err, &ssl)) { + if(!parse_options_file(opt, cfgfile, &print_ssl_cfg_err, &ssl, + xfrd->nsd->options)) { /* error already printed */ region_destroy(region); return; @@ -2461,7 +2601,8 @@ remote_handshake_later(struct daemon_remote* rc, struct rc_state* s, int fd, return; } s->shake_state = rc_hs_read; - event_del(&s->c); + if(s->event_added) + event_del(&s->c); memset(&s->c, 0, sizeof(s->c)); event_set(&s->c, fd, EV_PERSIST|EV_TIMEOUT|EV_READ, remote_control_callback, s); @@ -2469,6 +2610,7 @@ remote_handshake_later(struct daemon_remote* rc, struct rc_state* s, int fd, log_msg(LOG_ERR, "remote_accept: cannot set event_base"); if(event_add(&s->c, &s->tval) != 0) log_msg(LOG_ERR, "remote_accept: cannot add event"); + s->event_added = 1; return; } else if(r2 == SSL_ERROR_WANT_WRITE) { if(s->shake_state == rc_hs_write) { @@ -2476,7 +2618,8 @@ remote_handshake_later(struct daemon_remote* rc, struct rc_state* s, int fd, return; } s->shake_state = rc_hs_write; - event_del(&s->c); + if(s->event_added) + event_del(&s->c); memset(&s->c, 0, sizeof(s->c)); event_set(&s->c, fd, EV_PERSIST|EV_TIMEOUT|EV_WRITE, remote_control_callback, s); @@ -2484,6 +2627,7 @@ remote_handshake_later(struct daemon_remote* rc, struct rc_state* s, int fd, log_msg(LOG_ERR, "remote_accept: cannot set event_base"); if(event_add(&s->c, &s->tval) != 0) log_msg(LOG_ERR, "remote_accept: cannot add event"); + s->event_added = 1; return; } else { if(r == 0) @@ -2799,6 +2943,11 @@ print_stats(RES* ssl, xfrd_state_type* xfrd, struct timeval* now, int clear, print_stat_block(ssl, "", "", st); /* zone statistics */ + if(!ssl_printf(ssl, "zone.primary=%lu\n", + (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count))) + return; + if(!ssl_printf(ssl, "zone.secondary=%lu\n", (unsigned long)xfrd->zones->count)) + return; if(!ssl_printf(ssl, "zone.master=%lu\n", (unsigned long)(xfrd->notify_zones->count - xfrd->zones->count))) return; @@ -2927,7 +3076,9 @@ process_stats(RES* ssl, xfrd_state_type* xfrd, int peek) process_stats_manage_clear(xfrd, stats, peek); process_stats_add_total(xfrd, &total, stats); print_stats(ssl, xfrd, &stattime, !peek, &total, zonestats); - xfrd->nsd->rc->stats_time = stattime; + if(!peek) { + xfrd->nsd->rc->stats_time = stattime; + } free(stats); #ifdef USE_ZONE_STATS diff --git a/usr.sbin/nsd/server.c b/usr.sbin/nsd/server.c index 44a5e1aaf..4fe1aed11 100644 --- a/usr.sbin/nsd/server.c +++ b/usr.sbin/nsd/server.c @@ -1735,6 +1735,9 @@ server_start_xfrd(struct nsd *nsd, int del_db, int reload_active) #ifdef HAVE_SETPROCTITLE setproctitle("xfrd"); #endif +#ifdef USE_LOG_PROCESS_ROLE + log_set_process_role("xfrd"); +#endif #ifdef HAVE_CPUSET_T if(nsd->use_cpu_affinity) { set_cpu_affinity(nsd->xfrd_cpuset); @@ -1751,6 +1754,12 @@ server_start_xfrd(struct nsd *nsd, int del_db, int reload_active) log_msg(LOG_ERR, "cannot fcntl pipe: %s", strerror(errno)); } nsd->xfrd_listener->fd = sockets[0]; +#ifdef HAVE_SETPROCTITLE + setproctitle("main"); +#endif +#ifdef USE_LOG_PROCESS_ROLE + log_set_process_role("main"); +#endif break; } /* server-parent only */ @@ -2308,6 +2317,78 @@ reload_process_tasks(struct nsd* nsd, udb_ptr* last_task, int cmdsocket) void server_verify(struct nsd *nsd, int cmdsocket); +struct quit_sync_event_data { + struct event_base* base; + size_t read; + union { + uint8_t buf[sizeof(sig_atomic_t)]; + sig_atomic_t cmd; + } to_read; +}; + +static void server_reload_handle_sigchld(int sig, short event, + void* ATTR_UNUSED(arg)) +{ + assert(sig == SIGCHLD); + assert(event & EV_SIGNAL); + + /* reap the exited old-serve child(s) */ + while(waitpid(-1, NULL, WNOHANG) > 0) { + /* pass */ + } +} + +static void server_reload_handle_quit_sync_ack(int cmdsocket, short event, + void* arg) +{ + struct quit_sync_event_data* cb_data = + (struct quit_sync_event_data*)arg; + ssize_t r; + + if(event & EV_TIMEOUT) { + sig_atomic_t cmd = NSD_QUIT_SYNC; + + DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc send quit to main")); + if (!write_socket(cmdsocket, &cmd, sizeof(cmd))) { + log_msg(LOG_ERR, "problems sending command from " + "reload to old-main: %s", strerror(errno)); + } + /* Wait for cmdsocket to become readable or for next timeout, + * (this works because event is added EV_TIMEOUT|EV_PERSIST). + */ + return; + } + assert(event & EV_READ); + assert(cb_data->read < sizeof(cb_data->to_read.cmd)); + + r = read(cmdsocket, cb_data->to_read.buf + cb_data->read, + sizeof(cb_data->to_read.cmd) - cb_data->read); + if(r == 0) { + log_msg(LOG_ERR, "reload: old-main quit during quit sync"); + cb_data->to_read.cmd = NSD_RELOAD; + + } else if(r == -1) { + if(errno == EAGAIN || errno == EINTR) + return; + + log_msg(LOG_ERR, "reload: could not wait for parent to quit: " + "%s", strerror(errno)); + cb_data->to_read.cmd = NSD_RELOAD; + + } else if (cb_data->read + r < sizeof(cb_data->to_read.cmd)) { + /* More to read */ + cb_data->read += r; + return; + + } else { + assert(cb_data->read + r == sizeof(cb_data->to_read.cmd)); + DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc reply main %d", + (int)cb_data->to_read.cmd)); + } + /* Done */ + event_base_loopexit(cb_data->base, NULL); +} + /* * Reload the database, stop parent, re-fork children and continue. * as server_main. @@ -2317,21 +2398,21 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, int cmdsocket) { pid_t mypid; - sig_atomic_t cmd = NSD_QUIT_SYNC; - int ret; + sig_atomic_t cmd; udb_ptr last_task; struct sigaction old_sigchld, ign_sigchld; struct radnode* node; zone_type* zone; enum soainfo_hint hint; + struct quit_sync_event_data cb_data; + struct event signal_event, cmd_event; + struct timeval reload_sync_timeout; + /* ignore SIGCHLD from the previous server_main that used this pid */ memset(&ign_sigchld, 0, sizeof(ign_sigchld)); ign_sigchld.sa_handler = SIG_IGN; sigaction(SIGCHLD, &ign_sigchld, &old_sigchld); -#ifdef HAVE_SETPROCTITLE - setproctitle("main"); -#endif #ifdef HAVE_CPUSET_T if(nsd->use_cpu_affinity) { set_cpu_affinity(nsd->cpuset); @@ -2430,7 +2511,7 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, exit(1); } - /* if the parent has quit, we must quit too, poll the fd for cmds */ + /* if the old-main has quit, we must quit too, poll the fd for cmds */ if(block_read(nsd, cmdsocket, &cmd, sizeof(cmd), 0) == sizeof(cmd)) { DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc command from main %d", (int)cmd)); if(cmd == NSD_QUIT) { @@ -2440,34 +2521,55 @@ server_reload(struct nsd *nsd, region_type* server_region, netio_type* netio, } } - /* Send quit command to parent: blocking, wait for receipt. */ - do { - DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc send quit to main")); - cmd = NSD_QUIT_SYNC; - if (!write_socket(cmdsocket, &cmd, sizeof(cmd))) - { - log_msg(LOG_ERR, "problems sending command from reload to oldnsd: %s", - strerror(errno)); - } - /* blocking: wait for parent to really quit. (it sends RELOAD as ack) */ - DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc wait for ack main")); - ret = block_read(nsd, cmdsocket, &cmd, sizeof(cmd), - RELOAD_SYNC_TIMEOUT); - if(ret == -2) { - DEBUG(DEBUG_IPC, 1, (LOG_ERR, "reload timeout QUITSYNC. retry")); - } - } while (ret == -2); - if(ret == -1) { - log_msg(LOG_ERR, "reload: could not wait for parent to quit: %s", + /* Send quit command to old-main: blocking, wait for receipt. + * The old-main process asks the old-serve processes to quit, however + * if a reload succeeded before, this process is the parent of the + * old-serve processes, so we need to reap the children for it. + */ + DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc send quit to main")); + cmd = NSD_QUIT_SYNC; + if (!write_socket(cmdsocket, &cmd, sizeof(cmd))) + { + log_msg(LOG_ERR, "problems sending command from reload to oldnsd: %s", strerror(errno)); } - DEBUG(DEBUG_IPC,1, (LOG_INFO, "reload: ipc reply main %d %d", ret, (int)cmd)); + + reload_sync_timeout.tv_sec = RELOAD_SYNC_TIMEOUT; + reload_sync_timeout.tv_usec = 0; + + cb_data.base = nsd_child_event_base(); + cb_data.to_read.cmd = cmd; + cb_data.read = 0; + + event_set(&signal_event, SIGCHLD, EV_SIGNAL|EV_PERSIST, + server_reload_handle_sigchld, NULL); + if(event_base_set(cb_data.base, &signal_event) != 0 + || event_add(&signal_event, NULL) != 0) { + log_msg(LOG_ERR, "NSD quit sync: could not add signal event"); + } + + event_set(&cmd_event, cmdsocket, EV_READ|EV_TIMEOUT|EV_PERSIST, + server_reload_handle_quit_sync_ack, &cb_data); + if(event_base_set(cb_data.base, &cmd_event) != 0 + || event_add(&cmd_event, &reload_sync_timeout) != 0) { + log_msg(LOG_ERR, "NSD quit sync: could not add command event"); + } + + /* short-lived main loop */ + event_base_dispatch(cb_data.base); + + /* remove command and signal event handlers */ + event_del(&cmd_event); + event_del(&signal_event); + event_base_free(cb_data.base); + cmd = cb_data.to_read.cmd; + if(cmd == NSD_QUIT) { /* small race condition possible here, parent got quit cmd. */ send_children_quit(nsd); exit(1); } - assert(ret==-1 || ret == 0 || cmd == NSD_RELOAD); + assert(cmd == NSD_RELOAD); udb_ptr_unlink(&last_task, nsd->task[nsd->mytask]); task_process_sync(nsd->task[nsd->mytask]); #ifdef USE_ZONE_STATS @@ -2602,6 +2704,12 @@ server_main(struct nsd *nsd) log_msg(LOG_WARNING, "Reload process %d failed with status %d, continuing with old database", (int) child_pid, status); +#ifdef HAVE_SETPROCTITLE + setproctitle("main"); +#endif +#ifdef USE_LOG_PROCESS_ROLE + log_set_process_role("main"); +#endif reload_pid = -1; if(reload_listener.fd != -1) close(reload_listener.fd); netio_remove_handler(netio, &reload_listener); @@ -2679,7 +2787,7 @@ server_main(struct nsd *nsd) break; /* timeout to collect processes. In case no sigchild happens. */ - timeout_spec.tv_sec = 60; + timeout_spec.tv_sec = 1; timeout_spec.tv_nsec = 0; /* listen on ports, timeout for collecting terminated children */ @@ -2700,6 +2808,12 @@ server_main(struct nsd *nsd) log_msg(LOG_WARNING, "Reload process %d failed, continuing with old database", (int) reload_pid); +#ifdef HAVE_SETPROCTITLE + setproctitle("main"); +#endif +#ifdef USE_LOG_PROCESS_ROLE + log_set_process_role("main"); +#endif reload_pid = -1; if(reload_listener.fd != -1) close(reload_listener.fd); netio_remove_handler(netio, &reload_listener); @@ -2760,9 +2874,21 @@ server_main(struct nsd *nsd) default: /* PARENT */ close(reload_sockets[0]); +#ifdef HAVE_SETPROCTITLE + setproctitle("load"); +#endif +#ifdef USE_LOG_PROCESS_ROLE + log_set_process_role("load"); +#endif server_reload(nsd, server_region, netio, reload_sockets[1]); DEBUG(DEBUG_IPC,2, (LOG_INFO, "Reload exited to become new main")); +#ifdef HAVE_SETPROCTITLE + setproctitle("main"); +#endif +#ifdef USE_LOG_PROCESS_ROLE + log_set_process_role("main"); +#endif close(reload_sockets[1]); DEBUG(DEBUG_IPC,2, (LOG_INFO, "Reload closed")); /* drop stale xfrd ipc data */ @@ -2779,6 +2905,12 @@ server_main(struct nsd *nsd) /* server_main keep running until NSD_QUIT_SYNC * received from reload. */ close(reload_sockets[1]); +#ifdef HAVE_SETPROCTITLE + setproctitle("old-main"); +#endif +#ifdef USE_LOG_PROCESS_ROLE + log_set_process_role("old-main"); +#endif reload_listener.fd = reload_sockets[0]; reload_listener.timeout = NULL; reload_listener.user_data = nsd; @@ -3213,6 +3345,9 @@ server_child(struct nsd *nsd) region_type *server_region = region_create(xalloc, free); struct event_base* event_base = nsd_child_event_base(); sig_atomic_t mode; +#ifdef USE_LOG_PROCESS_ROLE + static char child_name[20]; +#endif if(!event_base) { log_msg(LOG_ERR, "nsd server could not create event base"); @@ -3226,11 +3361,17 @@ server_child(struct nsd *nsd) #endif assert(nsd->server_kind != NSD_SERVER_MAIN); - DEBUG(DEBUG_IPC, 2, (LOG_INFO, "child process started")); #ifdef HAVE_SETPROCTITLE setproctitle("server %d", nsd->this_child->child_num + 1); #endif +#ifdef USE_LOG_PROCESS_ROLE + snprintf(child_name, sizeof(child_name), "srv%d", + nsd->this_child->child_num + 1); + log_set_process_role(child_name); +#endif + DEBUG(DEBUG_IPC, 2, (LOG_INFO, "child process started")); + #ifdef HAVE_CPUSET_T if(nsd->use_cpu_affinity) { set_cpu_affinity(nsd->this_child->cpuset); diff --git a/usr.sbin/nsd/util.c b/usr.sbin/nsd/util.c index 7afe34e65..13a2ec9b4 100644 --- a/usr.sbin/nsd/util.c +++ b/usr.sbin/nsd/util.c @@ -63,6 +63,14 @@ static log_function_type *current_log_function = log_file; static FILE *current_log_file = NULL; int log_time_asc = 1; +#ifdef USE_LOG_PROCESS_ROLE +void +log_set_process_role(const char *process_role) +{ + global_ident = process_role; +} +#endif + void log_init(const char *ident) { diff --git a/usr.sbin/nsd/util.h b/usr.sbin/nsd/util.h index 97b7ba0cf..ab6315edf 100644 --- a/usr.sbin/nsd/util.h +++ b/usr.sbin/nsd/util.h @@ -43,6 +43,15 @@ struct nsd; */ void log_init(const char *ident); +#ifdef USE_LOG_PROCESS_ROLE +/* + * Set the name of the role for the process (for debugging purposes) + */ +void log_set_process_role(const char* role); +#else +#define log_set_process_role(role) /* empty */ +#endif + /* * Open the system log. If FILENAME is not NULL, a log file is opened * as well. diff --git a/usr.sbin/nsd/xfrd-catalog-zones.c b/usr.sbin/nsd/xfrd-catalog-zones.c new file mode 100644 index 000000000..bc0baa078 --- /dev/null +++ b/usr.sbin/nsd/xfrd-catalog-zones.c @@ -0,0 +1,1285 @@ +/* + * xfrd-catalog-zones.c -- catalog zone implementation for NSD + * + * Copyright (c) 2024, NLnet Labs. All rights reserved. + * + * See LICENSE for the license. + */ +#include "config.h" +#include "difffile.h" +#include "nsd.h" +#include "packet.h" +#include "xfrd-catalog-zones.h" +#include "xfrd-notify.h" + + +/****************** ****************** + ****************** catalog consumer zone processing ****************** + ****************** ******************/ + +/** process a catalog consumer zone, load if needed */ +static void xfrd_process_catalog_consumer_zone( + struct xfrd_catalog_consumer_zone* consumer_zone); + +/** make the catalog consumer zone invalid for given reason */ +static void vmake_catalog_consumer_invalid( + struct xfrd_catalog_consumer_zone *consumer_zone, + const char *format, va_list args); + +/** return (static) dname with label prepended to dname */ +static dname_type* label_plus_dname(const char* label,const dname_type* dname); + +/** delete the catalog member zone */ +static void catalog_del_consumer_member_zone( + struct xfrd_catalog_consumer_zone* consumer_zone, + struct catalog_member_zone* consumer_member_zone); + +#ifndef MULTIPLE_CATALOG_CONSUMER_ZONES +/* return a single catalog consumer zone from xfrd struct */ +static inline struct xfrd_catalog_consumer_zone* +xfrd_one_catalog_consumer_zone() +{ + return xfrd + && xfrd->catalog_consumer_zones + && xfrd->catalog_consumer_zones->count == 1 + ? (struct xfrd_catalog_consumer_zone*) + rbtree_first(xfrd->catalog_consumer_zones) : NULL; +} +#endif + +/** return the catalog-member-pattern or NULL on error if not present */ +static inline struct pattern_options* +catalog_member_pattern(struct xfrd_catalog_consumer_zone* consumer_zone) +{ + if (!consumer_zone->options->pattern + || !consumer_zone->options->pattern->catalog_member_pattern) + return NULL; + return pattern_options_find(xfrd->nsd->options, + consumer_zone->options->pattern->catalog_member_pattern); +} + +/** see if we have more zonestatistics entries and it has to be incremented */ +static inline void +zonestat_inc_ifneeded() +{ +#ifdef USE_ZONE_STATS + if(xfrd->nsd->options->zonestatnames->count != xfrd->zonestat_safe) + task_new_zonestat_inc(xfrd->nsd->task[xfrd->nsd->mytask], + xfrd->last_task, + xfrd->nsd->options->zonestatnames->count); +#endif /* USE_ZONE_STATS */ +} + + +/****************** ****************** + ****************** catalog producer zone processing ****************** + ****************** ******************/ + +/** process catalog producer zone producer_zone */ +static void xfrd_process_catalog_producer_zone( + struct xfrd_catalog_producer_zone* producer_zone); + +/** rbnode must be struct catalog_member_zone*; compares (key->member_id) */ +static int member_id_compare(const void *left, const void *right); + +/** return xfrd_catalog_producer_zone* pointed to by cmz' catalog-producer-zone + * pattern option. struct is created if necessary. returns NULL on failure. */ +static struct xfrd_catalog_producer_zone* xfrd_get_catalog_producer_zone( + struct catalog_member_zone* cmz); + +/** helper struct for generating XFR files, for conveying the catalog producer + * zone content to the server process. + */ +struct xfrd_xfr_writer { + struct xfrd_catalog_producer_zone* producer_zone; + char packet_space[16384]; + buffer_type packet; + uint32_t seq_nr; /* number of messages already handled */ + uint32_t old_serial, new_serial; /* host byte order */ + uint64_t xfrfilenumber; /* identifier for file to store xfr into */ +}; + +/** initialize xfrd_xfr_writer struct xw */ +static void xfr_writer_init(struct xfrd_xfr_writer* xw, + struct xfrd_catalog_producer_zone* producer_zone); + +/** write packet from xfrd_xfr_writer struct xw to xfr file */ +static void xfr_writer_write_packet(struct xfrd_xfr_writer* xw); + +/** commit xfr file (send to server process), with provided log message */ +static void xfr_writer_commit(struct xfrd_xfr_writer* xw, const char *fmt, + ...); + +/** try writing SOA RR with serial to packet buffer. returns 0 on failure */ +static int try_buffer_write_SOA(buffer_type* packet, const dname_type* owner, + uint32_t serial); + +/** try writing RR to packet buffer. returns 0 on failure */ +static int try_buffer_write_RR(buffer_type* packet, const dname_type* owner, + uint16_t rr_type, uint16_t rdata_len, const void* rdata); + +/** try writing PTR RR to packet buffer. returns 0 on failure */ +static inline int try_buffer_write_PTR(buffer_type* packet, + const dname_type* owner, const dname_type* name); + +/** try writing TXT RR to packet buffer. returns 0 on failure */ +static int try_buffer_write_TXT(buffer_type* packet, const dname_type* name, + const char *txt); + +/** add SOA RR with serial serial to xfrd_xfr_writer xw */ +static inline void xfr_writer_add_SOA(struct xfrd_xfr_writer* xw, + const dname_type* owner, uint32_t serial) +{ + if(try_buffer_write_SOA(&xw->packet, owner, serial)) + return; + xfr_writer_write_packet(xw); + assert(buffer_position(&xw->packet) == 12); + try_buffer_write_SOA(&xw->packet, owner, serial); +} + +/** add RR to xfrd_xfr_writer xw */ +static inline void xfr_writer_add_RR(struct xfrd_xfr_writer* xw, + const dname_type* owner, + uint16_t rr_type, uint16_t rdata_len, const void* rdata) +{ + if(try_buffer_write_RR(&xw->packet, owner, rr_type, rdata_len, rdata)) + return; + xfr_writer_write_packet(xw); + assert(buffer_position(&xw->packet) == 12); + try_buffer_write_RR(&xw->packet, owner, rr_type, rdata_len, rdata); +} + +/** add PTR RR to xfrd_xfr_writer xw */ +static inline void xfr_writer_add_PTR(struct xfrd_xfr_writer* xw, + const dname_type* owner, const dname_type* name) +{ + if(try_buffer_write_PTR(&xw->packet, owner, name)) + return; + xfr_writer_write_packet(xw); + assert(buffer_position(&xw->packet) == 12); + try_buffer_write_PTR(&xw->packet, owner, name); +} + +/** add TXT RR to xfrd_xfr_writer xw */ +static inline void xfr_writer_add_TXT(struct xfrd_xfr_writer* xw, + const dname_type* owner, const char* txt) +{ + if(try_buffer_write_TXT(&xw->packet, owner, txt)) + return; + xfr_writer_write_packet(xw); + assert(buffer_position(&xw->packet) == 12); + try_buffer_write_TXT(&xw->packet, owner, txt); +} + + +/****************** ****************** + ****************** catalog consumer zone processing ****************** + ****************** ******************/ + +void +xfrd_init_catalog_consumer_zone(xfrd_state_type* xfrd, + struct zone_options* zone) +{ + struct xfrd_catalog_consumer_zone* consumer_zone; + + if ((consumer_zone = (struct xfrd_catalog_consumer_zone*)rbtree_search( + xfrd->catalog_consumer_zones, zone->node.key))) { + log_msg(LOG_ERR, "cannot initialize new catalog consumer zone:" + " '%s: it already exists in xfrd's catalog " + " consumer zones index", zone->name); + /* Maybe we need to reprocess it? */ + make_catalog_consumer_valid(consumer_zone); + return; + } + consumer_zone = (struct xfrd_catalog_consumer_zone*) + region_alloc(xfrd->region, + sizeof(struct xfrd_catalog_consumer_zone)); + memset(consumer_zone, 0, sizeof(struct xfrd_catalog_consumer_zone)); + consumer_zone->node.key = zone->node.key; + consumer_zone->options = zone; + consumer_zone->member_ids.region = xfrd->region; + consumer_zone->member_ids.root = RBTREE_NULL; + consumer_zone->member_ids.count = 0; + consumer_zone->member_ids.cmp = member_id_compare; + consumer_zone->mtime.tv_sec = 0; + consumer_zone->mtime.tv_nsec = 0; + + consumer_zone->invalid = NULL; + rbtree_insert(xfrd->catalog_consumer_zones, + (rbnode_type*)consumer_zone); +#ifndef MULTIPLE_CATALOG_CONSUMER_ZONES + if ((int)xfrd->catalog_consumer_zones->count > 1) { + log_msg(LOG_ERR, "catalog consumer processing disabled: " + "only one single catalog consumer zone allowed"); + } +#endif + if(zone->pattern && zone->pattern->store_ixfr) { + /* Don't process ixfrs from xfrd */ + zone->pattern->store_ixfr = 0; + } +} + +void +xfrd_deinit_catalog_consumer_zone(xfrd_state_type* xfrd, + const dname_type* dname) +{ + struct xfrd_catalog_consumer_zone* consumer_zone; + zone_type* zone; + + if (!(consumer_zone =(struct xfrd_catalog_consumer_zone*)rbtree_delete( + xfrd->catalog_consumer_zones, dname))) { + log_msg(LOG_ERR, "cannot de-initialize catalog consumer zone:" + " '%s: it did not exist in xfrd's catalog " + " consumer zones index", + dname_to_string(dname, NULL)); + return; + } + if (consumer_zone->member_ids.count) + log_msg(LOG_WARNING, "de-initialize catalog consumer zone:" + " '%s: will cause all member zones to be " + " deleted", consumer_zone->options->name); + + while (consumer_zone->member_ids.count) { + struct catalog_member_zone* cmz = (struct catalog_member_zone*) + rbtree_first(&consumer_zone->member_ids)->key; + + log_msg(LOG_INFO, "deleting member zone '%s' on " + "de-initializing catalog consumer zone '%s'", + cmz->options.name, consumer_zone->options->name); + catalog_del_consumer_member_zone(consumer_zone, cmz); + } + if ((zone = namedb_find_zone(xfrd->nsd->db, dname))) { + namedb_zone_delete(xfrd->nsd->db, zone); + } + region_recycle(xfrd->region, consumer_zone, sizeof(*consumer_zone)); +#ifndef MULTIPLE_CATALOG_CONSUMER_ZONES + if((consumer_zone = xfrd_one_catalog_consumer_zone()) + && consumer_zone->options && consumer_zone->options->node.key) { + xfrd_zone_type* zone = (xfrd_zone_type*)rbtree_search( + xfrd->zones, + (const dname_type*)consumer_zone->options->node.key); + + if(zone) { + zone->soa_disk_acquired = 0; + zone->soa_nsd_acquired = 0; + xfrd_handle_notify_and_start_xfr(zone, NULL); + } + } +#endif +} + +/** make the catalog consumer zone invalid for given reason */ +static void +vmake_catalog_consumer_invalid( + struct xfrd_catalog_consumer_zone *consumer_zone, + const char *format, va_list args) +{ + char message[MAXSYSLOGMSGLEN]; + if (!consumer_zone || consumer_zone->invalid) return; + vsnprintf(message, sizeof(message), format, args); + log_msg(LOG_ERR, "invalid catalog consumer zone '%s': %s", + consumer_zone->options->name, message); + consumer_zone->invalid = region_strdup(xfrd->region, message); +} + +void +make_catalog_consumer_invalid(struct xfrd_catalog_consumer_zone *consumer_zone, + const char *format, ...) +{ + va_list args; + if (!consumer_zone || consumer_zone->invalid) return; + va_start(args, format); + vmake_catalog_consumer_invalid(consumer_zone, format, args); + va_end(args); +} + +void +make_catalog_consumer_valid(struct xfrd_catalog_consumer_zone *consumer_zone) +{ + if (consumer_zone->invalid) { + region_recycle(xfrd->region, consumer_zone->invalid, + strlen(consumer_zone->invalid) + 1); + consumer_zone->invalid = NULL; + } +} + +static dname_type* +label_plus_dname(const char* label, const dname_type* dname) +{ + static struct { + dname_type dname; + uint8_t bytes[MAXDOMAINLEN + 128 /* max number of labels */]; + } ATTR_PACKED name; + size_t i, ll; + + if (!label || !dname || dname->label_count > 127) + return NULL; + ll = strlen(label); + if ((int)dname->name_size + ll + 1 > MAXDOMAINLEN) + return NULL; + + /* In reversed order and first copy with memmove, so we can nest. + * i.e. label_plus_dname(label1, label_plus_dname(label2, dname)) + */ + memmove(name.bytes + dname->label_count + + 1 /* label_count increases by one */ + + 1 /* label type/length byte for label */ + ll, + ((void*)dname) + sizeof(dname_type) + dname->label_count, + dname->name_size); + memcpy(name.bytes + dname->label_count + + 1 /* label_count increases by one */ + + 1 /* label type/length byte for label */, label, ll); + name.bytes[dname->label_count + 1] = ll; /* label type/length byte */ + name.bytes[dname->label_count] = 0; /* first label follows last + * label_offsets element */ + for (i = 0; i < dname->label_count; i++) + name.bytes[i] = ((uint8_t*)(void*)dname)[sizeof(dname_type)+i] + + 1 /* label type/length byte for label */ + ll; + name.dname.label_count = dname->label_count + 1 /* label_count incr. */; + name.dname.name_size = dname->name_size + ll + + 1 /* label length */; + return &name.dname; +} + +static void +catalog_del_consumer_member_zone( + struct xfrd_catalog_consumer_zone* consumer_zone, + struct catalog_member_zone* consumer_member_zone) +{ + const dname_type* dname = consumer_member_zone->options.node.key; + + /* create deletion task */ + task_new_del_zone(xfrd->nsd->task[xfrd->nsd->mytask], + xfrd->last_task, dname); + xfrd_set_reload_now(xfrd); + /* delete it in xfrd */ + if(zone_is_slave(&consumer_member_zone->options)) { + xfrd_del_slave_zone(xfrd, dname); + } + xfrd_del_notify(xfrd, dname); +#ifdef MULTIPLE_CATALOG_CONSUMER_ZONES + /* delete it in xfrd's catalog consumers list */ + if(zone_is_catalog_consumer(&consumer_member_zone->options)) { + xfrd_deinit_catalog_consumer_zone(xfrd, dname); + } +#endif + if(consumer_member_zone->member_id) { + rbtree_delete(&consumer_zone->member_ids,consumer_member_zone); + consumer_member_zone->node = *RBTREE_NULL; + region_recycle( xfrd->nsd->options->region, + (void*)consumer_member_zone->member_id, + dname_total_size(consumer_member_zone->member_id)); + consumer_member_zone->member_id = NULL; + } + zone_options_delete(xfrd->nsd->options,&consumer_member_zone->options); +} + +void xfrd_check_catalog_consumer_zonefiles(const dname_type* name) +{ + struct xfrd_catalog_consumer_zone* consumer_zone; + +#ifndef MULTIPLE_CATALOG_CONSUMER_ZONES + consumer_zone = xfrd_one_catalog_consumer_zone(); + if (!consumer_zone) + return; + if (name && dname_compare(name, consumer_zone->node.key) != 0) + return; + name = consumer_zone->node.key; + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Mark %s " + "for checking", consumer_zone->options->name)); + make_catalog_consumer_valid(consumer_zone); + namedb_read_zonefile(xfrd->nsd, namedb_find_or_create_zone( + xfrd->nsd->db, name, consumer_zone->options), NULL, NULL); +#else + if (!name) { + RBTREE_FOR(consumer_zone, struct xfrd_catalog_consumer_zone*, + xfrd->catalog_consumer_zones) { + make_catalog_consumer_valid(consumer_zone); + namedb_read_zonefile(xfrd->nsd, + namedb_find_or_create_zone(xfrd->nsd->db, + consumer_zone->options->node.key, + consumer_zone->options), + NULL, NULL); + } + } else if ((consumer_zone = (struct xfrd_catalog_consumer_zone*) + rbtree_search(xfrd->catalog_consumer_zones, name))) { + make_catalog_consumer_valid(consumer_zone); + namedb_read_zonefile(xfrd->nsd, + namedb_find_or_create_zone( + xfrd->nsd->db, name, consumer_zone->options), + NULL, NULL); + } +#endif +} + +const char *invalid_catalog_consumer_zone(struct zone_options* zone) +{ + struct xfrd_catalog_consumer_zone* consumer_zone; + const char *msg; + + if (!zone || !zone_is_catalog_consumer(zone)) + msg = NULL; + + else if (!xfrd) + msg = "asked for catalog information outside of xfrd process"; + + else if (!xfrd->catalog_consumer_zones) + msg = "zone not found: " + "xfrd's catalog consumer zones index is empty"; + +#ifndef MULTIPLE_CATALOG_CONSUMER_ZONES + else if (xfrd->catalog_consumer_zones->count > 1) + return "not processing: more than one catalog consumer zone " + "configured and only a single one allowed"; +#endif + else if (!(consumer_zone = (struct xfrd_catalog_consumer_zone*) + rbtree_search(xfrd->catalog_consumer_zones, zone->node.key))) + msg = "zone not found in xfrd's catalog consumer zones index"; + else + return consumer_zone->invalid; + + if (msg) + log_msg(LOG_ERR, "catalog consumer zone '%s': %s", + zone->name, msg); + + return msg; +} + +void xfrd_process_catalog_consumer_zones() +{ + struct xfrd_catalog_consumer_zone* consumer_zone; + +#ifndef MULTIPLE_CATALOG_CONSUMER_ZONES + if((consumer_zone = xfrd_one_catalog_consumer_zone())) + xfrd_process_catalog_consumer_zone(consumer_zone); +#else + RBTREE_FOR(consumer_zone, struct xfrd_catalog_consumer_zone*, + xfrd->catalog_consumer_zones) { + xfrd_process_catalog_consumer_zone(consumer_zone); + } +#endif +} + +static inline struct catalog_member_zone* cursor_cmz(rbnode_type* node) +{ return node != RBTREE_NULL ? (struct catalog_member_zone*)node->key : NULL; } +static inline const dname_type* cursor_member_id(rbnode_type* node) +{ return cursor_cmz(node) ? cursor_cmz(node)->member_id : NULL; } + +#if !defined(NDEBUG) && 1 /* Only disable for seriously slow debugging */ +static void debug_log_consumer_members( + struct xfrd_catalog_consumer_zone* consumer_zone) +{ + rbnode_type* cursor; + size_t i; + + for ( cursor = rbtree_first(&consumer_zone->member_ids), i = 0 + ; cursor != RBTREE_NULL; i++, cursor = rbtree_next(cursor)) { + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Catalog member %.2zu: %s = %s", + i, dname_to_string(cursor_member_id(cursor), NULL), + cursor_cmz(cursor)->options.name)); + } +} +#else +# define debug_log_consumer_members(x) /* nothing */ +#endif + +static void +xfrd_process_catalog_consumer_zone( + struct xfrd_catalog_consumer_zone* consumer_zone) +{ + zone_type* zone; + const dname_type* dname; + domain_type *match, *closest_encloser, *member_id, *group; + rrset_type *rrset; + size_t i; + uint8_t version_2_found; + /* Currect catalog member zone */ + rbnode_type* cursor; + struct pattern_options *default_pattern = NULL; + /* A transfer of a catalog zone can contain deletion and adding of + * the same member zone. In such cases it can occur that the member + * is tried to be added before it is deleted. For these exceptional + * cases, we will rewalk the zone after the first pass, to retry + * adding those zones. + * + * Initial pass is mode "try_to_add". + * If a zone cannot be added, mode is set to "retry_to_add" + * If after the first pass the mode is "retry_to_add", + * mode will be set to "just_add", and a second pass is done. + */ + enum { try_to_add, retry_to_add, just_add } mode; + + assert(consumer_zone); + if (!xfrd->nsd->db) { + xfrd->nsd->db = namedb_open(xfrd->nsd->options); + } + dname = (const dname_type*)consumer_zone->node.key; + if (dname->name_size > 247) { + make_catalog_consumer_invalid(consumer_zone, "name too long"); + return; + } + if (dname->label_count > 126) { + make_catalog_consumer_invalid(consumer_zone,"too many labels"); + return; + } + zone = namedb_find_zone(xfrd->nsd->db, dname); + if (!zone) { + zone = namedb_zone_create(xfrd->nsd->db, dname, + consumer_zone->options); + namedb_read_zonefile(xfrd->nsd, zone, NULL, NULL); + } + if (timespec_compare(&consumer_zone->mtime, &zone->mtime) == 0) { + /* Not processing unchanged catalog consumer zone */ + return; + } + consumer_zone->mtime = zone->mtime; + /* start processing */ + /* Lookup version. TXT and check that it is version 2 */ + if(!namedb_lookup(xfrd->nsd->db, label_plus_dname("version", dname), + &match, &closest_encloser) + || !(rrset = domain_find_rrset(match, zone, TYPE_TXT))) { + make_catalog_consumer_invalid(consumer_zone, + "'version.%s TXT RRset not found", + consumer_zone->options->name); + return; + } + version_2_found = 0; + for (i = 0; i < rrset->rr_count; i++) { + if (rrset->rrs[i].rdata_count != 1) + continue; + if (rrset->rrs[i].rdatas[0].data[0] == 2 + && ((uint8_t*)(rrset->rrs[i].rdatas[0].data + 1))[0] == 1 + && ((uint8_t*)(rrset->rrs[i].rdatas[0].data + 1))[1] == '2') { + version_2_found = 1; + break; + } + } + if (!version_2_found) { + make_catalog_consumer_invalid(consumer_zone, + "'version.%s' TXT RR with value \"2\" not found", + consumer_zone->options->name); + return; + } + /* Walk over all names under zones. */ + if(!namedb_lookup(xfrd->nsd->db, label_plus_dname("zones", dname), + &match, &closest_encloser)) { + /* zones. does not exist, so the catalog has no + * members. This is just fine. But there may be members that need + * to be deleted. + */ + cursor = rbtree_first(&consumer_zone->member_ids); + mode = just_add; + goto delete_members; + } + mode = consumer_zone->member_ids.count ? try_to_add : just_add; +retry_adding: + cursor = rbtree_first(&consumer_zone->member_ids); + for ( member_id = domain_next(match) + ; member_id && domain_is_subdomain(member_id, match) + ; member_id = domain_next(member_id)) { + domain_type *member_domain; + char member_domain_str[5 * MAXDOMAINLEN]; + struct zone_options* zopt; + int valid_group_values; + struct pattern_options *pattern = NULL; + struct catalog_member_zone* to_add; + + if (domain_dname(member_id)->label_count > dname->label_count+2 + || !(rrset = domain_find_rrset(member_id, zone, TYPE_PTR))) + continue; + + /* RFC9432 Section 4.1. Member Zones: + * + * `` This PTR record MUST be the only record in the PTR RRset + * with the same name. The presence of more than one record + * in the RRset indicates a broken catalog zone that MUST + * NOT be processed (see Section 5.1). + */ + if (rrset->rr_count != 1) { + make_catalog_consumer_invalid(consumer_zone, + "only a single PTR RR expected on '%s'", + domain_to_string(member_id)); + return; + } + /* A PTR rr always has 1 rdata element which is a dname */ + if (rrset->rrs[0].rdata_count != 1) + continue; + member_domain = rrset->rrs[0].rdatas[0].domain; + domain_to_string_buf(member_domain, member_domain_str); + /* remove trailing dot */ + member_domain_str[strlen(member_domain_str) - 1] = 0; + + valid_group_values = 0; + /* Lookup group. TXT for matching patterns */ + if(!namedb_lookup(xfrd->nsd->db, label_plus_dname("group", + domain_dname(member_id)), + &group, &closest_encloser) + || !(rrset = domain_find_rrset(group, zone, TYPE_TXT))) { + ; /* pass */ + + } else for (i = 0; i < rrset->rr_count; i++) { + /* Max single TXT rdata field length + '\x00' == 256 */ + char group_value[256]; + + /* Looking for a single TXT rdata field */ + if (rrset->rrs[i].rdata_count != 1 + + /* rdata field should be at least 1 char */ + || rrset->rrs[i].rdatas[0].data[0] < 2 + + /* single rdata atom with single TXT rdata field */ + || (uint16_t)(((uint8_t*)(rrset->rrs[i].rdatas[0].data + 1))[0]) + != (uint16_t) (rrset->rrs[i].rdatas[0].data[0]-1)) + continue; + + memcpy( group_value + , (uint8_t*)(rrset->rrs[i].rdatas[0].data+1) + 1 + ,((uint8_t*)(rrset->rrs[i].rdatas[0].data+1))[0] + ); + group_value[ + ((uint8_t*)(rrset->rrs[i].rdatas[0].data+1))[0] + ] = 0; + if ((pattern = pattern_options_find( + xfrd->nsd->options, group_value))) + valid_group_values += 1; + } + if (valid_group_values > 1) { + log_msg(LOG_ERR, "member zone '%s': only a single " + "group property that matches a pattern is " + "allowed." + "The pattern from \"catalog-member-pattern\" " + "will be used instead.", + domain_to_string(member_id)); + valid_group_values = 0; + + } else if (valid_group_values == 1 && pattern + && pattern->catalog_producer_zone) { + log_msg(LOG_ERR, "member zone '%s': group property " + "'%s' matches a catalog producer member zone " + "pattern. In NSD, catalog member zones can be " + "either a member of a catalog consumer zone or" + " a catalog producer zone, but not both.", + domain_to_string(member_id), pattern->pname); + valid_group_values = 0; + } + if (valid_group_values == 1) { + /* pass: pattern is already set */ + assert(pattern); + + } else if (default_pattern) + pattern = default_pattern; /* pass */ + + else if (!(pattern = default_pattern = + catalog_member_pattern(consumer_zone))) { + make_catalog_consumer_invalid(consumer_zone, + "missing 'group.%s' TXT RR and no default " + "pattern from \"catalog-member-pattern\"", + domain_to_string(member_id)); + return; + } + if (cursor == RBTREE_NULL) + ; /* End of the current member zones list. + * From here onwards, zones will only be added. + */ + else { + int cmp = 0; +#ifndef NDEBUG + char member_id_str[5 * MAXDOMAINLEN]; + domain_to_string_buf(member_id, member_id_str); +#endif + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Comparing %s with %s", + member_id_str, + dname_to_string(cursor_member_id(cursor), + NULL))); + + while (cursor != RBTREE_NULL && + (cmp = dname_compare( + domain_dname(member_id), + cursor_member_id(cursor))) > 0) { + /* member_id is ahead of the current catalog + * member zone pointed to by cursor. + * The member zone must be deleted. + */ + struct catalog_member_zone* to_delete = + cursor_cmz(cursor); +#ifndef NDEBUG + const char *member_id_to_delete_str = + dname_to_string(to_delete->member_id, NULL); +#endif + cursor = rbtree_next(cursor); + + DEBUG(DEBUG_XFRD,1, (LOG_INFO, + "%s > %s: delete %s", + member_id_str, + member_id_to_delete_str, + member_id_to_delete_str)); + catalog_del_consumer_member_zone( + consumer_zone, to_delete); + if(cursor != RBTREE_NULL) + DEBUG(DEBUG_XFRD,1, (LOG_INFO, + "Comparing %s with %s", + member_id_str, + dname_to_string( + cursor_member_id(cursor), + NULL))); + } + if (cursor != RBTREE_NULL && cmp == 0) { + /* member_id is also in an current catalog + * member zone, and cursor is pointing + * to it. So, move along ... + */ + /* ... but first check if the pattern needs + * a change + */ + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "%s == %s: " + "Compare pattern %s with %s", + member_id_str, member_id_str, + cursor_cmz(cursor)->options.pattern->pname, + pattern->pname)); + + if (cursor_cmz(cursor)->options.pattern == + pattern) + ; /* pass: Pattern remains the same */ + else { + /* Changing patterns is basically + * deleting and adding the zone again + */ + zopt = &cursor_cmz(cursor)->options; + dname = (dname_type *)zopt->node.key; + task_new_del_zone( + xfrd->nsd->task[xfrd->nsd->mytask], + xfrd->last_task, + dname); + xfrd_set_reload_now(xfrd); + if(zone_is_slave(zopt)) { + xfrd_del_slave_zone( xfrd + , dname); + } + xfrd_del_notify(xfrd, dname); +#ifdef MULTIPLE_CATALOG_CONSUMER_ZONES + if(zone_is_catalog_consumer(zopt)) { + xfrd_deinit_catalog_consumer_zone( + xfrd, dname); + } +#endif + /* It is a catalog consumer member, + * so no need to check if it was a + * catalog producer member zone to + * delete and add + */ + zopt->pattern = pattern; + task_new_add_zone( + xfrd->nsd->task[xfrd->nsd->mytask], + xfrd->last_task, zopt->name, + pattern->pname, + getzonestatid( xfrd->nsd->options + , zopt)); + zonestat_inc_ifneeded(); + xfrd_set_reload_now(xfrd); +#ifdef MULTIPLE_CATALOG_CONSUMER_ZONES + if(zone_is_catalog_consumer(zopt)) { + xfrd_init_catalog_consumer_zone( + xfrd, zopt); + } +#endif + init_notify_send(xfrd->notify_zones, + xfrd->region, zopt); + if(zone_is_slave(zopt)) { + xfrd_init_slave_zone( + xfrd, zopt); + } + } + cursor = rbtree_next(cursor); + continue; + } + /* member_id is not in the current catalog member zone + * list, so it must be added + */ + assert(cursor == RBTREE_NULL || cmp < 0); + } + /* See if the zone already exists */ + zopt = zone_options_find(xfrd->nsd->options, + domain_dname(member_domain)); + if (zopt) { + /* Produce warning if zopt is from other catalog. + * Give debug message if zopt is not from this catalog. + */ + switch(mode) { + case try_to_add: + mode = retry_to_add; + break; + case just_add: + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Cannot add " + "catalog member zone %s (from %s): " + "zone already exists", + member_domain_str, + domain_to_string(member_id))); + break; + default: + break; + } + continue; + } + /* Add member zone if not already there */ + log_msg(LOG_INFO, "Adding '%s' PTR '%s'", + domain_to_string(member_id), + member_domain_str); + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Adding %s PTR %s", + domain_to_string(member_id), member_domain_str)); + to_add= catalog_member_zone_create(xfrd->nsd->options->region); + to_add->options.name = region_strdup( + xfrd->nsd->options->region, member_domain_str); + to_add->options.pattern = pattern; + if (!nsd_options_insert_zone(xfrd->nsd->options, + &to_add->options)) { + log_msg(LOG_ERR, "bad domain name '%s' pattern %s", + member_domain_str, + ( pattern->pname ? pattern->pname: "")); + zone_options_delete(xfrd->nsd->options, + &to_add->options); + continue; + } + to_add->member_id = dname_copy( xfrd->nsd->options->region + , domain_dname(member_id)); + /* Insert into the members_id list */ + to_add->node.key = to_add; + if(!rbtree_insert( &consumer_zone->member_ids, &to_add->node)){ + log_msg(LOG_ERR, "Error adding '%s' PTR '%s' to " + "consumer_zone->member_ids", + domain_to_string(member_id), + member_domain_str); + break; + } else + cursor = rbtree_next(&to_add->node); + /* make addzone task and schedule reload */ + task_new_add_zone(xfrd->nsd->task[xfrd->nsd->mytask], + xfrd->last_task, member_domain_str, + pattern->pname, + getzonestatid(xfrd->nsd->options, &to_add->options)); + zonestat_inc_ifneeded(); + xfrd_set_reload_now(xfrd); +#ifdef MULTIPLE_CATALOG_CONSUMER_ZONES + /* add to xfrd - catalog consumer zones */ + if(zone_is_catalog_consumer(&to_add->options)) { + xfrd_init_catalog_consumer_zone(xfrd,&to_add->options); + } +#endif + /* add to xfrd - notify (for master and slaves) */ + init_notify_send(xfrd->notify_zones, xfrd->region, + &to_add->options); + /* add to xfrd - slave */ + if(zone_is_slave(&to_add->options)) { + xfrd_init_slave_zone(xfrd, &to_add->options); + } + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "Added catalog " + "member zone %s (from %s)", + member_domain_str, domain_to_string(member_id))); + } +delete_members: + while (cursor != RBTREE_NULL) { + /* Any current catalog member zones remaining, don't have an + * member_id in the catalog anymore, so should be deleted too. + */ + struct catalog_member_zone* to_delete = cursor_cmz(cursor); + + cursor = rbtree_next(cursor); + catalog_del_consumer_member_zone(consumer_zone, to_delete); + } + if(mode == retry_to_add) { + mode = just_add; + goto retry_adding; + } + debug_log_consumer_members(consumer_zone); + make_catalog_consumer_valid(consumer_zone); +} + + +/****************** ****************** + ****************** catalog producer zone processing ****************** + ****************** ******************/ + +static int member_id_compare(const void *left, const void *right) +{ + return dname_compare( ((struct catalog_member_zone*)left )->member_id + , ((struct catalog_member_zone*)right)->member_id); +} + +static struct xfrd_catalog_producer_zone* +xfrd_get_catalog_producer_zone(struct catalog_member_zone* cmz) +{ + struct zone_options *producer_zopt; + struct xfrd_catalog_producer_zone* producer_zone; + const dname_type* producer_name; + const char* producer_name_str; + + assert(xfrd); + if(!cmz || !cmz->options.pattern->catalog_producer_zone) + return NULL; + + /* TODO: Store as dname in pattern->catalog_producer_zone */ + producer_name = dname_parse(xfrd->nsd->options->region, + cmz->options.pattern->catalog_producer_zone); + producer_zopt = zone_options_find(xfrd->nsd->options, producer_name); + producer_name_str = dname_to_string(producer_name, NULL); + region_recycle( xfrd->nsd->options->region, (void *)producer_name + , dname_total_size(producer_name)); + if(!producer_zopt) { + log_msg(LOG_ERR, "catalog producer zone '%s' not found for " + "zone '%s'", producer_name_str, cmz->options.name); + return NULL; + } + if(!zone_is_catalog_producer(producer_zopt)) { + log_msg(LOG_ERR, "cannot add catalog producer member " + "zone '%s' to non producer zone '%s'", + cmz->options.name, producer_zopt->name); + return NULL; + } + producer_name = (dname_type*)producer_zopt->node.key; + producer_zone = (struct xfrd_catalog_producer_zone*) + rbtree_search(xfrd->catalog_producer_zones, producer_name); + if (!producer_zone) { + /* Create a new one */ + DEBUG(DEBUG_XFRD, 1, (LOG_INFO,"creating catalog producer zone" + " '%s'", producer_zopt->name)); + producer_zone = (struct xfrd_catalog_producer_zone*) + region_alloc(xfrd->region, sizeof(*producer_zone)); + memset(producer_zone , 0, sizeof(*producer_zone)); + producer_zone->node.key = producer_zopt->node.key; + producer_zone->options = producer_zopt; + producer_zone->member_ids.region = xfrd->region; + producer_zone->member_ids.root = RBTREE_NULL; + producer_zone->member_ids.count = 0; + producer_zone->member_ids.cmp = member_id_compare; + producer_zone->serial = 0; + producer_zone->to_delete = NULL; + producer_zone->to_add = NULL; + producer_zone->latest_pxfr = NULL; + producer_zone->axfr = 1; + rbtree_insert(xfrd->catalog_producer_zones, + (rbnode_type*)producer_zone); + } + return producer_zone; +} + +void +xfrd_add_catalog_producer_member(struct catalog_member_zone* cmz) +{ + struct xfrd_catalog_producer_zone* producer_zone; + const dname_type* producer_name; + struct xfrd_producer_member* to_add; + + assert(xfrd); + if (!(producer_zone = xfrd_get_catalog_producer_zone(cmz))) { + return; + } + producer_name = producer_zone->node.key; + while(!cmz->member_id) { + /* Make new member_id with this catalog producer */ + char id_label[sizeof(uint32_t)*2+1]; + uint32_t new_id = (uint32_t)random_generate(0x7fffffff); + + hex_ntop((void*)&new_id, sizeof(uint32_t), id_label, sizeof(id_label)); + id_label[sizeof(uint32_t)*2] = 0; + cmz->member_id = label_plus_dname(id_label, + label_plus_dname("zones", producer_name)); + DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "does member_id %s exist?", + dname_to_string(cmz->member_id, NULL))); + if (!rbtree_search(&producer_zone->member_ids, cmz)) { + cmz->member_id = dname_copy(xfrd->nsd->options->region, + cmz->member_id); + break; + } + cmz->member_id = NULL; + } + cmz->node.key = cmz; + rbtree_insert(&producer_zone->member_ids, &cmz->node); + + /* Put data to be added to the producer zone to the to_add stack */ + to_add = (struct xfrd_producer_member*)region_alloc(xfrd->region, + sizeof(struct xfrd_producer_member)); + to_add->member_id = cmz->member_id; + to_add->member_zone_name = (dname_type*)cmz->options.node.key; + to_add->group_name = cmz->options.pattern->pname; + to_add->next = producer_zone->to_add; + producer_zone->to_add = to_add; +} + +int +xfrd_del_catalog_producer_member(struct xfrd_state* xfrd, + const dname_type* member_zone_name) +{ + struct xfrd_producer_member* to_delete; + struct catalog_member_zone* cmz; + struct xfrd_catalog_producer_zone* producer_zone; + + if(!(cmz = as_catalog_member_zone(zone_options_find(xfrd->nsd->options, + member_zone_name))) + || !(producer_zone = xfrd_get_catalog_producer_zone(cmz)) + || !rbtree_delete(&producer_zone->member_ids, cmz)) + return 0; + to_delete = (struct xfrd_producer_member*)region_alloc(xfrd->region, + sizeof(struct xfrd_producer_member)); + to_delete->member_id = cmz->member_id; cmz->member_id = NULL; + cmz->node = *RBTREE_NULL; + to_delete->member_zone_name = member_zone_name; + to_delete->group_name = cmz->options.pattern->pname; + to_delete->next = producer_zone->to_delete; + producer_zone->to_delete = to_delete; + return 1; +} + +static int +try_buffer_write_SOA(buffer_type* packet, const dname_type* owner, + uint32_t serial) +{ + size_t mark = buffer_position(packet); + + if(try_buffer_write(packet, dname_name(owner), owner->name_size) + && try_buffer_write_u16(packet, TYPE_SOA) + && try_buffer_write_u16(packet, CLASS_IN) + && try_buffer_write_u32(packet, 0) /* TTL*/ + && try_buffer_write_u16(packet, 9 + 9 + 5 * sizeof(uint32_t)) + && try_buffer_write(packet, "\007invalid\000", 9) /* primary */ + && try_buffer_write(packet, "\007invalid\000", 9) /* mailbox */ + && try_buffer_write_u32(packet, serial) /* serial */ + && try_buffer_write_u32(packet, 3600) /* refresh*/ + && try_buffer_write_u32(packet, 600) /* retry */ + && try_buffer_write_u32(packet, 2147483646) /* expire */ + && try_buffer_write_u32(packet, 0) /* minimum */) { + ANCOUNT_SET(packet, ANCOUNT(packet) + 1); + return 1; + } + buffer_set_position(packet, mark); + return 0; +} + +static int +try_buffer_write_RR(buffer_type* packet, const dname_type* owner, + uint16_t rr_type, uint16_t rdata_len, const void* rdata) +{ + size_t mark = buffer_position(packet); + + if(try_buffer_write(packet, dname_name(owner), owner->name_size) + && try_buffer_write_u16(packet, rr_type) + && try_buffer_write_u16(packet, CLASS_IN) + && try_buffer_write_u32(packet, 0) /* TTL*/ + && try_buffer_write_u16(packet, rdata_len) + && try_buffer_write(packet, rdata, rdata_len)) { + ANCOUNT_SET(packet, ANCOUNT(packet) + 1); + return 1; + } + buffer_set_position(packet, mark); + return 0; +} + +static inline int +try_buffer_write_PTR(buffer_type* packet, const dname_type* owner, + const dname_type* name) +{ + return try_buffer_write_RR(packet, owner, TYPE_PTR, + name->name_size, dname_name(name)); +} + +static int +try_buffer_write_TXT(buffer_type* packet, const dname_type* name, + const char *txt) +{ + size_t mark = buffer_position(packet); + size_t len = strlen(txt); + + if(len > 255) { + log_msg(LOG_ERR, "cannot make '%s 0 IN TXT \"%s\"': rdata " + "field too long", dname_to_string(name, NULL), txt); + return 1; + } + if(try_buffer_write(packet, dname_name(name), name->name_size) + && try_buffer_write_u16(packet, TYPE_TXT) + && try_buffer_write_u16(packet, CLASS_IN) + && try_buffer_write_u32(packet, 0) /* TTL*/ + && try_buffer_write_u16(packet, len + 1) + && try_buffer_write_u8(packet, len) + && try_buffer_write_string(packet, txt)) { + ANCOUNT_SET(packet, ANCOUNT(packet) + 1); + return 1; + } + buffer_set_position(packet, mark); + return 0; +} + +static void +xfr_writer_init(struct xfrd_xfr_writer* xw, + struct xfrd_catalog_producer_zone* producer_zone) +{ + xw->producer_zone = producer_zone; + buffer_create_from( &xw->packet, &xw->packet_space + , sizeof(xw->packet_space)); + buffer_write(&xw->packet, "\000\000\000\000\000\000" + "\000\000\000\000\000\000", 12); /* header */ + xw->seq_nr = 0; + xw->old_serial = xw->producer_zone->serial; + xw->new_serial = (uint32_t)xfrd_time(); + if(xw->new_serial <= xw->old_serial) + xw->new_serial = xw->old_serial + 1; + if(producer_zone->axfr) { + xw->old_serial = 0; + producer_zone->axfr = 0; + } + xw->xfrfilenumber = xfrd->xfrfilenumber++; +} + +static void +xfr_writer_write_packet(struct xfrd_xfr_writer* xw) +{ + const dname_type* producer_name = + (const dname_type*)xw->producer_zone->options->node.key; + + /* We want some content at least, so not just a header + * This can occur when final SOA was already written. + */ + if(buffer_position(&xw->packet) == 12) + return; + buffer_flip(&xw->packet); + diff_write_packet( dname_to_string(producer_name, NULL) + , xw->producer_zone->options->pattern->pname + , xw->old_serial, xw->new_serial, xw->seq_nr + , buffer_begin(&xw->packet), buffer_limit(&xw->packet) + , xfrd->nsd, xw->xfrfilenumber); + xw->seq_nr += 1; + buffer_clear(&xw->packet); + buffer_write(&xw->packet, "\000\000\000\000\000\000" + "\000\000\000\000\000\000", 12); /* header */ +} + + +static void +xfr_writer_commit(struct xfrd_xfr_writer* xw, const char *fmt, ...) +{ + va_list args; + char msg[1024]; + const dname_type* producer_name = + (const dname_type*)xw->producer_zone->options->node.key; + + va_start(args, fmt); + if (vsnprintf(msg, sizeof(msg), fmt, args) >= (int)sizeof(msg)) { + log_msg(LOG_WARNING, "truncated diff commit message: '%s'", + msg); + } + xfr_writer_write_packet(xw); /* Write remaining data */ + diff_write_commit( dname_to_string(producer_name, NULL) + , xw->old_serial, xw->new_serial + , xw->seq_nr /* Number of packets */ + , 1, msg, xfrd->nsd, xw->xfrfilenumber); + task_new_apply_xfr( xfrd->nsd->task[xfrd->nsd->mytask], xfrd->last_task + , producer_name + , xw->old_serial, xw->new_serial, xw->xfrfilenumber); + xfrd_set_reload_now(xfrd); +} + +static void +xfrd_process_catalog_producer_zone( + struct xfrd_catalog_producer_zone* producer_zone) +{ + struct xfrd_xfr_writer xw; + dname_type* producer_name; + struct xfrd_producer_xfr* pxfr; + + if(!producer_zone->to_add && !producer_zone->to_delete) + return; /* No changes */ + + producer_name = (dname_type*)producer_zone->node.key; + xfr_writer_init(&xw, producer_zone); + xfr_writer_add_SOA(&xw, producer_name, xw.new_serial); + + if(xw.old_serial == 0) { + /* initial deployment */ + assert(producer_zone->to_add && !producer_zone->to_delete); + + xfr_writer_add_RR (&xw, producer_name + , TYPE_NS, 9, "\007invalid\000"); + xfr_writer_add_TXT(&xw, label_plus_dname("version" + , producer_name), "2"); + goto add_member_zones; + } + /* IXFR */ + xfr_writer_add_SOA(&xw, producer_name, xw.old_serial); + while(producer_zone->to_delete) { + struct xfrd_producer_member* to_delete = + producer_zone->to_delete; + + /* Pop to_delete from stack */ + producer_zone->to_delete = to_delete->next; + to_delete->next = NULL; + + /* Write PTR */ + xfr_writer_add_PTR(&xw, to_delete->member_id + , to_delete->member_zone_name); + + /* Write group. TXT */ + xfr_writer_add_TXT( &xw + , label_plus_dname("group" + , to_delete->member_id) + , to_delete->group_name); + + region_recycle( xfrd->nsd->options->region + , (void *)to_delete->member_id + , dname_total_size(to_delete->member_id)); + region_recycle( xfrd->region /* allocated in perform_delzone */ + , (void *)to_delete->member_zone_name + , dname_total_size(to_delete->member_zone_name)); + /* Don't recycle to_delete->group_name it's pattern->pname */ + region_recycle( xfrd->region, to_delete, sizeof(*to_delete)); + } + xfr_writer_add_SOA(&xw, producer_name, xw.new_serial); + +add_member_zones: + while(producer_zone->to_add) { + struct xfrd_producer_member* to_add = producer_zone->to_add; + + /* Pop to_add from stack */ + producer_zone->to_add = to_add->next; + to_add->next = NULL; + + /* Write PTR */ + xfr_writer_add_PTR(&xw, to_add->member_id, + to_add->member_zone_name); + + /* Write group. TXT */ + xfr_writer_add_TXT( &xw + , label_plus_dname("group" + , to_add->member_id) + , to_add->group_name); + + /* Don't recycle any of the struct attributes as they come + * from zone_option's that are in use + */ + region_recycle(xfrd->region, to_add, sizeof(*to_add)); + } + xfr_writer_add_SOA(&xw, producer_name, xw.new_serial); + xfr_writer_commit(&xw, "xfr for catalog producer zone " + "'%s' with %d members from %u to %u", + dname_to_string(producer_name, NULL), + producer_zone->member_ids.count, + xw.old_serial, xw.new_serial); + producer_zone->serial = xw.new_serial; + + /* Hook up an xfrd_producer_xfr, to delete the xfr file when applied */ + pxfr = (struct xfrd_producer_xfr*)region_alloc(xfrd->region, + sizeof(struct xfrd_producer_xfr)); + pxfr->serial = xw.new_serial; + pxfr->xfrfilenumber = xw.xfrfilenumber; + if((pxfr->next = producer_zone->latest_pxfr)) + pxfr->next->prev_next_ptr = &pxfr->next; + pxfr->prev_next_ptr = &producer_zone->latest_pxfr; + producer_zone->latest_pxfr = pxfr; +} + +void xfrd_process_catalog_producer_zones() +{ + struct xfrd_catalog_producer_zone* producer_zone; + + RBTREE_FOR(producer_zone, struct xfrd_catalog_producer_zone*, + xfrd->catalog_producer_zones) { + xfrd_process_catalog_producer_zone(producer_zone); + } +} + diff --git a/usr.sbin/nsd/xfrd-catalog-zones.h b/usr.sbin/nsd/xfrd-catalog-zones.h new file mode 100644 index 000000000..17992b15c --- /dev/null +++ b/usr.sbin/nsd/xfrd-catalog-zones.h @@ -0,0 +1,128 @@ +/* + * xfrd-catalog-zones.h -- catalog zone implementation for NSD + * + * Copyright (c) 2024, NLnet Labs. All rights reserved. + * + * See LICENSE for the license. + */ +#ifndef XFRD_CATALOG_ZONES_H +#define XFRD_CATALOG_ZONES_H +#include "xfrd.h" +struct xfrd_producer_member; +struct xfrd_producer_xfr; + +/** + * Catalog zones withing the xfrd context + */ +struct xfrd_catalog_consumer_zone { + /* For indexing in struc xfrd_state { rbtree_type* catalog_consumer_zones; } */ + rbnode_type node; + + /* Associated zone options with this catalog consumer zone */ + struct zone_options* options; + + /* Member zones indexed by member_id */ + rbtree_type member_ids; + + /* Last time processed, compare with zone->mtime to see if we need to process */ + struct timespec mtime; + + /* The reason for this zone to be invalid, or NULL if it is valid */ + char *invalid; +} ATTR_PACKED; + +/** + * Catalog producer zones withing the xfrd context + */ +struct xfrd_catalog_producer_zone { + /* For indexing in struc xfrd_state { rbtree_type* catalog_producer_zones; } */ + rbnode_type node; + + /* Associated zone options with this catalog consumer zone */ + struct zone_options* options; + + /* Member zones indexed by member_id */ + rbtree_type member_ids; + + /* SOA serial for this zone */ + uint32_t serial; + + /* Stack of members to delete from this catalog producer zone */ + struct xfrd_producer_member* to_delete; + + /* Stack of member zones to add to this catalog producer zone */ + struct xfrd_producer_member* to_add; + + /* To cleanup on disk xfr files */ + struct xfrd_producer_xfr* latest_pxfr; + + /* Set if next generated xfr for the producer zone should be axfr */ + unsigned axfr: 1; +} ATTR_PACKED; + +/** + * Data to add or remove from a catalog producer zone + */ +struct xfrd_producer_member { + const dname_type* member_id; + const dname_type* member_zone_name; + const char* group_name; + struct xfrd_producer_member* next; +} ATTR_PACKED; + +/** + * To track applied generated transfers from catalog producer zones + */ +struct xfrd_producer_xfr { + uint32_t serial; + uint64_t xfrfilenumber; + struct xfrd_producer_xfr** prev_next_ptr; + struct xfrd_producer_xfr* next; +} ATTR_PACKED; + +/* Initialize as a catalog consumer zone */ +void xfrd_init_catalog_consumer_zone(xfrd_state_type* xfrd, + struct zone_options* zone); + +/* To be called if and a zone is no longer a catalog zone (changed pattern) */ +void xfrd_deinit_catalog_consumer_zone(xfrd_state_type* xfrd, + const dname_type* dname); + +/* make the catalog consumer zone invalid for given reason */ +void make_catalog_consumer_invalid( + struct xfrd_catalog_consumer_zone *consumer_zone, + const char *format, ...) ATTR_FORMAT(printf, 2, 3); + +/* Return the reason a zone is invalid, or NULL on a valid catalog */ +const char *invalid_catalog_consumer_zone(struct zone_options* zone); + +/* make the catalog consumer zone valid again */ +void make_catalog_consumer_valid( + struct xfrd_catalog_consumer_zone *consumer_zone); + +/* Check the catalog consumer zone files (or file if zone is given) */ +void xfrd_check_catalog_consumer_zonefiles(const dname_type* name); + +/* process the catalog consumer zones, load if needed */ +void xfrd_process_catalog_consumer_zones(); + + +/* Add (or change) PTR , and + * group. TXT pname> to the associated producer zone by + * constructed xfr. make cmz->member_id if needed. */ +void xfrd_add_catalog_producer_member(struct catalog_member_zone* cmz); + +/* Delete PTR , and + * group. TXT pname> from the associated producer zone by + * constructed xfr. Return 1 if zone is deleted. In this case, member_zone_name + * is taken over by xfrd and cannot be recycled by the caller. member_zone_name + * must have been allocated int the xfrd->nsd->options->region + */ +int xfrd_del_catalog_producer_member(xfrd_state_type* xfrd, + const dname_type* dname); + +/* process the catalog producer zones */ +void xfrd_process_catalog_producer_zones(); + +#endif + diff --git a/usr.sbin/nsd/xfrd-disk.c b/usr.sbin/nsd/xfrd-disk.c index 59ecf47ca..146d8d0b1 100644 --- a/usr.sbin/nsd/xfrd-disk.c +++ b/usr.sbin/nsd/xfrd-disk.c @@ -264,7 +264,7 @@ xfrd_read_state(struct xfrd_state* xfrd) zone->master = acl_find_num(zone->zone_options->pattern-> request_xfr, zone->master_num); if(!zone->master) { - DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: masters changed for zone %s", + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: primaries changed for zone %s", zone->apex_str)); zone->master = zone->zone_options->pattern->request_xfr; zone->master_num = 0; @@ -464,10 +464,10 @@ xfrd_write_state(struct xfrd_state* xfrd) fprintf(out, "%s\n", XFRD_FILE_MAGIC); fprintf(out, "# This file is written on exit by nsd xfr daemon.\n"); - fprintf(out, "# This file contains slave zone information:\n"); + fprintf(out, "# This file contains secondary zone information:\n"); fprintf(out, "# * timeouts (when was zone data acquired)\n"); fprintf(out, "# * state (OK, refreshing, expired)\n"); - fprintf(out, "# * which master transfer to attempt next\n"); + fprintf(out, "# * which primary transfer to attempt next\n"); fprintf(out, "# The file is read on start (but not on reload) by nsd xfr daemon.\n"); fprintf(out, "# You can edit; but do not change statement order\n"); fprintf(out, "# and no fancy stuff (like quoted \"strings\").\n"); @@ -475,7 +475,7 @@ xfrd_write_state(struct xfrd_state* xfrd) fprintf(out, "# If you remove a zone entry, it will be refreshed.\n"); fprintf(out, "# This can be useful for an expired zone; it revives\n"); fprintf(out, "# the zone temporarily, from refresh-expiry time.\n"); - fprintf(out, "# If you delete the file all slave zones are updated.\n"); + fprintf(out, "# If you delete the file all secondary zones are updated.\n"); fprintf(out, "#\n"); fprintf(out, "# Note: if you edit this file while nsd is running,\n"); fprintf(out, "# it will be overwritten on exit by nsd.\n"); diff --git a/usr.sbin/nsd/xfrd-tcp.c b/usr.sbin/nsd/xfrd-tcp.c index 3b499ae3c..69f9f82b3 100644 --- a/usr.sbin/nsd/xfrd-tcp.c +++ b/usr.sbin/nsd/xfrd-tcp.c @@ -1513,7 +1513,7 @@ xfrd_tcp_read(struct xfrd_tcp_pipeline* tp) /* fall through to remove zone from tp */ /* fallthrough */ case xfrd_packet_transfer: - if(zone->zone_options->pattern->multi_master_check) { + if(zone->zone_options->pattern->multi_primary_check) { xfrd_tcp_release(xfrd->tcp_set, zone); xfrd_make_request(zone); break; diff --git a/usr.sbin/nsd/xfrd.c b/usr.sbin/nsd/xfrd.c index 9271e919f..91b133098 100644 --- a/usr.sbin/nsd/xfrd.c +++ b/usr.sbin/nsd/xfrd.c @@ -20,6 +20,7 @@ #include "xfrd-tcp.h" #include "xfrd-disk.h" #include "xfrd-notify.h" +#include "xfrd-catalog-zones.h" #include "options.h" #include "util.h" #include "netio.h" @@ -315,6 +316,8 @@ xfrd_main(void) xfrd->shutdown = 0; while(!xfrd->shutdown) { + xfrd_process_catalog_producer_zones(); + xfrd_process_catalog_consumer_zones(); /* process activated zones before blocking in select again */ xfrd_process_activated(); /* dispatch may block for a longer period, so current is gone */ @@ -419,6 +422,10 @@ xfrd_shutdown() /* process-exit cleans up memory used by xfrd process */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd shutdown complete")); #ifdef MEMCLEAN /* OS collects memory pages */ + if(xfrd->nsd->db) { + namedb_close(xfrd->nsd->db); + } + /* TODO: cleanup xfrd->catalog_consumer_zones and xfrd->catalog_producer_zones */ if(xfrd->zones) { xfrd_zone_type* z; RBTREE_FOR(z, xfrd_zone_type*, xfrd->zones) { @@ -542,12 +549,25 @@ xfrd_init_zones() (int (*)(const void *, const void *)) dname_compare); xfrd->notify_zones = rbtree_create(xfrd->region, (int (*)(const void *, const void *)) dname_compare); + xfrd->catalog_consumer_zones = rbtree_create(xfrd->region, + (int (*)(const void *, const void *)) dname_compare); + xfrd->catalog_producer_zones = rbtree_create(xfrd->region, + (int (*)(const void *, const void *)) dname_compare); RBTREE_FOR(zone_opt, struct zone_options*, xfrd->nsd->options->zone_options) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: adding %s zone", zone_opt->name)); + if(zone_is_catalog_consumer(zone_opt)) { + DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s " + "is a catalog consumer zone", zone_opt->name)); + xfrd_init_catalog_consumer_zone(xfrd, zone_opt); + } + if(zone_is_catalog_producer_member(zone_opt)) { + xfrd_add_catalog_producer_member( + as_catalog_member_zone(zone_opt)); + } init_notify_send(xfrd->notify_zones, xfrd->region, zone_opt); if(!zone_is_slave(zone_opt)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s, " @@ -558,7 +578,77 @@ xfrd_init_zones() xfrd_init_slave_zone(xfrd, zone_opt); } DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: started server %d " - "secondary zones", (int)xfrd->zones->count)); + "secondary zones, %d catalog zones", (int)xfrd->zones->count, + (int)xfrd->catalog_consumer_zones->count)); +} + +static void +apply_xfrs_to_consumer_zone(struct xfrd_catalog_consumer_zone* consumer_zone, + zone_type* dbzone, xfrd_xfr_type* xfr) +{ + FILE* df; + + if(xfr->msg_is_ixfr) { + uint32_t soa_serial; + xfrd_xfr_type* prev; + + if(dbzone->soa_rrset == NULL || dbzone->soa_rrset->rrs == NULL + || dbzone->soa_rrset->rrs[0].rdata_count <= 2 + || rdata_atom_size(dbzone->soa_rrset->rrs[0].rdatas[2]) + != sizeof(uint32_t)) { + + make_catalog_consumer_invalid(consumer_zone, + "could not apply ixfr on catalog consumer zone " + "\'%s\': invalid SOA resource record", + consumer_zone->options->name); + return; + } + soa_serial = read_uint32(rdata_atom_data( + dbzone->soa_rrset->rrs[0].rdatas[2])); + if(soa_serial == xfr->msg_old_serial) + goto apply_xfr; + for(prev = xfr->prev; prev; prev = prev->prev) { + if(!prev->sent) + continue; + if(xfr->msg_old_serial != prev->msg_new_serial) + continue; + apply_xfrs_to_consumer_zone(consumer_zone, dbzone, prev); + break; + } + if(!prev || xfr->msg_old_serial != read_uint32(rdata_atom_data( + dbzone->soa_rrset->rrs[0].rdatas[2]))){ + make_catalog_consumer_invalid(consumer_zone, + "could not find and/or apply xfrs for catalog " + "consumer zone \'%s\': to update to serial %u", + consumer_zone->options->name, + xfr->msg_new_serial); + return; + } + } +apply_xfr: + DEBUG(DEBUG_IPC,1, (LOG_INFO, "apply %sXFR %u -> %u to consumer zone " + "\'%s\'", (xfr->msg_is_ixfr ? "I" : "A"), xfr->msg_old_serial, + xfr->msg_new_serial, consumer_zone->options->name)); + + if(!(df = xfrd_open_xfrfile(xfrd->nsd, xfr->xfrfilenumber, "r"))) { + make_catalog_consumer_invalid(consumer_zone, + "could not open transfer file %lld: %s", + (long long)xfr->xfrfilenumber, strerror(errno)); + + } else if(0 >= apply_ixfr_for_zone(xfrd->nsd, dbzone, df, + xfrd->nsd->options, NULL, NULL, xfr->xfrfilenumber)) { + make_catalog_consumer_invalid(consumer_zone, + "error processing transfer file %lld", + (long long)xfr->xfrfilenumber); + fclose(df); + } else { + /* Make valid for reprocessing */ + make_catalog_consumer_valid(consumer_zone); + fclose(df); + DEBUG(DEBUG_IPC,1, (LOG_INFO, "%sXFR %u -> %u to consumer zone \'%s\' " + "applied", (xfr->msg_is_ixfr ? "I" : "A"), xfr->msg_old_serial, + xfr->msg_new_serial, consumer_zone->options->name)); + } } static void @@ -567,6 +657,9 @@ xfrd_process_soa_info_task(struct task_list_d* task) xfrd_soa_type soa; xfrd_soa_type* soa_ptr = &soa; xfrd_zone_type* zone; + struct xfrd_catalog_producer_zone* producer_zone; + struct xfrd_catalog_consumer_zone* consumer_zone = NULL; + zone_type* dbzone = NULL; xfrd_xfr_type* xfr; xfrd_xfr_type* prev_xfr; enum soainfo_hint hint; @@ -627,14 +720,71 @@ xfrd_process_soa_info_task(struct task_list_d* task) #endif } - if(!zone) { - DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: zone %s master zone updated", + if(zone) + ; /* pass */ + + else if((producer_zone = (struct xfrd_catalog_producer_zone*) + rbtree_search(xfrd->catalog_producer_zones, task->zname))) { + struct xfrd_producer_xfr* pxfr, *next_pxfr; + + DEBUG(DEBUG_IPC,1, (LOG_INFO, "Zone %s is catalog producer", + dname_to_string(task->zname,0))); + + if(hint != soainfo_ok) + producer_zone->axfr = 1; + + for(pxfr = producer_zone->latest_pxfr; pxfr; pxfr = next_pxfr) { + next_pxfr = pxfr->next; + + DEBUG(DEBUG_IPC,1, (LOG_INFO, "pxfr for zone %s for serial %u", + dname_to_string(task->zname,0), pxfr->serial)); + + if(hint != soainfo_ok) + ; /* pass */ + else if(!soa_ptr || soa_ptr->serial != htonl(pxfr->serial)) + continue; + + else if(xfrd->reload_failed) { + DEBUG(DEBUG_IPC, 1, + (LOG_INFO, "xfrd: zone %s mark update " + "to serial %u verified", + producer_zone->options->name, + pxfr->serial)); + diff_update_commit( + producer_zone->options->name, + DIFF_VERIFIED, xfrd->nsd, + pxfr->xfrfilenumber); + return; + } + DEBUG(DEBUG_IPC, 1, + (LOG_INFO, "xfrd: zone %s delete update to " + "serial %u", producer_zone->options->name, + pxfr->serial)); + xfrd_unlink_xfrfile(xfrd->nsd, pxfr->xfrfilenumber); + if((*pxfr->prev_next_ptr = pxfr->next)) + pxfr->next->prev_next_ptr = pxfr->prev_next_ptr; + region_recycle(xfrd->region, pxfr, sizeof(*pxfr)); + notify_handle_master_zone_soainfo(xfrd->notify_zones, + task->zname, soa_ptr); + } + return; + } else { + DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: zone %s primary zone updated", dname_to_string(task->zname,0))); notify_handle_master_zone_soainfo(xfrd->notify_zones, task->zname, soa_ptr); return; } - + if(xfrd->nsd->db + && xfrd->catalog_consumer_zones +#ifndef MULTIPLE_CATALOG_CONSUMER_ZONES + && xfrd->catalog_consumer_zones->count == 1 +#endif + && (consumer_zone = (struct xfrd_catalog_consumer_zone*)rbtree_search( + xfrd->catalog_consumer_zones, task->zname))) { + dbzone = namedb_find_or_create_zone( xfrd->nsd->db, task->zname + , consumer_zone->options); + } /* soainfo_gone and soainfo_bad are straightforward, delete all updates that were transfered, i.e. acquired != 0. soainfo_ok is more complicated as it is possible that there are subsequent corrupt or @@ -670,6 +820,9 @@ xfrd_process_soa_info_task(struct task_list_d* task) xfrd->nsd, xfr->xfrfilenumber); return; } + if(consumer_zone && dbzone) + apply_xfrs_to_consumer_zone( + consumer_zone, dbzone, xfr); } DEBUG(DEBUG_IPC, 1, (LOG_INFO, "xfrd: zone %s delete update to serial %u", @@ -857,7 +1010,8 @@ xfrd_del_slave_zone(xfrd_state_type* xfrd, const dname_type* dname) xfrd_tcp_release(xfrd->tcp_set, z); } else if(z->zone_handler.ev_fd != -1 && z->event_added) { xfrd_udp_release(z); - } else if(z->event_added) + } + if(z->event_added) event_del(&z->zone_handler); while(z->latest_xfr) xfrd_delete_zone_xfr(z, z->latest_xfr); @@ -1023,7 +1177,7 @@ xfrd_make_request(xfrd_zone_type* zone) if(zone->next_master != -1) { /* we are told to use this next master */ DEBUG(DEBUG_XFRD,1, (LOG_INFO, - "xfrd zone %s use master %i", + "xfrd zone %s use primary %i", zone->apex_str, zone->next_master)); zone->master_num = zone->next_master; zone->master = acl_find_num(zone->zone_options->pattern-> @@ -1063,13 +1217,13 @@ xfrd_make_request(xfrd_zone_type* zone) } /* multi-master-check */ - if(zone->zone_options->pattern->multi_master_check) { + if(zone->zone_options->pattern->multi_primary_check) { if(zone->multi_master_first_master == zone->master_num && zone->round_num > 0 && zone->state != xfrd_zone_expired) { /* tried all servers and update zone */ if(zone->multi_master_update_check >= 0) { - VERBOSITY(2, (LOG_INFO, "xfrd: multi master " + VERBOSITY(2, (LOG_INFO, "xfrd: multi primary " "check: zone %s completed transfers", zone->apex_str)); } @@ -1088,7 +1242,7 @@ xfrd_make_request(xfrd_zone_type* zone) if (zone->master->ixfr_disabled && (zone->master->ixfr_disabled + XFRD_NO_IXFR_CACHE) <= time(NULL)) { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "clear negative caching ixfr " - "disabled for master %s num " + "disabled for primary %s num " "%d ", zone->master->ip_address_spec, zone->master_num)); zone->master->ixfr_disabled = 0; @@ -1119,7 +1273,7 @@ xfrd_make_request(xfrd_zone_type* zone) xfrd_tcp_obtain(xfrd->tcp_set, zone); } else { DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd zone %s axfr " - "fallback not allowed, skipping master %s.", + "fallback not allowed, skipping primary %s.", zone->apex_str, zone->master->ip_address_spec)); } } @@ -1527,7 +1681,7 @@ xfrd_udp_read(xfrd_zone_type* zone) xfrd_tcp_obtain(xfrd->tcp_set, zone); break; case xfrd_packet_transfer: - if(zone->zone_options->pattern->multi_master_check) { + if(zone->zone_options->pattern->multi_primary_check) { xfrd_udp_release(zone); xfrd_make_request(zone); break; @@ -2115,7 +2269,7 @@ xfrd_parse_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet, xfrd_set_zone_state(zone, xfrd_zone_ok); DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is ok", zone->apex_str)); - if(zone->zone_options->pattern->multi_master_check) { + if(zone->zone_options->pattern->multi_primary_check) { region_destroy(tempregion); return xfrd_packet_drop; } @@ -2384,7 +2538,7 @@ xfrd_handle_received_xfr_packet(xfrd_zone_type* zone, buffer_type* packet) DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfrd: zone %s is waiting for reload", zone->apex_str)); - if(zone->zone_options->pattern->multi_master_check) { + if(zone->zone_options->pattern->multi_primary_check) { zone->multi_master_update_check = zone->master_num; xfrd_set_reload_timeout(); return xfrd_packet_transfer; @@ -2514,7 +2668,7 @@ xfrd_handle_passed_packet(buffer_type* packet, if(next != -1) { zone->next_master = next; DEBUG(DEBUG_XFRD,1, (LOG_INFO, - "xfrd: notify set next master to query %d", + "xfrd: notify set next primary to query %d", next)); } } diff --git a/usr.sbin/nsd/xfrd.h b/usr.sbin/nsd/xfrd.h index 4749c4b6e..83086e870 100644 --- a/usr.sbin/nsd/xfrd.h +++ b/usr.sbin/nsd/xfrd.h @@ -119,6 +119,12 @@ struct xfrd_state { int notify_udp_num; /* first and last notify_zone* entries waiting for a UDP socket */ struct notify_zone *notify_waiting_first, *notify_waiting_last; + + /* tree of catalog consumer zones. Processing is disabled if > 1. */ + rbtree_type *catalog_consumer_zones; + + /* tree of updated catalog producer zones for which the content to serve */ + rbtree_type *catalog_producer_zones; }; /* diff --git a/usr.sbin/rpki-client/rrdp_notification.c b/usr.sbin/rpki-client/rrdp_notification.c index 310ba99ad..1d3e149a4 100644 --- a/usr.sbin/rpki-client/rrdp_notification.c +++ b/usr.sbin/rpki-client/rrdp_notification.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rrdp_notification.c,v 1.20 2024/03/22 03:38:12 job Exp $ */ +/* $OpenBSD: rrdp_notification.c,v 1.21 2024/04/12 11:50:29 job Exp $ */ /* * Copyright (c) 2020 Nils Fisher * Copyright (c) 2021 Claudio Jeker @@ -294,7 +294,7 @@ start_delta_elem(struct notification_xml *nxml, const char **attr) continue; } PARSE_FAIL(p, "parse failed - non conforming " - "attribute '%s' found in snapshot elem", attr[i]); + "attribute '%s' found in delta elem", attr[i]); } /* Only add to the list if we are relevant */ if (hasUri != 1 || hasHash != 1 || delta_serial == 0) diff --git a/usr.sbin/snmpd/snmpd.c b/usr.sbin/snmpd/snmpd.c index 5598ce58f..3bb050bc1 100644 --- a/usr.sbin/snmpd/snmpd.c +++ b/usr.sbin/snmpd/snmpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: snmpd.c,v 1.51 2024/04/08 13:18:54 tobhe Exp $ */ +/* $OpenBSD: snmpd.c,v 1.52 2024/04/12 14:17:42 bluhm Exp $ */ /* * Copyright (c) 2007, 2008, 2012 Reyk Floeter @@ -358,14 +358,10 @@ snmpd_backend(struct snmpd *env) } if (env->sc_flags & SNMPD_F_VERBOSE) argv[i++] = "-vv"; - if (env->sc_flags & SNMPD_F_DEBUG) { + if (env->sc_flags & SNMPD_F_DEBUG) argv[i++] = "-d"; - argv[i++] = "-x"; - argv[i++] = "3"; - } else { - argv[i++] = "-x"; - argv[i++] = "0"; - } + argv[i++] = "-x"; + argv[i++] = "3"; argv[i] = NULL; while ((file = readdir(dir)) != NULL) { if (file->d_name[0] == '.') @@ -377,10 +373,9 @@ snmpd_backend(struct snmpd *env) fatal("fork"); case 0: close(pair[1]); - if (dup2(pair[0], - env->sc_flags & SNMPD_F_DEBUG ? 3 : 0) == -1) + if (dup2(pair[0], 3) == -1) fatal("dup2"); - if (closefrom(env->sc_flags & SNMPD_F_DEBUG ? 4 : 1) == -1) + if (closefrom(4) == -1) fatal("closefrom"); (void)snprintf(execpath, sizeof(execpath), "%s/%s", SNMPD_BACKEND, file->d_name); diff --git a/usr.sbin/unbound/Makefile.in b/usr.sbin/unbound/Makefile.in index fef4c5283..1c4f5fe85 100644 --- a/usr.sbin/unbound/Makefile.in +++ b/usr.sbin/unbound/Makefile.in @@ -739,7 +739,7 @@ msgencode.lo msgencode.o: $(srcdir)/util/data/msgencode.c config.h $(srcdir)/uti msgparse.lo msgparse.o: $(srcdir)/util/data/msgparse.c config.h $(srcdir)/util/data/msgparse.h \ $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/sldns/pkthdr.h \ $(srcdir)/sldns/rrdef.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h \ - $(srcdir)/util/data/dname.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/regional.h $(srcdir)/sldns/sbuffer.h \ + $(srcdir)/util/data/dname.h $(srcdir)/util/storage/lookup3.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h $(srcdir)/sldns/sbuffer.h \ $(srcdir)/sldns/parseutil.h $(srcdir)/sldns/wire2str.h msgreply.lo msgreply.o: $(srcdir)/util/data/msgreply.c config.h $(srcdir)/util/data/msgreply.h \ $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/data/packed_rrset.h \ @@ -794,7 +794,7 @@ iter_priv.lo iter_priv.o: $(srcdir)/iterator/iter_priv.c config.h $(srcdir)/iter $(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/net_help.h \ $(srcdir)/util/storage/dnstree.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/sbuffer.h iter_resptype.lo iter_resptype.o: $(srcdir)/iterator/iter_resptype.c config.h \ - $(srcdir)/iterator/iter_resptype.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/util/log.h \ + $(srcdir)/iterator/iter_resptype.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/iterator/iterator.h $(srcdir)/util/log.h \ $(srcdir)/services/cache/dns.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h \ $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/net_help.h \ $(srcdir)/util/data/dname.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/pkthdr.h diff --git a/usr.sbin/unbound/README.md b/usr.sbin/unbound/README.md index c220da030..3bbd38b3b 100644 --- a/usr.sbin/unbound/README.md +++ b/usr.sbin/unbound/README.md @@ -17,7 +17,9 @@ You can learn more about Unbound by reading our ## Compiling Make sure you have the C toolchain, OpenSSL and its include files, and libexpat -installed. Unbound can be compiled and installed using: +installed. +If building from the repository source you also need flex and bison installed. +Unbound can be compiled and installed using: ``` ./configure && make && make install @@ -27,7 +29,7 @@ You can use libevent if you want. libevent is useful when using many (10000) outgoing ports. By default max 256 ports are opened at the same time and the builtin alternative is equally capable and a little faster. -Use the `--with-libevent=dir` configure option to compile Unbound with libevent +Use the `--with-libevent` configure option to compile Unbound with libevent support. ## Unbound configuration diff --git a/usr.sbin/unbound/cachedb/cachedb.c b/usr.sbin/unbound/cachedb/cachedb.c index 0a6c05d6f..002bbf8d7 100644 --- a/usr.sbin/unbound/cachedb/cachedb.c +++ b/usr.sbin/unbound/cachedb/cachedb.c @@ -265,11 +265,11 @@ cachedb_init(struct module_env* env, int id) return 0; } cachedb_env->enabled = 1; - if(env->cfg->serve_expired_reply_ttl) + if(env->cfg->serve_expired && env->cfg->serve_expired_reply_ttl) log_warn( "cachedb: serve-expired-reply-ttl is set but not working for data " - "originating from the external cache; 0 TLL is used for those."); - if(env->cfg->serve_expired_client_timeout) + "originating from the external cache; 0 TTL is used for those."); + if(env->cfg->serve_expired && env->cfg->serve_expired_client_timeout) log_warn( "cachedb: serve-expired-client-timeout is set but not working for " "data originating from the external cache; expired data are used " @@ -815,6 +815,11 @@ cachedb_handle_response(struct module_qstate* qstate, qstate->ext_state[id] = module_finished; return; } + if(qstate->env->cfg->cachedb_no_store) { + /* do not store the item in the external cache */ + qstate->ext_state[id] = module_finished; + return; + } /* store the item into the backend cache */ cachedb_extcache_store(qstate, ie); diff --git a/usr.sbin/unbound/cachedb/redis.c b/usr.sbin/unbound/cachedb/redis.c index 61a34c2a1..1e2e757d3 100644 --- a/usr.sbin/unbound/cachedb/redis.c +++ b/usr.sbin/unbound/cachedb/redis.c @@ -59,11 +59,28 @@ struct redis_moddata { const char* server_path; /* server's unix path, or "", NULL if unused */ const char* server_password; /* server's AUTH password, or "", NULL if unused */ struct timeval timeout; /* timeout for connection setup and commands */ + int logical_db; /* the redis logical database to use */ }; static redisReply* redis_command(struct module_env*, struct cachedb_env*, const char*, const uint8_t*, size_t); +static void +moddata_clean(struct redis_moddata** moddata) { + if(!moddata || !*moddata) + return; + if((*moddata)->ctxs) { + int i; + for(i = 0; i < (*moddata)->numctxs; i++) { + if((*moddata)->ctxs[i]) + redisFree((*moddata)->ctxs[i]); + } + free((*moddata)->ctxs); + } + free(*moddata); + *moddata = NULL; +} + static redisContext* redis_connect(const struct redis_moddata* moddata) { @@ -97,10 +114,21 @@ redis_connect(const struct redis_moddata* moddata) } freeReplyObject(rep); } + if(moddata->logical_db > 0) { + redisReply* rep; + rep = redisCommand(ctx, "SELECT %d", moddata->logical_db); + if(!rep || rep->type == REDIS_REPLY_ERROR) { + log_err("failed to set logical database (%d)", + moddata->logical_db); + freeReplyObject(rep); + goto fail; + } + freeReplyObject(rep); + } verbose(VERB_OPS, "Connection to Redis established"); return ctx; - fail: +fail: if(ctx) redisFree(ctx); return NULL; @@ -117,14 +145,13 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env) moddata = calloc(1, sizeof(struct redis_moddata)); if(!moddata) { log_err("out of memory"); - return 0; + goto fail; } moddata->numctxs = env->cfg->num_threads; moddata->ctxs = calloc(env->cfg->num_threads, sizeof(redisContext*)); if(!moddata->ctxs) { log_err("out of memory"); - free(moddata); - return 0; + goto fail; } /* note: server_host is a shallow reference to configured string. * we don't have to free it in this module. */ @@ -134,8 +161,15 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env) moddata->server_password = env->cfg->redis_server_password; moddata->timeout.tv_sec = env->cfg->redis_timeout / 1000; moddata->timeout.tv_usec = (env->cfg->redis_timeout % 1000) * 1000; - for(i = 0; i < moddata->numctxs; i++) - moddata->ctxs[i] = redis_connect(moddata); + moddata->logical_db = env->cfg->redis_logical_db; + for(i = 0; i < moddata->numctxs; i++) { + redisContext* ctx = redis_connect(moddata); + if(!ctx) { + log_err("redis_init: failed to init redis"); + goto fail; + } + moddata->ctxs[i] = ctx; + } cachedb_env->backend_data = moddata; if(env->cfg->redis_expire_records) { redisReply* rep = NULL; @@ -148,7 +182,7 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env) log_err("redis_init: failed to init redis, the " "redis-expire-records option requires the SETEX command " "(redis >= 2.0.0)"); - return 0; + goto fail; } redis_reply_type = rep->type; freeReplyObject(rep); @@ -160,11 +194,14 @@ redis_init(struct module_env* env, struct cachedb_env* cachedb_env) log_err("redis_init: failed to init redis, the " "redis-expire-records option requires the SETEX command " "(redis >= 2.0.0)"); - return 0; + goto fail; } } - return 1; + +fail: + moddata_clean(&moddata); + return 0; } static void @@ -175,18 +212,7 @@ redis_deinit(struct module_env* env, struct cachedb_env* cachedb_env) (void)env; verbose(VERB_OPS, "Redis deinitialization"); - - if(!moddata) - return; - if(moddata->ctxs) { - int i; - for(i = 0; i < moddata->numctxs; i++) { - if(moddata->ctxs[i]) - redisFree(moddata->ctxs[i]); - } - free(moddata->ctxs); - } - free(moddata); + moddata_clean(&moddata); } /* diff --git a/usr.sbin/unbound/config.guess b/usr.sbin/unbound/config.guess index b18721393..f6d217a49 100644 --- a/usr.sbin/unbound/config.guess +++ b/usr.sbin/unbound/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2023 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2023-07-20' +timestamp='2024-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -60,7 +60,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2023 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -155,6 +155,9 @@ Linux|GNU|GNU/*) set_cc_for_build cat <<-EOF > "$dummy.c" + #if defined(__ANDROID__) + LIBC=android + #else #include #if defined(__UCLIBC__) LIBC=uclibc @@ -162,6 +165,8 @@ Linux|GNU|GNU/*) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu + #elif defined(__LLVM_LIBC__) + LIBC=llvm #else #include /* First heuristic to detect musl libc. */ @@ -169,6 +174,7 @@ Linux|GNU|GNU/*) LIBC=musl #endif #endif + #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" @@ -904,7 +910,7 @@ EOF fi ;; *:FreeBSD:*:*) - UNAME_PROCESSOR=`/usr/bin/uname -p` + UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; @@ -1589,6 +1595,9 @@ EOF *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; + *:Ironclad:*:*) + GUESS=$UNAME_MACHINE-unknown-ironclad + ;; esac # Do we have a guess based on uname results? diff --git a/usr.sbin/unbound/config.sub b/usr.sbin/unbound/config.sub index 6ae250275..2c6a07ab3 100644 --- a/usr.sbin/unbound/config.sub +++ b/usr.sbin/unbound/config.sub @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2023 Free Software Foundation, Inc. +# Copyright 1992-2024 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale -timestamp='2023-07-31' +timestamp='2024-01-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -76,7 +76,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2023 Free Software Foundation, Inc. +Copyright 1992-2024 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -1181,7 +1181,7 @@ case $cpu-$vendor in case $cpu in 1750a | 580 \ | a29k \ - | aarch64 | aarch64_be \ + | aarch64 | aarch64_be | aarch64c | arm64ec \ | abacus \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ @@ -1200,6 +1200,7 @@ case $cpu-$vendor in | d10v | d30v | dlx | dsp16xx \ | e2k | elxsi | epiphany \ | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ + | javascript \ | h8300 | h8500 \ | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ @@ -1221,6 +1222,7 @@ case $cpu-$vendor in | moxie \ | mt \ | msp430 \ + | nanomips* \ | nds32 | nds32le | nds32be \ | nfp \ | nios | nios2 | nios2eb | nios2el \ @@ -1252,6 +1254,7 @@ case $cpu-$vendor in | ubicom32 \ | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \ | vax \ + | vc4 \ | visium \ | w65 \ | wasm32 | wasm64 \ @@ -1284,11 +1287,12 @@ esac # Decode manufacturer-specific aliases for certain operating systems. -if test x$basic_os != x +if test x"$basic_os" != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. +obj= case $basic_os in gnu/linux*) kernel=linux @@ -1488,10 +1492,16 @@ case $os in os=eabi ;; *) - os=elf + os= + obj=elf ;; esac ;; + aout* | coff* | elf* | pe*) + # These are machine code file formats, not OSes + obj=$os + os= + ;; *) # No normalization, but not necessarily accepted, that comes below. ;; @@ -1510,12 +1520,15 @@ else # system, and we'll never get to this point. kernel= +obj= case $cpu-$vendor in score-*) - os=elf + os= + obj=elf ;; spu-*) - os=elf + os= + obj=elf ;; *-acorn) os=riscix1.2 @@ -1525,28 +1538,35 @@ case $cpu-$vendor in os=gnu ;; arm*-semi) - os=aout + os= + obj=aout ;; c4x-* | tic4x-*) - os=coff + os= + obj=coff ;; c8051-*) - os=elf + os= + obj=elf ;; clipper-intergraph) os=clix ;; hexagon-*) - os=elf + os= + obj=elf ;; tic54x-*) - os=coff + os= + obj=coff ;; tic55x-*) - os=coff + os= + obj=coff ;; tic6x-*) - os=coff + os= + obj=coff ;; # This must come before the *-dec entry. pdp10-*) @@ -1568,19 +1588,24 @@ case $cpu-$vendor in os=sunos3 ;; m68*-cisco) - os=aout + os= + obj=aout ;; mep-*) - os=elf + os= + obj=elf ;; mips*-cisco) - os=elf + os= + obj=elf ;; - mips*-*) - os=elf + mips*-*|nanomips*-*) + os= + obj=elf ;; or32-*) - os=coff + os= + obj=coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=sysv3 @@ -1589,7 +1614,8 @@ case $cpu-$vendor in os=sunos4.1.1 ;; pru-*) - os=elf + os= + obj=elf ;; *-be) os=beos @@ -1670,10 +1696,12 @@ case $cpu-$vendor in os=uxpv ;; *-rom68k) - os=coff + os= + obj=coff ;; *-*bug) - os=coff + os= + obj=coff ;; *-apple) os=macos @@ -1691,10 +1719,11 @@ esac fi -# Now, validate our (potentially fixed-up) OS. +# Now, validate our (potentially fixed-up) individual pieces (OS, OBJ). + case $os in # Sometimes we do "kernel-libc", so those need to count as OSes. - musl* | newlib* | relibc* | uclibc*) + llvm* | musl* | newlib* | relibc* | uclibc*) ;; # Likewise for "kernel-abi" eabi* | gnueabi*) @@ -1702,6 +1731,9 @@ case $os in # VxWorks passes extra cpu info in the 4th filed. simlinux | simwindows | spe) ;; + # See `case $cpu-$os` validation below + ghcjs) + ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. @@ -1719,11 +1751,11 @@ case $os in | mirbsd* | netbsd* | dicos* | openedition* | ose* \ | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ - | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ - | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | bosx* | nextstep* | cxux* | oabi* \ + | ptx* | ecoff* | winnt* | domain* | vsta* \ | udi* | lites* | ieee* | go32* | aux* | hcos* \ | chorusrdb* | cegcc* | glidix* | serenity* \ - | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | cygwin* | msys* | moss* | proelf* | rtems* \ | midipix* | mingw32* | mingw64* | mint* \ | uxpv* | beos* | mpeix* | udk* | moxiebox* \ | interix* | uwin* | mks* | rhapsody* | darwin* \ @@ -1736,71 +1768,115 @@ case $os in | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ - | fiwix* | mlibc* | cos* | mbr* ) + | fiwix* | mlibc* | cos* | mbr* | ironclad* ) ;; # This one is extra strict with allowed versions sco3.2v2 | sco3.2v[4-9]* | sco5v6*) # Don't forget version if it is 3.2v4 or newer. ;; + # This refers to builds using the UEFI calling convention + # (which depends on the architecture) and PE file format. + # Note that this is both a different calling convention and + # different file format than that of GNU-EFI + # (x86_64-w64-mingw32). + uefi) + ;; none) ;; kernel* | msvc* ) # Restricted further below ;; + '') + if test x"$obj" = x + then + echo "Invalid configuration '$1': Blank OS only allowed with explicit machine code file format" 1>&2 + fi + ;; *) echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 exit 1 ;; esac +case $obj in + aout* | coff* | elf* | pe*) + ;; + '') + # empty is fine + ;; + *) + echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 + exit 1 + ;; +esac + +# Here we handle the constraint that a (synthetic) cpu and os are +# valid only in combination with each other and nowhere else. +case $cpu-$os in + # The "javascript-unknown-ghcjs" triple is used by GHC; we + # accept it here in order to tolerate that, but reject any + # variations. + javascript-ghcjs) + ;; + javascript-* | *-ghcjs) + echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 + exit 1 + ;; +esac + # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. -case $kernel-$os in - linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ - | linux-musl* | linux-relibc* | linux-uclibc* | linux-mlibc* ) +case $kernel-$os-$obj in + linux-gnu*- | linux-android*- | linux-dietlibc*- | linux-llvm*- \ + | linux-mlibc*- | linux-musl*- | linux-newlib*- \ + | linux-relibc*- | linux-uclibc*- ) ;; - uclinux-uclibc* ) + uclinux-uclibc*- ) ;; - managarm-mlibc* | managarm-kernel* ) + managarm-mlibc*- | managarm-kernel*- ) ;; - windows*-gnu* | windows*-msvc*) + windows*-msvc*-) ;; - -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* | -mlibc* ) + -dietlibc*- | -llvm*- | -mlibc*- | -musl*- | -newlib*- | -relibc*- \ + | -uclibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 exit 1 ;; - -kernel* ) + -kernel*- ) echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 exit 1 ;; - *-kernel* ) + *-kernel*- ) echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 exit 1 ;; - *-msvc* ) + *-msvc*- ) echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 exit 1 ;; - kfreebsd*-gnu* | kopensolaris*-gnu*) + kfreebsd*-gnu*- | kopensolaris*-gnu*-) ;; - vxworks-simlinux | vxworks-simwindows | vxworks-spe) + vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) ;; - nto-qnx*) + nto-qnx*-) ;; - os2-emx) + os2-emx-) ;; - *-eabi* | *-gnueabi*) + *-eabi*- | *-gnueabi*-) ;; - none-coff* | none-elf*) + none--*) # None (no kernel, i.e. freestanding / bare metal), - # can be paired with an output format "OS" + # can be paired with an machine code file format ;; - -*) + -*-) # Blank kernel with real OS is always fine. ;; - *-*) + --*) + # Blank kernel and OS with real machine code file format is always fine. + ;; + *-*-*) echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; @@ -1884,7 +1960,7 @@ case $vendor in ;; esac -echo "$cpu-$vendor-${kernel:+$kernel-}$os" +echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: diff --git a/usr.sbin/unbound/configure b/usr.sbin/unbound/configure index 9f8a19087..55caa2208 100644 --- a/usr.sbin/unbound/configure +++ b/usr.sbin/unbound/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for unbound 1.18.0. +# Generated by GNU Autoconf 2.69 for unbound 1.19.2. # # Report bugs to . # @@ -591,8 +591,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='unbound' PACKAGE_TARNAME='unbound' -PACKAGE_VERSION='1.18.0' -PACKAGE_STRING='unbound 1.18.0' +PACKAGE_VERSION='1.19.2' +PACKAGE_STRING='unbound 1.19.2' PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues' PACKAGE_URL='' @@ -1477,7 +1477,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures unbound 1.18.0 to adapt to many kinds of systems. +\`configure' configures unbound 1.19.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1543,7 +1543,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of unbound 1.18.0:";; + short | recursive ) echo "Configuration of unbound 1.19.2:";; esac cat <<\_ACEOF @@ -1785,7 +1785,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -unbound configure 1.18.0 +unbound configure 1.19.2 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2494,7 +2494,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by unbound $as_me 1.18.0, which was +It was created by unbound $as_me 1.19.2, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2844,13 +2844,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu UNBOUND_VERSION_MAJOR=1 -UNBOUND_VERSION_MINOR=18 +UNBOUND_VERSION_MINOR=19 -UNBOUND_VERSION_MICRO=0 +UNBOUND_VERSION_MICRO=2 LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=22 +LIBUNBOUND_REVISION=25 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -2940,6 +2940,9 @@ LIBUNBOUND_AGE=1 # 1.17.0 had 9:20:1 # 1.17.1 had 9:21:1 # 1.18.0 had 9:22:1 +# 1.19.0 had 9:23:1 +# 1.19.1 had 9:24:1 +# 1.19.2 had 9:25:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -4604,450 +4607,186 @@ fi default_cflags=yes fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : + case $ac_cv_prog_cc_stdc in #( + no) : + ac_cv_prog_cc_c99=no; ac_cv_prog_cc_c89=no ;; #( + *) : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 +$as_echo_n "checking for $CC option to accept ISO C99... " >&6; } +if ${ac_cv_prog_cc_c99+:} false; then : $as_echo_n "(cached) " >&6 else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - fi - rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ +#include +#include +#include +#include +#include -int -main () +// Check varargs macros. These examples are taken from C99 6.10.3.5. +#define debug(...) fprintf (stderr, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) { -#ifndef __GNUC__ - choke me + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + your preprocessor is broken; #endif +#if BIG_OK +#else + your preprocessor is broken; +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; - ; +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\0'; ++i) + continue; return 0; } -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +// Check varargs and va_copy. +static void +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str; + int number; + float fnumber; + + while (*format) + { + switch (*format++) + { + case 's': // string + str = va_arg (args_copy, const char *); + break; + case 'd': // int + number = va_arg (args_copy, int); + break; + case 'f': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); +} int main () { - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -else - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + // Check bool. + _Bool success = false; -int -main () -{ + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + test_varargs ("s, d' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' + || dynamic_array[ni.number - 1] != 543); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c99" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c99" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +$as_echo "$ac_cv_prog_cc_c99" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c99" != xno; then : + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 else - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 @@ -5134,14 +4873,31 @@ $as_echo "unsupported" >&6; } ;; $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : - + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 +else + ac_cv_prog_cc_stdc=no fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu +fi + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO Standard C" >&5 +$as_echo_n "checking for $CC option to accept ISO Standard C... " >&6; } + if ${ac_cv_prog_cc_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +fi + + case $ac_cv_prog_cc_stdc in #( + no) : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; #( + '') : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; #( + *) : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_stdc" >&5 +$as_echo "$ac_cv_prog_cc_stdc" >&6; } ;; +esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking $CC dependency flag" >&5 @@ -16247,10 +16003,7 @@ _ACEOF $as_echo_n "checking whether strptime works... " >&6; } if test c${cross_compiling} = cno; then if test "$cross_compiling" = yes; then : - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } + eval "ac_cv_c_strptime_works=maybe" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19039,10 +18792,7 @@ if test -n "$ssldir"; then CFLAGS="$CFLAGS -Wl,-rpath,$ssldir_lib" fi if test "$cross_compiling" = yes; then : - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } + eval "ac_cv_c_gost_works=maybe" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -20916,10 +20666,8 @@ if test "x$ac_cv_func_snprintf" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for correct snprintf return value" >&5 $as_echo_n "checking for correct snprintf return value... " >&6; } if test "$cross_compiling" = yes; then : - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: maybe" >&5 +$as_echo "maybe" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -21594,7 +21342,7 @@ if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else - as_fn_error $? "The protobuf-c library was not found. Please install protobuf-c!" "$LINENO" 5 + as_fn_error $? "The protobuf-c library was not found. Please install the development libraries for protobuf-c!" "$LINENO" 5 fi @@ -22148,7 +21896,7 @@ _ACEOF -version=1.18.0 +version=1.19.2 date=`date +'%b %e, %Y'` @@ -22667,7 +22415,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by unbound $as_me 1.18.0, which was +This file was extended by unbound $as_me 1.19.2, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -22733,7 +22481,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -unbound config.status 1.18.0 +unbound config.status 1.19.2 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/usr.sbin/unbound/configure.ac b/usr.sbin/unbound/configure.ac index c49b67c93..6bd176c43 100644 --- a/usr.sbin/unbound/configure.ac +++ b/usr.sbin/unbound/configure.ac @@ -10,15 +10,15 @@ sinclude(dnscrypt/dnscrypt.m4) # must be numbers. ac_defun because of later processing m4_define([VERSION_MAJOR],[1]) -m4_define([VERSION_MINOR],[18]) -m4_define([VERSION_MICRO],[0]) +m4_define([VERSION_MINOR],[19]) +m4_define([VERSION_MICRO],[2]) AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound]) AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR]) AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR]) AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO]) LIBUNBOUND_CURRENT=9 -LIBUNBOUND_REVISION=22 +LIBUNBOUND_REVISION=25 LIBUNBOUND_AGE=1 # 1.0.0 had 0:12:0 # 1.0.1 had 0:13:0 @@ -108,6 +108,9 @@ LIBUNBOUND_AGE=1 # 1.17.0 had 9:20:1 # 1.17.1 had 9:21:1 # 1.18.0 had 9:22:1 +# 1.19.0 had 9:23:1 +# 1.19.1 had 9:24:1 +# 1.19.2 had 9:25:1 # Current -- the number of the binary API that we're implementing # Revision -- which iteration of the implementation of the binary @@ -279,7 +282,7 @@ ACX_CHECK_COMPILER_FLAG(g, [CFLAGS="$CFLAGS -g"]) ACX_CHECK_COMPILER_FLAG(O2, [CFLAGS="$CFLAGS -O2"]) default_cflags=yes fi -AC_PROG_CC +m4_version_prereq([2.70], [AC_PROG_CC], [AC_PROG_CC_STDC]) ACX_DEPFLAG ACX_DETERMINE_EXT_FLAGS_UNBOUND @@ -525,7 +528,8 @@ res = strptime("2010-07-15T00:00:00+00:00", "%t%Y%t-%t%m%t-%t%d%tT%t%H%t:%t%M%t: if (!res) return 2; res = strptime("20070207111842", "%Y%m%d%H%M%S", &tm); if (!res) return 1; return 0; } -]])] , [eval "ac_cv_c_strptime_works=yes"], [eval "ac_cv_c_strptime_works=no"]) +]])] , [eval "ac_cv_c_strptime_works=yes"], [eval "ac_cv_c_strptime_works=no"], +[eval "ac_cv_c_strptime_works=maybe"]) else eval "ac_cv_c_strptime_works=maybe" fi @@ -1137,7 +1141,8 @@ int main(void) { return 6; return 0; } -]])] , [eval "ac_cv_c_gost_works=yes"], [eval "ac_cv_c_gost_works=no"]) +]])] , [eval "ac_cv_c_gost_works=yes"], [eval "ac_cv_c_gost_works=no"], +[eval "ac_cv_c_gost_works=maybe"]) CFLAGS="$BAKCFLAGS" else eval "ac_cv_c_gost_works=maybe" @@ -1714,7 +1719,7 @@ int main(void) { return !(snprintf(NULL, 0, "test") == 4); } AC_MSG_RESULT(no) AC_DEFINE([SNPRINTF_RET_BROKEN], [], [define if (v)snprintf does not return length needed, (but length used)]) AC_LIBOBJ(snprintf) - ]) + ], [AC_MSG_RESULT(maybe)]) fi fi AC_REPLACE_FUNCS(strlcat) @@ -1944,7 +1949,7 @@ case "$enable_explicit_port_randomisation" in esac if echo "$host" | $GREP -i -e linux >/dev/null; then - AC_ARG_ENABLE(linux-ip-local-port-range, AC_HELP_STRING([--enable-linux-ip-local-port-range], [Define this to enable use of /proc/sys/net/ipv4/ip_local_port_range as a default outgoing port range. This is only for the libunbound on Linux and does not affect unbound resolving daemon itself. This may severely limit the number of available outgoing ports and thus decrease randomness. Define this only when the target system restricts (e.g. some of SELinux enabled distributions) the use of non-ephemeral ports.])) + AC_ARG_ENABLE(linux-ip-local-port-range, AS_HELP_STRING([--enable-linux-ip-local-port-range], [Define this to enable use of /proc/sys/net/ipv4/ip_local_port_range as a default outgoing port range. This is only for the libunbound on Linux and does not affect unbound resolving daemon itself. This may severely limit the number of available outgoing ports and thus decrease randomness. Define this only when the target system restricts (e.g. some of SELinux enabled distributions) the use of non-ephemeral ports.])) case "$enable_linux_ip_local_port_range" in yes) AC_DEFINE([USE_LINUX_IP_LOCAL_PORT_RANGE], [1], [Define this to enable use of /proc/sys/net/ipv4/ip_local_port_range as a default outgoing port range. This is only for the libunbound on Linux and does not affect unbound resolving daemon itself. This may severely limit the number of available outgoing ports and thus decrease randomness. Define this only when the target system restricts (e.g. some of SELinux enabled distributions) the use of non-ephemeral ports.]) diff --git a/usr.sbin/unbound/daemon/remote.c b/usr.sbin/unbound/daemon/remote.c index 4990fc8e9..3eb711ce6 100644 --- a/usr.sbin/unbound/daemon/remote.c +++ b/usr.sbin/unbound/daemon/remote.c @@ -523,12 +523,13 @@ ssl_print_text(RES* res, const char* text) if(res->ssl) { ERR_clear_error(); if((r=SSL_write(res->ssl, text, (int)strlen(text))) <= 0) { - if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) { + int r2; + if((r2=SSL_get_error(res->ssl, r)) == SSL_ERROR_ZERO_RETURN) { verbose(VERB_QUERY, "warning, in SSL_write, peer " "closed connection"); return 0; } - log_crypto_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", r2); return 0; } } else { @@ -579,11 +580,12 @@ ssl_read_line(RES* res, char* buf, size_t max) if(res->ssl) { ERR_clear_error(); if((r=SSL_read(res->ssl, buf+len, 1)) <= 0) { - if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) { + int r2; + if((r2=SSL_get_error(res->ssl, r)) == SSL_ERROR_ZERO_RETURN) { buf[len] = 0; return 1; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", r2); return 0; } } else { @@ -596,7 +598,7 @@ ssl_read_line(RES* res, char* buf, size_t max) } if(errno == EINTR || errno == EAGAIN) continue; - log_err("could not recv: %s", + if(rr < 0) log_err("could not recv: %s", sock_strerror(errno)); return 0; } @@ -1223,8 +1225,8 @@ do_zones_add(RES* ssl, struct local_zones* zones) char buf[2048]; int num = 0; while(ssl_read_line(ssl, buf, sizeof(buf))) { - if(buf[0] == 0x04 && buf[1] == 0) - break; /* end of transmission */ + if(buf[0] == 0 || (buf[0] == 0x04 && buf[1] == 0)) + break; /* zero byte line or end of transmission */ if(!perform_zone_add(ssl, zones, buf)) { if(!ssl_printf(ssl, "error for input line: %s\n", buf)) return; @@ -1272,8 +1274,8 @@ do_zones_remove(RES* ssl, struct local_zones* zones) char buf[2048]; int num = 0; while(ssl_read_line(ssl, buf, sizeof(buf))) { - if(buf[0] == 0x04 && buf[1] == 0) - break; /* end of transmission */ + if(buf[0] == 0 || (buf[0] == 0x04 && buf[1] == 0)) + break; /* zero byte line or end of transmission */ if(!perform_zone_remove(ssl, zones, buf)) { if(!ssl_printf(ssl, "error for input line: %s\n", buf)) return; @@ -1336,8 +1338,8 @@ do_datas_add(RES* ssl, struct local_zones* zones) char buf[2048]; int num = 0, line = 0; while(ssl_read_line(ssl, buf, sizeof(buf))) { - if(buf[0] == 0x04 && buf[1] == 0) - break; /* end of transmission */ + if(buf[0] == 0 || (buf[0] == 0x04 && buf[1] == 0)) + break; /* zero byte line or end of transmission */ line++; if(perform_data_add(ssl, zones, buf, line)) num++; @@ -1376,8 +1378,8 @@ do_datas_remove(RES* ssl, struct local_zones* zones) char buf[2048]; int num = 0; while(ssl_read_line(ssl, buf, sizeof(buf))) { - if(buf[0] == 0x04 && buf[1] == 0) - break; /* end of transmission */ + if(buf[0] == 0 || (buf[0] == 0x04 && buf[1] == 0)) + break; /* zero byte line or end of transmission */ if(!perform_data_remove(ssl, zones, buf)) { if(!ssl_printf(ssl, "error for input line: %s\n", buf)) return; @@ -3222,9 +3224,10 @@ handle_req(struct daemon_remote* rc, struct rc_state* s, RES* res) if(res->ssl) { ERR_clear_error(); if((r=SSL_read(res->ssl, magic, (int)sizeof(magic)-1)) <= 0) { - if(SSL_get_error(res->ssl, r) == SSL_ERROR_ZERO_RETURN) + int r2; + if((r2=SSL_get_error(res->ssl, r)) == SSL_ERROR_ZERO_RETURN) return; - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", r2); return; } } else { @@ -3291,7 +3294,7 @@ remote_handshake_later(struct daemon_remote* rc, struct rc_state* s, log_err("remote control connection closed prematurely"); log_addr(VERB_OPS, "failed connection from", &s->c->repinfo.remote_addr, s->c->repinfo.remote_addrlen); - log_crypto_err("remote control failed ssl"); + log_crypto_err_io("remote control failed ssl", r2); clean_point(rc, s); } return 0; diff --git a/usr.sbin/unbound/daemon/worker.c b/usr.sbin/unbound/daemon/worker.c index 8c6fa3b9a..8ae05eb67 100644 --- a/usr.sbin/unbound/daemon/worker.c +++ b/usr.sbin/unbound/daemon/worker.c @@ -66,6 +66,7 @@ #include "util/data/msgencode.h" #include "util/data/dname.h" #include "util/fptr_wlist.h" +#include "util/proxy_protocol.h" #include "util/tube.h" #include "util/edns.h" #include "util/timeval_func.h" @@ -542,6 +543,8 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; + if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO)) + edns->edns_present = 0; if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, msg->rep, (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad, worker->env.now_tv)) @@ -702,6 +705,8 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; + if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO)) + edns->edns_present = 0; if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, worker->env.now_tv)) @@ -742,6 +747,8 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; + if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO)) + edns->edns_present = 0; *alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */ if((worker->daemon->use_response_ip || worker->daemon->use_rpz) && !partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep, @@ -2317,6 +2324,7 @@ worker_init(struct worker* worker, struct config_file *cfg, worker->env.cfg->stat_interval); worker_restart_timer(worker); } + pp_init(&sldns_write_uint16, &sldns_write_uint32); return 1; } diff --git a/usr.sbin/unbound/dns64/dns64.c b/usr.sbin/unbound/dns64/dns64.c index f74bfef2e..dcd7017bb 100644 --- a/usr.sbin/unbound/dns64/dns64.c +++ b/usr.sbin/unbound/dns64/dns64.c @@ -573,28 +573,29 @@ static enum module_ext_state handle_event_pass(struct module_qstate* qstate, int id) { struct dns64_qstate* iq = (struct dns64_qstate*)qstate->minfo[id]; - if (iq && iq->state == DNS64_NEW_QUERY - && qstate->qinfo.qtype == LDNS_RR_TYPE_PTR - && qstate->qinfo.qname_len == 74 - && !strcmp((char*)&qstate->qinfo.qname[64], "\03ip6\04arpa")) - /* Handle PTR queries for IPv6 addresses. */ - return handle_ipv6_ptr(qstate, id); + int synth_all_cfg = qstate->env->cfg->dns64_synthall; + int synth_qname = 0; - if (qstate->env->cfg->dns64_synthall && - iq && iq->state == DNS64_NEW_QUERY - && qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA) - return generate_type_A_query(qstate, id); + if(iq && iq->state == DNS64_NEW_QUERY + && qstate->qinfo.qtype == LDNS_RR_TYPE_PTR + && qstate->qinfo.qname_len == 74 + && !strcmp((char*)&qstate->qinfo.qname[64], "\03ip6\04arpa")) { + /* Handle PTR queries for IPv6 addresses. */ + return handle_ipv6_ptr(qstate, id); + } - if(dns64_always_synth_for_qname(qstate, id) && - iq && iq->state == DNS64_NEW_QUERY - && !(qstate->query_flags & BIT_CD) - && qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA) { - verbose(VERB_ALGO, "dns64: ignore-aaaa and synthesize anyway"); + if(iq && iq->state == DNS64_NEW_QUERY && + qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA && + (synth_all_cfg || + (synth_qname=(dns64_always_synth_for_qname(qstate, id) + && !(qstate->query_flags & BIT_CD))))) { + if(synth_qname) + verbose(VERB_ALGO, "dns64: ignore-aaaa and synthesize anyway"); return generate_type_A_query(qstate, id); } /* We are finished when our sub-query is finished. */ - if (iq && iq->state == DNS64_SUBQUERY_FINISHED) + if(iq && iq->state == DNS64_SUBQUERY_FINISHED) return module_finished; /* Otherwise, pass request to next module. */ @@ -627,32 +628,37 @@ handle_event_moddone(struct module_qstate* qstate, int id) * synthesize in (sec 5.1.2 of RFC6147). * - A successful AAAA query with an answer. */ - if((!iq || iq->state != DNS64_INTERNAL_QUERY) - && qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA - && !(qstate->query_flags & BIT_CD) - && !(qstate->return_msg && - qstate->return_msg->rep && - reply_find_answer_rrset(&qstate->qinfo, - qstate->return_msg->rep))) - /* not internal, type AAAA, not CD, and no answer RRset, - * So, this is a AAAA noerror/nodata answer */ - return generate_type_A_query(qstate, id); - if((!iq || iq->state != DNS64_INTERNAL_QUERY) - && qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA - && !(qstate->query_flags & BIT_CD) - && dns64_always_synth_for_qname(qstate, id)) { - /* if it is not internal, AAAA, not CD and listed domain, - * generate from A record and ignore AAAA */ - verbose(VERB_ALGO, "dns64: ignore-aaaa and synthesize anyway"); + /* When an AAAA query completes check if we want to perform DNS64 + * synthesis. We skip queries with DNSSEC enabled (!CD) and + * ones generated by us to retrive the A/PTR record to use for + * synth. */ + int could_synth = + qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA && + (!iq || iq->state != DNS64_INTERNAL_QUERY) && + !(qstate->query_flags & BIT_CD); + int has_data = /* whether query returned non-empty rrset */ + qstate->return_msg && + qstate->return_msg->rep && + reply_find_answer_rrset(&qstate->qinfo, qstate->return_msg->rep); + int synth_qname = 0; + + if(could_synth && + (!has_data || + (synth_qname=dns64_always_synth_for_qname(qstate, id)))) { + if(synth_qname) + verbose(VERB_ALGO, "dns64: ignore-aaaa and synthesize anyway"); return generate_type_A_query(qstate, id); } /* Store the response in cache. */ - if ( (!iq || !iq->started_no_cache_store) && - qstate->return_msg && qstate->return_msg->rep && - !dns_cache_store(qstate->env, &qstate->qinfo, qstate->return_msg->rep, - 0, 0, 0, NULL, qstate->query_flags, qstate->qstarttime)) + if( (!iq || !iq->started_no_cache_store) && + qstate->return_msg && + qstate->return_msg->rep && + !dns_cache_store( + qstate->env, &qstate->qinfo, qstate->return_msg->rep, + 0, 0, 0, NULL, + qstate->query_flags, qstate->qstarttime)) log_err("out of memory"); /* do nothing */ @@ -969,10 +975,19 @@ dns64_inform_super(struct module_qstate* qstate, int id, } super_dq->state = DNS64_SUBQUERY_FINISHED; - /* If there is no successful answer, we're done. */ - if (qstate->return_rcode != LDNS_RCODE_NOERROR - || !qstate->return_msg - || !qstate->return_msg->rep) { + /* If there is no successful answer, we're done. + * Guarantee that we have at least a NOERROR reply further on. */ + if(qstate->return_rcode != LDNS_RCODE_NOERROR + || !qstate->return_msg + || !qstate->return_msg->rep) { + return; + } + + /* When no A record is found for synthesis fall back to AAAA again. */ + if(qstate->qinfo.qtype == LDNS_RR_TYPE_A && + !reply_find_answer_rrset(&qstate->qinfo, + qstate->return_msg->rep)) { + super_dq->state = DNS64_INTERNAL_QUERY; return; } diff --git a/usr.sbin/unbound/dnstap/dnstap.m4 b/usr.sbin/unbound/dnstap/dnstap.m4 index 1ff6c3fea..be8b40c45 100644 --- a/usr.sbin/unbound/dnstap/dnstap.m4 +++ b/usr.sbin/unbound/dnstap/dnstap.m4 @@ -41,7 +41,7 @@ AC_DEFUN([dt_DNSTAP], fi ]) AC_SEARCH_LIBS([protobuf_c_message_pack], [protobuf-c], [], - AC_MSG_ERROR([The protobuf-c library was not found. Please install protobuf-c!])) + AC_MSG_ERROR([The protobuf-c library was not found. Please install the development libraries for protobuf-c!])) $2 else $3 diff --git a/usr.sbin/unbound/dnstap/dtstream.c b/usr.sbin/unbound/dnstap/dtstream.c index 907c871c9..6ab10ecb2 100644 --- a/usr.sbin/unbound/dnstap/dtstream.c +++ b/usr.sbin/unbound/dnstap/dtstream.c @@ -788,7 +788,7 @@ static int dtio_write_ssl(struct dt_io_thread* dtio, uint8_t* buf, } return -1; } - log_crypto_err("dnstap io, could not SSL_write"); + log_crypto_err_io("dnstap io, could not SSL_write", want); return -1; } return r; @@ -1029,7 +1029,7 @@ static int ssl_read_bytes(struct dt_io_thread* dtio, void* buf, size_t len) "other side"); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); verbose(VERB_DETAIL, "dnstap io: output closed by the " "other side"); return 0; @@ -1431,8 +1431,8 @@ static int dtio_ssl_handshake(struct dt_io_thread* dtio, } else { unsigned long err = ERR_get_error(); if(!squelch_err_ssl_handshake(err)) { - log_crypto_err_code("dnstap io, ssl handshake failed", - err); + log_crypto_err_io_code("dnstap io, ssl handshake failed", + want, err); verbose(VERB_OPS, "dnstap io, ssl handshake failed " "from %s", dtio->ip_str); } diff --git a/usr.sbin/unbound/dnstap/unbound-dnstap-socket.c b/usr.sbin/unbound/dnstap/unbound-dnstap-socket.c index 525b8cb3f..4e426791f 100644 --- a/usr.sbin/unbound/dnstap/unbound-dnstap-socket.c +++ b/usr.sbin/unbound/dnstap/unbound-dnstap-socket.c @@ -708,7 +708,7 @@ static ssize_t ssl_read_bytes(struct tap_data* data, void* buf, size_t len) (data->id?data->id:"")); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); if(verbosity) log_info("dnstap client stream closed from %s", (data->id?data->id:"")); return 0; @@ -760,10 +760,11 @@ static int reply_with_accept(struct tap_data* data) fd_set_block(data->fd); if(data->ssl) { if((r=SSL_write(data->ssl, acceptframe, len)) <= 0) { - if(SSL_get_error(data->ssl, r) == SSL_ERROR_ZERO_RETURN) + int r2; + if((r2=SSL_get_error(data->ssl, r)) == SSL_ERROR_ZERO_RETURN) log_err("SSL_write, peer closed connection"); else - log_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", r2); fd_set_nonblock(data->fd); free(acceptframe); return 0; @@ -805,10 +806,11 @@ static int reply_with_finish(struct tap_data* data) if(data->ssl) { int r; if((r=SSL_write(data->ssl, finishframe, len)) <= 0) { - if(SSL_get_error(data->ssl, r) == SSL_ERROR_ZERO_RETURN) + int r2; + if((r2=SSL_get_error(data->ssl, r)) == SSL_ERROR_ZERO_RETURN) log_err("SSL_write, peer closed connection"); else - log_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", r2); fd_set_nonblock(data->fd); free(finishframe); return 0; diff --git a/usr.sbin/unbound/doc/Changelog b/usr.sbin/unbound/doc/Changelog index c495795be..8205fbe85 100644 --- a/usr.sbin/unbound/doc/Changelog +++ b/usr.sbin/unbound/doc/Changelog @@ -1,13 +1,158 @@ +2 November 2023: Wouter + - Set version number to 1.19.0. + - Tag for 1.19.0rc1 release. + +1 November 2023: George + - Mention flex and bison in README.md when building from repository + source. + +1 November 2023: Wouter + - Fix SSL compile failure for definition in log_crypto_err_io_code_arg. + - Fix SSL compile failure for other missing definitions in + log_crypto_err_io_code_arg. + - Fix compilation without openssl, remove unused function warning. + +31 October 2023: George + - Fix #941: dnscrypt doesn't work after upgrade to 1.18 with + suggestion by dukeartem to also fix the udp_ancil with dnscrypt. + +30 October 2023: George + - Merge #930 from Stuart Henderson: add void to + log_ident_revert_to_default declaration. + +30 October 2023: Wouter + - autoconf. + +24 October 2023: George + - Clearer configure text for missing protobuf-c development libraries. + +20 October 2023: Wouter + - Merge #951: Cachedb no store. The cachedb-no-store: yes option is + used to stop cachedb from writing messages to the backend storage. + It reads messages when data is available from the backend. The + default is no. + +19 October 2023: Wouter + - Fix to print detailed errors when an SSL IO routine fails via + SSL_get_error. + +18 October 2023: George + - Mailing list patches from Daniel Gröber for DNS64 fallback to plain + AAAA when no A record exists for synthesis, and minor DNS64 code + refactoring for better readability. + - Fixes for the DNS64 patches. + - Update the dns64_lookup.rpl test for the DNS64 fallback patch. + - Merge #955 from buevsan: fix ipset wrong behavior. + - Update testdata/ipset.tdir test for ipset fix. + +17 October 2023: Wouter + - Fix #954: Inconsistent RPZ handling for A record returned along with + CNAME. + +16 October 2023: George + - Expose the script filename in the Python module environment 'mod_env' + instead of the config_file structure which includes the linked list + of scripts in a multi Python module setup; fixes #79. + - Expose the configured listening and outgoing interfaces, if any, as + a list of strings in the Python 'config_file' class instead of the + current Swig object proxy; fixes #79. + - For multi Python module setups, clean previously parsed module + functions in __main__'s dictionary, if any, so that only current + module functions are registered. + +13 October 2023: George + - Better fix for infinite loop when reading multiple lines of input on + a broken remote control socket, by treating a zero byte line the + same as transmission end. Addesses #947 and #948. + +12 October 2023: Wouter + - Merge #944: Disable EDNS DO. + Disable the EDNS DO flag in upstream requests. This can be helpful + for devices that cannot handle DNSSEC information. But it should not + be enabled otherwise, because that would stop DNSSEC validation. The + DNSSEC validation would not work for Unbound itself, and also not + for downstream users. Default is no. The option + is disable-edns-do: no + +11 October 2023: George + - Fix #850: [FR] Ability to use specific database in Redis, with new + redis-logical-db configuration option. + +11 October 2023: Wouter + - Fix #949: "could not create control compt". + - Fix that cachedb does not warn when serve-expired is disabled about + use of serve-expired-reply-ttl and serve-expired-client-timeout. + - Fix for #949: Fix pythonmod/ubmodule-tst.py for Python 3.x. + +10 October 2023: George + - Fix infinite loop when reading multiple lines of input on a broken + remote control socket. Addesses #947 and #948. + +9 October 2023: Wouter + - Fix edns subnet so that queries with a source prefix of zero cause + the recursor send no edns subnet option to the upstream. + - Fix that printout of EDNS options shows the EDNS cookie option by + name. + +4 October 2023: Wouter + - Fix #946: Forwarder returns servfail on upstream response noerror no + data. + +3 October 2023: George + - Merge #881: Generalise the proxy protocol code. + +2 October 2023: George + - Fix misplaced comment. + +22 September 2023: Wouter + - Fix #942: 1.18.0 libunbound DNS regression when built without + OpenSSL. + +18 September 2023: Wouter + - Fix rpz tcp-only action with rpz triggers nsdname and nsip. + +15 September 2023: Wouter + - Merge #936: Check for c99 with autoconf versions prior to 2.70. + - Fix to remove two c99 notations. + +14 September 2023: Wouter + - Fix authority zone answers for obscured DNAMEs and delegations. + 8 September 2023: Wouter - Fix send of udp retries when ENOBUFS is returned. It stops looping and also waits for the condition to go away. Reported by Florian Obser. +7 September 2023: Wouter + - Fix to scrub resource records of type A and AAAA that have an + inappropriate size. They are removed from responses. + - Fix to move msgparse_rrset_remove_rr code to util/msgparse.c. + - Fix to add EDE text when RRs have been removed due to length. + - Fix to set ede match in unit test for rr length removal. + - Fix to print EDE text in readable form in output logs. + +6 September 2023: Wouter + - Merge #931: Prevent warnings from -Wmissing-prototypes. + +31 August 2023: Wouter + - Fix autoconf 2.69 warnings in configure. + - Fix #927: unbound 1.18.0 make test error. Fix make test without SHA1. + +30 August 2023: Wouter + - Fix for WKS call to getservbyname that creates allocation on exit + in unit test by testing numbers first and testing from the services + list later. + +28 August 2023: Wouter + - Fix for version generation race condition that ignored changes. + 25 August 2023: Wouter - Fix compile error on NetBSD in util/netevent.h. 23 August 2023: Wouter - - Tag for 1.18.0rc1 release. + - Tag for 1.18.0rc1 release. This became the 1.18.0 release on + 30 aug 2023, with the fix from 25 aug, fix compile on NetBSD + included. The repository continues with version 1.18.1. 22 August 2023: Wouter - Set version number to 1.18.0. @@ -4754,7 +4899,7 @@ - Fix that with openssl 1.1 control-use-cert: no uses less cpu, by using no encryption over the unix socket. -22 Novenber 2016: Ralph +22 November 2016: Ralph - Make access-control-tag-data RDATA absolute. This makes the RDATA origin consistent between local-data and access-control-tag-data. - Fix NSEC ENT wildcard check. Matching wildcard does not have to be a diff --git a/usr.sbin/unbound/doc/README b/usr.sbin/unbound/doc/README index 7c443c5af..6af1d0143 100644 --- a/usr.sbin/unbound/doc/README +++ b/usr.sbin/unbound/doc/README @@ -1,4 +1,4 @@ -README for Unbound 1.18.0 +README for Unbound 1.19.2 Copyright 2007 NLnet Labs http://unbound.net diff --git a/usr.sbin/unbound/doc/example.conf.in b/usr.sbin/unbound/doc/example.conf.in index b7195360c..2bf460b8d 100644 --- a/usr.sbin/unbound/doc/example.conf.in +++ b/usr.sbin/unbound/doc/example.conf.in @@ -1,7 +1,7 @@ # # Example configuration file. # -# See unbound.conf(5) man page, version 1.18.0. +# See unbound.conf(5) man page, version 1.19.2. # # this is a comment. @@ -683,6 +683,11 @@ server: # that set CD but cannot validate themselves. # ignore-cd-flag: no + # Disable the DO flag in outgoing requests. It is helpful for upstream + # devices that cannot handle DNSSEC information. But do not enable it + # otherwise, because it would stop DNSSEC validation. + # disable-edns-do: no + # Serve expired responses from cache, with serve-expired-reply-ttl in # the response, and then attempt to fetch the data afresh. # serve-expired: no @@ -1221,6 +1226,8 @@ remote-control: # backend: "testframe" # # secret seed string to calculate hashed keys # secret-seed: "default" +# # if the backend should be read from, but not written to. +# cachedb-no-store: no # # # For "redis" backend: # # (to enable, use --with-libhiredis to configure before compiling) @@ -1236,6 +1243,8 @@ remote-control: # redis-timeout: 100 # # set timeout on redis records based on DNS response TTL # redis-expire-records: no +# # redis logical database to use, 0 is the default database. +# redis-logical-db: 0 # IPSet # Add specify domain into set via ipset. diff --git a/usr.sbin/unbound/doc/libunbound.3.in b/usr.sbin/unbound/doc/libunbound.3.in index 315d02dca..841c4ebc6 100644 --- a/usr.sbin/unbound/doc/libunbound.3.in +++ b/usr.sbin/unbound/doc/libunbound.3.in @@ -1,4 +1,4 @@ -.TH "libunbound" "3" "Aug 30, 2023" "NLnet Labs" "unbound 1.18.0" +.TH "libunbound" "3" "Mar 7, 2024" "NLnet Labs" "unbound 1.19.2" .\" .\" libunbound.3 -- unbound library functions manual .\" @@ -44,7 +44,7 @@ .B ub_ctx_zone_remove, .B ub_ctx_data_add, .B ub_ctx_data_remove -\- Unbound DNS validating resolver 1.18.0 functions. +\- Unbound DNS validating resolver 1.19.2 functions. .SH "SYNOPSIS" .B #include .LP diff --git a/usr.sbin/unbound/doc/unbound-anchor.8.in b/usr.sbin/unbound/doc/unbound-anchor.8.in index 4e862fc89..978208e9f 100644 --- a/usr.sbin/unbound/doc/unbound-anchor.8.in +++ b/usr.sbin/unbound/doc/unbound-anchor.8.in @@ -1,4 +1,4 @@ -.TH "unbound-anchor" "8" "Aug 30, 2023" "NLnet Labs" "unbound 1.18.0" +.TH "unbound-anchor" "8" "Mar 7, 2024" "NLnet Labs" "unbound 1.19.2" .\" .\" unbound-anchor.8 -- unbound anchor maintenance utility manual .\" diff --git a/usr.sbin/unbound/doc/unbound-checkconf.8.in b/usr.sbin/unbound/doc/unbound-checkconf.8.in index 6a2c2cc94..2d7f58387 100644 --- a/usr.sbin/unbound/doc/unbound-checkconf.8.in +++ b/usr.sbin/unbound/doc/unbound-checkconf.8.in @@ -1,4 +1,4 @@ -.TH "unbound-checkconf" "8" "Aug 30, 2023" "NLnet Labs" "unbound 1.18.0" +.TH "unbound-checkconf" "8" "Mar 7, 2024" "NLnet Labs" "unbound 1.19.2" .\" .\" unbound-checkconf.8 -- unbound configuration checker manual .\" diff --git a/usr.sbin/unbound/doc/unbound-control.8.in b/usr.sbin/unbound/doc/unbound-control.8.in index db4eb7230..5588d2231 100644 --- a/usr.sbin/unbound/doc/unbound-control.8.in +++ b/usr.sbin/unbound/doc/unbound-control.8.in @@ -1,4 +1,4 @@ -.TH "unbound-control" "8" "Aug 30, 2023" "NLnet Labs" "unbound 1.18.0" +.TH "unbound-control" "8" "Mar 7, 2024" "NLnet Labs" "unbound 1.19.2" .\" .\" unbound-control.8 -- unbound remote control manual .\" diff --git a/usr.sbin/unbound/doc/unbound-host.1.in b/usr.sbin/unbound/doc/unbound-host.1.in index e4fe718ab..2bb881d18 100644 --- a/usr.sbin/unbound/doc/unbound-host.1.in +++ b/usr.sbin/unbound/doc/unbound-host.1.in @@ -1,4 +1,4 @@ -.TH "unbound\-host" "1" "Aug 30, 2023" "NLnet Labs" "unbound 1.18.0" +.TH "unbound\-host" "1" "Mar 7, 2024" "NLnet Labs" "unbound 1.19.2" .\" .\" unbound-host.1 -- unbound DNS lookup utility .\" diff --git a/usr.sbin/unbound/doc/unbound.8.in b/usr.sbin/unbound/doc/unbound.8.in index 7b955a92e..c9babdb57 100644 --- a/usr.sbin/unbound/doc/unbound.8.in +++ b/usr.sbin/unbound/doc/unbound.8.in @@ -1,4 +1,4 @@ -.TH "unbound" "8" "Aug 30, 2023" "NLnet Labs" "unbound 1.18.0" +.TH "unbound" "8" "Mar 7, 2024" "NLnet Labs" "unbound 1.19.2" .\" .\" unbound.8 -- unbound manual .\" @@ -9,7 +9,7 @@ .\" .SH "NAME" .B unbound -\- Unbound DNS validating resolver 1.18.0. +\- Unbound DNS validating resolver 1.19.2. .SH "SYNOPSIS" .B unbound .RB [ \-h ] diff --git a/usr.sbin/unbound/doc/unbound.conf.5.in b/usr.sbin/unbound/doc/unbound.conf.5.in index 07ee83906..a1bb1a4a5 100644 --- a/usr.sbin/unbound/doc/unbound.conf.5.in +++ b/usr.sbin/unbound/doc/unbound.conf.5.in @@ -1,4 +1,4 @@ -.TH "unbound.conf" "5" "Aug 30, 2023" "NLnet Labs" "unbound 1.18.0" +.TH "unbound.conf" "5" "Mar 7, 2024" "NLnet Labs" "unbound 1.19.2" .\" .\" unbound.conf.5 -- unbound.conf manual .\" @@ -1257,6 +1257,20 @@ servers that set the CD flag but cannot validate DNSSEC themselves are the clients, and then Unbound provides them with DNSSEC protection. The default value is "no". .TP +.B disable\-edns\-do: \fI +Disable the EDNS DO flag in upstream requests. +It breaks DNSSEC validation for Unbound's clients. +This results in the upstream name servers to not include DNSSEC records in +their replies and could be helpful for devices that cannot handle DNSSEC +information. +When the option is enabled, clients that set the DO flag receive no EDNS +record in the response to indicate the lack of support to them. +If this option is enabled but Unbound is already configured for DNSSEC +validation (i.e., the validator module is enabled; default) this option is +implicitly turned off with a warning as to not break DNSSEC validation in +Unbound. +Default is no. +.TP .B serve\-expired: \fI If enabled, Unbound attempts to serve old responses from cache with a TTL of \fBserve\-expired\-reply\-ttl\fR in the response without waiting for the @@ -2622,6 +2636,11 @@ operationally. If the backend database is shared by multiple Unbound instances, all instances must use the same secret seed. This option defaults to "default". +.TP +.B cachedb-no-store: \fI\fR +If the backend should be read from, but not written to. This makes this +instance not store dns messages in the backend. But if data is available it +is retrieved. The default is no. .P The following .B cachedb @@ -2662,6 +2681,17 @@ Unbound is configured with \fBserve-expired\fR and \fBserve-expired-ttl\fR is 0, this option is internally reverted to "no". Redis SETEX support is required for this option (Redis >= 2.0.0). This option defaults to no. +.TP +.B redis-logical-db: \fI +The logical database in Redis to use. +These are databases in the same Redis instance sharing the same configuration +and persisted in the same RDB/AOF file. +If unsure about using this option, Redis documentation +(https://redis.io/commands/select/) suggests not to use a single Redis instance +for multiple unrelated applications. +The default database in Redis is 0 while other logical databases need to be +explicitly SELECT'ed upon connecting. +This option defaults to 0. .SS DNSTAP Logging Options DNSTAP support, when compiled in by using \fB\-\-enable\-dnstap\fR, is enabled in the \fBdnstap:\fR section. diff --git a/usr.sbin/unbound/dynlibmod/dynlibmod.c b/usr.sbin/unbound/dynlibmod/dynlibmod.c index ffac7ff30..1e040a30e 100644 --- a/usr.sbin/unbound/dynlibmod/dynlibmod.c +++ b/usr.sbin/unbound/dynlibmod/dynlibmod.c @@ -75,6 +75,7 @@ int dynlibmod_init(struct module_env* env, int id) { struct config_strlist* cfg_item = env->cfg->dynlib_file; struct dynlibmod_env* de = (struct dynlibmod_env*)calloc(1, sizeof(struct dynlibmod_env)); __DYNMOD dynamic_library; + int i; if (!de) { log_err("dynlibmod[%d]: malloc failure", dynlib_mod_idx); @@ -84,7 +85,7 @@ int dynlibmod_init(struct module_env* env, int id) { env->modinfo[id] = (void*) de; de->fname = NULL; - for(int i = dynlib_mod_idx; + for(i = dynlib_mod_idx; i != 0 && cfg_item != NULL; i--, cfg_item = cfg_item->next) {} diff --git a/usr.sbin/unbound/edns-subnet/subnetmod.c b/usr.sbin/unbound/edns-subnet/subnetmod.c index ec0ff78b7..be24cef2b 100644 --- a/usr.sbin/unbound/edns-subnet/subnetmod.c +++ b/usr.sbin/unbound/edns-subnet/subnetmod.c @@ -156,6 +156,7 @@ int ecs_whitelist_check(struct query_info* qinfo, qstate->no_cache_store = 0; } + sq->subnet_sent_no_subnet = 0; if(sq->ecs_server_out.subnet_validdata && ((sq->subnet_downstream && qstate->env->cfg->client_subnet_always_forward) || ecs_is_whitelisted(sn_env->whitelist, @@ -166,6 +167,14 @@ int ecs_whitelist_check(struct query_info* qinfo, * set. */ if(!edns_opt_list_find(qstate->edns_opts_back_out, qstate->env->cfg->client_subnet_opcode)) { + /* if the client is not wanting an EDNS subnet option, + * omit it and store that we omitted it but actually + * are doing EDNS subnet to the server. */ + if(sq->ecs_server_out.subnet_source_mask == 0) { + sq->subnet_sent_no_subnet = 1; + sq->subnet_sent = 0; + return 1; + } subnet_ecs_opt_list_append(&sq->ecs_server_out, &qstate->edns_opts_back_out, qstate, region); } @@ -515,7 +524,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) } /* We have not asked for subnet data */ - if (!sq->subnet_sent) { + if (!sq->subnet_sent && !sq->subnet_sent_no_subnet) { if (s_in->subnet_validdata) verbose(VERB_QUERY, "subnetcache: received spurious data"); if (sq->subnet_downstream) /* Copy back to client */ @@ -524,7 +533,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) } /* subnet sent but nothing came back */ - if (!s_in->subnet_validdata) { + if (!s_in->subnet_validdata && !sq->subnet_sent_no_subnet) { /* The authority indicated no support for edns subnet. As a * consequence the answer ended up in the regular cache. It * is still useful to put it in the edns subnet cache for @@ -540,6 +549,18 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) return module_finished; } + /* Purposefully there was no sent subnet, and there is consequently + * no subnet in the answer. If there was, use the subnet in the answer + * anyway. But if there is not, treat it as a prefix 0 answer. */ + if(sq->subnet_sent_no_subnet && !s_in->subnet_validdata) { + /* Fill in 0.0.0.0/0 scope 0, or ::0/0 scope 0, for caching. */ + s_in->subnet_addr_fam = s_out->subnet_addr_fam; + s_in->subnet_source_mask = 0; + s_in->subnet_scope_mask = 0; + memset(s_in->subnet_addr, 0, INET6_SIZE); + s_in->subnet_validdata = 1; + } + /* Being here means we have asked for and got a subnet specific * answer. Also, the answer from the authority is not yet cached * anywhere. */ @@ -556,6 +577,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq) (void)edns_opt_list_remove(&qstate->edns_opts_back_out, qstate->env->cfg->client_subnet_opcode); sq->subnet_sent = 0; + sq->subnet_sent_no_subnet = 0; return module_restart_next; } @@ -676,6 +698,7 @@ ecs_query_response(struct module_qstate* qstate, struct dns_msg* response, edns_opt_list_remove(&qstate->edns_opts_back_out, qstate->env->cfg->client_subnet_opcode); sq->subnet_sent = 0; + sq->subnet_sent_no_subnet = 0; memset(&sq->ecs_server_out, 0, sizeof(sq->ecs_server_out)); } else if (!sq->track_max_scope && FLAGS_GET_RCODE(response->rep->flags) == LDNS_RCODE_NOERROR && @@ -737,6 +760,9 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id, sq->ecs_server_in.subnet_scope_mask > sq->max_scope)) sq->max_scope = sq->ecs_server_in.subnet_scope_mask; + } else if(sq->subnet_sent_no_subnet) { + /* The answer can be stored as scope 0, not in global cache. */ + qstate->no_cache_store = 1; } return 1; diff --git a/usr.sbin/unbound/edns-subnet/subnetmod.h b/usr.sbin/unbound/edns-subnet/subnetmod.h index e035be272..fad8b4eb7 100644 --- a/usr.sbin/unbound/edns-subnet/subnetmod.h +++ b/usr.sbin/unbound/edns-subnet/subnetmod.h @@ -85,6 +85,13 @@ struct subnet_qstate { struct ecs_data ecs_server_out; int subnet_downstream; int subnet_sent; + /** + * If there was no subnet sent because the client used source prefix + * length 0 for omitting the information. Then the answer is cached + * like subnet was a /0 scope. Like the subnet_sent flag, but when + * the EDNS subnet option is omitted because the client asked. + */ + int subnet_sent_no_subnet; /** keep track of longest received scope, set after receiving CNAME for * incoming QNAME. */ int track_max_scope; diff --git a/usr.sbin/unbound/ipset/ipset.c b/usr.sbin/unbound/ipset/ipset.c index fb7cca537..b372503c8 100644 --- a/usr.sbin/unbound/ipset/ipset.c +++ b/usr.sbin/unbound/ipset/ipset.c @@ -158,10 +158,10 @@ ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie, qs = NULL; plen = strlen(p->str); - if (dlen >= plen) { + if (dlen == plen || (dlen > plen && dname[dlen - plen - 1] == '.' )) { ds = dname + (dlen - plen); } - if (qlen >= plen) { + if (qlen == plen || (qlen > plen && qname[qlen - plen - 1] == '.' )) { qs = qname + (qlen - plen); } if ((ds && strncasecmp(p->str, ds, plen) == 0) diff --git a/usr.sbin/unbound/iterator/iter_priv.c b/usr.sbin/unbound/iterator/iter_priv.c index 038bc5d87..964014f51 100644 --- a/usr.sbin/unbound/iterator/iter_priv.c +++ b/usr.sbin/unbound/iterator/iter_priv.c @@ -207,28 +207,6 @@ size_t priv_get_mem(struct iter_priv* priv) return sizeof(*priv) + regional_get_mem(priv->region); } -/** remove RR from msgparse RRset, return true if rrset is entirely bad */ -static int -remove_rr(const char* str, sldns_buffer* pkt, struct rrset_parse* rrset, - struct rr_parse* prev, struct rr_parse** rr, struct sockaddr_storage* addr, socklen_t addrlen) -{ - if(verbosity >= VERB_QUERY && rrset->dname_len <= LDNS_MAX_DOMAINLEN && str) { - uint8_t buf[LDNS_MAX_DOMAINLEN+1]; - dname_pkt_copy(pkt, buf, rrset->dname); - log_name_addr(VERB_QUERY, str, buf, addr, addrlen); - } - if(prev) - prev->next = (*rr)->next; - else rrset->rr_first = (*rr)->next; - if(rrset->rr_last == *rr) - rrset->rr_last = prev; - rrset->rr_count --; - rrset->size -= (*rr)->size; - /* rr struct still exists, but is unlinked, so that in the for loop - * the rr->next works fine to continue. */ - return rrset->rr_count == 0; -} - int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt, struct rrset_parse* rrset) { @@ -261,7 +239,7 @@ int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt, INET_SIZE); memmove(&addr, &sa, len); if(priv_lookup_addr(priv, &addr, len)) { - if(remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, &rr, &addr, len)) + if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len)) return 1; continue; } @@ -284,7 +262,7 @@ int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt, INET6_SIZE); memmove(&addr, &sa, len); if(priv_lookup_addr(priv, &addr, len)) { - if(remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, &rr, &addr, len)) + if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, len)) return 1; continue; } diff --git a/usr.sbin/unbound/iterator/iter_resptype.c b/usr.sbin/unbound/iterator/iter_resptype.c index e284987e0..72806d459 100644 --- a/usr.sbin/unbound/iterator/iter_resptype.c +++ b/usr.sbin/unbound/iterator/iter_resptype.c @@ -42,6 +42,7 @@ #include "config.h" #include "iterator/iter_resptype.h" #include "iterator/iter_delegpt.h" +#include "iterator/iterator.h" #include "services/cache/dns.h" #include "util/net_help.h" #include "util/data/dname.h" @@ -105,7 +106,8 @@ response_type_from_cache(struct dns_msg* msg, enum response_type response_type_from_server(int rdset, - struct dns_msg* msg, struct query_info* request, struct delegpt* dp) + struct dns_msg* msg, struct query_info* request, struct delegpt* dp, + int* empty_nodata_found) { uint8_t* origzone = (uint8_t*)"\000"; /* the default */ struct ub_packed_rrset_key* s; @@ -284,13 +286,22 @@ response_type_from_server(int rdset, /* If we've gotten this far, this is NOERROR/NODATA (which could * be an entirely empty message) */ - /* but ignore entirely empty messages, noerror/nodata has a soa - * negative ttl value in the authority section, this makes it try - * again at another authority. And turns it from a 5 second empty - * message into a 5 second servfail response. */ + /* For entirely empty messages, try again, at first, then accept + * it it happens more. A regular noerror/nodata response has a soa + * negative ttl value in the authority section. This makes it try + * again at another authority. And decides between storing a 5 second + * empty message or a 5 second servfail response. */ if(msg->rep->an_numrrsets == 0 && msg->rep->ns_numrrsets == 0 && - msg->rep->ar_numrrsets == 0) - return RESPONSE_TYPE_THROWAWAY; + msg->rep->ar_numrrsets == 0) { + if(empty_nodata_found) { + /* detect as throwaway at first, but accept later. */ + (*empty_nodata_found)++; + if(*empty_nodata_found < EMPTY_NODATA_RETRY_COUNT) + return RESPONSE_TYPE_THROWAWAY; + return RESPONSE_TYPE_ANSWER; + } + return RESPONSE_TYPE_ANSWER; + } /* check if recursive answer; saying it has empty cache */ if( (msg->rep->flags&BIT_RA) && !(msg->rep->flags&BIT_AA) && !rdset) return RESPONSE_TYPE_REC_LAME; diff --git a/usr.sbin/unbound/iterator/iter_resptype.h b/usr.sbin/unbound/iterator/iter_resptype.h index d253c0195..e345ac635 100644 --- a/usr.sbin/unbound/iterator/iter_resptype.h +++ b/usr.sbin/unbound/iterator/iter_resptype.h @@ -119,9 +119,11 @@ enum response_type response_type_from_cache(struct dns_msg* msg, * @param request: the request that generated the response. * @param dp: The delegation point that was being queried * when the response was returned. + * @param empty_nodata_found: flag to keep track of empty nodata detection. * @return the response type (CNAME or ANSWER). */ enum response_type response_type_from_server(int rdset, - struct dns_msg* msg, struct query_info* request, struct delegpt* dp); + struct dns_msg* msg, struct query_info* request, struct delegpt* dp, + int* empty_nodata_found); #endif /* ITERATOR_ITER_RESPTYPE_H */ diff --git a/usr.sbin/unbound/iterator/iter_scrub.c b/usr.sbin/unbound/iterator/iter_scrub.c index 8d8aa8a4f..685935bc6 100644 --- a/usr.sbin/unbound/iterator/iter_scrub.c +++ b/usr.sbin/unbound/iterator/iter_scrub.c @@ -716,6 +716,56 @@ static int sanitize_nsec_is_overreach(sldns_buffer* pkt, return 0; } +/** Remove individual RRs, if the length is wrong. Returns true if the RRset + * has been removed. */ +static int +scrub_sanitize_rr_length(sldns_buffer* pkt, struct msg_parse* msg, + struct rrset_parse* prev, struct rrset_parse** rrset, int* added_ede, + struct module_qstate* qstate) +{ + struct rr_parse* rr, *rr_prev = NULL; + for(rr = (*rrset)->rr_first; rr; rr = rr->next) { + + /* Sanity check for length of records + * An A record should be 6 bytes only + * (2 bytes for length and 4 for IPv4 addr)*/ + if((*rrset)->type == LDNS_RR_TYPE_A && rr->size != 6 ) { + if(!*added_ede) { + *added_ede = 1; + errinf_ede(qstate, "sanitize: records of inappropriate length have been removed.", + LDNS_EDE_OTHER); + } + if(msgparse_rrset_remove_rr("sanitize: removing type A RR of inappropriate length:", + pkt, *rrset, rr_prev, rr, NULL, 0)) { + remove_rrset("sanitize: removing type A RRset of inappropriate length:", + pkt, msg, prev, rrset); + return 1; + } + continue; + } + + /* Sanity check for length of records + * An AAAA record should be 18 bytes only + * (2 bytes for length and 16 for IPv6 addr)*/ + if((*rrset)->type == LDNS_RR_TYPE_AAAA && rr->size != 18 ) { + if(!*added_ede) { + *added_ede = 1; + errinf_ede(qstate, "sanitize: records of inappropriate length have been removed.", + LDNS_EDE_OTHER); + } + if(msgparse_rrset_remove_rr("sanitize: removing type AAAA RR of inappropriate length:", + pkt, *rrset, rr_prev, rr, NULL, 0)) { + remove_rrset("sanitize: removing type AAAA RRset of inappropriate length:", + pkt, msg, prev, rrset); + return 1; + } + continue; + } + rr_prev = rr; + } + return 0; +} + /** * Given a response event, remove suspect RRsets from the response. * "Suspect" rrsets are potentially poison. Note that this routine expects @@ -728,15 +778,17 @@ static int sanitize_nsec_is_overreach(sldns_buffer* pkt, * @param zonename: name of server zone. * @param env: module environment with config and cache. * @param ie: iterator environment with private address data. + * @param qstate: for setting errinf for EDE error messages. * @return 0 on error. */ static int scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg, struct query_info* qinfo, uint8_t* zonename, struct module_env* env, - struct iter_env* ie) + struct iter_env* ie, struct module_qstate* qstate) { int del_addi = 0; /* if additional-holding rrsets are deleted, we do not trust the normalized additional-A-AAAA any more */ + int added_rrlen_ede = 0; struct rrset_parse* rrset, *prev; prev = NULL; rrset = msg->rrset_first; @@ -781,6 +833,14 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg, rrset = msg->rrset_first; while(rrset) { + /* Sanity check for length of records */ + if(rrset->type == LDNS_RR_TYPE_A || + rrset->type == LDNS_RR_TYPE_AAAA) { + if(scrub_sanitize_rr_length(pkt, msg, prev, &rrset, + &added_rrlen_ede, qstate)) + continue; + } + /* remove private addresses */ if( (rrset->type == LDNS_RR_TYPE_A || rrset->type == LDNS_RR_TYPE_AAAA)) { @@ -854,7 +914,8 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg, int scrub_message(sldns_buffer* pkt, struct msg_parse* msg, struct query_info* qinfo, uint8_t* zonename, struct regional* region, - struct module_env* env, struct iter_env* ie) + struct module_env* env, struct module_qstate* qstate, + struct iter_env* ie) { /* basic sanity checks */ log_nametypeclass(VERB_ALGO, "scrub for", zonename, LDNS_RR_TYPE_NS, @@ -886,7 +947,7 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg, if(!scrub_normalize(pkt, msg, qinfo, region, env)) return 0; /* delete all out-of-zone information */ - if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie)) + if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate)) return 0; return 1; } diff --git a/usr.sbin/unbound/iterator/iter_scrub.h b/usr.sbin/unbound/iterator/iter_scrub.h index 2756c1a8e..2e66f31f9 100644 --- a/usr.sbin/unbound/iterator/iter_scrub.h +++ b/usr.sbin/unbound/iterator/iter_scrub.h @@ -48,6 +48,7 @@ struct query_info; struct regional; struct module_env; struct iter_env; +struct module_qstate; /** * Cleanup the passed dns message. @@ -59,11 +60,13 @@ struct iter_env; * Used to determine out of bailiwick information. * @param regional: where to allocate (new) parts of the message. * @param env: module environment with config settings and cache. + * @param qstate: for setting errinf for EDE error messages. * @param ie: iterator module environment data. * @return: false if the message is total waste. true if scrubbed with success. */ int scrub_message(struct sldns_buffer* pkt, struct msg_parse* msg, struct query_info* qinfo, uint8_t* zonename, struct regional* regional, - struct module_env* env, struct iter_env* ie); + struct module_env* env, struct module_qstate* qstate, + struct iter_env* ie); #endif /* ITERATOR_ITER_SCRUB_H */ diff --git a/usr.sbin/unbound/iterator/iterator.c b/usr.sbin/unbound/iterator/iterator.c index 290273176..d35eb23f9 100644 --- a/usr.sbin/unbound/iterator/iterator.c +++ b/usr.sbin/unbound/iterator/iterator.c @@ -1449,6 +1449,39 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq, } iq->qchase.qname = sname; iq->qchase.qname_len = slen; + if(qstate->env->auth_zones) { + /* apply rpz qname triggers after cname */ + struct dns_msg* forged_response = + rpz_callback_from_iterator_cname(qstate, iq); + while(forged_response && reply_find_rrset_section_an( + forged_response->rep, iq->qchase.qname, + iq->qchase.qname_len, LDNS_RR_TYPE_CNAME, + iq->qchase.qclass)) { + /* another cname to follow */ + if(!handle_cname_response(qstate, iq, forged_response, + &sname, &slen)) { + errinf(qstate, "malloc failure, CNAME info"); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } + iq->qchase.qname = sname; + iq->qchase.qname_len = slen; + forged_response = + rpz_callback_from_iterator_cname(qstate, iq); + } + if(forged_response != NULL) { + qstate->ext_state[id] = module_finished; + qstate->return_rcode = LDNS_RCODE_NOERROR; + qstate->return_msg = forged_response; + iq->response = forged_response; + next_state(iq, FINISHED_STATE); + if(!iter_prepend(iq, qstate->return_msg, qstate->region)) { + log_err("rpz: after cached cname, prepend rrsets: out of memory"); + return error_response(qstate, id, LDNS_RCODE_SERVFAIL); + } + qstate->return_msg->qinfo = qstate->qinfo; + return 0; + } + } /* This *is* a query restart, even if it is a cheap * one. */ iq->dp = NULL; @@ -2875,7 +2908,8 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, /* unset CD if to forwarder(RD set) and not dnssec retry * (blacklist nonempty) and no trust-anchors are configured * above the qname or on the first attempt when dnssec is on */ - EDNS_DO| ((iq->chase_to_rd||(iq->chase_flags&BIT_RD)!=0)&& + (qstate->env->cfg->disable_edns_do?0:EDNS_DO)| + ((iq->chase_to_rd||(iq->chase_flags&BIT_RD)!=0)&& !qstate->blacklist&&(!iter_qname_indicates_dnssec(qstate->env, &iq->qinfo_out)||target->attempts==1)?0:BIT_CD), iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted( @@ -2940,7 +2974,7 @@ static int processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, struct iter_env* ie, int id) { - int dnsseclame = 0, origtypecname = 0; + int dnsseclame = 0, origtypecname = 0, orig_empty_nodata_found; enum response_type type; iq->num_current_queries--; @@ -2960,12 +2994,25 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, return next_state(iq, QUERYTARGETS_STATE); } iq->timeout_count = 0; + orig_empty_nodata_found = iq->empty_nodata_found; type = response_type_from_server( (int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd), - iq->response, &iq->qinfo_out, iq->dp); + iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found); iq->chase_to_rd = 0; /* remove TC flag, if this is erroneously set by TCP upstream */ iq->response->rep->flags &= ~BIT_TC; + if(orig_empty_nodata_found != iq->empty_nodata_found && + iq->empty_nodata_found < EMPTY_NODATA_RETRY_COUNT) { + /* try to search at another server */ + if(qstate->reply) { + struct delegpt_addr* a = delegpt_find_addr( + iq->dp, &qstate->reply->remote_addr, + qstate->reply->remote_addrlen); + /* make selection disprefer it */ + if(a) a->lame = 1; + } + return next_state(iq, QUERYTARGETS_STATE); + } if(type == RESPONSE_TYPE_REFERRAL && (iq->chase_flags&BIT_RD) && !iq->auth_zone_response) { /* When forwarding (RD bit is set), we handle referrals @@ -3501,7 +3548,7 @@ processPrimeResponse(struct module_qstate* qstate, int id) iq->response->rep->flags &= ~(BIT_RD|BIT_RA); /* ignore rec-lame */ type = response_type_from_server( (int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd), - iq->response, &iq->qchase, iq->dp); + iq->response, &iq->qchase, iq->dp, NULL); if(type == RESPONSE_TYPE_ANSWER) { qstate->return_rcode = LDNS_RCODE_NOERROR; qstate->return_msg = iq->response; @@ -3874,6 +3921,23 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq, /* explicitly set the EDE string to NULL */ iq->response->rep->reason_bogus_str = NULL; + if((qstate->env->cfg->val_log_level >= 2 || + qstate->env->cfg->log_servfail) && qstate->errinf && + !qstate->env->cfg->val_log_squelch) { + char* err_str = errinf_to_str_misc(qstate); + if(err_str) { + size_t err_str_len = strlen(err_str); + verbose(VERB_ALGO, "iterator EDE: %s", err_str); + /* allocate space and store the error + * string */ + iq->response->rep->reason_bogus_str = regional_alloc( + qstate->region, + sizeof(char) * (err_str_len+1)); + memcpy(iq->response->rep->reason_bogus_str, + err_str, err_str_len+1); + } + free(err_str); + } /* we have finished processing this query */ qstate->ext_state[id] = module_finished; @@ -4098,7 +4162,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, /* normalize and sanitize: easy to delete items from linked lists */ if(!scrub_message(pkt, prs, &iq->qinfo_out, iq->dp->name, - qstate->env->scratch, qstate->env, ie)) { + qstate->env->scratch, qstate->env, qstate, ie)) { /* if 0x20 enabled, start fallback, but we have no message */ if(event == module_event_capsfail && !iq->caps_fallback) { iq->caps_fallback = 1; diff --git a/usr.sbin/unbound/iterator/iterator.h b/usr.sbin/unbound/iterator/iterator.h index 0fe160beb..c81eb9435 100644 --- a/usr.sbin/unbound/iterator/iterator.h +++ b/usr.sbin/unbound/iterator/iterator.h @@ -101,6 +101,8 @@ extern int BLACKLIST_PENALTY; * Chosen so that the UNKNOWN_SERVER_NICENESS falls within the band of a * fast server, this causes server exploration as a side benefit. msec. */ #define RTT_BAND 400 +/** Number of retries for empty nodata packets before it is accepted. */ +#define EMPTY_NODATA_RETRY_COUNT 2 /** * Global state for the iterator. @@ -415,6 +417,11 @@ struct iter_qstate { */ int refetch_glue; + /** + * This flag detects that a completely empty nodata was received, + * already so that it is accepted later. */ + int empty_nodata_found; + /** list of pending queries to authoritative servers. */ struct outbound_list outlist; diff --git a/usr.sbin/unbound/libunbound/libworker.c b/usr.sbin/unbound/libunbound/libworker.c index 1b0f2f1f1..f4b098225 100644 --- a/usr.sbin/unbound/libunbound/libworker.c +++ b/usr.sbin/unbound/libunbound/libworker.c @@ -62,6 +62,7 @@ #include "util/random.h" #include "util/config_file.h" #include "util/netevent.h" +#include "util/proxy_protocol.h" #include "util/storage/lookup3.h" #include "util/storage/slabhash.h" #include "util/net_help.h" @@ -168,6 +169,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb) hints_delete(w->env->hints); w->env->hints = NULL; } +#ifdef HAVE_SSL w->sslctx = connect_sslctx_create(NULL, NULL, cfg->tls_cert_bundle, cfg->tls_win_cert); if(!w->sslctx) { @@ -175,6 +177,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb) hints_delete(w->env->hints); w->env->hints = NULL; } +#endif if(!w->is_bg || w->is_bg_thread) { lock_basic_unlock(&ctx->cfglock); } @@ -263,6 +266,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb) w->env->kill_sub = &mesh_state_delete; w->env->detect_cycle = &mesh_detect_cycle; comm_base_timept(w->base, &w->env->now, &w->env->now_tv); + pp_init(&sldns_write_uint16, &sldns_write_uint32); return w; } diff --git a/usr.sbin/unbound/services/authzone.c b/usr.sbin/unbound/services/authzone.c index 024392d43..7cb394dd2 100644 --- a/usr.sbin/unbound/services/authzone.c +++ b/usr.sbin/unbound/services/authzone.c @@ -2475,6 +2475,7 @@ az_find_ce(struct auth_zone* z, struct query_info* qinfo, struct auth_rrset** rrset) { struct auth_data* n = node; + struct auth_rrset* lookrrset; *ce = NULL; *rrset = NULL; if(!node_exact) { @@ -2497,21 +2498,23 @@ az_find_ce(struct auth_zone* z, struct query_info* qinfo, /* see if the current candidate has issues */ /* not zone apex and has type NS */ if(n->namelen != z->namelen && - (*rrset=az_domain_rrset(n, LDNS_RR_TYPE_NS)) && + (lookrrset=az_domain_rrset(n, LDNS_RR_TYPE_NS)) && /* delegate here, but DS at exact the dp has notype */ (qinfo->qtype != LDNS_RR_TYPE_DS || n->namelen != qinfo->qname_len)) { /* referral */ /* this is ce and the lowernode is nonexisting */ *ce = n; - return 0; + *rrset = lookrrset; + node_exact = 0; } /* not equal to qname and has type DNAME */ if(n->namelen != qinfo->qname_len && - (*rrset=az_domain_rrset(n, LDNS_RR_TYPE_DNAME))) { + (lookrrset=az_domain_rrset(n, LDNS_RR_TYPE_DNAME))) { /* this is ce and the lowernode is nonexisting */ *ce = n; - return 0; + *rrset = lookrrset; + node_exact = 0; } if(*ce == NULL && !domain_has_only_nsec3(n)) { diff --git a/usr.sbin/unbound/services/listen_dnsport.c b/usr.sbin/unbound/services/listen_dnsport.c index 60f9b41e5..753550978 100644 --- a/usr.sbin/unbound/services/listen_dnsport.c +++ b/usr.sbin/unbound/services/listen_dnsport.c @@ -1327,7 +1327,9 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, log_warn("socket timestamping is not available"); } if(!port_insert(list, s, is_dnscrypt - ?listen_type_udp_dnscrypt:listen_type_udp, + ?listen_type_udp_dnscrypt : + (sock_queue_timeout ? + listen_type_udpancil:listen_type_udp), is_pp2, ub_sock)) { sock_close(s); if(ub_sock->addr) @@ -1498,9 +1500,13 @@ listen_create(struct comm_base* base, struct listen_port* ports, } } else if(ports->ftype == listen_type_udpancil || ports->ftype == listen_type_udpancil_dnscrypt) { +#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) cp = comm_point_create_udp_ancil(base, ports->fd, front->udp_buff, ports->pp2_enabled, cb, cb_arg, ports->socket); +#else + log_warn("This system does not support UDP ancilliary data."); +#endif } if(!cp) { log_err("can't create commpoint"); diff --git a/usr.sbin/unbound/services/mesh.c b/usr.sbin/unbound/services/mesh.c index 52d14a2d1..509bee36a 100644 --- a/usr.sbin/unbound/services/mesh.c +++ b/usr.sbin/unbound/services/mesh.c @@ -1197,6 +1197,8 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, r->edns.udp_size = EDNS_ADVERTISED_SIZE; r->edns.ext_rcode = 0; r->edns.bits &= EDNS_DO; + if(m->s.env->cfg->disable_edns_do && (r->edns.bits&EDNS_DO)) + r->edns.edns_present = 0; if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, LDNS_RCODE_NOERROR, &r->edns, NULL, m->s.region, start_time) || @@ -1224,11 +1226,12 @@ static inline int mesh_is_rpz_respip_tcponly_action(struct mesh_state const* m) { struct respip_action_info const* respip_info = m->s.respip_action_info; - return respip_info == NULL + return (respip_info == NULL ? 0 : (respip_info->rpz_used && !respip_info->rpz_disabled - && respip_info->action == respip_truncate); + && respip_info->action == respip_truncate)) + || m->s.tcp_required; } static inline int @@ -1371,6 +1374,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, r->edns.udp_size = EDNS_ADVERTISED_SIZE; r->edns.ext_rcode = 0; r->edns.bits &= EDNS_DO; + if(m->s.env->cfg->disable_edns_do && (r->edns.bits&EDNS_DO)) + r->edns.edns_present = 0; m->s.qinfo.qname = r->qname; m->s.qinfo.local_alias = r->local_alias; diff --git a/usr.sbin/unbound/services/outside_network.c b/usr.sbin/unbound/services/outside_network.c index 9e50a2cb1..c8aa5718b 100644 --- a/usr.sbin/unbound/services/outside_network.c +++ b/usr.sbin/unbound/services/outside_network.c @@ -550,7 +550,6 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr, log_assert(&key_p.reuse != (struct reuse_tcp*)result); log_assert(&key_p != ((struct reuse_tcp*)result)->pending); } - /* not found, return null */ /* It is possible that we search for something before the first element * in the tree. Replace a null pointer with the first element. @@ -560,6 +559,7 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr, result = rbtree_first(&outnet->tcp_reuse); } + /* not found, return null */ if(!result || result == RBTREE_NULL) return NULL; diff --git a/usr.sbin/unbound/services/rpz.c b/usr.sbin/unbound/services/rpz.c index d903562e5..e7446fcc6 100644 --- a/usr.sbin/unbound/services/rpz.c +++ b/usr.sbin/unbound/services/rpz.c @@ -2162,7 +2162,7 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r, case RPZ_TCP_ONLY_ACTION: /* basically a passthru here but the tcp-only will be * honored before the query gets sent. */ - ms->respip_action_info->action = respip_truncate; + ms->tcp_required = 1; ret = NULL; break; case RPZ_DROP_ACTION: @@ -2217,7 +2217,7 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r, case RPZ_TCP_ONLY_ACTION: /* basically a passthru here but the tcp-only will be * honored before the query gets sent. */ - ms->respip_action_info->action = respip_truncate; + ms->tcp_required = 1; ret = NULL; break; case RPZ_DROP_ACTION: @@ -2428,7 +2428,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, case RPZ_TCP_ONLY_ACTION: /* basically a passthru here but the tcp-only will be * honored before the query gets sent. */ - ms->respip_action_info->action = respip_truncate; + ms->tcp_required = 1; ret = NULL; break; case RPZ_DROP_ACTION: @@ -2448,6 +2448,10 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms, rpz_action_to_string(localzone_type_to_rpz_action(lzt))); ret = NULL; } + if(r->log) + log_rpz_apply("qname", (z?z->name:NULL), NULL, + localzone_type_to_rpz_action(lzt), + &is->qchase, NULL, ms, r->log_name); lock_rw_unlock(&z->lock); lock_rw_unlock(&a->lock); return ret; diff --git a/usr.sbin/unbound/sldns/str2wire.c b/usr.sbin/unbound/sldns/str2wire.c index 521d08a9f..ca59dfbad 100644 --- a/usr.sbin/unbound/sldns/str2wire.c +++ b/usr.sbin/unbound/sldns/str2wire.c @@ -2459,12 +2459,13 @@ int sldns_str2wire_wks_buf(const char* str, uint8_t* rd, size_t* len) (void)strlcpy(proto_str, token, sizeof(proto_str)); } else { int serv_port; - struct servent *serv = getservbyname(token, proto_str); - if(serv) serv_port=(int)ntohs((uint16_t)serv->s_port); + if(atoi(token) != 0) serv_port=atoi(token); + else if(strcmp(token, "0") == 0) serv_port=0; else if(strcasecmp(token, "domain")==0) serv_port=53; else { - serv_port = atoi(token); - if(serv_port == 0 && strcmp(token, "0") != 0) { + struct servent *serv = getservbyname(token, proto_str); + if(serv) serv_port=(int)ntohs((uint16_t)serv->s_port); + else { #ifdef HAVE_ENDSERVENT endservent(); #endif @@ -2474,16 +2475,16 @@ int sldns_str2wire_wks_buf(const char* str, uint8_t* rd, size_t* len) return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, sldns_buffer_position(&strbuf)); } - if(serv_port < 0 || serv_port > 65535) { + } + if(serv_port < 0 || serv_port > 65535) { #ifdef HAVE_ENDSERVENT - endservent(); + endservent(); #endif #ifdef HAVE_ENDPROTOENT - endprotoent(); + endprotoent(); #endif - return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, - sldns_buffer_position(&strbuf)); - } + return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, + sldns_buffer_position(&strbuf)); } if(rd_len < 1+serv_port/8+1) { /* bitmap is larger, init new bytes at 0 */ diff --git a/usr.sbin/unbound/sldns/wire2str.c b/usr.sbin/unbound/sldns/wire2str.c index e6278ff56..2b5dc0513 100644 --- a/usr.sbin/unbound/sldns/wire2str.c +++ b/usr.sbin/unbound/sldns/wire2str.c @@ -192,6 +192,7 @@ static sldns_lookup_table sldns_edns_options_data[] = { { 6, "DHU" }, { 7, "N3U" }, { 8, "edns-client-subnet" }, + { 10, "COOKIE" }, { 11, "edns-tcp-keepalive"}, { 12, "Padding" }, { 15, "EDE"}, @@ -199,6 +200,38 @@ static sldns_lookup_table sldns_edns_options_data[] = { }; sldns_lookup_table* sldns_edns_options = sldns_edns_options_data; +/* From RFC8914 5.2 Table 3, the "Extended DNS Error Codes" registry. */ +static sldns_lookup_table sldns_edns_ede_codes_data[] = { + { LDNS_EDE_NONE, "None" }, + { LDNS_EDE_OTHER, "Other Error" }, + { LDNS_EDE_UNSUPPORTED_DNSKEY_ALG, "Unsupported DNSKEY Algorithm" }, + { LDNS_EDE_UNSUPPORTED_DS_DIGEST, "Unsupported DS Digest Type" }, + { LDNS_EDE_STALE_ANSWER, "Stale Answer" }, + { LDNS_EDE_FORGED_ANSWER, "Forged Answer" }, + { LDNS_EDE_DNSSEC_INDETERMINATE, "DNSSEC Indeterminate" }, + { LDNS_EDE_DNSSEC_BOGUS, "DNSSEC Bogus" }, + { LDNS_EDE_SIGNATURE_EXPIRED, "Signature Expired" }, + { LDNS_EDE_SIGNATURE_NOT_YET_VALID, "Signature Not Yet Valid" }, + { LDNS_EDE_DNSKEY_MISSING, "DNSKEY Missing" }, + { LDNS_EDE_RRSIGS_MISSING, "RRSIGs Missing" }, + { LDNS_EDE_NO_ZONE_KEY_BIT_SET, "No Zone Key Bit Set" }, + { LDNS_EDE_NSEC_MISSING, "NSEC Missing" }, + { LDNS_EDE_CACHED_ERROR, "Cached Error" }, + { LDNS_EDE_NOT_READY, "Not Ready" }, + { LDNS_EDE_BLOCKED, "Blocked" }, + { LDNS_EDE_CENSORED, "Censored" }, + { LDNS_EDE_FILTERED, "Filtered" }, + { LDNS_EDE_PROHIBITED, "Prohibited" }, + { LDNS_EDE_STALE_NXDOMAIN_ANSWER, "Stale NXDOMAIN Answer" }, + { LDNS_EDE_NOT_AUTHORITATIVE, "Not Authoritative" }, + { LDNS_EDE_NOT_SUPPORTED, "Not Supported" }, + { LDNS_EDE_NO_REACHABLE_AUTHORITY, "No Reachable Authority" }, + { LDNS_EDE_NETWORK_ERROR, "Network Error" }, + { LDNS_EDE_INVALID_DATA, "Invalid Data" }, + { 0, NULL} +}; +sldns_lookup_table* sldns_edns_ede_codes = sldns_edns_ede_codes_data; + static sldns_lookup_table sldns_tsig_errors_data[] = { { LDNS_TSIG_ERROR_NOERROR, "NOERROR" }, { LDNS_RCODE_FORMERR, "FORMERR" }, @@ -2234,6 +2267,52 @@ static int sldns_wire2str_edns_keepalive_print(char** s, size_t* sl, return w; } +int sldns_wire2str_edns_ede_print(char** s, size_t* sl, + uint8_t* data, size_t len) +{ + uint16_t ede_code; + int w = 0; + sldns_lookup_table *lt; + size_t i; + int printable; + + if(len < 2) { + w += sldns_str_print(s, sl, "malformed ede "); + w += print_hex_buf(s, sl, data, len); + return w; + } + + ede_code = sldns_read_uint16(data); + lt = sldns_lookup_by_id(sldns_edns_ede_codes, (int)ede_code); + if(lt && lt->name) + w += sldns_str_print(s, sl, "%s", lt->name); + else w += sldns_str_print(s, sl, "%d", (int)ede_code); + + if(len == 2) + return w; + + w += sldns_str_print(s, sl, " "); + + /* If it looks like text, show it as text. */ + printable=1; + for(i=2; iauto_trust_anchor_file_list, cfg->chrootdir, cfg); check_chroot_filelist_wild("trusted-keys-file", cfg->trusted_keys_file_list, cfg->chrootdir, cfg); + if(cfg->disable_edns_do && strstr(cfg->module_conf, "validator") + && (cfg->trust_anchor_file_list + || cfg->trust_anchor_list + || cfg->auto_trust_anchor_file_list + || cfg->trusted_keys_file_list)) { + char* key = NULL; + if(cfg->auto_trust_anchor_file_list) + key = cfg->auto_trust_anchor_file_list->str; + if(!key && cfg->trust_anchor_file_list) + key = cfg->trust_anchor_file_list->str; + if(!key && cfg->trust_anchor_list) + key = cfg->trust_anchor_list->str; + if(!key && cfg->trusted_keys_file_list) + key = cfg->trusted_keys_file_list->str; + if(!key) key = ""; + fatal_exit("disable-edns-do does not allow DNSSEC to work, but the validator module uses a trust anchor %s, turn off disable-edns-do or disable validation", key); + } #ifdef USE_IPSECMOD if(cfg->ipsecmod_enabled && strstr(cfg->module_conf, "ipsecmod")) { /* only check hook if enabled */ diff --git a/usr.sbin/unbound/testcode/dohclient.c b/usr.sbin/unbound/testcode/dohclient.c index 6b6bfd66d..0635c3c7b 100644 --- a/usr.sbin/unbound/testcode/dohclient.c +++ b/usr.sbin/unbound/testcode/dohclient.c @@ -286,7 +286,7 @@ static ssize_t http2_recv_cb(nghttp2_session* ATTR_UNUSED(session), if(want == SSL_ERROR_ZERO_RETURN) { return NGHTTP2_ERR_EOF; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); return NGHTTP2_ERR_EOF; } return r; @@ -317,7 +317,7 @@ static ssize_t http2_send_cb(nghttp2_session* ATTR_UNUSED(session), if(want == SSL_ERROR_ZERO_RETURN) { return NGHTTP2_ERR_CALLBACK_FAILURE; } - log_crypto_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", want); return NGHTTP2_ERR_CALLBACK_FAILURE; } return r; @@ -526,7 +526,7 @@ run(struct http2_session* h2_session, int port, int no_tls, int count, char** q) r = SSL_get_error(ssl, r); if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) { - log_crypto_err("could not ssl_handshake"); + log_crypto_err_io("could not ssl_handshake", r); exit(1); } } diff --git a/usr.sbin/unbound/testcode/fake_event.c b/usr.sbin/unbound/testcode/fake_event.c index 2140b212a..13970c377 100644 --- a/usr.sbin/unbound/testcode/fake_event.c +++ b/usr.sbin/unbound/testcode/fake_event.c @@ -1249,7 +1249,7 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet, edns.edns_version = EDNS_ADVERTISED_VERSION; edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits = 0; - if(dnssec) + if((dnssec & EDNS_DO)) edns.bits = EDNS_DO; edns.padding_block_size = 0; edns.cookie_present = 0; diff --git a/usr.sbin/unbound/testcode/streamtcp.1 b/usr.sbin/unbound/testcode/streamtcp.1 index 273bbc976..6c83c7e06 100644 --- a/usr.sbin/unbound/testcode/streamtcp.1 +++ b/usr.sbin/unbound/testcode/streamtcp.1 @@ -61,6 +61,17 @@ Specify the server to send the queries to. If not specified localhost (127.0.0.1 .B \-d \fIsecs Delay after the connection before sending query. This tests the timeout on the other side, eg. if shorter the connection is closed. +.TP +.B \-p \fIclient +Use proxy protocol to send the query. Specify the ipaddr@portnr of the client +to include in PROXYv2. +.TP +.B IXFR=serial +Pass the type of the query as IXFR=N to send an IXFR query with serial N. +.TP +.B NOTIFY[=serial] +Pass the type of the query as NOTIFY[=N] to send a notify packet. The serial N +of the new zone can be included. .SH "EXAMPLES" .LP Some examples of use. diff --git a/usr.sbin/unbound/testcode/streamtcp.c b/usr.sbin/unbound/testcode/streamtcp.c index 6a81118f9..79b25039c 100644 --- a/usr.sbin/unbound/testcode/streamtcp.c +++ b/usr.sbin/unbound/testcode/streamtcp.c @@ -79,6 +79,8 @@ static void usage(char* argv[]) printf("-d secs delay after connection before sending query\n"); printf("-s use ssl\n"); printf("-h this help text\n"); + printf("IXFR=N for the type, sends ixfr query with serial N.\n"); + printf("NOTIFY[=N] for the type, sends notify. Can set new zone serial N.\n"); exit(1); } @@ -115,6 +117,29 @@ open_svr(const char* svr, int udp, struct sockaddr_storage* addr, return fd; } +/** Append a SOA record with serial number */ +static void +write_soa_serial_to_buf(sldns_buffer* buf, struct query_info* qinfo, + uint32_t serial) +{ + sldns_buffer_set_position(buf, sldns_buffer_limit(buf)); + sldns_buffer_set_limit(buf, sldns_buffer_capacity(buf)); + /* Write compressed reference to the query */ + sldns_buffer_write_u16(buf, PTR_CREATE(LDNS_HEADER_SIZE)); + sldns_buffer_write_u16(buf, LDNS_RR_TYPE_SOA); + sldns_buffer_write_u16(buf, qinfo->qclass); + sldns_buffer_write_u32(buf, 3600); /* TTL */ + sldns_buffer_write_u16(buf, 1+1+4*5); /* rdatalen */ + sldns_buffer_write_u8(buf, 0); /* primary "." */ + sldns_buffer_write_u8(buf, 0); /* email "." */ + sldns_buffer_write_u32(buf, serial); /* serial */ + sldns_buffer_write_u32(buf, 0); /* refresh */ + sldns_buffer_write_u32(buf, 0); /* retry */ + sldns_buffer_write_u32(buf, 0); /* expire */ + sldns_buffer_write_u32(buf, 0); /* minimum */ + sldns_buffer_flip(buf); +} + /** write a query over the TCP fd */ static void write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id, @@ -123,6 +148,8 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id, { struct query_info qinfo; size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf); + int have_serial = 0, is_notify = 0; + uint32_t serial = 0; /* qname */ qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len); if(!qinfo.qname) { @@ -130,12 +157,27 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id, exit(1); } - /* qtype and qclass */ - qinfo.qtype = sldns_get_rr_type_by_name(strtype); - if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) { - printf("cannot parse query type: '%s'\n", strtype); - exit(1); + /* qtype */ + if(strncasecmp(strtype, "IXFR=", 5) == 0) { + serial = (uint32_t)atoi(strtype+5); + have_serial = 1; + qinfo.qtype = LDNS_RR_TYPE_IXFR; + } else if(strcasecmp(strtype, "NOTIFY") == 0) { + is_notify = 1; + qinfo.qtype = LDNS_RR_TYPE_SOA; + } else if(strncasecmp(strtype, "NOTIFY=", 7) == 0) { + serial = (uint32_t)atoi(strtype+7); + have_serial = 1; + is_notify = 1; + qinfo.qtype = LDNS_RR_TYPE_SOA; + } else { + qinfo.qtype = sldns_get_rr_type_by_name(strtype); + if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) { + printf("cannot parse query type: '%s'\n", strtype); + exit(1); + } } + /* qclass */ qinfo.qclass = sldns_get_rr_class_by_name(strclass); if(qinfo.qclass == 0 && strcmp(strclass, "CLASS0") != 0) { printf("cannot parse query class: '%s'\n", strclass); @@ -150,6 +192,21 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id, sldns_buffer_write_u16_at(buf, 0, id); sldns_buffer_write_u16_at(buf, 2, BIT_RD); + if(have_serial && qinfo.qtype == LDNS_RR_TYPE_IXFR) { + /* Attach serial to SOA record in the authority section. */ + write_soa_serial_to_buf(buf, &qinfo, serial); + LDNS_NSCOUNT_SET(sldns_buffer_begin(buf), 1); + } + if(is_notify) { + LDNS_OPCODE_SET(sldns_buffer_begin(buf), LDNS_PACKET_NOTIFY); + LDNS_RD_CLR(sldns_buffer_begin(buf)); + LDNS_AA_SET(sldns_buffer_begin(buf)); + if(have_serial) { + write_soa_serial_to_buf(buf, &qinfo, serial); + LDNS_ANCOUNT_SET(sldns_buffer_begin(buf), 1); + } + } + if(1) { /* add EDNS DO */ struct edns_data edns; @@ -361,6 +418,7 @@ static int parse_pp2_client(const char* pp2_client, int udp, sldns_buffer* proxy_buf) { struct sockaddr_storage pp2_addr; + size_t bytes_written; socklen_t pp2_addrlen = 0; memset(&pp2_addr, 0, sizeof(pp2_addr)); if(*pp2_client == 0) return 0; @@ -369,7 +427,9 @@ static int parse_pp2_client(const char* pp2_client, int udp, exit(1); } sldns_buffer_clear(proxy_buf); - pp2_write_to_buf(proxy_buf, &pp2_addr, !udp); + bytes_written = pp2_write_to_buf(sldns_buffer_begin(proxy_buf), + sldns_buffer_remaining(proxy_buf), &pp2_addr, !udp); + sldns_buffer_set_position(proxy_buf, bytes_written); sldns_buffer_flip(proxy_buf); return 1; } @@ -406,7 +466,7 @@ send_em(const char* svr, const char* pp2_client, int udp, int usessl, r = SSL_get_error(ssl, r); if(r != SSL_ERROR_WANT_READ && r != SSL_ERROR_WANT_WRITE) { - log_crypto_err("could not ssl_handshake"); + log_crypto_err_io("could not ssl_handshake", r); exit(1); } } @@ -541,6 +601,8 @@ int main(int argc, char** argv) break; case 'p': pp2_client = optarg; + pp_init(&sldns_write_uint16, + &sldns_write_uint32); break; case 'a': onarrival = 1; diff --git a/usr.sbin/unbound/testcode/unitauth.c b/usr.sbin/unbound/testcode/unitauth.c index c47597ca2..569646f5f 100644 --- a/usr.sbin/unbound/testcode/unitauth.c +++ b/usr.sbin/unbound/testcode/unitauth.c @@ -76,10 +76,18 @@ static const char* zone_example_com = "out.example.com. 3600 IN CNAME www.example.com.\n" "plan.example.com. 3600 IN CNAME nonexist.example.com.\n" "redir.example.com. 3600 IN DNAME redir.example.org.\n" +"redir2.example.com. 3600 IN DNAME redir2.example.org.\n" +"obscured.redir2.example.com. 3600 IN A 10.0.0.12\n" +"under2.redir2.example.com. 3600 IN DNAME redir3.example.net.\n" +"doubleobscured.under2.redir2.example.com. 3600 IN A 10.0.0.13\n" "sub.example.com. 3600 IN NS ns1.sub.example.com.\n" "sub.example.com. 3600 IN NS ns2.sub.example.com.\n" "ns1.sub.example.com. 3600 IN A 10.0.0.6\n" "ns2.sub.example.com. 3600 IN AAAA 2001::7\n" +"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n" +"obscured.sub2.example.com. 3600 IN A 10.0.0.10\n" +"under.sub2.example.com. 3600 IN NS ns.under.sub2.example.com.\n" +"doubleobscured.under.sub2.example.com. 3600 IN A 10.0.0.11\n" "*.wild.example.com. 3600 IN A 10.0.0.8\n" "*.wild2.example.com. 3600 IN CNAME www.example.com.\n" "*.wild3.example.com. 3600 IN A 10.0.0.8\n" @@ -281,6 +289,54 @@ static struct q_ans example_com_queries[] = { "foo.abc.redir.example.com. 0 IN CNAME foo.abc.redir.example.org.\n" }, + { "example.com", "redir2.example.com. DNAME", "", +";flags QR AA rcode NOERROR\n" +";answer section\n" +"redir2.example.com. 3600 IN DNAME redir2.example.org.\n" + }, + + { "example.com", "abc.redir2.example.com. A", "", +";flags QR AA rcode NOERROR\n" +";answer section\n" +"redir2.example.com. 3600 IN DNAME redir2.example.org.\n" +"abc.redir2.example.com. 0 IN CNAME abc.redir2.example.org.\n" + }, + + { "example.com", "obscured.redir2.example.com. A", "", +";flags QR AA rcode NOERROR\n" +";answer section\n" +"redir2.example.com. 3600 IN DNAME redir2.example.org.\n" +"obscured.redir2.example.com. 0 IN CNAME obscured.redir2.example.org.\n" + }, + + { "example.com", "under2.redir2.example.com. A", "", +";flags QR AA rcode NOERROR\n" +";answer section\n" +"redir2.example.com. 3600 IN DNAME redir2.example.org.\n" +"under2.redir2.example.com. 0 IN CNAME under2.redir2.example.org.\n" + }, + + { "example.com", "doubleobscured.under2.redir2.example.com. A", "", +";flags QR AA rcode NOERROR\n" +";answer section\n" +"redir2.example.com. 3600 IN DNAME redir2.example.org.\n" +"doubleobscured.under2.redir2.example.com. 0 IN CNAME doubleobscured.under2.redir2.example.org.\n" + }, + + { "example.com", "foo.doubleobscured.under2.redir2.example.com. A", "", +";flags QR AA rcode NOERROR\n" +";answer section\n" +"redir2.example.com. 3600 IN DNAME redir2.example.org.\n" +"foo.doubleobscured.under2.redir2.example.com. 0 IN CNAME foo.doubleobscured.under2.redir2.example.org.\n" + }, + + { "example.com", "foo.under2.redir2.example.com. A", "", +";flags QR AA rcode NOERROR\n" +";answer section\n" +"redir2.example.com. 3600 IN DNAME redir2.example.org.\n" +"foo.under2.redir2.example.com. 0 IN CNAME foo.under2.redir2.example.org.\n" + }, + { "example.com", "sub.example.com. NS", "", ";flags QR rcode NOERROR\n" ";authority section\n" @@ -357,6 +413,78 @@ static struct q_ans example_com_queries[] = { "ns2.sub.example.com. 3600 IN AAAA 2001::7\n" }, + { "example.com", "sub2.example.com. A", "", +";flags QR rcode NOERROR\n" +";authority section\n" +"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n" +";additional section\n" +"ns1.sub.example.com. 3600 IN A 10.0.0.6\n" + }, + + { "example.com", "sub2.example.com. NS", "", +";flags QR rcode NOERROR\n" +";authority section\n" +"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n" +";additional section\n" +"ns1.sub.example.com. 3600 IN A 10.0.0.6\n" + }, + + { "example.com", "obscured.sub2.example.com. A", "", +";flags QR rcode NOERROR\n" +";authority section\n" +"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n" +";additional section\n" +"ns1.sub.example.com. 3600 IN A 10.0.0.6\n" + }, + + { "example.com", "abc.obscured.sub2.example.com. A", "", +";flags QR rcode NOERROR\n" +";authority section\n" +"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n" +";additional section\n" +"ns1.sub.example.com. 3600 IN A 10.0.0.6\n" + }, + + { "example.com", "under.sub2.example.com. A", "", +";flags QR rcode NOERROR\n" +";authority section\n" +"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n" +";additional section\n" +"ns1.sub.example.com. 3600 IN A 10.0.0.6\n" + }, + + { "example.com", "under.sub2.example.com. NS", "", +";flags QR rcode NOERROR\n" +";authority section\n" +"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n" +";additional section\n" +"ns1.sub.example.com. 3600 IN A 10.0.0.6\n" + }, + + { "example.com", "abc.under.sub2.example.com. A", "", +";flags QR rcode NOERROR\n" +";authority section\n" +"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n" +";additional section\n" +"ns1.sub.example.com. 3600 IN A 10.0.0.6\n" + }, + + { "example.com", "doubleobscured.under.sub2.example.com. A", "", +";flags QR rcode NOERROR\n" +";authority section\n" +"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n" +";additional section\n" +"ns1.sub.example.com. 3600 IN A 10.0.0.6\n" + }, + + { "example.com", "abc.doubleobscured.under.sub2.example.com. A", "", +";flags QR rcode NOERROR\n" +";authority section\n" +"sub2.example.com. 3600 IN NS ns1.sub.example.com.\n" +";additional section\n" +"ns1.sub.example.com. 3600 IN A 10.0.0.6\n" + }, + { "example.com", "wild.example.com. A", "", ";flags QR AA rcode NOERROR\n" ";authority section\n" diff --git a/usr.sbin/unbound/util/config_file.c b/usr.sbin/unbound/util/config_file.c index b7aed66dc..8d1fd5521 100644 --- a/usr.sbin/unbound/util/config_file.c +++ b/usr.sbin/unbound/util/config_file.c @@ -271,6 +271,7 @@ config_create(void) cfg->val_permissive_mode = 0; cfg->aggressive_nsec = 1; cfg->ignore_cd = 0; + cfg->disable_edns_do = 0; cfg->serve_expired = 0; cfg->serve_expired_ttl = 0; cfg->serve_expired_ttl_reset = 0; @@ -381,6 +382,7 @@ config_create(void) #ifdef USE_CACHEDB if(!(cfg->cachedb_backend = strdup("testframe"))) goto error_exit; if(!(cfg->cachedb_secret = strdup("default"))) goto error_exit; + cfg->cachedb_no_store = 0; #ifdef USE_REDIS if(!(cfg->redis_server_host = strdup("127.0.0.1"))) goto error_exit; cfg->redis_server_path = NULL; @@ -388,6 +390,7 @@ config_create(void) cfg->redis_timeout = 100; cfg->redis_server_port = 6379; cfg->redis_expire_records = 0; + cfg->redis_logical_db = 0; #endif /* USE_REDIS */ #endif /* USE_CACHEDB */ #ifdef USE_IPSET @@ -690,6 +693,7 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_YNO("val-permissive-mode:", val_permissive_mode) else S_YNO("aggressive-nsec:", aggressive_nsec) else S_YNO("ignore-cd-flag:", ignore_cd) + else S_YNO("disable-edns-do:", disable_edns_do) else if(strcmp(opt, "serve-expired:") == 0) { IS_YES_OR_NO; cfg->serve_expired = (strcmp(val, "yes") == 0); SERVE_EXPIRED = cfg->serve_expired; } @@ -819,6 +823,9 @@ int config_set_option(struct config_file* cfg, const char* opt, { IS_NUMBER_OR_ZERO; cfg->ipsecmod_max_ttl = atoi(val); } else S_YNO("ipsecmod-strict:", ipsecmod_strict) #endif +#ifdef USE_CACHEDB + else S_YNO("cachedb-no-store:", cachedb_no_store) +#endif /* USE_CACHEDB */ else if(strcmp(opt, "define-tag:") ==0) { return config_add_tag(cfg, val); /* val_sig_skew_min, max and val_max_restart are copied into val_env @@ -1149,6 +1156,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_YNO(opt, "val-permissive-mode", val_permissive_mode) else O_YNO(opt, "aggressive-nsec", aggressive_nsec) else O_YNO(opt, "ignore-cd-flag", ignore_cd) + else O_YNO(opt, "disable-edns-do", disable_edns_do) else O_YNO(opt, "serve-expired", serve_expired) else O_DEC(opt, "serve-expired-ttl", serve_expired_ttl) else O_YNO(opt, "serve-expired-ttl-reset", serve_expired_ttl_reset) @@ -1306,6 +1314,7 @@ config_get_option(struct config_file* cfg, const char* opt, #ifdef USE_CACHEDB else O_STR(opt, "backend", cachedb_backend) else O_STR(opt, "secret-seed", cachedb_secret) + else O_YNO(opt, "cachedb-no-store", cachedb_no_store) #ifdef USE_REDIS else O_STR(opt, "redis-server-host", redis_server_host) else O_DEC(opt, "redis-server-port", redis_server_port) @@ -1313,6 +1322,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_STR(opt, "redis-server-password", redis_server_password) else O_DEC(opt, "redis-timeout", redis_timeout) else O_YNO(opt, "redis-expire-records", redis_expire_records) + else O_DEC(opt, "redis-logical-db", redis_logical_db) #endif /* USE_REDIS */ #endif /* USE_CACHEDB */ #ifdef USE_IPSET diff --git a/usr.sbin/unbound/util/config_file.h b/usr.sbin/unbound/util/config_file.h index 452f3c6a7..ad22b8330 100644 --- a/usr.sbin/unbound/util/config_file.h +++ b/usr.sbin/unbound/util/config_file.h @@ -409,6 +409,8 @@ struct config_file { int aggressive_nsec; /** ignore the CD flag in incoming queries and refuse them bogus data */ int ignore_cd; + /** disable EDNS DO flag in outgoing requests */ + int disable_edns_do; /** serve expired entries and prefetch them */ int serve_expired; /** serve expired entries until TTL after expiration */ @@ -699,6 +701,8 @@ struct config_file { char* cachedb_backend; /** secret seed for hash key calculation */ char* cachedb_secret; + /** cachedb that does not store, but only reads from database, if on */ + int cachedb_no_store; #ifdef USE_REDIS /** redis server's IP address or host name */ char* redis_server_host; @@ -712,6 +716,8 @@ struct config_file { int redis_timeout; /** set timeout on redis records based on DNS response ttl */ int redis_expire_records; + /** set the redis logical database upon connection */ + int redis_logical_db; #endif #endif /** Downstream DNS Cookies */ diff --git a/usr.sbin/unbound/util/configlexer.lex b/usr.sbin/unbound/util/configlexer.lex index 3fcdfa62e..fdc267434 100644 --- a/usr.sbin/unbound/util/configlexer.lex +++ b/usr.sbin/unbound/util/configlexer.lex @@ -403,6 +403,7 @@ val-clean-additional{COLON} { YDVAR(1, VAR_VAL_CLEAN_ADDITIONAL) } val-permissive-mode{COLON} { YDVAR(1, VAR_VAL_PERMISSIVE_MODE) } aggressive-nsec{COLON} { YDVAR(1, VAR_AGGRESSIVE_NSEC) } ignore-cd-flag{COLON} { YDVAR(1, VAR_IGNORE_CD_FLAG) } +disable-edns-do{COLON} { YDVAR(1, VAR_DISABLE_EDNS_DO) } serve-expired{COLON} { YDVAR(1, VAR_SERVE_EXPIRED) } serve-expired-ttl{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL) } serve-expired-ttl-reset{COLON} { YDVAR(1, VAR_SERVE_EXPIRED_TTL_RESET) } @@ -557,12 +558,14 @@ ipsecmod-strict{COLON} { YDVAR(1, VAR_IPSECMOD_STRICT) } cachedb{COLON} { YDVAR(0, VAR_CACHEDB) } backend{COLON} { YDVAR(1, VAR_CACHEDB_BACKEND) } secret-seed{COLON} { YDVAR(1, VAR_CACHEDB_SECRETSEED) } +cachedb-no-store{COLON} { YDVAR(1, VAR_CACHEDB_NO_STORE) } redis-server-host{COLON} { YDVAR(1, VAR_CACHEDB_REDISHOST) } redis-server-port{COLON} { YDVAR(1, VAR_CACHEDB_REDISPORT) } redis-server-path{COLON} { YDVAR(1, VAR_CACHEDB_REDISPATH) } redis-server-password{COLON} { YDVAR(1, VAR_CACHEDB_REDISPASSWORD) } redis-timeout{COLON} { YDVAR(1, VAR_CACHEDB_REDISTIMEOUT) } redis-expire-records{COLON} { YDVAR(1, VAR_CACHEDB_REDISEXPIRERECORDS) } +redis-logical-db{COLON} { YDVAR(1, VAR_CACHEDB_REDISLOGICALDB) } ipset{COLON} { YDVAR(0, VAR_IPSET) } name-v4{COLON} { YDVAR(1, VAR_IPSET_NAME_V4) } name-v6{COLON} { YDVAR(1, VAR_IPSET_NAME_V6) } diff --git a/usr.sbin/unbound/util/configparser.y b/usr.sbin/unbound/util/configparser.y index d8f25a67e..da5d6608f 100644 --- a/usr.sbin/unbound/util/configparser.y +++ b/usr.sbin/unbound/util/configparser.y @@ -179,6 +179,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_CACHEDB VAR_CACHEDB_BACKEND VAR_CACHEDB_SECRETSEED %token VAR_CACHEDB_REDISHOST VAR_CACHEDB_REDISPORT VAR_CACHEDB_REDISTIMEOUT %token VAR_CACHEDB_REDISEXPIRERECORDS VAR_CACHEDB_REDISPATH VAR_CACHEDB_REDISPASSWORD +%token VAR_CACHEDB_REDISLOGICALDB %token VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM VAR_FOR_UPSTREAM %token VAR_AUTH_ZONE VAR_ZONEFILE VAR_MASTER VAR_URL VAR_FOR_DOWNSTREAM %token VAR_FALLBACK_ENABLED VAR_TLS_ADDITIONAL_PORT VAR_LOW_RTT VAR_LOW_RTT_PERMIL @@ -198,7 +199,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_INTERFACE_ACTION VAR_INTERFACE_VIEW VAR_INTERFACE_TAG %token VAR_INTERFACE_TAG_ACTION VAR_INTERFACE_TAG_DATA %token VAR_PROXY_PROTOCOL_PORT VAR_STATISTICS_INHIBIT_ZERO -%token VAR_HARDEN_UNKNOWN_ADDITIONAL +%token VAR_HARDEN_UNKNOWN_ADDITIONAL VAR_DISABLE_EDNS_DO VAR_CACHEDB_NO_STORE %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -332,7 +333,7 @@ content_server: server_num_threads | server_verbosity | server_port | server_tcp_reuse_timeout | server_tcp_auth_query_timeout | server_interface_automatic_ports | server_ede | server_proxy_protocol_port | server_statistics_inhibit_zero | - server_harden_unknown_additional + server_harden_unknown_additional | server_disable_edns_do ; stubstart: VAR_STUB_ZONE { @@ -2060,6 +2061,15 @@ server_ignore_cd_flag: VAR_IGNORE_CD_FLAG STRING_ARG free($2); } ; +server_disable_edns_do: VAR_DISABLE_EDNS_DO STRING_ARG + { + OUTYY(("P(server_disable_edns_do:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->disable_edns_do = (strcmp($2, "yes")==0); + free($2); + } + ; server_serve_expired: VAR_SERVE_EXPIRED STRING_ARG { OUTYY(("P(server_serve_expired:%s)\n", $2)); @@ -3701,7 +3711,8 @@ contents_cachedb: contents_cachedb content_cachedb | ; content_cachedb: cachedb_backend_name | cachedb_secret_seed | redis_server_host | redis_server_port | redis_timeout | - redis_expire_records | redis_server_path | redis_server_password + redis_expire_records | redis_server_path | redis_server_password | + cachedb_no_store | redis_logical_db ; cachedb_backend_name: VAR_CACHEDB_BACKEND STRING_ARG { @@ -3727,6 +3738,19 @@ cachedb_secret_seed: VAR_CACHEDB_SECRETSEED STRING_ARG #endif } ; +cachedb_no_store: VAR_CACHEDB_NO_STORE STRING_ARG + { + #ifdef USE_CACHEDB + OUTYY(("P(cachedb_no_store:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->cachedb_no_store = (strcmp($2, "yes")==0); + #else + OUTYY(("P(Compiled without cachedb, ignoring)\n")); + #endif + free($2); + } + ; redis_server_host: VAR_CACHEDB_REDISHOST STRING_ARG { #if defined(USE_CACHEDB) && defined(USE_REDIS) @@ -3804,6 +3828,21 @@ redis_expire_records: VAR_CACHEDB_REDISEXPIRERECORDS STRING_ARG free($2); } ; +redis_logical_db: VAR_CACHEDB_REDISLOGICALDB STRING_ARG + { + #if defined(USE_CACHEDB) && defined(USE_REDIS) + int db; + OUTYY(("P(redis_logical_db:%s)\n", $2)); + db = atoi($2); + if((db == 0 && strcmp($2, "0") != 0) || db < 0) + yyerror("valid redis logical database index expected"); + else cfg_parser->cfg->redis_logical_db = db; + #else + OUTYY(("P(Compiled without cachedb or redis, ignoring)\n")); + #endif + free($2); + } + ; server_tcp_connection_limit: VAR_TCP_CONNECTION_LIMIT STRING_ARG STRING_ARG { OUTYY(("P(server_tcp_connection_limit:%s %s)\n", $2, $3)); diff --git a/usr.sbin/unbound/util/data/msgencode.c b/usr.sbin/unbound/util/data/msgencode.c index db70edf2d..2cbc5fc5e 100644 --- a/usr.sbin/unbound/util/data/msgencode.c +++ b/usr.sbin/unbound/util/data/msgencode.c @@ -1015,8 +1015,10 @@ reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep, ede_size = calc_ede_option_size(edns, &ede_txt_size); if(sldns_buffer_capacity(pkt) < udpsize) udpsize = sldns_buffer_capacity(pkt); + if(!edns || !edns->edns_present) { + attach_edns = 0; /* EDEs are optional, try to fit anything else before them */ - if(udpsize < LDNS_HEADER_SIZE + edns_field_size - ede_size) { + } else if(udpsize < LDNS_HEADER_SIZE + edns_field_size - ede_size) { /* packet too small to contain edns, omit it. */ attach_edns = 0; } else { diff --git a/usr.sbin/unbound/util/data/msgparse.c b/usr.sbin/unbound/util/data/msgparse.c index 880cf89ae..037a673e8 100644 --- a/usr.sbin/unbound/util/data/msgparse.c +++ b/usr.sbin/unbound/util/data/msgparse.c @@ -47,6 +47,7 @@ #include "util/regional.h" #include "util/rfc_1982.h" #include "util/edns.h" +#include "util/net_help.h" #include "sldns/rrdef.h" #include "sldns/sbuffer.h" #include "sldns/parseutil.h" @@ -1306,3 +1307,27 @@ log_edns_opt_list(enum verbosity_value level, const char* info_str, } } +/** remove RR from msgparse RRset, return true if rrset is entirely bad */ +int +msgparse_rrset_remove_rr(const char* str, sldns_buffer* pkt, struct rrset_parse* rrset, + struct rr_parse* prev, struct rr_parse* rr, struct sockaddr_storage* addr, socklen_t addrlen) +{ + if(verbosity >= VERB_QUERY && rrset->dname_len <= LDNS_MAX_DOMAINLEN && str) { + uint8_t buf[LDNS_MAX_DOMAINLEN+1]; + dname_pkt_copy(pkt, buf, rrset->dname); + if(addr) + log_name_addr(VERB_QUERY, str, buf, addr, addrlen); + else log_nametypeclass(VERB_QUERY, str, buf, + rrset->type, ntohs(rrset->rrset_class)); + } + if(prev) + prev->next = rr->next; + else rrset->rr_first = rr->next; + if(rrset->rr_last == rr) + rrset->rr_last = prev; + rrset->rr_count --; + rrset->size -= rr->size; + /* rr struct still exists, but is unlinked, so that in the for loop + * the rr->next works fine to continue. */ + return rrset->rr_count == 0; +} diff --git a/usr.sbin/unbound/util/data/msgparse.h b/usr.sbin/unbound/util/data/msgparse.h index 1f2f825b2..85f106ed2 100644 --- a/usr.sbin/unbound/util/data/msgparse.h +++ b/usr.sbin/unbound/util/data/msgparse.h @@ -371,4 +371,22 @@ void msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset); void log_edns_opt_list(enum verbosity_value level, const char* info_str, struct edns_option* list); +/** + * Remove RR from msgparse RRset. + * @param str: this string is used for logging if verbose. If NULL, there is + * no logging of the remove. + * @param pkt: packet in buffer that is removed from. Used to log the name + * of the item removed. + * @param rrset: RRset that the RR is removed from. + * @param prev: previous RR in list, or NULL. + * @param rr: RR that is removed. + * @param addr: address used for logging, if verbose, or NULL then it is not + * used. + * @param addrlen: length of addr, if that is not NULL. + * @return true if rrset is entirely bad, it would then need to be removed. + */ +int msgparse_rrset_remove_rr(const char* str, struct sldns_buffer* pkt, + struct rrset_parse* rrset, struct rr_parse* prev, struct rr_parse* rr, + struct sockaddr_storage* addr, socklen_t addrlen); + #endif /* UTIL_DATA_MSGPARSE_H */ diff --git a/usr.sbin/unbound/util/fptr_wlist.c b/usr.sbin/unbound/util/fptr_wlist.c index 6c94d00fd..261acf7cb 100644 --- a/usr.sbin/unbound/util/fptr_wlist.c +++ b/usr.sbin/unbound/util/fptr_wlist.c @@ -169,7 +169,9 @@ int fptr_whitelist_event(void (*fptr)(int, short, void *)) { if(fptr == &comm_point_udp_callback) return 1; +#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) else if(fptr == &comm_point_udp_ancil_callback) return 1; +#endif else if(fptr == &comm_point_tcp_accept_callback) return 1; else if(fptr == &comm_point_tcp_handle_callback) return 1; else if(fptr == &comm_timer_callback) return 1; diff --git a/usr.sbin/unbound/util/log.c b/usr.sbin/unbound/util/log.c index 1360df52f..a25632bb7 100644 --- a/usr.sbin/unbound/util/log.c +++ b/usr.sbin/unbound/util/log.c @@ -187,7 +187,7 @@ void log_ident_set_default(const char* id) default_ident = id; } -void log_ident_revert_to_default() +void log_ident_revert_to_default(void) { ident = default_ident; } diff --git a/usr.sbin/unbound/util/module.c b/usr.sbin/unbound/util/module.c index 86ab24a07..428651b2b 100644 --- a/usr.sbin/unbound/util/module.c +++ b/usr.sbin/unbound/util/module.c @@ -194,6 +194,24 @@ char* errinf_to_str_servfail(struct module_qstate* qstate) return p; } +char* errinf_to_str_misc(struct module_qstate* qstate) +{ + char buf[20480]; + char* p = buf; + size_t left = sizeof(buf); + struct errinf_strlist* s; + if(!qstate->errinf) + snprintf(p, left, "misc failure"); + else for(s=qstate->errinf; s; s=s->next) { + snprintf(p, left, "%s%s", (s==qstate->errinf?"":" "), s->str); + left -= strlen(p); p += strlen(p); + } + p = strdup(buf); + if(!p) + log_err("malloc failure in errinf_to_str"); + return p; +} + void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr) { char buf[1024]; diff --git a/usr.sbin/unbound/util/module.h b/usr.sbin/unbound/util/module.h index f8e7e762b..b07597c3f 100644 --- a/usr.sbin/unbound/util/module.h +++ b/usr.sbin/unbound/util/module.h @@ -691,6 +691,8 @@ struct module_qstate { struct respip_action_info* respip_action_info; /** if the query is rpz passthru, no further rpz processing for it */ int rpz_passthru; + /* Flag tcp required. */ + int tcp_required; /** whether the reply should be dropped */ int is_drop; @@ -842,6 +844,14 @@ sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate); */ char* errinf_to_str_servfail(struct module_qstate* qstate); +/** + * Create error info in string. For misc failures that are not servfail. + * @param qstate: query state. + * @return string or NULL on malloc failure (already logged). + * This string is malloced and has to be freed by caller. + */ +char* errinf_to_str_misc(struct module_qstate* qstate); + /** * Initialize the edns known options by allocating the required space. * @param env: the module environment. diff --git a/usr.sbin/unbound/util/net_help.c b/usr.sbin/unbound/util/net_help.c index b0cb90464..b2bf97614 100644 --- a/usr.sbin/unbound/util/net_help.c +++ b/usr.sbin/unbound/util/net_help.c @@ -952,6 +952,111 @@ void log_crypto_err_code(const char* str, unsigned long err) #endif /* HAVE_SSL */ } +#ifdef HAVE_SSL +/** Print crypt erro with SSL_get_error want code and err_get_error code */ +static void log_crypto_err_io_code_arg(const char* str, int r, + unsigned long err, int err_present) +{ + int print_errno = 0, print_crypto_err = 0; + const char* inf = NULL; + + switch(r) { + case SSL_ERROR_NONE: + inf = "no error"; + break; + case SSL_ERROR_ZERO_RETURN: + inf = "channel closed"; + break; + case SSL_ERROR_WANT_READ: + inf = "want read"; + break; + case SSL_ERROR_WANT_WRITE: + inf = "want write"; + break; + case SSL_ERROR_WANT_CONNECT: + inf = "want connect"; + break; + case SSL_ERROR_WANT_ACCEPT: + inf = "want accept"; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + inf = "want X509 lookup"; + break; +#ifdef SSL_ERROR_WANT_ASYNC + case SSL_ERROR_WANT_ASYNC: + inf = "want async"; + break; +#endif +#ifdef SSL_ERROR_WANT_ASYNC_JOB + case SSL_ERROR_WANT_ASYNC_JOB: + inf = "want async job"; + break; +#endif +#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB + case SSL_ERROR_WANT_CLIENT_HELLO_CB: + inf = "want client hello cb"; + break; +#endif + case SSL_ERROR_SYSCALL: + print_errno = 1; + inf = "syscall"; + break; + case SSL_ERROR_SSL: + print_crypto_err = 1; + inf = "SSL, usually protocol, error"; + break; + default: + inf = "unknown SSL_get_error result code"; + print_errno = 1; + print_crypto_err = 1; + } + if(print_crypto_err) { + if(print_errno) { + char buf[1024]; + snprintf(buf, sizeof(buf), "%s with errno %s", + str, strerror(errno)); + if(err_present) + log_crypto_err_code(buf, err); + else log_crypto_err(buf); + } else { + if(err_present) + log_crypto_err_code(str, err); + else log_crypto_err(str); + } + } else { + if(print_errno) { + if(errno == 0) + log_err("str: syscall error with errno %s", + strerror(errno)); + else log_err("str: %s", strerror(errno)); + } else { + log_err("str: %s", inf); + } + } +} +#endif /* HAVE_SSL */ + +void log_crypto_err_io(const char* str, int r) +{ +#ifdef HAVE_SSL + log_crypto_err_io_code_arg(str, r, 0, 0); +#else + (void)str; + (void)r; +#endif /* HAVE_SSL */ +} + +void log_crypto_err_io_code(const char* str, int r, unsigned long err) +{ +#ifdef HAVE_SSL + log_crypto_err_io_code_arg(str, r, err, 1); +#else + (void)str; + (void)r; + (void)err; +#endif /* HAVE_SSL */ +} + #ifdef HAVE_SSL /** log certificate details */ void diff --git a/usr.sbin/unbound/util/net_help.h b/usr.sbin/unbound/util/net_help.h index 78f639da2..a253c1923 100644 --- a/usr.sbin/unbound/util/net_help.h +++ b/usr.sbin/unbound/util/net_help.h @@ -429,6 +429,24 @@ void log_crypto_err(const char* str); */ void log_crypto_err_code(const char* str, unsigned long err); +/** + * Log an error from libcrypto that came from SSL_write and so on, with + * a value from SSL_get_error, calls log_err. If that fails it logs with + * log_crypto_err. + * @param str: what failed + * @param r: output of SSL_get_error on the I/O operation result. + */ +void log_crypto_err_io(const char* str, int r); + +/** + * Log an error from libcrypt that came from an I/O routine with the + * errcode from ERR_get_error. Calls log_err() and log_crypto_err_code. + * @param str: what failed + * @param r: output of SSL_get_error on the I/O operation result. + * @param err: error code from ERR_get_error + */ +void log_crypto_err_io_code(const char* str, int r, unsigned long err); + /** * Log certificate details verbosity, string, of X509 cert * @param level: verbosity level diff --git a/usr.sbin/unbound/util/netevent.c b/usr.sbin/unbound/util/netevent.c index b9395a899..141e48d48 100644 --- a/usr.sbin/unbound/util/netevent.c +++ b/usr.sbin/unbound/util/netevent.c @@ -892,15 +892,18 @@ static int udp_recv_needs_log(int err) static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep, int stream) { size_t size; - struct pp2_header *header = pp2_read_header(buf); - if(header == NULL) return 0; + struct pp2_header *header; + int err = pp2_read_header(sldns_buffer_begin(buf), + sldns_buffer_remaining(buf)); + if(err) return 0; + header = (struct pp2_header*)sldns_buffer_begin(buf); size = PP2_HEADER_SIZE + ntohs(header->len); if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) { /* A connection from the proxy itself. * No need to do anything with addresses. */ goto done; } - if(header->fam_prot == 0x00) { + if(header->fam_prot == PP2_UNSPEC_UNSPEC) { /* Unspecified family and protocol. This could be used for * health checks by proxies. * No need to do anything with addresses. */ @@ -908,8 +911,8 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep, } /* Read the proxied address */ switch(header->fam_prot) { - case 0x11: /* AF_INET|STREAM */ - case 0x12: /* AF_INET|DGRAM */ + case PP2_INET_STREAM: + case PP2_INET_DGRAM: { struct sockaddr_in* addr = (struct sockaddr_in*)&rep->client_addr; @@ -920,8 +923,8 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep, } /* Ignore the destination address; it should be us. */ break; - case 0x21: /* AF_INET6|STREAM */ - case 0x22: /* AF_INET6|DGRAM */ + case PP2_INET6_STREAM: + case PP2_INET6_DGRAM: { struct sockaddr_in6* addr = (struct sockaddr_in6*)&rep->client_addr; @@ -934,6 +937,10 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep, } /* Ignore the destination address; it should be us. */ break; + default: + log_err("proxy_protocol: unsupported family and " + "protocol 0x%x", (int)header->fam_prot); + return 0; } rep->is_proxied = 1; done: @@ -948,10 +955,10 @@ done: return 1; } +#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) void comm_point_udp_ancil_callback(int fd, short event, void* arg) { -#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) struct comm_reply rep; struct msghdr msg; struct iovec iov[1]; @@ -1063,21 +1070,21 @@ comm_point_udp_ancil_callback(int fd, short event, void* arg) fptr_ok(fptr_whitelist_comm_point(rep.c->callback)); if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) { /* send back immediate reply */ - (void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer, + struct sldns_buffer *buffer; +#ifdef USE_DNSCRYPT + buffer = rep.c->dnscrypt_buffer; +#else + buffer = rep.c->buffer; +#endif + (void)comm_point_send_udp_msg_if(rep.c, buffer, (struct sockaddr*)&rep.remote_addr, rep.remote_addrlen, &rep); } if(!rep.c || rep.c->fd == -1) /* commpoint closed */ break; } -#else - (void)fd; - (void)event; - (void)arg; - fatal_exit("recvmsg: No support for IPV6_PKTINFO; IP_PKTINFO or IP_RECVDSTADDR. " - "Please disable interface-automatic"); -#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */ } +#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */ void comm_point_udp_callback(int fd, short event, void* arg) @@ -1665,7 +1672,8 @@ ssl_handshake(struct comm_point* c) } else { unsigned long err = ERR_get_error(); if(!squelch_err_ssl_handshake(err)) { - log_crypto_err_code("ssl handshake failed", err); + log_crypto_err_io_code("ssl handshake failed", + want, err); log_addr(VERB_OPS, "ssl handshake failed", &c->repinfo.remote_addr, c->repinfo.remote_addrlen); @@ -1815,23 +1823,30 @@ ssl_handle_read(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", + want); return 0; } c->tcp_byte_count += r; + sldns_buffer_skip(c->buffer, r); if(c->tcp_byte_count != current_read_size) return 1; c->pp2_header_state = pp2_header_init; } } if(c->pp2_header_state == pp2_header_init) { - header = pp2_read_header(c->buffer); - if(!header) { + int err; + err = pp2_read_header( + sldns_buffer_begin(c->buffer), + sldns_buffer_limit(c->buffer)); + if(err) { log_err("proxy_protocol: could not parse " - "PROXYv2 header"); + "PROXYv2 header (%s)", + pp_lookup_error(err)); return 0; } + header = (struct pp2_header*)sldns_buffer_begin(c->buffer); want_read_size = ntohs(header->len); - if(sldns_buffer_remaining(c->buffer) < + if(sldns_buffer_limit(c->buffer) < PP2_HEADER_SIZE + want_read_size) { log_err_addr("proxy_protocol: not enough " "buffer size to read PROXYv2 header", "", @@ -1876,10 +1891,12 @@ ssl_handle_read(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", + want); return 0; } c->tcp_byte_count += r; + sldns_buffer_skip(c->buffer, r); if(c->tcp_byte_count != current_read_size) return 1; c->pp2_header_state = pp2_header_done; } @@ -1890,6 +1907,7 @@ ssl_handle_read(struct comm_point* c) c->repinfo.remote_addrlen); return 0; } + sldns_buffer_flip(c->buffer); if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) { log_err_addr("proxy_protocol: could not consume " "PROXYv2 header", "", &c->repinfo.remote_addr, @@ -1934,7 +1952,7 @@ ssl_handle_read(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); return 0; } c->tcp_byte_count += r; @@ -1984,7 +2002,7 @@ ssl_handle_read(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); return 0; } sldns_buffer_skip(c->buffer, (ssize_t)r); @@ -2075,7 +2093,7 @@ ssl_handle_write(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", want); return 0; } if(c->tcp_write_and_read) { @@ -2127,7 +2145,7 @@ ssl_handle_write(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", want); return 0; } if(c->tcp_write_and_read) { @@ -2211,19 +2229,25 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) goto recv_error_initial; } c->tcp_byte_count += r; + sldns_buffer_skip(c->buffer, r); if(c->tcp_byte_count != current_read_size) return 1; c->pp2_header_state = pp2_header_init; } } if(c->pp2_header_state == pp2_header_init) { - header = pp2_read_header(c->buffer); - if(!header) { + int err; + err = pp2_read_header( + sldns_buffer_begin(c->buffer), + sldns_buffer_limit(c->buffer)); + if(err) { log_err("proxy_protocol: could not parse " - "PROXYv2 header"); + "PROXYv2 header (%s)", + pp_lookup_error(err)); return 0; } + header = (struct pp2_header*)sldns_buffer_begin(c->buffer); want_read_size = ntohs(header->len); - if(sldns_buffer_remaining(c->buffer) < + if(sldns_buffer_limit(c->buffer) < PP2_HEADER_SIZE + want_read_size) { log_err_addr("proxy_protocol: not enough " "buffer size to read PROXYv2 header", "", @@ -2250,6 +2274,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) goto recv_error; } c->tcp_byte_count += r; + sldns_buffer_skip(c->buffer, r); if(c->tcp_byte_count != current_read_size) return 1; c->pp2_header_state = pp2_header_done; } @@ -2260,6 +2285,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) c->repinfo.remote_addrlen); return 0; } + sldns_buffer_flip(c->buffer); if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) { log_err_addr("proxy_protocol: could not consume " "PROXYv2 header", "", &c->repinfo.remote_addr, @@ -2913,7 +2939,7 @@ ssl_http_read_more(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); return 0; } verbose(VERB_ALGO, "ssl http read more skip to %d + %d", @@ -3364,7 +3390,7 @@ ssize_t http2_recv_cb(nghttp2_session* ATTR_UNUSED(session), uint8_t* buf, strerror(errno)); return NGHTTP2_ERR_CALLBACK_FAILURE; } - log_crypto_err("could not SSL_read"); + log_crypto_err_io("could not SSL_read", want); return NGHTTP2_ERR_CALLBACK_FAILURE; } return r; @@ -3619,7 +3645,7 @@ ssl_http_write_more(struct comm_point* c) strerror(errno)); return 0; } - log_crypto_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", want); return 0; } sldns_buffer_skip(c->buffer, (ssize_t)r); @@ -3692,7 +3718,7 @@ ssize_t http2_send_cb(nghttp2_session* ATTR_UNUSED(session), const uint8_t* buf, strerror(errno)); return NGHTTP2_ERR_CALLBACK_FAILURE; } - log_crypto_err("could not SSL_write"); + log_crypto_err_io("could not SSL_write", want); return NGHTTP2_ERR_CALLBACK_FAILURE; } return r; @@ -3958,11 +3984,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, evbits = UB_EV_READ | UB_EV_PERSIST; /* ub_event stuff */ c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, -#ifdef USE_WINSOCK comm_point_udp_callback, c); -#else - comm_point_udp_ancil_callback, c); -#endif if(c->ev->ev == NULL) { log_err("could not baseset udp event"); comm_point_delete(c); @@ -3977,6 +3999,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, return c; } +#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) struct comm_point* comm_point_create_udp_ancil(struct comm_base *base, int fd, sldns_buffer* buffer, int pp2_enabled, @@ -4039,6 +4062,7 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd, c->event_added = 1; return c; } +#endif static struct comm_point* comm_point_create_tcp_handler(struct comm_base *base, diff --git a/usr.sbin/unbound/util/proxy_protocol.c b/usr.sbin/unbound/util/proxy_protocol.c index 13270ba40..08c4be7d7 100644 --- a/usr.sbin/unbound/util/proxy_protocol.c +++ b/usr.sbin/unbound/util/proxy_protocol.c @@ -38,102 +38,162 @@ * * This file contains PROXY protocol functions. */ -#include "config.h" -#include "util/log.h" #include "util/proxy_protocol.h" -int -pp2_write_to_buf(struct sldns_buffer* buf, struct sockaddr_storage* src, +/** + * Internal struct initialized with function pointers for writing uint16 and + * uint32. + */ +struct proxy_protocol_data { + void (*write_uint16)(void* buf, uint16_t data); + void (*write_uint32)(void* buf, uint32_t data); +}; +struct proxy_protocol_data pp_data; + +/** + * Internal lookup table; could be further generic like sldns_lookup_table + * for all the future generic stuff. + */ +struct proxy_protocol_lookup_table { + int id; + const char *text; +}; + +/** + * Internal parsing error text; could be exposed with pp_lookup_error. + */ +static struct proxy_protocol_lookup_table pp_parse_errors_data[] = { + { PP_PARSE_NOERROR, "no parse error" }, + { PP_PARSE_SIZE, "not enough space for header" }, + { PP_PARSE_WRONG_HEADERv2, "could not match PROXYv2 header" }, + { PP_PARSE_UNKNOWN_CMD, "unknown command" }, + { PP_PARSE_UNKNOWN_FAM_PROT, "unknown family and protocol" }, +}; + +void +pp_init(void (*write_uint16)(void* buf, uint16_t data), + void (*write_uint32)(void* buf, uint32_t data)) { + pp_data.write_uint16 = write_uint16; + pp_data.write_uint32 = write_uint32; +} + +const char* +pp_lookup_error(enum pp_parse_errors error) { + return pp_parse_errors_data[error].text; +} + +size_t +pp2_write_to_buf(uint8_t* buf, size_t buflen, +#ifdef INET6 + struct sockaddr_storage* src, +#else + struct sockaddr_in* src, +#endif int stream) { int af; + size_t expected_size; if(!src) return 0; af = (int)((struct sockaddr_in*)src)->sin_family; - if(sldns_buffer_remaining(buf) < - PP2_HEADER_SIZE + (af==AF_INET?12:36)) { + expected_size = PP2_HEADER_SIZE + (af==AF_INET?12:36); + if(buflen < expected_size) { return 0; } /* sig */ - sldns_buffer_write(buf, PP2_SIG, PP2_SIG_LEN); + memcpy(buf, PP2_SIG, PP2_SIG_LEN); + buf += PP2_SIG_LEN; /* version and command */ - sldns_buffer_write_u8(buf, (PP2_VERSION << 4) | PP2_CMD_PROXY); - if(af==AF_INET) { + *buf = (PP2_VERSION << 4) | PP2_CMD_PROXY; + buf++; + switch(af) { + case AF_INET: /* family and protocol */ - sldns_buffer_write_u8(buf, - (PP2_AF_INET<<4) | - (stream?PP2_PROT_STREAM:PP2_PROT_DGRAM)); + *buf = (PP2_AF_INET<<4) | + (stream?PP2_PROT_STREAM:PP2_PROT_DGRAM); + buf++; /* length */ - sldns_buffer_write_u16(buf, 12); + (*pp_data.write_uint16)(buf, 12); + buf += 2; /* src addr */ - sldns_buffer_write(buf, + memcpy(buf, &((struct sockaddr_in*)src)->sin_addr.s_addr, 4); + buf += 4; /* dst addr */ - sldns_buffer_write_u32(buf, 0); + (*pp_data.write_uint32)(buf, 0); + buf += 4; /* src port */ - sldns_buffer_write(buf, + memcpy(buf, &((struct sockaddr_in*)src)->sin_port, 2); - /* dst port */ - sldns_buffer_write_u16(buf, 0); - } else { - /* family and protocol */ - sldns_buffer_write_u8(buf, - (PP2_AF_INET6<<4) | - (stream?PP2_PROT_STREAM:PP2_PROT_DGRAM)); - /* length */ - sldns_buffer_write_u16(buf, 36); - /* src addr */ - sldns_buffer_write(buf, - &((struct sockaddr_in6*)src)->sin6_addr, 16); + buf += 2; /* dst addr */ - sldns_buffer_set_at(buf, - sldns_buffer_position(buf), 0, 16); - sldns_buffer_skip(buf, 16); - /* src port */ - sldns_buffer_write(buf, - &((struct sockaddr_in6*)src)->sin6_port, 2); /* dst port */ - sldns_buffer_write_u16(buf, 0); + (*pp_data.write_uint16)(buf, 12); + break; +#ifdef INET6 + case AF_INET6: + /* family and protocol */ + *buf = (PP2_AF_INET6<<4) | + (stream?PP2_PROT_STREAM:PP2_PROT_DGRAM); + buf++; + /* length */ + (*pp_data.write_uint16)(buf, 36); + buf += 2; + /* src addr */ + memcpy(buf, + &((struct sockaddr_in6*)src)->sin6_addr, 16); + buf += 16; + /* dst addr */ + memset(buf, 0, 16); + buf += 16; + /* src port */ + memcpy(buf, &((struct sockaddr_in6*)src)->sin6_port, 2); + buf += 2; + /* dst port */ + (*pp_data.write_uint16)(buf, 0); + break; +#endif /* INET6 */ + case AF_UNIX: + /* fallthrough */ + default: + return 0; } - return 1; + return expected_size; } -struct pp2_header* -pp2_read_header(struct sldns_buffer* buf) +int +pp2_read_header(uint8_t* buf, size_t buflen) { size_t size; - struct pp2_header* header = (struct pp2_header*)sldns_buffer_begin(buf); + struct pp2_header* header = (struct pp2_header*)buf; /* Try to fail all the unsupported cases first. */ - if(sldns_buffer_remaining(buf) < PP2_HEADER_SIZE) { - log_err("proxy_protocol: not enough space for header"); - return NULL; + if(buflen < PP2_HEADER_SIZE) { + return PP_PARSE_SIZE; } /* Check for PROXYv2 header */ if(memcmp(header, PP2_SIG, PP2_SIG_LEN) != 0 || ((header->ver_cmd & 0xF0)>>4) != PP2_VERSION) { - log_err("proxy_protocol: could not match PROXYv2 header"); - return NULL; + return PP_PARSE_WRONG_HEADERv2; } /* Check the length */ size = PP2_HEADER_SIZE + ntohs(header->len); - if(sldns_buffer_remaining(buf) < size) { - log_err("proxy_protocol: not enough space for header"); - return NULL; + if(buflen < size) { + return PP_PARSE_SIZE; } /* Check for supported commands */ if((header->ver_cmd & 0xF) != PP2_CMD_LOCAL && (header->ver_cmd & 0xF) != PP2_CMD_PROXY) { - log_err("proxy_protocol: unsupported command"); - return NULL; + return PP_PARSE_UNKNOWN_CMD; } /* Check for supported family and protocol */ - if(header->fam_prot != 0x00 /* AF_UNSPEC|UNSPEC */ && - header->fam_prot != 0x11 /* AF_INET|STREAM */ && - header->fam_prot != 0x12 /* AF_INET|DGRAM */ && - header->fam_prot != 0x21 /* AF_INET6|STREAM */ && - header->fam_prot != 0x22 /* AF_INET6|DGRAM */) { - log_err("proxy_protocol: unsupported family and protocol"); - return NULL; + if(header->fam_prot != PP2_UNSPEC_UNSPEC && + header->fam_prot != PP2_INET_STREAM && + header->fam_prot != PP2_INET_DGRAM && + header->fam_prot != PP2_INET6_STREAM && + header->fam_prot != PP2_INET6_DGRAM && + header->fam_prot != PP2_UNIX_STREAM && + header->fam_prot != PP2_UNIX_DGRAM) { + return PP_PARSE_UNKNOWN_FAM_PROT; } /* We have a correct header */ - return header; + return PP_PARSE_NOERROR; } diff --git a/usr.sbin/unbound/util/proxy_protocol.h b/usr.sbin/unbound/util/proxy_protocol.h index 38addb290..e33ce20d4 100644 --- a/usr.sbin/unbound/util/proxy_protocol.h +++ b/usr.sbin/unbound/util/proxy_protocol.h @@ -42,7 +42,7 @@ #ifndef PROXY_PROTOCOL_H #define PROXY_PROTOCOL_H -#include "sldns/sbuffer.h" +#include "config.h" /** PROXYv2 minimum header size */ #define PP2_HEADER_SIZE 16 @@ -51,11 +51,11 @@ #define PP2_SIG "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A" #define PP2_SIG_LEN 12 -/** PROXYv2 version */ +/** PROXYv2 version (protocol value) */ #define PP2_VERSION 0x2 /** - * PROXYv2 command. + * PROXYv2 command (protocol value). */ enum pp2_command { PP2_CMD_LOCAL = 0x0, @@ -63,7 +63,7 @@ enum pp2_command { }; /** - * PROXYv2 address family. + * PROXYv2 address family (protocol value). */ enum pp2_af { PP2_AF_UNSPEC = 0x0, @@ -73,7 +73,7 @@ enum pp2_af { }; /** - * PROXYv2 protocol. + * PROXYv2 protocol (protocol value). */ enum pp2_protocol { PP2_PROT_UNSPEC = 0x0, @@ -81,6 +81,19 @@ enum pp2_protocol { PP2_PROT_DGRAM = 0x2 }; +/** + * Expected combinations of address family and protocol values used in checks. + */ +enum pp2_af_protocol_combination { + PP2_UNSPEC_UNSPEC = (PP2_AF_UNSPEC<<4)|PP2_PROT_UNSPEC, + PP2_INET_STREAM = (PP2_AF_INET<<4)|PP2_PROT_STREAM, + PP2_INET_DGRAM = (PP2_AF_INET<<4)|PP2_PROT_DGRAM, + PP2_INET6_STREAM = (PP2_AF_INET6<<4)|PP2_PROT_STREAM, + PP2_INET6_DGRAM = (PP2_AF_INET6<<4)|PP2_PROT_DGRAM, + PP2_UNIX_STREAM = (PP2_AF_UNIX<<4)|PP2_PROT_STREAM, + PP2_UNIX_DGRAM = (PP2_AF_UNIX<<4)|PP2_PROT_DGRAM +}; + /** * PROXYv2 header. */ @@ -109,23 +122,56 @@ struct pp2_header { } addr; }; +/** + * PROXY parse errors. + */ +enum pp_parse_errors { + PP_PARSE_NOERROR = 0, + PP_PARSE_SIZE, + PP_PARSE_WRONG_HEADERv2, + PP_PARSE_UNKNOWN_CMD, + PP_PARSE_UNKNOWN_FAM_PROT, +}; + +/** + * Initialize the internal proxy structure. + * @param write_uint16: pointer to a function that can write uint16. + * @param write_uint32: pointer to a function that can write uint32. + */ +void pp_init(void (*write_uint16)(void* buf, uint16_t data), + void (*write_uint32)(void* buf, uint32_t data)); + +/** + * Lookup the parsing error description. + * @param error: parsing error from pp2_read_header. + * @return the description. + */ +const char* pp_lookup_error(enum pp_parse_errors error); + /** * Write a PROXYv2 header at the current position of the buffer. - * @param buf: the buffer to write to. + * @param buf: pointer to the buffer to write data to. + * @param buflen: available size on the buffer. * @param src: the source address. * @param stream: if the protocol is stream or datagram. * @return 1 on success, 0 on failure. */ -int pp2_write_to_buf(struct sldns_buffer* buf, struct sockaddr_storage* src, +size_t pp2_write_to_buf(uint8_t* buf, size_t buflen, +#ifdef INET6 + struct sockaddr_storage* src, +#else + struct sockaddr_in* src, +#endif int stream); /** * Read a PROXYv2 header from the current position of the buffer. * It does initial validation and returns a pointer to the buffer position on * success. - * @param buf: the buffer to read from. - * @return the pointer to the buffer position on success, NULL on error. + * @param buf: pointer to the buffer data to read from. + * @param buflen: available size on the buffer. + * @return parsing error, 0 on success. */ -struct pp2_header* pp2_read_header(struct sldns_buffer* buf); +int pp2_read_header(uint8_t* buf, size_t buflen); #endif /* PROXY_PROTOCOL_H */ diff --git a/usr.sbin/unbound/util/rfc_1982.c b/usr.sbin/unbound/util/rfc_1982.c index c28deded6..cf64e21d0 100644 --- a/usr.sbin/unbound/util/rfc_1982.c +++ b/usr.sbin/unbound/util/rfc_1982.c @@ -39,6 +39,7 @@ * This file contains functions for RFC 1982 serial number arithmetic. */ #include "config.h" +#include "util/rfc_1982.h" int compare_1982(uint32_t a, uint32_t b) diff --git a/usr.sbin/unbound/util/siphash.c b/usr.sbin/unbound/util/siphash.c index 0e1b597d0..32797dff6 100644 --- a/usr.sbin/unbound/util/siphash.c +++ b/usr.sbin/unbound/util/siphash.c @@ -26,6 +26,11 @@ */ #include "config.h" +/** EDIT + * prevent warning from -Wmissing-prototypes + */ +#include "util/siphash.h" + /* default: SipHash-2-4 */ #define cROUNDS 2 #define dROUNDS 4 diff --git a/usr.sbin/unbound/validator/val_anchor.c b/usr.sbin/unbound/validator/val_anchor.c index 006c129f0..db9cb2328 100644 --- a/usr.sbin/unbound/validator/val_anchor.c +++ b/usr.sbin/unbound/validator/val_anchor.c @@ -1322,3 +1322,24 @@ anchor_has_keytag(struct val_anchors* anchors, uint8_t* name, int namelabs, free(taglist); return 0; } + +struct trust_anchor* +anchors_find_any_noninsecure(struct val_anchors* anchors) +{ + struct trust_anchor* ta, *next; + lock_basic_lock(&anchors->lock); + ta=(struct trust_anchor*)rbtree_first(anchors->tree); + while((rbnode_type*)ta != RBTREE_NULL) { + next = (struct trust_anchor*)rbtree_next(&ta->node); + lock_basic_lock(&ta->lock); + if(ta->numDS != 0 || ta->numDNSKEY != 0) { + /* not an insecurepoint */ + lock_basic_unlock(&anchors->lock); + return ta; + } + lock_basic_unlock(&ta->lock); + ta = next; + } + lock_basic_unlock(&anchors->lock); + return NULL; +} diff --git a/usr.sbin/unbound/validator/val_anchor.h b/usr.sbin/unbound/validator/val_anchor.h index e37f451e0..3331d56a6 100644 --- a/usr.sbin/unbound/validator/val_anchor.h +++ b/usr.sbin/unbound/validator/val_anchor.h @@ -240,4 +240,12 @@ size_t anchor_list_keytags(struct trust_anchor* ta, uint16_t* list, size_t num); int anchor_has_keytag(struct val_anchors* anchors, uint8_t* name, int namelabs, size_t namelen, uint16_t dclass, uint16_t keytag); +/** + * Find an anchor that is not an insecure point, if any, or there are no + * DNSSEC verification anchors if none. + * @param anchors: anchor storage + * @return trust anchor or NULL. It is locked. + */ +struct trust_anchor* anchors_find_any_noninsecure(struct val_anchors* anchors); + #endif /* VALIDATOR_VAL_ANCHOR_H */ diff --git a/usr.sbin/unbound/validator/validator.c b/usr.sbin/unbound/validator/validator.c index c0666b885..8d9b763cb 100644 --- a/usr.sbin/unbound/validator/validator.c +++ b/usr.sbin/unbound/validator/validator.c @@ -205,6 +205,17 @@ val_init(struct module_env* env, int id) log_err("validator: could not apply configuration settings."); return 0; } + if(env->cfg->disable_edns_do) { + struct trust_anchor* anchor = anchors_find_any_noninsecure( + env->anchors); + if(anchor) { + char b[LDNS_MAX_DOMAINLEN+2]; + dname_str(anchor->name, b); + log_warn("validator: disable-edns-do is enabled, but there is a trust anchor for '%s'. Since DNSSEC could not work, the disable-edns-do setting is turned off. Continuing without it.", b); + lock_basic_unlock(&anchor->lock); + env->cfg->disable_edns_do = 0; + } + } return 1; }