11cb0ef41Sopenharmony_ci/* MIT License 21cb0ef41Sopenharmony_ci * 31cb0ef41Sopenharmony_ci * Copyright (c) 2023 Brad House 41cb0ef41Sopenharmony_ci * 51cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 61cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal 71cb0ef41Sopenharmony_ci * in the Software without restriction, including without limitation the rights 81cb0ef41Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 91cb0ef41Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is 101cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions: 111cb0ef41Sopenharmony_ci * 121cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice (including the next 131cb0ef41Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 141cb0ef41Sopenharmony_ci * Software. 151cb0ef41Sopenharmony_ci * 161cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 171cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 181cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 191cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 201cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 211cb0ef41Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 221cb0ef41Sopenharmony_ci * SOFTWARE. 231cb0ef41Sopenharmony_ci * 241cb0ef41Sopenharmony_ci * SPDX-License-Identifier: MIT 251cb0ef41Sopenharmony_ci */ 261cb0ef41Sopenharmony_ci#include "ares_setup.h" 271cb0ef41Sopenharmony_ci#include "ares.h" 281cb0ef41Sopenharmony_ci#include "ares_private.h" 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_cistruct ares__qcache { 311cb0ef41Sopenharmony_ci ares__htable_strvp_t *cache; 321cb0ef41Sopenharmony_ci ares__slist_t *expire; 331cb0ef41Sopenharmony_ci unsigned int max_ttl; 341cb0ef41Sopenharmony_ci}; 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_citypedef struct { 371cb0ef41Sopenharmony_ci char *key; 381cb0ef41Sopenharmony_ci ares_dns_record_t *dnsrec; 391cb0ef41Sopenharmony_ci time_t expire_ts; 401cb0ef41Sopenharmony_ci time_t insert_ts; 411cb0ef41Sopenharmony_ci} ares__qcache_entry_t; 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_cistatic char *ares__qcache_calc_key(const ares_dns_record_t *dnsrec) 441cb0ef41Sopenharmony_ci{ 451cb0ef41Sopenharmony_ci ares__buf_t *buf = ares__buf_create(); 461cb0ef41Sopenharmony_ci size_t i; 471cb0ef41Sopenharmony_ci ares_status_t status; 481cb0ef41Sopenharmony_ci ares_dns_flags_t flags; 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci if (dnsrec == NULL || buf == NULL) { 511cb0ef41Sopenharmony_ci return NULL; 521cb0ef41Sopenharmony_ci } 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci /* Format is OPCODE|FLAGS[|QTYPE1|QCLASS1|QNAME1]... */ 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci status = ares__buf_append_str( 571cb0ef41Sopenharmony_ci buf, ares_dns_opcode_tostr(ares_dns_record_get_opcode(dnsrec))); 581cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 591cb0ef41Sopenharmony_ci goto fail; 601cb0ef41Sopenharmony_ci } 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci status = ares__buf_append_byte(buf, '|'); 631cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 641cb0ef41Sopenharmony_ci goto fail; 651cb0ef41Sopenharmony_ci } 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci flags = ares_dns_record_get_flags(dnsrec); 681cb0ef41Sopenharmony_ci /* Only care about RD and CD */ 691cb0ef41Sopenharmony_ci if (flags & ARES_FLAG_RD) { 701cb0ef41Sopenharmony_ci status = ares__buf_append_str(buf, "rd"); 711cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 721cb0ef41Sopenharmony_ci goto fail; 731cb0ef41Sopenharmony_ci } 741cb0ef41Sopenharmony_ci } 751cb0ef41Sopenharmony_ci if (flags & ARES_FLAG_CD) { 761cb0ef41Sopenharmony_ci status = ares__buf_append_str(buf, "cd"); 771cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 781cb0ef41Sopenharmony_ci goto fail; 791cb0ef41Sopenharmony_ci } 801cb0ef41Sopenharmony_ci } 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci for (i = 0; i < ares_dns_record_query_cnt(dnsrec); i++) { 831cb0ef41Sopenharmony_ci const char *name; 841cb0ef41Sopenharmony_ci ares_dns_rec_type_t qtype; 851cb0ef41Sopenharmony_ci ares_dns_class_t qclass; 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci status = ares_dns_record_query_get(dnsrec, i, &name, &qtype, &qclass); 881cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 891cb0ef41Sopenharmony_ci goto fail; 901cb0ef41Sopenharmony_ci } 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci status = ares__buf_append_byte(buf, '|'); 931cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 941cb0ef41Sopenharmony_ci goto fail; 951cb0ef41Sopenharmony_ci } 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci status = ares__buf_append_str(buf, ares_dns_rec_type_tostr(qtype)); 981cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 991cb0ef41Sopenharmony_ci goto fail; 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci status = ares__buf_append_byte(buf, '|'); 1031cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 1041cb0ef41Sopenharmony_ci goto fail; 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci status = ares__buf_append_str(buf, ares_dns_class_tostr(qclass)); 1081cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 1091cb0ef41Sopenharmony_ci goto fail; 1101cb0ef41Sopenharmony_ci } 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci status = ares__buf_append_byte(buf, '|'); 1131cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 1141cb0ef41Sopenharmony_ci goto fail; 1151cb0ef41Sopenharmony_ci } 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ci status = ares__buf_append_str(buf, name); 1181cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 1191cb0ef41Sopenharmony_ci goto fail; 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci } 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_ci return ares__buf_finish_str(buf, NULL); 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_cifail: 1261cb0ef41Sopenharmony_ci ares__buf_destroy(buf); 1271cb0ef41Sopenharmony_ci return NULL; 1281cb0ef41Sopenharmony_ci} 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_cistatic void ares__qcache_expire(ares__qcache_t *cache, 1311cb0ef41Sopenharmony_ci const struct timeval *now) 1321cb0ef41Sopenharmony_ci{ 1331cb0ef41Sopenharmony_ci ares__slist_node_t *node; 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci if (cache == NULL) { 1361cb0ef41Sopenharmony_ci return; 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci while ((node = ares__slist_node_first(cache->expire)) != NULL) { 1401cb0ef41Sopenharmony_ci const ares__qcache_entry_t *entry = ares__slist_node_val(node); 1411cb0ef41Sopenharmony_ci if (entry->expire_ts > now->tv_sec) { 1421cb0ef41Sopenharmony_ci break; 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci ares__htable_strvp_remove(cache->cache, entry->key); 1461cb0ef41Sopenharmony_ci ares__slist_node_destroy(node); 1471cb0ef41Sopenharmony_ci } 1481cb0ef41Sopenharmony_ci} 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_civoid ares__qcache_flush(ares__qcache_t *cache) 1511cb0ef41Sopenharmony_ci{ 1521cb0ef41Sopenharmony_ci struct timeval now; 1531cb0ef41Sopenharmony_ci memset(&now, 0, sizeof(now)); 1541cb0ef41Sopenharmony_ci ares__qcache_expire(cache, &now); 1551cb0ef41Sopenharmony_ci} 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_civoid ares__qcache_destroy(ares__qcache_t *cache) 1581cb0ef41Sopenharmony_ci{ 1591cb0ef41Sopenharmony_ci if (cache == NULL) { 1601cb0ef41Sopenharmony_ci return; 1611cb0ef41Sopenharmony_ci } 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci ares__htable_strvp_destroy(cache->cache); 1641cb0ef41Sopenharmony_ci ares__slist_destroy(cache->expire); 1651cb0ef41Sopenharmony_ci ares_free(cache); 1661cb0ef41Sopenharmony_ci} 1671cb0ef41Sopenharmony_ci 1681cb0ef41Sopenharmony_cistatic int ares__qcache_entry_sort_cb(const void *arg1, const void *arg2) 1691cb0ef41Sopenharmony_ci{ 1701cb0ef41Sopenharmony_ci const ares__qcache_entry_t *entry1 = arg1; 1711cb0ef41Sopenharmony_ci const ares__qcache_entry_t *entry2 = arg2; 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_ci if (entry1->expire_ts > entry2->expire_ts) { 1741cb0ef41Sopenharmony_ci return 1; 1751cb0ef41Sopenharmony_ci } 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci if (entry1->expire_ts < entry2->expire_ts) { 1781cb0ef41Sopenharmony_ci return -1; 1791cb0ef41Sopenharmony_ci } 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_ci return 0; 1821cb0ef41Sopenharmony_ci} 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_cistatic void ares__qcache_entry_destroy_cb(void *arg) 1851cb0ef41Sopenharmony_ci{ 1861cb0ef41Sopenharmony_ci ares__qcache_entry_t *entry = arg; 1871cb0ef41Sopenharmony_ci if (entry == NULL) { 1881cb0ef41Sopenharmony_ci return; 1891cb0ef41Sopenharmony_ci } 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci ares_free(entry->key); 1921cb0ef41Sopenharmony_ci ares_dns_record_destroy(entry->dnsrec); 1931cb0ef41Sopenharmony_ci ares_free(entry); 1941cb0ef41Sopenharmony_ci} 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ciares_status_t ares__qcache_create(ares_rand_state *rand_state, 1971cb0ef41Sopenharmony_ci unsigned int max_ttl, 1981cb0ef41Sopenharmony_ci ares__qcache_t **cache_out) 1991cb0ef41Sopenharmony_ci{ 2001cb0ef41Sopenharmony_ci ares_status_t status = ARES_SUCCESS; 2011cb0ef41Sopenharmony_ci ares__qcache_t *cache; 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci cache = ares_malloc_zero(sizeof(*cache)); 2041cb0ef41Sopenharmony_ci if (cache == NULL) { 2051cb0ef41Sopenharmony_ci status = ARES_ENOMEM; 2061cb0ef41Sopenharmony_ci goto done; 2071cb0ef41Sopenharmony_ci } 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci cache->cache = ares__htable_strvp_create(NULL); 2101cb0ef41Sopenharmony_ci if (cache->cache == NULL) { 2111cb0ef41Sopenharmony_ci status = ARES_ENOMEM; 2121cb0ef41Sopenharmony_ci goto done; 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci 2151cb0ef41Sopenharmony_ci cache->expire = ares__slist_create(rand_state, ares__qcache_entry_sort_cb, 2161cb0ef41Sopenharmony_ci ares__qcache_entry_destroy_cb); 2171cb0ef41Sopenharmony_ci if (cache->expire == NULL) { 2181cb0ef41Sopenharmony_ci status = ARES_ENOMEM; 2191cb0ef41Sopenharmony_ci goto done; 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci cache->max_ttl = max_ttl; 2231cb0ef41Sopenharmony_ci 2241cb0ef41Sopenharmony_cidone: 2251cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 2261cb0ef41Sopenharmony_ci *cache_out = NULL; 2271cb0ef41Sopenharmony_ci ares__qcache_destroy(cache); 2281cb0ef41Sopenharmony_ci return status; 2291cb0ef41Sopenharmony_ci } 2301cb0ef41Sopenharmony_ci 2311cb0ef41Sopenharmony_ci *cache_out = cache; 2321cb0ef41Sopenharmony_ci return status; 2331cb0ef41Sopenharmony_ci} 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_cistatic unsigned int ares__qcache_calc_minttl(ares_dns_record_t *dnsrec) 2361cb0ef41Sopenharmony_ci{ 2371cb0ef41Sopenharmony_ci unsigned int minttl = 0xFFFFFFFF; 2381cb0ef41Sopenharmony_ci size_t sect; 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci for (sect = ARES_SECTION_ANSWER; sect <= ARES_SECTION_ADDITIONAL; sect++) { 2411cb0ef41Sopenharmony_ci size_t i; 2421cb0ef41Sopenharmony_ci for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, (ares_dns_section_t)sect); 2431cb0ef41Sopenharmony_ci i++) { 2441cb0ef41Sopenharmony_ci const ares_dns_rr_t *rr = 2451cb0ef41Sopenharmony_ci ares_dns_record_rr_get(dnsrec, (ares_dns_section_t)sect, i); 2461cb0ef41Sopenharmony_ci ares_dns_rec_type_t type = ares_dns_rr_get_type(rr); 2471cb0ef41Sopenharmony_ci unsigned int ttl = ares_dns_rr_get_ttl(rr); 2481cb0ef41Sopenharmony_ci if (type == ARES_REC_TYPE_OPT || type == ARES_REC_TYPE_SOA) { 2491cb0ef41Sopenharmony_ci continue; 2501cb0ef41Sopenharmony_ci } 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci if (ttl < minttl) { 2531cb0ef41Sopenharmony_ci minttl = ttl; 2541cb0ef41Sopenharmony_ci } 2551cb0ef41Sopenharmony_ci } 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci return minttl; 2591cb0ef41Sopenharmony_ci} 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_cistatic unsigned int ares__qcache_soa_minimum(ares_dns_record_t *dnsrec) 2621cb0ef41Sopenharmony_ci{ 2631cb0ef41Sopenharmony_ci size_t i; 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci /* RFC 2308 Section 5 says its the minimum of MINIMUM and the TTL of the 2661cb0ef41Sopenharmony_ci * record. */ 2671cb0ef41Sopenharmony_ci for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_AUTHORITY); i++) { 2681cb0ef41Sopenharmony_ci const ares_dns_rr_t *rr = 2691cb0ef41Sopenharmony_ci ares_dns_record_rr_get(dnsrec, ARES_SECTION_AUTHORITY, i); 2701cb0ef41Sopenharmony_ci ares_dns_rec_type_t type = ares_dns_rr_get_type(rr); 2711cb0ef41Sopenharmony_ci unsigned int ttl; 2721cb0ef41Sopenharmony_ci unsigned int minimum; 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_ci if (type != ARES_REC_TYPE_SOA) { 2751cb0ef41Sopenharmony_ci continue; 2761cb0ef41Sopenharmony_ci } 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_ci minimum = ares_dns_rr_get_u32(rr, ARES_RR_SOA_MINIMUM); 2791cb0ef41Sopenharmony_ci ttl = ares_dns_rr_get_ttl(rr); 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci if (ttl > minimum) { 2821cb0ef41Sopenharmony_ci return minimum; 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci return ttl; 2851cb0ef41Sopenharmony_ci } 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci return 0; 2881cb0ef41Sopenharmony_ci} 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_cistatic char *ares__qcache_calc_key_frombuf(const unsigned char *qbuf, 2911cb0ef41Sopenharmony_ci size_t qlen) 2921cb0ef41Sopenharmony_ci{ 2931cb0ef41Sopenharmony_ci ares_status_t status; 2941cb0ef41Sopenharmony_ci ares_dns_record_t *dnsrec = NULL; 2951cb0ef41Sopenharmony_ci char *key = NULL; 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ci status = ares_dns_parse(qbuf, qlen, 0, &dnsrec); 2981cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 2991cb0ef41Sopenharmony_ci goto done; 3001cb0ef41Sopenharmony_ci } 3011cb0ef41Sopenharmony_ci 3021cb0ef41Sopenharmony_ci key = ares__qcache_calc_key(dnsrec); 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_cidone: 3051cb0ef41Sopenharmony_ci ares_dns_record_destroy(dnsrec); 3061cb0ef41Sopenharmony_ci return key; 3071cb0ef41Sopenharmony_ci} 3081cb0ef41Sopenharmony_ci 3091cb0ef41Sopenharmony_ci/* On success, takes ownership of dnsrec */ 3101cb0ef41Sopenharmony_cistatic ares_status_t ares__qcache_insert(ares__qcache_t *qcache, 3111cb0ef41Sopenharmony_ci ares_dns_record_t *dnsrec, 3121cb0ef41Sopenharmony_ci const unsigned char *qbuf, size_t qlen, 3131cb0ef41Sopenharmony_ci const struct timeval *now) 3141cb0ef41Sopenharmony_ci{ 3151cb0ef41Sopenharmony_ci ares__qcache_entry_t *entry; 3161cb0ef41Sopenharmony_ci unsigned int ttl; 3171cb0ef41Sopenharmony_ci ares_dns_rcode_t rcode = ares_dns_record_get_rcode(dnsrec); 3181cb0ef41Sopenharmony_ci ares_dns_flags_t flags = ares_dns_record_get_flags(dnsrec); 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci if (qcache == NULL || dnsrec == NULL) { 3211cb0ef41Sopenharmony_ci return ARES_EFORMERR; 3221cb0ef41Sopenharmony_ci } 3231cb0ef41Sopenharmony_ci 3241cb0ef41Sopenharmony_ci /* Only save NOERROR or NXDOMAIN */ 3251cb0ef41Sopenharmony_ci if (rcode != ARES_RCODE_NOERROR && rcode != ARES_RCODE_NXDOMAIN) { 3261cb0ef41Sopenharmony_ci return ARES_ENOTIMP; 3271cb0ef41Sopenharmony_ci } 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_ci /* Don't save truncated queries */ 3301cb0ef41Sopenharmony_ci if (flags & ARES_FLAG_TC) { 3311cb0ef41Sopenharmony_ci return ARES_ENOTIMP; 3321cb0ef41Sopenharmony_ci } 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci /* Look at SOA for NXDOMAIN for minimum */ 3351cb0ef41Sopenharmony_ci if (rcode == ARES_RCODE_NXDOMAIN) { 3361cb0ef41Sopenharmony_ci ttl = ares__qcache_soa_minimum(dnsrec); 3371cb0ef41Sopenharmony_ci } else { 3381cb0ef41Sopenharmony_ci ttl = ares__qcache_calc_minttl(dnsrec); 3391cb0ef41Sopenharmony_ci } 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_ci /* Don't cache something that is already expired */ 3421cb0ef41Sopenharmony_ci if (ttl == 0) { 3431cb0ef41Sopenharmony_ci return ARES_EREFUSED; 3441cb0ef41Sopenharmony_ci } 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_ci if (ttl > qcache->max_ttl) { 3471cb0ef41Sopenharmony_ci ttl = qcache->max_ttl; 3481cb0ef41Sopenharmony_ci } 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_ci entry = ares_malloc_zero(sizeof(*entry)); 3511cb0ef41Sopenharmony_ci if (entry == NULL) { 3521cb0ef41Sopenharmony_ci goto fail; 3531cb0ef41Sopenharmony_ci } 3541cb0ef41Sopenharmony_ci 3551cb0ef41Sopenharmony_ci entry->dnsrec = dnsrec; 3561cb0ef41Sopenharmony_ci entry->expire_ts = now->tv_sec + (time_t)ttl; 3571cb0ef41Sopenharmony_ci entry->insert_ts = now->tv_sec; 3581cb0ef41Sopenharmony_ci 3591cb0ef41Sopenharmony_ci /* We can't guarantee the server responded with the same flags as the 3601cb0ef41Sopenharmony_ci * request had, so we have to re-parse the request in order to generate the 3611cb0ef41Sopenharmony_ci * key for caching, but we'll only do this once we know for sure we really 3621cb0ef41Sopenharmony_ci * want to cache it */ 3631cb0ef41Sopenharmony_ci entry->key = ares__qcache_calc_key_frombuf(qbuf, qlen); 3641cb0ef41Sopenharmony_ci if (entry->key == NULL) { 3651cb0ef41Sopenharmony_ci goto fail; 3661cb0ef41Sopenharmony_ci } 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_ci if (!ares__htable_strvp_insert(qcache->cache, entry->key, entry)) { 3691cb0ef41Sopenharmony_ci goto fail; 3701cb0ef41Sopenharmony_ci } 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ci if (ares__slist_insert(qcache->expire, entry) == NULL) { 3731cb0ef41Sopenharmony_ci goto fail; 3741cb0ef41Sopenharmony_ci } 3751cb0ef41Sopenharmony_ci 3761cb0ef41Sopenharmony_ci return ARES_SUCCESS; 3771cb0ef41Sopenharmony_ci 3781cb0ef41Sopenharmony_cifail: 3791cb0ef41Sopenharmony_ci if (entry != NULL && entry->key != NULL) { 3801cb0ef41Sopenharmony_ci ares__htable_strvp_remove(qcache->cache, entry->key); 3811cb0ef41Sopenharmony_ci ares_free(entry->key); 3821cb0ef41Sopenharmony_ci ares_free(entry); 3831cb0ef41Sopenharmony_ci } 3841cb0ef41Sopenharmony_ci return ARES_ENOMEM; 3851cb0ef41Sopenharmony_ci} 3861cb0ef41Sopenharmony_ci 3871cb0ef41Sopenharmony_cistatic ares_status_t ares__qcache_fetch(ares__qcache_t *qcache, 3881cb0ef41Sopenharmony_ci const ares_dns_record_t *dnsrec, 3891cb0ef41Sopenharmony_ci const struct timeval *now, 3901cb0ef41Sopenharmony_ci unsigned char **buf, size_t *buf_len) 3911cb0ef41Sopenharmony_ci{ 3921cb0ef41Sopenharmony_ci char *key = NULL; 3931cb0ef41Sopenharmony_ci ares__qcache_entry_t *entry; 3941cb0ef41Sopenharmony_ci ares_status_t status; 3951cb0ef41Sopenharmony_ci 3961cb0ef41Sopenharmony_ci if (qcache == NULL || dnsrec == NULL) { 3971cb0ef41Sopenharmony_ci return ARES_EFORMERR; 3981cb0ef41Sopenharmony_ci } 3991cb0ef41Sopenharmony_ci 4001cb0ef41Sopenharmony_ci ares__qcache_expire(qcache, now); 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci key = ares__qcache_calc_key(dnsrec); 4031cb0ef41Sopenharmony_ci if (key == NULL) { 4041cb0ef41Sopenharmony_ci status = ARES_ENOMEM; 4051cb0ef41Sopenharmony_ci goto done; 4061cb0ef41Sopenharmony_ci } 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci entry = ares__htable_strvp_get_direct(qcache->cache, key); 4091cb0ef41Sopenharmony_ci if (entry == NULL) { 4101cb0ef41Sopenharmony_ci status = ARES_ENOTFOUND; 4111cb0ef41Sopenharmony_ci goto done; 4121cb0ef41Sopenharmony_ci } 4131cb0ef41Sopenharmony_ci 4141cb0ef41Sopenharmony_ci ares_dns_record_write_ttl_decrement( 4151cb0ef41Sopenharmony_ci entry->dnsrec, (unsigned int)(now->tv_sec - entry->insert_ts)); 4161cb0ef41Sopenharmony_ci 4171cb0ef41Sopenharmony_ci status = ares_dns_write(entry->dnsrec, buf, buf_len); 4181cb0ef41Sopenharmony_ci 4191cb0ef41Sopenharmony_cidone: 4201cb0ef41Sopenharmony_ci ares_free(key); 4211cb0ef41Sopenharmony_ci return status; 4221cb0ef41Sopenharmony_ci} 4231cb0ef41Sopenharmony_ci 4241cb0ef41Sopenharmony_ciares_status_t ares_qcache_insert(ares_channel_t *channel, 4251cb0ef41Sopenharmony_ci const struct timeval *now, 4261cb0ef41Sopenharmony_ci const struct query *query, 4271cb0ef41Sopenharmony_ci ares_dns_record_t *dnsrec) 4281cb0ef41Sopenharmony_ci{ 4291cb0ef41Sopenharmony_ci return ares__qcache_insert(channel->qcache, dnsrec, query->qbuf, query->qlen, 4301cb0ef41Sopenharmony_ci now); 4311cb0ef41Sopenharmony_ci} 4321cb0ef41Sopenharmony_ci 4331cb0ef41Sopenharmony_ciares_status_t ares_qcache_fetch(ares_channel_t *channel, 4341cb0ef41Sopenharmony_ci const struct timeval *now, 4351cb0ef41Sopenharmony_ci const unsigned char *qbuf, size_t qlen, 4361cb0ef41Sopenharmony_ci unsigned char **abuf, size_t *alen) 4371cb0ef41Sopenharmony_ci{ 4381cb0ef41Sopenharmony_ci ares_status_t status; 4391cb0ef41Sopenharmony_ci ares_dns_record_t *dnsrec = NULL; 4401cb0ef41Sopenharmony_ci 4411cb0ef41Sopenharmony_ci if (channel->qcache == NULL) { 4421cb0ef41Sopenharmony_ci return ARES_ENOTFOUND; 4431cb0ef41Sopenharmony_ci } 4441cb0ef41Sopenharmony_ci 4451cb0ef41Sopenharmony_ci status = ares_dns_parse(qbuf, qlen, 0, &dnsrec); 4461cb0ef41Sopenharmony_ci if (status != ARES_SUCCESS) { 4471cb0ef41Sopenharmony_ci goto done; 4481cb0ef41Sopenharmony_ci } 4491cb0ef41Sopenharmony_ci 4501cb0ef41Sopenharmony_ci status = ares__qcache_fetch(channel->qcache, dnsrec, now, abuf, alen); 4511cb0ef41Sopenharmony_ci 4521cb0ef41Sopenharmony_cidone: 4531cb0ef41Sopenharmony_ci ares_dns_record_destroy(dnsrec); 4541cb0ef41Sopenharmony_ci return status; 4551cb0ef41Sopenharmony_ci} 456