diff options
| author | Patrick Vogelaar <patrick.vogelaar@belden.com> | 2025-11-02 22:33:37 +0100 |
|---|---|---|
| committer | Anuj Mittal <anuj.mittal@oss.qualcomm.com> | 2025-11-12 11:14:56 +0530 |
| commit | d9c8972cb71a85ce6dfcfce55477937ea954b1ce (patch) | |
| tree | f3444f13c49b12040b29b00e4cd269dbd143927c | |
| parent | 4084b10111b49944cbe2b9464a5a002b32bcefd0 (diff) | |
| download | meta-openembedded-d9c8972cb71a85ce6dfcfce55477937ea954b1ce.tar.gz | |
unbound: patch CVE-2024-33655 and CVE-2025-11411
For CVE-2024-33655 applied patch [1] mentioned in [2].
For CVE-2025-11411 applied minimal patch [3] mentioned in [4]. (Slightly
adjustments were required to apply properly)
[1] https://nlnetlabs.nl/downloads/unbound/patch_CVE-2024-33655.diff
[2] https://www.nlnetlabs.nl/downloads/unbound/CVE-2024-33655.txt
[3] https://nlnetlabs.nl/downloads/unbound/patch_CVE-2025-11411.diff
[4] https://www.nlnetlabs.nl/downloads/unbound/CVE-2025-11411.txt
Signed-off-by: Patrick Vogelaar <patrick.vogelaar@belden.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
3 files changed, 842 insertions, 0 deletions
diff --git a/meta-networking/recipes-support/unbound/unbound/CVE-2024-33655.patch b/meta-networking/recipes-support/unbound/unbound/CVE-2024-33655.patch new file mode 100644 index 0000000000..9431b0e0c6 --- /dev/null +++ b/meta-networking/recipes-support/unbound/unbound/CVE-2024-33655.patch | |||
| @@ -0,0 +1,792 @@ | |||
| 1 | From e386c19bfb79e42910704b7f152693aa996a5da5 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Patrick Vogelaar <patrick.vogelaar@belden.com> | ||
| 3 | Date: Sun, 2 Nov 2025 21:23:18 +0100 | ||
| 4 | Subject: [PATCH] Fix CVE-2024-33655 (DNSBomb attack) | ||
| 5 | |||
| 6 | This fixes CVE-2024-33655 by applying a patch [1] listed in [2] | ||
| 7 | |||
| 8 | [1] https://nlnetlabs.nl/downloads/unbound/patch_CVE-2024-33655.diff | ||
| 9 | [2] https://www.nlnetlabs.nl/downloads/unbound/CVE-2024-33655.txt | ||
| 10 | |||
| 11 | CVE: CVE-2024-33655 | ||
| 12 | Upstream-Status: Backport [https://nlnetlabs.nl/downloads/unbound/patch_CVE-2024-33655.diff] | ||
| 13 | |||
| 14 | Signed-off-by: Patrick Vogelaar <patrick.vogelaar@belden.com> | ||
| 15 | --- | ||
| 16 | doc/example.conf.in | 15 ++ | ||
| 17 | doc/unbound.conf.5.in | 30 ++++ | ||
| 18 | services/cache/infra.c | 170 +++++++++++++++++- | ||
| 19 | services/cache/infra.h | 28 +++ | ||
| 20 | services/mesh.c | 65 +++++++ | ||
| 21 | .../doh_downstream.tdir/doh_downstream.conf | 1 + | ||
| 22 | .../doh_downstream_notls.conf | 1 + | ||
| 23 | .../doh_downstream_post.conf | 1 + | ||
| 24 | .../fwd_three_service.conf | 1 + | ||
| 25 | testdata/iter_ghost_timewindow.rpl | 1 + | ||
| 26 | .../ssl_req_order.tdir/ssl_req_order.conf | 1 + | ||
| 27 | .../tcp_req_order.tdir/tcp_req_order.conf | 1 + | ||
| 28 | testdata/tcp_sigpipe.tdir/tcp_sigpipe.conf | 3 +- | ||
| 29 | util/config_file.c | 15 ++ | ||
| 30 | util/config_file.h | 15 ++ | ||
| 31 | util/configlexer.lex | 5 + | ||
| 32 | util/configparser.y | 55 ++++++ | ||
| 33 | 17 files changed, 405 insertions(+), 3 deletions(-) | ||
| 34 | |||
| 35 | diff --git a/doc/example.conf.in b/doc/example.conf.in | ||
| 36 | index 1ac155b7..67047980 100644 | ||
| 37 | --- a/doc/example.conf.in | ||
| 38 | +++ b/doc/example.conf.in | ||
| 39 | @@ -191,6 +191,21 @@ server: | ||
| 40 | # are behind a slow satellite link, to eg. 1128. | ||
| 41 | # unknown-server-time-limit: 376 | ||
| 42 | |||
| 43 | + # msec before recursion replies are dropped. The work item continues. | ||
| 44 | + # discard-timeout: 1900 | ||
| 45 | + | ||
| 46 | + # Max number of replies waiting for recursion per IP address. | ||
| 47 | + # wait-limit: 1000 | ||
| 48 | + | ||
| 49 | + # Max replies waiting for recursion for IP address with cookie. | ||
| 50 | + # wait-limit-cookie: 10000 | ||
| 51 | + | ||
| 52 | + # Apart from the default, the wait limit can be set for a netblock. | ||
| 53 | + # wait-limit-netblock: 192.0.2.0/24 50000 | ||
| 54 | + | ||
| 55 | + # Apart from the default, the wait limit with cookie can be adjusted. | ||
| 56 | + # wait-limit-cookie-netblock: 192.0.2.0/24 50000 | ||
| 57 | + | ||
| 58 | # the amount of memory to use for the RRset cache. | ||
| 59 | # plain value in bytes or you can append k, m or G. default is "4Mb". | ||
| 60 | # rrset-cache-size: 4m | ||
| 61 | diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in | ||
| 62 | index 84eddd94..cc5fd64d 100644 | ||
| 63 | --- a/doc/unbound.conf.5.in | ||
| 64 | +++ b/doc/unbound.conf.5.in | ||
| 65 | @@ -302,6 +302,36 @@ Increase this if you are behind a slow satellite link, to eg. 1128. | ||
| 66 | That would then avoid re\-querying every initial query because it times out. | ||
| 67 | Default is 376 msec. | ||
| 68 | .TP | ||
| 69 | +.B discard\-timeout: \fI<msec> | ||
| 70 | +The wait time in msec where recursion requests are dropped. This is | ||
| 71 | +to stop a large number of replies from accumulating. They receive | ||
| 72 | +no reply, the work item continues to recurse. It is nice to be a bit | ||
| 73 | +larger than serve\-expired\-client\-timeout if that is enabled. | ||
| 74 | +A value of 1900 msec is suggested. The value 0 disables it. | ||
| 75 | +Default 1900 msec. | ||
| 76 | +.TP | ||
| 77 | +.B wait\-limit: \fI<number> | ||
| 78 | +The number of replies that can wait for recursion, for an IP address. | ||
| 79 | +This makes a ratelimit per IP address of waiting replies for recursion. | ||
| 80 | +It stops very large amounts of queries waiting to be returned to one | ||
| 81 | +destination. The value 0 disables wait limits. Default is 1000. | ||
| 82 | +.TP | ||
| 83 | +.B wait\-limit\-cookie: \fI<number> | ||
| 84 | +The number of replies that can wait for recursion, for an IP address | ||
| 85 | +that sent the query with a valid DNS cookie. Since the cookie validates | ||
| 86 | +the client address, the limit can be higher. Default is 10000. | ||
| 87 | +.TP | ||
| 88 | +.B wait\-limit\-netblock: \fI<netblock> <number> | ||
| 89 | +The wait limit for the netblock. If not given the wait\-limit value is | ||
| 90 | +used. The most specific netblock is used to determine the limit. Useful for | ||
| 91 | +overriding the default for a specific, group or individual, server. | ||
| 92 | +The value -1 disables wait limits for the netblock. | ||
| 93 | +.TP | ||
| 94 | +.B wait\-limit\-cookie\-netblock: \fI<netblock> <number> | ||
| 95 | +The wait limit for the netblock, when the query has a DNS cookie. | ||
| 96 | +If not given, the wait\-limit\-cookie value is used. | ||
| 97 | +The value -1 disables wait limits for the netblock. | ||
| 98 | +.TP | ||
| 99 | .B so\-rcvbuf: \fI<number> | ||
| 100 | If not 0, then set the SO_RCVBUF socket option to get more buffer | ||
| 101 | space on UDP port 53 incoming queries. So that short spikes on busy | ||
| 102 | diff --git a/services/cache/infra.c b/services/cache/infra.c | ||
| 103 | index 31462d13..457685ab 100644 | ||
| 104 | --- a/services/cache/infra.c | ||
| 105 | +++ b/services/cache/infra.c | ||
| 106 | @@ -234,6 +234,81 @@ setup_domain_limits(struct infra_cache* infra, struct config_file* cfg) | ||
| 107 | return 1; | ||
| 108 | } | ||
| 109 | |||
| 110 | +/** find or create element in wait limit netblock tree */ | ||
| 111 | +static struct wait_limit_netblock_info* | ||
| 112 | +wait_limit_netblock_findcreate(struct infra_cache* infra, char* str, | ||
| 113 | + int cookie) | ||
| 114 | +{ | ||
| 115 | + rbtree_type* tree; | ||
| 116 | + struct sockaddr_storage addr; | ||
| 117 | + int net; | ||
| 118 | + socklen_t addrlen; | ||
| 119 | + struct wait_limit_netblock_info* d; | ||
| 120 | + | ||
| 121 | + if(!netblockstrtoaddr(str, 0, &addr, &addrlen, &net)) { | ||
| 122 | + log_err("cannot parse wait limit netblock '%s'", str); | ||
| 123 | + return 0; | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + /* can we find it? */ | ||
| 127 | + if(cookie) | ||
| 128 | + tree = &infra->wait_limits_cookie_netblock; | ||
| 129 | + else | ||
| 130 | + tree = &infra->wait_limits_netblock; | ||
| 131 | + d = (struct wait_limit_netblock_info*)addr_tree_find(tree, &addr, | ||
| 132 | + addrlen, net); | ||
| 133 | + if(d) | ||
| 134 | + return d; | ||
| 135 | + | ||
| 136 | + /* create it */ | ||
| 137 | + d = (struct wait_limit_netblock_info*)calloc(1, sizeof(*d)); | ||
| 138 | + if(!d) | ||
| 139 | + return NULL; | ||
| 140 | + d->limit = -1; | ||
| 141 | + if(!addr_tree_insert(tree, &d->node, &addr, addrlen, net)) { | ||
| 142 | + log_err("duplicate element in domainlimit tree"); | ||
| 143 | + free(d); | ||
| 144 | + return NULL; | ||
| 145 | + } | ||
| 146 | + return d; | ||
| 147 | +} | ||
| 148 | + | ||
| 149 | + | ||
| 150 | +/** insert wait limit information into lookup tree */ | ||
| 151 | +static int | ||
| 152 | +infra_wait_limit_netblock_insert(struct infra_cache* infra, | ||
| 153 | + struct config_file* cfg) | ||
| 154 | +{ | ||
| 155 | + struct config_str2list* p; | ||
| 156 | + struct wait_limit_netblock_info* d; | ||
| 157 | + for(p = cfg->wait_limit_netblock; p; p = p->next) { | ||
| 158 | + d = wait_limit_netblock_findcreate(infra, p->str, 0); | ||
| 159 | + if(!d) | ||
| 160 | + return 0; | ||
| 161 | + d->limit = atoi(p->str2); | ||
| 162 | + } | ||
| 163 | + for(p = cfg->wait_limit_cookie_netblock; p; p = p->next) { | ||
| 164 | + d = wait_limit_netblock_findcreate(infra, p->str, 1); | ||
| 165 | + if(!d) | ||
| 166 | + return 0; | ||
| 167 | + d->limit = atoi(p->str2); | ||
| 168 | + } | ||
| 169 | + return 1; | ||
| 170 | +} | ||
| 171 | + | ||
| 172 | +/** setup wait limits tree (0 on failure) */ | ||
| 173 | +static int | ||
| 174 | +setup_wait_limits(struct infra_cache* infra, struct config_file* cfg) | ||
| 175 | +{ | ||
| 176 | + addr_tree_init(&infra->wait_limits_netblock); | ||
| 177 | + addr_tree_init(&infra->wait_limits_cookie_netblock); | ||
| 178 | + if(!infra_wait_limit_netblock_insert(infra, cfg)) | ||
| 179 | + return 0; | ||
| 180 | + addr_tree_init_parents(&infra->wait_limits_netblock); | ||
| 181 | + addr_tree_init_parents(&infra->wait_limits_cookie_netblock); | ||
| 182 | + return 1; | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | struct infra_cache* | ||
| 186 | infra_create(struct config_file* cfg) | ||
| 187 | { | ||
| 188 | @@ -267,6 +342,10 @@ infra_create(struct config_file* cfg) | ||
| 189 | infra_delete(infra); | ||
| 190 | return NULL; | ||
| 191 | } | ||
| 192 | + if(!setup_wait_limits(infra, cfg)) { | ||
| 193 | + infra_delete(infra); | ||
| 194 | + return NULL; | ||
| 195 | + } | ||
| 196 | infra_ip_ratelimit = cfg->ip_ratelimit; | ||
| 197 | infra->client_ip_rates = slabhash_create(cfg->ip_ratelimit_slabs, | ||
| 198 | INFRA_HOST_STARTSIZE, cfg->ip_ratelimit_size, &ip_rate_sizefunc, | ||
| 199 | @@ -287,6 +366,12 @@ static void domain_limit_free(rbnode_type* n, void* ATTR_UNUSED(arg)) | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | +/** delete wait_limit_netblock_info entries */ | ||
| 204 | +static void wait_limit_netblock_del(rbnode_type* n, void* ATTR_UNUSED(arg)) | ||
| 205 | +{ | ||
| 206 | + free(n); | ||
| 207 | +} | ||
| 208 | + | ||
| 209 | void | ||
| 210 | infra_delete(struct infra_cache* infra) | ||
| 211 | { | ||
| 212 | @@ -296,6 +381,10 @@ infra_delete(struct infra_cache* infra) | ||
| 213 | slabhash_delete(infra->domain_rates); | ||
| 214 | traverse_postorder(&infra->domain_limits, domain_limit_free, NULL); | ||
| 215 | slabhash_delete(infra->client_ip_rates); | ||
| 216 | + traverse_postorder(&infra->wait_limits_netblock, | ||
| 217 | + wait_limit_netblock_del, NULL); | ||
| 218 | + traverse_postorder(&infra->wait_limits_cookie_netblock, | ||
| 219 | + wait_limit_netblock_del, NULL); | ||
| 220 | free(infra); | ||
| 221 | } | ||
| 222 | |||
| 223 | @@ -880,7 +969,8 @@ static void infra_create_ratedata(struct infra_cache* infra, | ||
| 224 | |||
| 225 | /** create rate data item for ip address */ | ||
| 226 | static void infra_ip_create_ratedata(struct infra_cache* infra, | ||
| 227 | - struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow) | ||
| 228 | + struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow, | ||
| 229 | + int mesh_wait) | ||
| 230 | { | ||
| 231 | hashvalue_type h = hash_addr(addr, addrlen, 0); | ||
| 232 | struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k)); | ||
| 233 | @@ -898,6 +988,7 @@ static void infra_ip_create_ratedata(struct infra_cache* infra, | ||
| 234 | k->entry.data = d; | ||
| 235 | d->qps[0] = 1; | ||
| 236 | d->timestamp[0] = timenow; | ||
| 237 | + d->mesh_wait = mesh_wait; | ||
| 238 | slabhash_insert(infra->client_ip_rates, h, &k->entry, d, NULL); | ||
| 239 | } | ||
| 240 | |||
| 241 | @@ -1121,6 +1212,81 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra, | ||
| 242 | } | ||
| 243 | |||
| 244 | /* create */ | ||
| 245 | - infra_ip_create_ratedata(infra, addr, addrlen, timenow); | ||
| 246 | + infra_ip_create_ratedata(infra, addr, addrlen, timenow, 0); | ||
| 247 | return 1; | ||
| 248 | } | ||
| 249 | + | ||
| 250 | +int infra_wait_limit_allowed(struct infra_cache* infra, struct comm_reply* rep, | ||
| 251 | + int cookie_valid, struct config_file* cfg) | ||
| 252 | +{ | ||
| 253 | + struct lruhash_entry* entry; | ||
| 254 | + if(cfg->wait_limit == 0) | ||
| 255 | + return 1; | ||
| 256 | + | ||
| 257 | + entry = infra_find_ip_ratedata(infra, &rep->client_addr, | ||
| 258 | + rep->client_addrlen, 0); | ||
| 259 | + if(entry) { | ||
| 260 | + rbtree_type* tree; | ||
| 261 | + struct wait_limit_netblock_info* w; | ||
| 262 | + struct rate_data* d = (struct rate_data*)entry->data; | ||
| 263 | + int mesh_wait = d->mesh_wait; | ||
| 264 | + lock_rw_unlock(&entry->lock); | ||
| 265 | + | ||
| 266 | + /* have the wait amount, check how much is allowed */ | ||
| 267 | + if(cookie_valid) | ||
| 268 | + tree = &infra->wait_limits_cookie_netblock; | ||
| 269 | + else tree = &infra->wait_limits_netblock; | ||
| 270 | + w = (struct wait_limit_netblock_info*)addr_tree_lookup(tree, | ||
| 271 | + &rep->client_addr, rep->client_addrlen); | ||
| 272 | + if(w) { | ||
| 273 | + if(w->limit != -1 && mesh_wait > w->limit) | ||
| 274 | + return 0; | ||
| 275 | + } else { | ||
| 276 | + /* if there is no IP netblock specific information, | ||
| 277 | + * use the configured value. */ | ||
| 278 | + if(mesh_wait > (cookie_valid?cfg->wait_limit_cookie: | ||
| 279 | + cfg->wait_limit)) | ||
| 280 | + return 0; | ||
| 281 | + } | ||
| 282 | + } | ||
| 283 | + return 1; | ||
| 284 | +} | ||
| 285 | + | ||
| 286 | +void infra_wait_limit_inc(struct infra_cache* infra, struct comm_reply* rep, | ||
| 287 | + time_t timenow, struct config_file* cfg) | ||
| 288 | +{ | ||
| 289 | + struct lruhash_entry* entry; | ||
| 290 | + if(cfg->wait_limit == 0) | ||
| 291 | + return; | ||
| 292 | + | ||
| 293 | + /* Find it */ | ||
| 294 | + entry = infra_find_ip_ratedata(infra, &rep->client_addr, | ||
| 295 | + rep->client_addrlen, 1); | ||
| 296 | + if(entry) { | ||
| 297 | + struct rate_data* d = (struct rate_data*)entry->data; | ||
| 298 | + d->mesh_wait++; | ||
| 299 | + lock_rw_unlock(&entry->lock); | ||
| 300 | + return; | ||
| 301 | + } | ||
| 302 | + | ||
| 303 | + /* Create it */ | ||
| 304 | + infra_ip_create_ratedata(infra, &rep->client_addr, | ||
| 305 | + rep->client_addrlen, timenow, 1); | ||
| 306 | +} | ||
| 307 | + | ||
| 308 | +void infra_wait_limit_dec(struct infra_cache* infra, struct comm_reply* rep, | ||
| 309 | + struct config_file* cfg) | ||
| 310 | +{ | ||
| 311 | + struct lruhash_entry* entry; | ||
| 312 | + if(cfg->wait_limit == 0) | ||
| 313 | + return; | ||
| 314 | + | ||
| 315 | + entry = infra_find_ip_ratedata(infra, &rep->client_addr, | ||
| 316 | + rep->client_addrlen, 1); | ||
| 317 | + if(entry) { | ||
| 318 | + struct rate_data* d = (struct rate_data*)entry->data; | ||
| 319 | + if(d->mesh_wait > 0) | ||
| 320 | + d->mesh_wait--; | ||
| 321 | + lock_rw_unlock(&entry->lock); | ||
| 322 | + } | ||
| 323 | +} | ||
| 324 | diff --git a/services/cache/infra.h b/services/cache/infra.h | ||
| 325 | index 525073bf..ee6f384d 100644 | ||
| 326 | --- a/services/cache/infra.h | ||
| 327 | +++ b/services/cache/infra.h | ||
| 328 | @@ -122,6 +122,10 @@ struct infra_cache { | ||
| 329 | rbtree_type domain_limits; | ||
| 330 | /** hash table with query rates per client ip: ip_rate_key, ip_rate_data */ | ||
| 331 | struct slabhash* client_ip_rates; | ||
| 332 | + /** tree of addr_tree_node, with wait_limit_netblock_info information */ | ||
| 333 | + rbtree_type wait_limits_netblock; | ||
| 334 | + /** tree of addr_tree_node, with wait_limit_netblock_info information */ | ||
| 335 | + rbtree_type wait_limits_cookie_netblock; | ||
| 336 | }; | ||
| 337 | |||
| 338 | /** ratelimit, unless overridden by domain_limits, 0 is off */ | ||
| 339 | @@ -184,10 +188,22 @@ struct rate_data { | ||
| 340 | /** what the timestamp is of the qps array members, counter is | ||
| 341 | * valid for that timestamp. Usually now and now-1. */ | ||
| 342 | time_t timestamp[RATE_WINDOW]; | ||
| 343 | + /** the number of queries waiting in the mesh */ | ||
| 344 | + int mesh_wait; | ||
| 345 | }; | ||
| 346 | |||
| 347 | #define ip_rate_data rate_data | ||
| 348 | |||
| 349 | +/** | ||
| 350 | + * Data to store the configuration per netblock for the wait limit | ||
| 351 | + */ | ||
| 352 | +struct wait_limit_netblock_info { | ||
| 353 | + /** The addr tree node, this must be first. */ | ||
| 354 | + struct addr_tree_node node; | ||
| 355 | + /** the limit on the amount */ | ||
| 356 | + int limit; | ||
| 357 | +}; | ||
| 358 | + | ||
| 359 | /** infra host cache default hash lookup size */ | ||
| 360 | #define INFRA_HOST_STARTSIZE 32 | ||
| 361 | /** bytes per zonename reserved in the hostcache, dnamelen(zonename.com.) */ | ||
| 362 | @@ -474,4 +490,16 @@ void ip_rate_delkeyfunc(void* d, void* arg); | ||
| 363 | /* delete data */ | ||
| 364 | #define ip_rate_deldatafunc rate_deldatafunc | ||
| 365 | |||
| 366 | +/** See if the IP address can have another reply in the wait limit */ | ||
| 367 | +int infra_wait_limit_allowed(struct infra_cache* infra, struct comm_reply* rep, | ||
| 368 | + int cookie_valid, struct config_file* cfg); | ||
| 369 | + | ||
| 370 | +/** Increment number of waiting replies for IP */ | ||
| 371 | +void infra_wait_limit_inc(struct infra_cache* infra, struct comm_reply* rep, | ||
| 372 | + time_t timenow, struct config_file* cfg); | ||
| 373 | + | ||
| 374 | +/** Decrement number of waiting replies for IP */ | ||
| 375 | +void infra_wait_limit_dec(struct infra_cache* infra, struct comm_reply* rep, | ||
| 376 | + struct config_file* cfg); | ||
| 377 | + | ||
| 378 | #endif /* SERVICES_CACHE_INFRA_H */ | ||
| 379 | diff --git a/services/mesh.c b/services/mesh.c | ||
| 380 | index 47cfb042..2b06957d 100644 | ||
| 381 | --- a/services/mesh.c | ||
| 382 | +++ b/services/mesh.c | ||
| 383 | @@ -47,6 +47,7 @@ | ||
| 384 | #include "services/outbound_list.h" | ||
| 385 | #include "services/cache/dns.h" | ||
| 386 | #include "services/cache/rrset.h" | ||
| 387 | +#include "services/cache/infra.h" | ||
| 388 | #include "util/log.h" | ||
| 389 | #include "util/net_help.h" | ||
| 390 | #include "util/module.h" | ||
| 391 | @@ -415,6 +416,14 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, | ||
| 392 | if(rep->c->tcp_req_info) { | ||
| 393 | r_buffer = rep->c->tcp_req_info->spool_buffer; | ||
| 394 | } | ||
| 395 | + if(!infra_wait_limit_allowed(mesh->env->infra_cache, rep, | ||
| 396 | + edns->cookie_valid, mesh->env->cfg)) { | ||
| 397 | + verbose(VERB_ALGO, "Too many queries waiting from the IP. " | ||
| 398 | + "dropping incoming query."); | ||
| 399 | + comm_point_drop_reply(rep); | ||
| 400 | + mesh->stats_dropped++; | ||
| 401 | + return; | ||
| 402 | + } | ||
| 403 | if(!unique) | ||
| 404 | s = mesh_area_find(mesh, cinfo, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0); | ||
| 405 | /* does this create a new reply state? */ | ||
| 406 | @@ -511,6 +520,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, | ||
| 407 | log_err("mesh_new_client: out of memory initializing serve expired"); | ||
| 408 | goto servfail_mem; | ||
| 409 | } | ||
| 410 | + infra_wait_limit_inc(mesh->env->infra_cache, rep, *mesh->env->now, | ||
| 411 | + mesh->env->cfg); | ||
| 412 | /* update statistics */ | ||
| 413 | if(was_detached) { | ||
| 414 | log_assert(mesh->num_detached_states > 0); | ||
| 415 | @@ -930,6 +941,8 @@ mesh_state_cleanup(struct mesh_state* mstate) | ||
| 416 | * takes no time and also it does not do the mesh accounting */ | ||
| 417 | mstate->reply_list = NULL; | ||
| 418 | for(; rep; rep=rep->next) { | ||
| 419 | + infra_wait_limit_dec(mesh->env->infra_cache, | ||
| 420 | + &rep->query_reply, mesh->env->cfg); | ||
| 421 | comm_point_drop_reply(&rep->query_reply); | ||
| 422 | log_assert(mesh->num_reply_addrs > 0); | ||
| 423 | mesh->num_reply_addrs--; | ||
| 424 | @@ -1413,6 +1426,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, | ||
| 425 | comm_point_send_reply(&r->query_reply); | ||
| 426 | m->reply_list = rlist; | ||
| 427 | } | ||
| 428 | + infra_wait_limit_dec(m->s.env->infra_cache, &r->query_reply, | ||
| 429 | + m->s.env->cfg); | ||
| 430 | /* account */ | ||
| 431 | log_assert(m->s.env->mesh->num_reply_addrs > 0); | ||
| 432 | m->s.env->mesh->num_reply_addrs--; | ||
| 433 | @@ -1470,6 +1485,28 @@ void mesh_query_done(struct mesh_state* mstate) | ||
| 434 | } | ||
| 435 | } | ||
| 436 | for(r = mstate->reply_list; r; r = r->next) { | ||
| 437 | + struct timeval old; | ||
| 438 | + timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); | ||
| 439 | + if(mstate->s.env->cfg->discard_timeout != 0 && | ||
| 440 | + ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > | ||
| 441 | + mstate->s.env->cfg->discard_timeout) { | ||
| 442 | + /* Drop the reply, it is too old */ | ||
| 443 | + /* briefly set the reply_list to NULL, so that the | ||
| 444 | + * tcp req info cleanup routine that calls the mesh | ||
| 445 | + * to deregister the meshstate for it is not done | ||
| 446 | + * because the list is NULL and also accounting is not | ||
| 447 | + * done there, but instead we do that here. */ | ||
| 448 | + struct mesh_reply* reply_list = mstate->reply_list; | ||
| 449 | + verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); | ||
| 450 | + infra_wait_limit_dec(mstate->s.env->infra_cache, | ||
| 451 | + &r->query_reply, mstate->s.env->cfg); | ||
| 452 | + mstate->reply_list = NULL; | ||
| 453 | + comm_point_drop_reply(&r->query_reply); | ||
| 454 | + mstate->reply_list = reply_list; | ||
| 455 | + mstate->s.env->mesh->stats_dropped++; | ||
| 456 | + continue; | ||
| 457 | + } | ||
| 458 | + | ||
| 459 | i++; | ||
| 460 | tv = r->start_time; | ||
| 461 | |||
| 462 | @@ -1493,6 +1530,8 @@ void mesh_query_done(struct mesh_state* mstate) | ||
| 463 | * because the list is NULL and also accounting is not | ||
| 464 | * done there, but instead we do that here. */ | ||
| 465 | struct mesh_reply* reply_list = mstate->reply_list; | ||
| 466 | + infra_wait_limit_dec(mstate->s.env->infra_cache, | ||
| 467 | + &r->query_reply, mstate->s.env->cfg); | ||
| 468 | mstate->reply_list = NULL; | ||
| 469 | comm_point_drop_reply(&r->query_reply); | ||
| 470 | mstate->reply_list = reply_list; | ||
| 471 | @@ -2025,6 +2064,8 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m, | ||
| 472 | /* delete it, but allocated in m region */ | ||
| 473 | log_assert(mesh->num_reply_addrs > 0); | ||
| 474 | mesh->num_reply_addrs--; | ||
| 475 | + infra_wait_limit_dec(mesh->env->infra_cache, | ||
| 476 | + &n->query_reply, mesh->env->cfg); | ||
| 477 | |||
| 478 | /* prev = prev; */ | ||
| 479 | n = n->next; | ||
| 480 | @@ -2165,6 +2206,28 @@ mesh_serve_expired_callback(void* arg) | ||
| 481 | log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep); | ||
| 482 | |||
| 483 | for(r = mstate->reply_list; r; r = r->next) { | ||
| 484 | + struct timeval old; | ||
| 485 | + timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time); | ||
| 486 | + if(mstate->s.env->cfg->discard_timeout != 0 && | ||
| 487 | + ((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 > | ||
| 488 | + mstate->s.env->cfg->discard_timeout) { | ||
| 489 | + /* Drop the reply, it is too old */ | ||
| 490 | + /* briefly set the reply_list to NULL, so that the | ||
| 491 | + * tcp req info cleanup routine that calls the mesh | ||
| 492 | + * to deregister the meshstate for it is not done | ||
| 493 | + * because the list is NULL and also accounting is not | ||
| 494 | + * done there, but instead we do that here. */ | ||
| 495 | + struct mesh_reply* reply_list = mstate->reply_list; | ||
| 496 | + verbose(VERB_ALGO, "drop reply, it is older than discard-timeout"); | ||
| 497 | + infra_wait_limit_dec(mstate->s.env->infra_cache, | ||
| 498 | + &r->query_reply, mstate->s.env->cfg); | ||
| 499 | + mstate->reply_list = NULL; | ||
| 500 | + comm_point_drop_reply(&r->query_reply); | ||
| 501 | + mstate->reply_list = reply_list; | ||
| 502 | + mstate->s.env->mesh->stats_dropped++; | ||
| 503 | + continue; | ||
| 504 | + } | ||
| 505 | + | ||
| 506 | i++; | ||
| 507 | tv = r->start_time; | ||
| 508 | |||
| 509 | @@ -2192,6 +2255,8 @@ mesh_serve_expired_callback(void* arg) | ||
| 510 | r, r_buffer, prev, prev_buffer); | ||
| 511 | if(r->query_reply.c->tcp_req_info) | ||
| 512 | tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); | ||
| 513 | + infra_wait_limit_dec(mstate->s.env->infra_cache, | ||
| 514 | + &r->query_reply, mstate->s.env->cfg); | ||
| 515 | prev = r; | ||
| 516 | prev_buffer = r_buffer; | ||
| 517 | } | ||
| 518 | diff --git a/testdata/doh_downstream.tdir/doh_downstream.conf b/testdata/doh_downstream.tdir/doh_downstream.conf | ||
| 519 | index f0857bb5..222c2159 100644 | ||
| 520 | --- a/testdata/doh_downstream.tdir/doh_downstream.conf | ||
| 521 | +++ b/testdata/doh_downstream.tdir/doh_downstream.conf | ||
| 522 | @@ -11,6 +11,7 @@ server: | ||
| 523 | chroot: "" | ||
| 524 | username: "" | ||
| 525 | do-not-query-localhost: no | ||
| 526 | + discard-timeout: 3000 # testns uses sleep=2 | ||
| 527 | http-query-buffer-size: 1G | ||
| 528 | http-response-buffer-size: 1G | ||
| 529 | http-max-streams: 200 | ||
| 530 | diff --git a/testdata/doh_downstream_notls.tdir/doh_downstream_notls.conf b/testdata/doh_downstream_notls.tdir/doh_downstream_notls.conf | ||
| 531 | index bdca4564..161c3555 100644 | ||
| 532 | --- a/testdata/doh_downstream_notls.tdir/doh_downstream_notls.conf | ||
| 533 | +++ b/testdata/doh_downstream_notls.tdir/doh_downstream_notls.conf | ||
| 534 | @@ -11,6 +11,7 @@ server: | ||
| 535 | chroot: "" | ||
| 536 | username: "" | ||
| 537 | do-not-query-localhost: no | ||
| 538 | + discard-timeout: 3000 # testns uses sleep=2 | ||
| 539 | http-query-buffer-size: 1G | ||
| 540 | http-response-buffer-size: 1G | ||
| 541 | http-max-streams: 200 | ||
| 542 | diff --git a/testdata/doh_downstream_post.tdir/doh_downstream_post.conf b/testdata/doh_downstream_post.tdir/doh_downstream_post.conf | ||
| 543 | index f0857bb5..222c2159 100644 | ||
| 544 | --- a/testdata/doh_downstream_post.tdir/doh_downstream_post.conf | ||
| 545 | +++ b/testdata/doh_downstream_post.tdir/doh_downstream_post.conf | ||
| 546 | @@ -11,6 +11,7 @@ server: | ||
| 547 | chroot: "" | ||
| 548 | username: "" | ||
| 549 | do-not-query-localhost: no | ||
| 550 | + discard-timeout: 3000 # testns uses sleep=2 | ||
| 551 | http-query-buffer-size: 1G | ||
| 552 | http-response-buffer-size: 1G | ||
| 553 | http-max-streams: 200 | ||
| 554 | diff --git a/testdata/fwd_three_service.tdir/fwd_three_service.conf b/testdata/fwd_three_service.tdir/fwd_three_service.conf | ||
| 555 | index 05fafe01..d6c9a205 100644 | ||
| 556 | --- a/testdata/fwd_three_service.tdir/fwd_three_service.conf | ||
| 557 | +++ b/testdata/fwd_three_service.tdir/fwd_three_service.conf | ||
| 558 | @@ -11,6 +11,7 @@ server: | ||
| 559 | num-queries-per-thread: 1024 | ||
| 560 | use-syslog: no | ||
| 561 | do-not-query-localhost: no | ||
| 562 | + discard-timeout: 3000 # testns uses sleep=2 | ||
| 563 | forward-zone: | ||
| 564 | name: "." | ||
| 565 | forward-addr: "127.0.0.1@@TOPORT@" | ||
| 566 | diff --git a/testdata/iter_ghost_timewindow.rpl b/testdata/iter_ghost_timewindow.rpl | ||
| 567 | index 566be82a..9e304628 100644 | ||
| 568 | --- a/testdata/iter_ghost_timewindow.rpl | ||
| 569 | +++ b/testdata/iter_ghost_timewindow.rpl | ||
| 570 | @@ -3,6 +3,7 @@ server: | ||
| 571 | target-fetch-policy: "0 0 0 0 0" | ||
| 572 | qname-minimisation: "no" | ||
| 573 | minimal-responses: no | ||
| 574 | + discard-timeout: 86400 | ||
| 575 | |||
| 576 | stub-zone: | ||
| 577 | name: "." | ||
| 578 | diff --git a/testdata/ssl_req_order.tdir/ssl_req_order.conf b/testdata/ssl_req_order.tdir/ssl_req_order.conf | ||
| 579 | index 3b2e2b1b..ec39d3ab 100644 | ||
| 580 | --- a/testdata/ssl_req_order.tdir/ssl_req_order.conf | ||
| 581 | +++ b/testdata/ssl_req_order.tdir/ssl_req_order.conf | ||
| 582 | @@ -9,6 +9,7 @@ server: | ||
| 583 | chroot: "" | ||
| 584 | username: "" | ||
| 585 | do-not-query-localhost: no | ||
| 586 | + discard-timeout: 3000 # testns uses sleep=2 | ||
| 587 | ssl-port: @PORT@ | ||
| 588 | ssl-service-key: "unbound_server.key" | ||
| 589 | ssl-service-pem: "unbound_server.pem" | ||
| 590 | diff --git a/testdata/tcp_req_order.tdir/tcp_req_order.conf b/testdata/tcp_req_order.tdir/tcp_req_order.conf | ||
| 591 | index 40d6f55c..b2804e8e 100644 | ||
| 592 | --- a/testdata/tcp_req_order.tdir/tcp_req_order.conf | ||
| 593 | +++ b/testdata/tcp_req_order.tdir/tcp_req_order.conf | ||
| 594 | @@ -9,6 +9,7 @@ server: | ||
| 595 | chroot: "" | ||
| 596 | username: "" | ||
| 597 | do-not-query-localhost: no | ||
| 598 | + discard-timeout: 3000 # testns uses sleep=2 | ||
| 599 | |||
| 600 | local-zone: "example.net" static | ||
| 601 | local-data: "www1.example.net. IN A 1.2.3.1" | ||
| 602 | diff --git a/testdata/tcp_sigpipe.tdir/tcp_sigpipe.conf b/testdata/tcp_sigpipe.tdir/tcp_sigpipe.conf | ||
| 603 | index 384f16b0..4f1ff9b0 100644 | ||
| 604 | --- a/testdata/tcp_sigpipe.tdir/tcp_sigpipe.conf | ||
| 605 | +++ b/testdata/tcp_sigpipe.tdir/tcp_sigpipe.conf | ||
| 606 | @@ -1,5 +1,5 @@ | ||
| 607 | server: | ||
| 608 | - verbosity: 2 | ||
| 609 | + verbosity: 4 | ||
| 610 | # num-threads: 1 | ||
| 611 | interface: 127.0.0.1 | ||
| 612 | port: @PORT@ | ||
| 613 | @@ -9,6 +9,7 @@ server: | ||
| 614 | chroot: "" | ||
| 615 | username: "" | ||
| 616 | do-not-query-localhost: no | ||
| 617 | + discard-timeout: 3000 # testns uses sleep=2 | ||
| 618 | |||
| 619 | forward-zone: | ||
| 620 | name: "." | ||
| 621 | diff --git a/util/config_file.c b/util/config_file.c | ||
| 622 | index 26185da0..147f41e8 100644 | ||
| 623 | --- a/util/config_file.c | ||
| 624 | +++ b/util/config_file.c | ||
| 625 | @@ -308,6 +308,11 @@ config_create(void) | ||
| 626 | cfg->minimal_responses = 1; | ||
| 627 | cfg->rrset_roundrobin = 1; | ||
| 628 | cfg->unknown_server_time_limit = 376; | ||
| 629 | + cfg->discard_timeout = 1900; /* msec */ | ||
| 630 | + cfg->wait_limit = 1000; | ||
| 631 | + cfg->wait_limit_cookie = 10000; | ||
| 632 | + cfg->wait_limit_netblock = NULL; | ||
| 633 | + cfg->wait_limit_cookie_netblock = NULL; | ||
| 634 | cfg->max_udp_size = 1232; /* value taken from edns_buffer_size */ | ||
| 635 | if(!(cfg->server_key_file = strdup(RUN_DIR"/unbound_server.key"))) | ||
| 636 | goto error_exit; | ||
| 637 | @@ -722,6 +727,9 @@ int config_set_option(struct config_file* cfg, const char* opt, | ||
| 638 | else S_YNO("minimal-responses:", minimal_responses) | ||
| 639 | else S_YNO("rrset-roundrobin:", rrset_roundrobin) | ||
| 640 | else S_NUMBER_OR_ZERO("unknown-server-time-limit:", unknown_server_time_limit) | ||
| 641 | + else S_NUMBER_OR_ZERO("discard-timeout:", discard_timeout) | ||
| 642 | + else S_NUMBER_OR_ZERO("wait-limit:", wait_limit) | ||
| 643 | + else S_NUMBER_OR_ZERO("wait-limit-cookie:", wait_limit_cookie) | ||
| 644 | else S_STRLIST("local-data:", local_data) | ||
| 645 | else S_YNO("unblock-lan-zones:", unblock_lan_zones) | ||
| 646 | else S_YNO("insecure-lan-zones:", insecure_lan_zones) | ||
| 647 | @@ -1201,6 +1209,11 @@ config_get_option(struct config_file* cfg, const char* opt, | ||
| 648 | else O_YNO(opt, "minimal-responses", minimal_responses) | ||
| 649 | else O_YNO(opt, "rrset-roundrobin", rrset_roundrobin) | ||
| 650 | else O_DEC(opt, "unknown-server-time-limit", unknown_server_time_limit) | ||
| 651 | + else O_DEC(opt, "discard-timeout", discard_timeout) | ||
| 652 | + else O_DEC(opt, "wait-limit", wait_limit) | ||
| 653 | + else O_DEC(opt, "wait-limit-cookie", wait_limit_cookie) | ||
| 654 | + else O_LS2(opt, "wait-limit-netblock", wait_limit_netblock) | ||
| 655 | + else O_LS2(opt, "wait-limit-cookie-netblock", wait_limit_cookie_netblock) | ||
| 656 | #ifdef CLIENT_SUBNET | ||
| 657 | else O_LST(opt, "send-client-subnet", client_subnet) | ||
| 658 | else O_LST(opt, "client-subnet-zone", client_subnet_zone) | ||
| 659 | @@ -1671,6 +1684,8 @@ config_delete(struct config_file* cfg) | ||
| 660 | config_deltrplstrlist(cfg->interface_tag_actions); | ||
| 661 | config_deltrplstrlist(cfg->interface_tag_datas); | ||
| 662 | config_delstrlist(cfg->control_ifs.first); | ||
| 663 | + config_deldblstrlist(cfg->wait_limit_netblock); | ||
| 664 | + config_deldblstrlist(cfg->wait_limit_cookie_netblock); | ||
| 665 | free(cfg->server_key_file); | ||
| 666 | free(cfg->server_cert_file); | ||
| 667 | free(cfg->control_key_file); | ||
| 668 | diff --git a/util/config_file.h b/util/config_file.h | ||
| 669 | index 49110983..7ded3c24 100644 | ||
| 670 | --- a/util/config_file.h | ||
| 671 | +++ b/util/config_file.h | ||
| 672 | @@ -535,6 +535,21 @@ struct config_file { | ||
| 673 | /* wait time for unknown server in msec */ | ||
| 674 | int unknown_server_time_limit; | ||
| 675 | |||
| 676 | + /** Wait time to drop recursion replies */ | ||
| 677 | + int discard_timeout; | ||
| 678 | + | ||
| 679 | + /** Wait limit for number of replies per IP address */ | ||
| 680 | + int wait_limit; | ||
| 681 | + | ||
| 682 | + /** Wait limit for number of replies per IP address with cookie */ | ||
| 683 | + int wait_limit_cookie; | ||
| 684 | + | ||
| 685 | + /** wait limit per netblock */ | ||
| 686 | + struct config_str2list* wait_limit_netblock; | ||
| 687 | + | ||
| 688 | + /** wait limit with cookie per netblock */ | ||
| 689 | + struct config_str2list* wait_limit_cookie_netblock; | ||
| 690 | + | ||
| 691 | /* maximum UDP response size */ | ||
| 692 | size_t max_udp_size; | ||
| 693 | |||
| 694 | diff --git a/util/configlexer.lex b/util/configlexer.lex | ||
| 695 | index e1ab76e2..7455f50c 100644 | ||
| 696 | --- a/util/configlexer.lex | ||
| 697 | +++ b/util/configlexer.lex | ||
| 698 | @@ -463,6 +463,11 @@ domain-insecure{COLON} { YDVAR(1, VAR_DOMAIN_INSECURE) } | ||
| 699 | minimal-responses{COLON} { YDVAR(1, VAR_MINIMAL_RESPONSES) } | ||
| 700 | rrset-roundrobin{COLON} { YDVAR(1, VAR_RRSET_ROUNDROBIN) } | ||
| 701 | unknown-server-time-limit{COLON} { YDVAR(1, VAR_UNKNOWN_SERVER_TIME_LIMIT) } | ||
| 702 | +discard-timeout{COLON} { YDVAR(1, VAR_DISCARD_TIMEOUT) } | ||
| 703 | +wait-limit{COLON} { YDVAR(1, VAR_WAIT_LIMIT) } | ||
| 704 | +wait-limit-cookie{COLON} { YDVAR(1, VAR_WAIT_LIMIT_COOKIE) } | ||
| 705 | +wait-limit-netblock{COLON} { YDVAR(1, VAR_WAIT_LIMIT_NETBLOCK) } | ||
| 706 | +wait-limit-cookie-netblock{COLON} { YDVAR(1, VAR_WAIT_LIMIT_COOKIE_NETBLOCK) } | ||
| 707 | max-udp-size{COLON} { YDVAR(1, VAR_MAX_UDP_SIZE) } | ||
| 708 | dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) } | ||
| 709 | dns64-synthall{COLON} { YDVAR(1, VAR_DNS64_SYNTHALL) } | ||
| 710 | diff --git a/util/configparser.y b/util/configparser.y | ||
| 711 | index 0e4cd596..7d95690e 100644 | ||
| 712 | --- a/util/configparser.y | ||
| 713 | +++ b/util/configparser.y | ||
| 714 | @@ -188,6 +188,8 @@ extern struct config_parser_state* cfg_parser; | ||
| 715 | %token VAR_ANSWER_COOKIE VAR_COOKIE_SECRET VAR_IP_RATELIMIT_COOKIE | ||
| 716 | %token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL VAR_DENY_ANY | ||
| 717 | %token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY | ||
| 718 | +%token VAR_DISCARD_TIMEOUT VAR_WAIT_LIMIT VAR_WAIT_LIMIT_COOKIE | ||
| 719 | +%token VAR_WAIT_LIMIT_NETBLOCK VAR_WAIT_LIMIT_COOKIE_NETBLOCK | ||
| 720 | %token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES VAR_TLS_USE_SNI | ||
| 721 | %token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6 | ||
| 722 | %token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE | ||
| 723 | @@ -325,6 +327,8 @@ content_server: server_num_threads | server_verbosity | server_port | | ||
| 724 | server_fast_server_permil | server_fast_server_num | server_tls_win_cert | | ||
| 725 | server_tcp_connection_limit | server_log_servfail | server_deny_any | | ||
| 726 | server_unknown_server_time_limit | server_log_tag_queryreply | | ||
| 727 | + server_discard_timeout | server_wait_limit | server_wait_limit_cookie | | ||
| 728 | + server_wait_limit_netblock | server_wait_limit_cookie_netblock | | ||
| 729 | server_stream_wait_size | server_tls_ciphers | | ||
| 730 | server_tls_ciphersuites | server_tls_session_ticket_keys | | ||
| 731 | server_answer_cookie | server_cookie_secret | server_ip_ratelimit_cookie | | ||
| 732 | @@ -2366,6 +2370,57 @@ server_unknown_server_time_limit: VAR_UNKNOWN_SERVER_TIME_LIMIT STRING_ARG | ||
| 733 | free($2); | ||
| 734 | } | ||
| 735 | ; | ||
| 736 | +server_discard_timeout: VAR_DISCARD_TIMEOUT STRING_ARG | ||
| 737 | + { | ||
| 738 | + OUTYY(("P(server_discard_timeout:%s)\n", $2)); | ||
| 739 | + cfg_parser->cfg->discard_timeout = atoi($2); | ||
| 740 | + free($2); | ||
| 741 | + } | ||
| 742 | + ; | ||
| 743 | +server_wait_limit: VAR_WAIT_LIMIT STRING_ARG | ||
| 744 | + { | ||
| 745 | + OUTYY(("P(server_wait_limit:%s)\n", $2)); | ||
| 746 | + cfg_parser->cfg->wait_limit = atoi($2); | ||
| 747 | + free($2); | ||
| 748 | + } | ||
| 749 | + ; | ||
| 750 | +server_wait_limit_cookie: VAR_WAIT_LIMIT_COOKIE STRING_ARG | ||
| 751 | + { | ||
| 752 | + OUTYY(("P(server_wait_limit_cookie:%s)\n", $2)); | ||
| 753 | + cfg_parser->cfg->wait_limit_cookie = atoi($2); | ||
| 754 | + free($2); | ||
| 755 | + } | ||
| 756 | + ; | ||
| 757 | +server_wait_limit_netblock: VAR_WAIT_LIMIT_NETBLOCK STRING_ARG STRING_ARG | ||
| 758 | + { | ||
| 759 | + OUTYY(("P(server_wait_limit_netblock:%s %s)\n", $2, $3)); | ||
| 760 | + if(atoi($3) == 0 && strcmp($3, "0") != 0) { | ||
| 761 | + yyerror("number expected"); | ||
| 762 | + free($2); | ||
| 763 | + free($3); | ||
| 764 | + } else { | ||
| 765 | + if(!cfg_str2list_insert(&cfg_parser->cfg-> | ||
| 766 | + wait_limit_netblock, $2, $3)) | ||
| 767 | + fatal_exit("out of memory adding " | ||
| 768 | + "wait-limit-netblock"); | ||
| 769 | + } | ||
| 770 | + } | ||
| 771 | + ; | ||
| 772 | +server_wait_limit_cookie_netblock: VAR_WAIT_LIMIT_COOKIE_NETBLOCK STRING_ARG STRING_ARG | ||
| 773 | + { | ||
| 774 | + OUTYY(("P(server_wait_limit_cookie_netblock:%s %s)\n", $2, $3)); | ||
| 775 | + if(atoi($3) == 0 && strcmp($3, "0") != 0) { | ||
| 776 | + yyerror("number expected"); | ||
| 777 | + free($2); | ||
| 778 | + free($3); | ||
| 779 | + } else { | ||
| 780 | + if(!cfg_str2list_insert(&cfg_parser->cfg-> | ||
| 781 | + wait_limit_cookie_netblock, $2, $3)) | ||
| 782 | + fatal_exit("out of memory adding " | ||
| 783 | + "wait-limit-cookie-netblock"); | ||
| 784 | + } | ||
| 785 | + } | ||
| 786 | + ; | ||
| 787 | server_max_udp_size: VAR_MAX_UDP_SIZE STRING_ARG | ||
| 788 | { | ||
| 789 | OUTYY(("P(server_max_udp_size:%s)\n", $2)); | ||
| 790 | -- | ||
| 791 | 2.34.1 | ||
| 792 | |||
diff --git a/meta-networking/recipes-support/unbound/unbound/CVE-2025-11411.patch b/meta-networking/recipes-support/unbound/unbound/CVE-2025-11411.patch new file mode 100644 index 0000000000..a653090770 --- /dev/null +++ b/meta-networking/recipes-support/unbound/unbound/CVE-2025-11411.patch | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | From 98fac0b396e1e85a6345baa59fc178b1f51759b8 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Patrick Vogelaar <patrick.vogelaar@belden.com> | ||
| 3 | Date: Wed, 29 Oct 2025 13:33:23 +0100 | ||
| 4 | Subject: [PATCH] Fix CVE-2025-11411 (possible domain hijacking attack) | ||
| 5 | |||
| 6 | This fixes CVE-2025-11411 by applying the minimal patch [1] listed in [2] | ||
| 7 | |||
| 8 | [1] https://nlnetlabs.nl/downloads/unbound/patch_CVE-2025-11411.diff | ||
| 9 | [2] https://www.nlnetlabs.nl/downloads/unbound/CVE-2025-11411.txt | ||
| 10 | |||
| 11 | CVE: CVE-2025-11411 | ||
| 12 | Upstream-Status: Backport [minimal backport of https://github.com/NLnetLabs/unbound/commit/a33f0638e1dacf2633cf2292078a674576bca852] | ||
| 13 | |||
| 14 | Signed-off-by: Patrick Vogelaar <patrick.vogelaar@belden.com> | ||
| 15 | --- | ||
| 16 | iterator/iter_scrub.c | 16 ++++++++++++++++ | ||
| 17 | 1 file changed, 16 insertions(+) | ||
| 18 | |||
| 19 | diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c | ||
| 20 | index 48867e50..5beaa048 100644 | ||
| 21 | --- a/iterator/iter_scrub.c | ||
| 22 | +++ b/iterator/iter_scrub.c | ||
| 23 | @@ -571,6 +571,22 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, | ||
| 24 | "RRset:", pkt, msg, prev, &rrset); | ||
| 25 | continue; | ||
| 26 | } | ||
| 27 | + /* If the NS set is a promiscuous NS set, scrub that | ||
| 28 | + * to remove potential for poisonous contents that | ||
| 29 | + * affects other names in the same zone. Remove | ||
| 30 | + * promiscuous NS sets in positive answers, that | ||
| 31 | + * thus have records in the answer section. Nodata | ||
| 32 | + * and nxdomain promiscuous NS sets have been removed | ||
| 33 | + * already. Since the NS rrset is scrubbed, its | ||
| 34 | + * address records are also not marked to be allowed | ||
| 35 | + * and are removed later. */ | ||
| 36 | + if(FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR && | ||
| 37 | + msg->an_rrsets != 0 && | ||
| 38 | + 1 /* env->cfg->iter_scrub_promiscuous */) { | ||
| 39 | + remove_rrset("normalize: removing promiscuous " | ||
| 40 | + "RRset:", pkt, msg, prev, &rrset); | ||
| 41 | + continue; | ||
| 42 | + } | ||
| 43 | if(nsset == NULL) { | ||
| 44 | nsset = rrset; | ||
| 45 | } else { | ||
| 46 | -- | ||
| 47 | 2.34.1 | ||
| 48 | |||
diff --git a/meta-networking/recipes-support/unbound/unbound_1.19.3.bb b/meta-networking/recipes-support/unbound/unbound_1.19.3.bb index 6f54038c6c..e48d76ea59 100644 --- a/meta-networking/recipes-support/unbound/unbound_1.19.3.bb +++ b/meta-networking/recipes-support/unbound/unbound_1.19.3.bb | |||
| @@ -11,6 +11,8 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=5308494bc0590c0cb036afd781d78f06" | |||
| 11 | 11 | ||
| 12 | SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;branch=branch-1.19.3 \ | 12 | SRC_URI = "git://github.com/NLnetLabs/unbound.git;protocol=https;branch=branch-1.19.3 \ |
| 13 | file://CVE-2024-8508.patch \ | 13 | file://CVE-2024-8508.patch \ |
| 14 | file://CVE-2024-33655.patch \ | ||
| 15 | file://CVE-2025-11411.patch \ | ||
| 14 | " | 16 | " |
| 15 | SRCREV = "48b6c60a24e9a5d6d369a7a37c9fe2a767f26abd" | 17 | SRCREV = "48b6c60a24e9a5d6d369a7a37c9fe2a767f26abd" |
| 16 | 18 | ||
