mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-10-20 15:21:31 +02:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f2d9229e7 | ||
|
|
3d429e7fed | ||
|
|
ed5b3b23b3 | ||
|
|
ed954b6c18 | ||
|
|
024730aca7 | ||
|
|
660bfddeba | ||
|
|
d4999d418c | ||
|
|
7994365385 |
@@ -0,0 +1,54 @@
|
||||
# Contributing to Unbound
|
||||
|
||||
This document offers guidelines on how to best contribute to Unbound, whether
|
||||
it being new features or correcting flaws or bugs.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project and everyone participating in it is governed by the [NLnet Labs
|
||||
Code of Conduct](https://www.nlnetlabs.nl/conduct/).
|
||||
By participating, you are expected to uphold this code.
|
||||
|
||||
## LLM Policy
|
||||
|
||||
Before contributing to this project, please be aware of the [NLnet Labs LLM Policy](https://www.nlnetlabs.nl/llm-policy).
|
||||
In a nutshell: we do not accept any LLM-generated contributions to
|
||||
code or documentation.
|
||||
|
||||
## Join the Community
|
||||
|
||||
We invite you to join the [NLnet Labs Commununity
|
||||
Forum](https://community.nlnetlabs.nl/) where Unbound has its own category.
|
||||
Please don't open a GitHub issue for a question.
|
||||
Instead, follow the discussion on the forum and ask questions there before you
|
||||
start sending patches.
|
||||
We prefer public discussions over private ones, so everyone in the community
|
||||
can participate and learn.
|
||||
|
||||
## License and copyright
|
||||
|
||||
When contributing with code, you agree to put your changes and new code under
|
||||
the same license Unbound is already using.
|
||||
When changing existing source code, do not alter the copyright of the original
|
||||
file(s).
|
||||
The copyright will still be owned by the original creator(s) or those who have
|
||||
been assigned copyright by the original author(s).
|
||||
|
||||
By submitting a patch to Unbound, you are assumed to have the right to the code
|
||||
and to be allowed by your employer or whatever to hand over that patch/code
|
||||
to us.
|
||||
We will credit you for your changes as far as possible, to give credit but also
|
||||
to keep a trace back to who made what changes.
|
||||
|
||||
## Sharing Your Changes
|
||||
|
||||
We would like you to submit a [pull request on
|
||||
GitHub](https://github.com/NLnetLabs/Unbound/pulls).
|
||||
Please note that you can create a draft pull request to indicate that you're
|
||||
still working on something but still share it with the maintainers to get some
|
||||
early feedback.
|
||||
|
||||
Once final, your change will be reviewed and discussed on GitHub.
|
||||
You will be expected to correct flaws pointed out and update accordingly.
|
||||
As a submitter of a change, you are the owner of that change until it has been
|
||||
merged.
|
||||
+1
-1
@@ -1077,7 +1077,7 @@ daemon_fork(struct daemon* daemon)
|
||||
daemon_setup_modules(daemon);
|
||||
|
||||
/* read auth zonefiles */
|
||||
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1,
|
||||
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1, 1,
|
||||
&daemon->use_rpz, daemon->env, &daemon->mods))
|
||||
fatal_exit("auth_zones could not be setup");
|
||||
|
||||
|
||||
+1
-1
@@ -5980,7 +5980,7 @@ fr_construct_from_config(struct fast_reload_thread* fr,
|
||||
fr_construct_clear(ct);
|
||||
return 0;
|
||||
}
|
||||
if(!auth_zones_apply_cfg(ct->auth_zones, newcfg, 1, &ct->use_rpz,
|
||||
if(!auth_zones_apply_cfg(ct->auth_zones, newcfg, 1, 1, &ct->use_rpz,
|
||||
fr->worker->daemon->env, &fr->worker->daemon->mods)) {
|
||||
fr_construct_clear(ct);
|
||||
return 0;
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
20 October 2026: Wouter
|
||||
- Merge #1534: unbound-checkconf reads config, but zonefiles
|
||||
are read with an option, '-a'. This speeds up the checkconf
|
||||
before server start in the presence of large zone files.
|
||||
And it is similar to how nsd-checkconf behaves.
|
||||
|
||||
20 October 2026: Yorgos
|
||||
- Add CONTRIBUTING.md, similar to other NLnet Labs projects.
|
||||
- Merge #1536: Better documentation and warning message for no
|
||||
configured trust anchors.
|
||||
|
||||
19 October 2026: Wouter
|
||||
- Merge #1528 from Ar-maan05: Fix NSEC at apex detection for
|
||||
short type bitmaps.
|
||||
|
||||
@@ -42,7 +42,7 @@ unbound-checkconf(8)
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
**unbound-checkconf** [``-hf``] [``-o option``] [cfgfile]
|
||||
**unbound-checkconf** [``-ahf``] [``-o option``] [cfgfile]
|
||||
|
||||
Description
|
||||
-----------
|
||||
@@ -54,6 +54,11 @@ The config file syntax is described in
|
||||
|
||||
The available options are:
|
||||
|
||||
.. option:: -a
|
||||
|
||||
Also read the zonefiles for auth-zones and RPZ.
|
||||
It checks if the syntax is okay of the zonefiles.
|
||||
|
||||
.. option:: -h
|
||||
|
||||
Show the version and commandline option help.
|
||||
|
||||
@@ -86,7 +86,7 @@ context_finalize(struct ub_ctx* ctx)
|
||||
return UB_NOMEM;
|
||||
if(!local_zones_apply_cfg(ctx->local_zones, cfg))
|
||||
return UB_INITFAIL;
|
||||
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz,
|
||||
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, 1, &is_rpz,
|
||||
ctx->env, &ctx->mods))
|
||||
return UB_INITFAIL;
|
||||
if(!(ctx->env->fwds = forwards_create()) ||
|
||||
|
||||
+47
-14
@@ -2350,7 +2350,7 @@ az_delete_deleted_zones(struct auth_zones* az)
|
||||
}
|
||||
|
||||
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
|
||||
int setup, int* is_rpz, struct module_env* env,
|
||||
int setup, int readauth, int* is_rpz, struct module_env* env,
|
||||
struct module_stack* mods)
|
||||
{
|
||||
struct config_auth* p;
|
||||
@@ -2367,8 +2367,10 @@ int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
|
||||
}
|
||||
}
|
||||
az_delete_deleted_zones(az);
|
||||
if(!auth_zones_read_zones(az, cfg, env, mods))
|
||||
return 0;
|
||||
if(readauth) {
|
||||
if(!auth_zones_read_zones(az, cfg, env, mods))
|
||||
return 0;
|
||||
}
|
||||
if(setup) {
|
||||
if(!auth_zones_setup_zones(az))
|
||||
return 0;
|
||||
@@ -5236,7 +5238,7 @@ apply_axfr(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
/** apply HTTP to zone in memory. z is locked. false on failure(mallocfail) */
|
||||
static int
|
||||
apply_http(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
struct sldns_buffer* scratch_buffer)
|
||||
struct sldns_buffer* scratch_buffer, char* etag)
|
||||
{
|
||||
/* parse data in chunks */
|
||||
/* parse RR's and read into memory. ignore $INCLUDE from the
|
||||
@@ -5332,7 +5334,11 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
pstate.lineno,
|
||||
sldns_buffer_begin(scratch_buffer));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (etag) {
|
||||
verbose(VERB_OPS, "etag %s stored", etag);
|
||||
strcpy(z->etag, etag);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -5490,7 +5496,7 @@ static int xfr_process_reacquire_locks(struct auth_xfer* xfr,
|
||||
* return false if it did not work */
|
||||
static int
|
||||
xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
|
||||
int* ixfr_fail)
|
||||
int* ixfr_fail, char *etag)
|
||||
{
|
||||
struct auth_zone* z;
|
||||
int zonemd_in_progress;
|
||||
@@ -5506,7 +5512,7 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
|
||||
|
||||
/* apply data */
|
||||
if(xfr->task_transfer->master->http) {
|
||||
if(!apply_http(xfr, z, env->scratch_buffer)) {
|
||||
if(!apply_http(xfr, z, env->scratch_buffer, etag)) {
|
||||
auth_zone_clear_data(z);
|
||||
lock_rw_unlock(&z->lock);
|
||||
verbose(VERB_ALGO, "http from %s: could not store data",
|
||||
@@ -5786,6 +5792,21 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env)
|
||||
xfr->task_transfer->start_time = *env->now_tv;
|
||||
|
||||
if(master->http) {
|
||||
char etag[128], *etag_str = NULL;
|
||||
struct auth_zone* z;
|
||||
/* Obtain locks and structures. */
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
if(!xfr_process_reacquire_locks(xfr, env, &z)) {
|
||||
/* The zone is gone, ignore xfr transfer. */
|
||||
return 1; /* Stop processing this xfr. */
|
||||
}
|
||||
/* Holding xfr and z locks. */
|
||||
|
||||
if(z && z->etag[0] && strlen(z->etag) < sizeof(etag)) {
|
||||
strlcpy(etag, z->etag, sizeof(etag));
|
||||
etag_str = etag;
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
/* perform http fetch */
|
||||
/* store http port number into sockaddr,
|
||||
* unless someone used unbound's host@port notation */
|
||||
@@ -5795,7 +5816,7 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env)
|
||||
xfr->task_transfer->cp = outnet_comm_point_for_http(
|
||||
env->outnet, auth_xfer_transfer_http_callback, xfr,
|
||||
&addr, addrlen, -1, master->ssl, master->host,
|
||||
master->file, env->cfg);
|
||||
master->file, env->cfg, etag_str);
|
||||
if(!xfr->task_transfer->cp) {
|
||||
char zname[LDNS_MAX_DOMAINLEN], as[256];
|
||||
dname_str(xfr->name, zname);
|
||||
@@ -6387,10 +6408,10 @@ xfer_link_data(sldns_buffer* pkt, struct auth_xfer* xfr)
|
||||
/** task transfer. the list of data is complete. process it and if failed
|
||||
* move to next master, if succeeded, end the task transfer */
|
||||
static void
|
||||
process_list_end_transfer(struct auth_xfer* xfr, struct module_env* env)
|
||||
process_list_end_transfer(struct auth_xfer* xfr, struct module_env* env, char* etag)
|
||||
{
|
||||
int ixfr_fail = 0;
|
||||
if(xfr_process_chunk_list(xfr, env, &ixfr_fail)) {
|
||||
if(xfr_process_chunk_list(xfr, env, &ixfr_fail, etag)) {
|
||||
/* it worked! */
|
||||
auth_chunks_delete(xfr->task_transfer);
|
||||
|
||||
@@ -6562,9 +6583,15 @@ auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err,
|
||||
}
|
||||
/* if the transfer is done now, disconnect and process the list */
|
||||
if(transferdone) {
|
||||
comm_point_delete(xfr->task_transfer->cp);
|
||||
/* Convey etag (captured on the comm_point) to auth zone,
|
||||
* if there was any */
|
||||
struct comm_point *cp;
|
||||
cp = xfr->task_transfer->cp;
|
||||
xfr->task_transfer->cp = NULL;
|
||||
process_list_end_transfer(xfr, env);
|
||||
process_list_end_transfer(xfr, env,
|
||||
( xfr->task_transfer->master->http && cp->etag[0]
|
||||
? cp->etag : NULL));
|
||||
comm_point_delete(cp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6646,11 +6673,17 @@ auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err,
|
||||
}
|
||||
/* if the transfer is done now, disconnect and process the list */
|
||||
if(err == NETEVENT_DONE) {
|
||||
/* Convey etag (captured on the comm_point) to auth zone,
|
||||
* if there was any */
|
||||
struct comm_point *cp;
|
||||
if(repinfo) repinfo->c = NULL; /* signal cp deleted to
|
||||
the routine calling this callback */
|
||||
comm_point_delete(xfr->task_transfer->cp);
|
||||
cp = xfr->task_transfer->cp;
|
||||
xfr->task_transfer->cp = NULL;
|
||||
process_list_end_transfer(xfr, env);
|
||||
process_list_end_transfer(xfr, env,
|
||||
( xfr->task_transfer->master->http && cp->etag[0]
|
||||
? cp->etag : NULL));
|
||||
comm_point_delete(cp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -125,6 +125,8 @@ struct auth_zone {
|
||||
int zone_expired;
|
||||
/** zone is a slave zone (it has masters) */
|
||||
int zone_is_slave;
|
||||
/** store etag */
|
||||
char etag[128];
|
||||
/** for downstream: this zone answers queries towards the downstream
|
||||
* clients */
|
||||
int for_downstream;
|
||||
@@ -514,13 +516,15 @@ struct auth_zones* auth_zones_create(void);
|
||||
* @param az: auth zones structure
|
||||
* @param cfg: config to apply.
|
||||
* @param setup: if true, also sets up values in the auth zones structure
|
||||
* @param readauth: if true, reads zone files. False to omit zone file read,
|
||||
* for use by checkconf.
|
||||
* @param is_rpz: set to 1 if at least one RPZ zone is configured.
|
||||
* @param env: environment for offline verification.
|
||||
* @param mods: modules in environment.
|
||||
* @return false on failure.
|
||||
*/
|
||||
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
|
||||
int setup, int* is_rpz, struct module_env* env,
|
||||
int setup, int readauth, int* is_rpz, struct module_env* env,
|
||||
struct module_stack* mods);
|
||||
|
||||
/** initial pick up of worker timeouts, ties events to worker event loop
|
||||
|
||||
@@ -3900,11 +3900,15 @@ setup_http_user_agent(sldns_buffer* buf, struct config_file* cfg)
|
||||
/** setup http request headers in buffer for sending query to destination */
|
||||
static int
|
||||
setup_http_request(sldns_buffer* buf, char* host, char* path,
|
||||
struct config_file* cfg)
|
||||
struct config_file* cfg, const char* etag)
|
||||
{
|
||||
sldns_buffer_clear(buf);
|
||||
sldns_buffer_printf(buf, "GET /%s HTTP/1.1\r\n", path);
|
||||
sldns_buffer_printf(buf, "Host: %s\r\n", host);
|
||||
if (etag) {
|
||||
verbose(VERB_OPS, "sending along ETag %s in http request", etag);
|
||||
sldns_buffer_printf(buf, "If-None-Match: %s\r\n", etag);
|
||||
}
|
||||
setup_http_user_agent(buf, cfg);
|
||||
/* We do not really do multiple queries per connection,
|
||||
* but this header setting is also not needed.
|
||||
@@ -3921,7 +3925,7 @@ struct comm_point*
|
||||
outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
comm_point_callback_type* cb, void* cb_arg,
|
||||
struct sockaddr_storage* to_addr, socklen_t to_addrlen, int timeout,
|
||||
int ssl, char* host, char* path, struct config_file* cfg)
|
||||
int ssl, char* host, char* path, struct config_file* cfg, char* etag)
|
||||
{
|
||||
/* cp calls cb with err=NETEVENT_DONE when transfer is done */
|
||||
struct comm_point* cp;
|
||||
@@ -3959,7 +3963,7 @@ outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
comm_point_start_listening(cp, fd, timeout);
|
||||
|
||||
/* setup http request in cp->buffer */
|
||||
if(!setup_http_request(cp->buffer, host, path, cfg)) {
|
||||
if(!setup_http_request(cp->buffer, host, path, cfg, etag)) {
|
||||
log_err("error setting up http request");
|
||||
comm_point_delete(cp);
|
||||
return NULL;
|
||||
|
||||
@@ -854,7 +854,7 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet,
|
||||
struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
comm_point_callback_type* cb, void* cb_arg,
|
||||
struct sockaddr_storage* to_addr, socklen_t to_addrlen, int timeout,
|
||||
int ssl, char* host, char* path, struct config_file* cfg);
|
||||
int ssl, char* host, char* path, struct config_file* cfg, char* etag);
|
||||
|
||||
/** connect tcp connection to addr, 0 on failure */
|
||||
int outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen);
|
||||
|
||||
@@ -90,6 +90,7 @@ usage(void)
|
||||
printf("Usage: unbound-checkconf [file]\n");
|
||||
printf(" Checks unbound configuration file for errors.\n");
|
||||
printf("file if omitted %s is used.\n", CONFIGFILE);
|
||||
printf("-a read zone files of auth-zones and RPZ.\n");
|
||||
printf("-o option print value of option to stdout.\n");
|
||||
printf("-f output full pathname with chroot applied, eg. with -o pidfile.\n");
|
||||
printf("-q quiet (suppress output on success).\n");
|
||||
@@ -1166,11 +1167,12 @@ check_hints(struct config_file* cfg)
|
||||
|
||||
/** check auth zones */
|
||||
static void
|
||||
check_auth(struct config_file* cfg)
|
||||
check_auth(struct config_file* cfg, int readauth)
|
||||
{
|
||||
int is_rpz = 0;
|
||||
struct auth_zones* az = auth_zones_create();
|
||||
if(!az || !auth_zones_apply_cfg(az, cfg, 0, &is_rpz, NULL, NULL)) {
|
||||
if(!az || !auth_zones_apply_cfg(az, cfg, 0, readauth, &is_rpz, NULL,
|
||||
NULL)) {
|
||||
fatal_exit("Could not setup authority zones");
|
||||
}
|
||||
if(is_rpz && !strstr(cfg->module_conf, "respip"))
|
||||
@@ -1180,7 +1182,8 @@ check_auth(struct config_file* cfg)
|
||||
|
||||
/** check config file */
|
||||
static void
|
||||
checkconf(const char* cfgfile, const char* opt, int final, int quiet)
|
||||
checkconf(const char* cfgfile, const char* opt, int final, int quiet,
|
||||
int readauth)
|
||||
{
|
||||
char oldwd[4096];
|
||||
struct config_file* cfg = config_create();
|
||||
@@ -1212,7 +1215,7 @@ checkconf(const char* cfgfile, const char* opt, int final, int quiet)
|
||||
#endif
|
||||
check_fwd(cfg);
|
||||
check_hints(cfg);
|
||||
check_auth(cfg);
|
||||
check_auth(cfg, readauth);
|
||||
if(!quiet) { printf("unbound-checkconf: no errors in %s\n", cfgfile); }
|
||||
config_delete(cfg);
|
||||
}
|
||||
@@ -1228,6 +1231,7 @@ int main(int argc, char* argv[])
|
||||
int c;
|
||||
int final = 0;
|
||||
int quiet = 0;
|
||||
int readauth = 0;
|
||||
const char* f;
|
||||
const char* opt = NULL;
|
||||
const char* cfgfile = CONFIGFILE;
|
||||
@@ -1240,8 +1244,11 @@ int main(int argc, char* argv[])
|
||||
cfgfile = CONFIGFILE;
|
||||
#endif /* USE_WINSOCK */
|
||||
/* parse the options */
|
||||
while( (c=getopt(argc, argv, "fhqo:")) != -1) {
|
||||
while( (c=getopt(argc, argv, "afhqo:")) != -1) {
|
||||
switch(c) {
|
||||
case 'a':
|
||||
readauth = 1;
|
||||
break;
|
||||
case 'f':
|
||||
final = 1;
|
||||
break;
|
||||
@@ -1264,7 +1271,7 @@ int main(int argc, char* argv[])
|
||||
if(argc == 1)
|
||||
f = argv[0];
|
||||
else f = cfgfile;
|
||||
checkconf(f, opt, final, quiet);
|
||||
checkconf(f, opt, final, quiet, readauth);
|
||||
checklock_stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5037,6 +5037,10 @@ http_process_initial_header(struct comm_point* c)
|
||||
} else if(strncasecmp(line, "Transfer-Encoding: chunked", 19+7) == 0) {
|
||||
c->tcp_byte_count = 0;
|
||||
c->http_is_chunked = 1;
|
||||
} else if(strncasecmp(line, "ETag: ", 6) == 0) {
|
||||
if (strlen(line + 6) < sizeof(c->etag)) {
|
||||
strcpy(c->etag, line + 6);
|
||||
}
|
||||
} else if(line[0] == 0) {
|
||||
/* end of initial headers */
|
||||
c->http_in_headers = 0;
|
||||
@@ -6581,6 +6585,7 @@ comm_point_create_http_out(struct comm_base *base, size_t bufsize,
|
||||
c->http_in_chunk_headers = 0;
|
||||
c->http_is_chunked = 0;
|
||||
c->http_temp = temp;
|
||||
c->etag[0] = 0;
|
||||
#ifdef USE_MSG_FASTOPEN
|
||||
c->tcp_do_fastopen = 1;
|
||||
#endif
|
||||
|
||||
@@ -286,6 +286,8 @@ struct comm_point {
|
||||
struct sldns_buffer* http_temp;
|
||||
/** http stored content in buffer */
|
||||
size_t http_stored;
|
||||
/** http Entity-Tag */
|
||||
char etag[128];
|
||||
/* -------- HTTP/2 ------- */
|
||||
/** http2 session */
|
||||
struct http2_session* h2_session;
|
||||
|
||||
Reference in New Issue
Block a user