| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064 |
- /*************************************************************************
- *
- * Copyright (C) 2018-2025 Ruilin Peng (Nick) <[email protected]>.
- *
- * smartdns is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * smartdns is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "context.h"
- #include "address.h"
- #include "audit.h"
- #include "cache.h"
- #include "dns_server.h"
- #include "ip_rule.h"
- #include "ipset_nftset.h"
- #include "request.h"
- #include "request_pending.h"
- #include "rules.h"
- #include "soa.h"
- void _dns_server_post_context_init(struct dns_server_post_context *context, struct dns_request *request)
- {
- memset(context, 0, sizeof(*context));
- context->packet = (struct dns_packet *)(context->packet_buff);
- context->packet_maxlen = sizeof(context->packet_buff);
- context->inpacket = (unsigned char *)(context->inpacket_buff);
- context->inpacket_maxlen = sizeof(context->inpacket_buff);
- context->qtype = request->qtype;
- context->request = request;
- }
- static void _dns_server_context_add_ip(struct dns_server_post_context *context, const unsigned char *ip_addr)
- {
- if (context->ip_num < MAX_IP_NUM) {
- context->ip_addr[context->ip_num] = ip_addr;
- }
- context->ip_num++;
- }
- void _dns_server_post_context_init_from(struct dns_server_post_context *context, struct dns_request *request,
- struct dns_packet *packet, unsigned char *inpacket, int inpacket_len)
- {
- memset(context, 0, sizeof(*context));
- context->packet = packet;
- context->packet_maxlen = sizeof(context->packet_buff);
- context->inpacket = inpacket;
- context->inpacket_len = inpacket_len;
- context->inpacket_maxlen = sizeof(context->inpacket);
- context->qtype = request->qtype;
- context->request = request;
- }
- static void _dns_rrs_result_log(struct dns_server_post_context *context, struct dns_ip_address *addr_map)
- {
- struct dns_request *request = context->request;
- if (context->do_log_result == 0 || addr_map == NULL) {
- return;
- }
- if (addr_map->addr_type == DNS_T_A) {
- tlog(TLOG_INFO, "result: %s, id: %d, index: %d, rtt: %.1f ms, %d.%d.%d.%d", request->domain, request->id,
- context->ip_num, ((float)addr_map->ping_time) / 10, addr_map->ip_addr[0], addr_map->ip_addr[1],
- addr_map->ip_addr[2], addr_map->ip_addr[3]);
- } else if (addr_map->addr_type == DNS_T_AAAA) {
- tlog(TLOG_INFO,
- "result: %s, id: %d, index: %d, rtt: %.1f ms, "
- "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
- request->domain, request->id, context->ip_num, ((float)addr_map->ping_time) / 10, addr_map->ip_addr[0],
- addr_map->ip_addr[1], addr_map->ip_addr[2], addr_map->ip_addr[3], addr_map->ip_addr[4],
- addr_map->ip_addr[5], addr_map->ip_addr[6], addr_map->ip_addr[7], addr_map->ip_addr[8],
- addr_map->ip_addr[9], addr_map->ip_addr[10], addr_map->ip_addr[11], addr_map->ip_addr[12],
- addr_map->ip_addr[13], addr_map->ip_addr[14], addr_map->ip_addr[15]);
- }
- }
- static int _dns_rrs_add_all_best_ip(struct dns_server_post_context *context)
- {
- struct dns_ip_address *addr_map = NULL;
- struct dns_ip_address *added_ip_addr = NULL;
- struct hlist_node *tmp = NULL;
- struct dns_request *request = context->request;
- unsigned long bucket = 0;
- char *domain = NULL;
- int ret = 0;
- int ignore_speed = 0;
- int maxhit = 0;
- if (context->select_all_best_ip == 0 || context->ip_num >= request->conf->dns_max_reply_ip_num) {
- return 0;
- }
- domain = request->domain;
- /* add CNAME record */
- if (request->has_cname) {
- domain = request->cname;
- }
- /* add fasted ip address at first place of dns RR */
- if (request->has_ip) {
- added_ip_addr = _dns_ip_address_get(request, request->ip_addr, request->qtype);
- _dns_rrs_result_log(context, added_ip_addr);
- }
- if (request->passthrough == 2) {
- ignore_speed = 1;
- }
- while (true) {
- pthread_mutex_lock(&request->ip_map_lock);
- hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
- {
- if (context->ip_num >= request->conf->dns_max_reply_ip_num) {
- break;
- }
- if (context->qtype != addr_map->addr_type) {
- continue;
- }
- if (addr_map == added_ip_addr) {
- continue;
- }
- if (addr_map->hitnum > maxhit) {
- maxhit = addr_map->hitnum;
- }
- if (addr_map->ping_time < 0 && ignore_speed == 0) {
- continue;
- }
- if (addr_map->hitnum < maxhit && ignore_speed == 1) {
- continue;
- }
- /* if ping time is larger than 5ms, check again. */
- if (addr_map->ping_time - request->ping_time >= 50) {
- int ttl_range = request->ping_time + request->ping_time / 10 + 5;
- if ((ttl_range < addr_map->ping_time) && addr_map->ping_time >= 100 && ignore_speed == 0) {
- continue;
- }
- }
- _dns_server_context_add_ip(context, addr_map->ip_addr);
- if (addr_map->addr_type == DNS_T_A) {
- ret |= dns_add_A(context->packet, DNS_RRS_AN, domain, request->ip_ttl, addr_map->ip_addr);
- } else if (addr_map->addr_type == DNS_T_AAAA) {
- ret |= dns_add_AAAA(context->packet, DNS_RRS_AN, domain, request->ip_ttl, addr_map->ip_addr);
- }
- _dns_rrs_result_log(context, addr_map);
- }
- pthread_mutex_unlock(&request->ip_map_lock);
- if (context->ip_num <= 0 && ignore_speed == 0) {
- ignore_speed = 1;
- } else {
- break;
- }
- }
- return ret;
- }
- static int _dns_server_add_srv(struct dns_server_post_context *context)
- {
- struct dns_request *request = context->request;
- struct dns_srv_records *srv_records = request->srv_records;
- struct dns_srv_record *srv_record = NULL;
- int ret = 0;
- if (srv_records == NULL) {
- return 0;
- }
- list_for_each_entry(srv_record, &srv_records->list, list)
- {
- ret = dns_add_SRV(context->packet, DNS_RRS_AN, request->domain, request->ip_ttl, srv_record->priority,
- srv_record->weight, srv_record->port, srv_record->host);
- if (ret != 0) {
- return -1;
- }
- }
- return 0;
- }
- static int _dns_add_rrs_ip_hint(struct dns_server_post_context *context, struct dns_rr_nested *param, dns_type_t qtype)
- {
- typedef int (*addfunc)(struct dns_rr_nested *svcparam, unsigned char *addr[], int addr_num);
- struct dns_request *request = context->request;
- struct dns_ip_address *addr_map = NULL;
- unsigned long bucket = 0;
- struct hlist_node *tmp = NULL;
- int ret = 0;
- int all_ips = 0;
- int addr_num = 0;
- addfunc add_func = NULL;
- unsigned char *addr[8];
- int addr_buffer_size = sizeof(addr) / sizeof(addr[0]);
- if (qtype == DNS_T_A) {
- add_func = dns_HTTPS_add_ipv4hint;
- } else if (qtype == DNS_T_AAAA) {
- add_func = dns_HTTPS_add_ipv6hint;
- } else {
- return 0; // Unsupported type
- }
- if (request->passthrough == 2) {
- all_ips = 1;
- }
- if (request->has_ip == 0) {
- return 0;
- }
- if (all_ips == 0) {
- if (request->ip_addr_type == (int)qtype) {
- addr[0] = request->ip_addr;
- ret = add_func(param, addr, 1);
- return ret;
- }
- return 0;
- }
- ret = 0;
- pthread_mutex_lock(&request->ip_map_lock);
- hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
- {
- if (addr_map->addr_type == qtype) {
- addr[addr_num] = addr_map->ip_addr;
- addr_num++;
- if (addr_num >= addr_buffer_size) {
- break;
- }
- }
- }
- pthread_mutex_unlock(&request->ip_map_lock);
- if (addr_num > 0) {
- ret = add_func(param, addr, addr_num);
- }
- return ret;
- }
- static int _dns_add_rrs_HTTPS(struct dns_server_post_context *context)
- {
- struct dns_request *request = context->request;
- struct dns_request_https *https_svcb = request->https_svcb;
- int ret = 0;
- struct dns_rr_nested param;
- if (https_svcb == NULL || request->qtype != DNS_T_HTTPS) {
- return 0;
- }
- ret = dns_add_HTTPS_start(¶m, context->packet, DNS_RRS_AN, https_svcb->domain, https_svcb->ttl,
- https_svcb->priority, https_svcb->target);
- if (ret != 0) {
- return ret;
- }
- if (https_svcb->alpn[0] != '\0' && https_svcb->alpn_len > 0) {
- ret = dns_HTTPS_add_alpn(¶m, https_svcb->alpn, https_svcb->alpn_len);
- if (ret != 0) {
- return ret;
- }
- }
- if (https_svcb->port != 0) {
- ret = dns_HTTPS_add_port(¶m, https_svcb->port);
- if (ret != 0) {
- return ret;
- }
- }
- ret = _dns_add_rrs_ip_hint(context, ¶m, DNS_T_A);
- if (ret != 0) {
- return ret;
- }
- if (https_svcb->ech_len > 0) {
- ret = dns_HTTPS_add_ech(¶m, https_svcb->ech, https_svcb->ech_len);
- if (ret != 0) {
- return ret;
- }
- }
- ret = _dns_add_rrs_ip_hint(context, ¶m, DNS_T_AAAA);
- if (ret != 0) {
- return ret;
- }
- dns_add_HTTPS_end(¶m);
- return 0;
- }
- static int _dns_add_rrs(struct dns_server_post_context *context)
- {
- struct dns_request *request = context->request;
- int ret = 0;
- int has_soa = request->has_soa;
- char *domain = request->domain;
- if (request->has_ptr) {
- /* add PTR record */
- ret = dns_add_PTR(context->packet, DNS_RRS_AN, request->domain, request->ip_ttl, request->ptr_hostname);
- }
- /* add CNAME record */
- if (request->has_cname && context->do_force_soa == 0) {
- ret |= dns_add_CNAME(context->packet, DNS_RRS_AN, request->domain, request->ttl_cname, request->cname);
- domain = request->cname;
- }
- if (request->https_svcb != NULL) {
- ret = _dns_add_rrs_HTTPS(context);
- }
- /* add A record */
- if (request->has_ip && context->do_force_soa == 0) {
- _dns_server_context_add_ip(context, request->ip_addr);
- if (context->qtype == DNS_T_A) {
- ret |= dns_add_A(context->packet, DNS_RRS_AN, domain, request->ip_ttl, request->ip_addr);
- tlog(TLOG_DEBUG, "result: %s, rtt: %.1f ms, %d.%d.%d.%d", request->domain, ((float)request->ping_time) / 10,
- request->ip_addr[0], request->ip_addr[1], request->ip_addr[2], request->ip_addr[3]);
- }
- /* add AAAA record */
- if (context->qtype == DNS_T_AAAA) {
- ret |= dns_add_AAAA(context->packet, DNS_RRS_AN, domain, request->ip_ttl, request->ip_addr);
- tlog(TLOG_DEBUG,
- "result: %s, rtt: %.1f ms, "
- "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
- request->domain, ((float)request->ping_time) / 10, request->ip_addr[0], request->ip_addr[1],
- request->ip_addr[2], request->ip_addr[3], request->ip_addr[4], request->ip_addr[5],
- request->ip_addr[6], request->ip_addr[7], request->ip_addr[8], request->ip_addr[9],
- request->ip_addr[10], request->ip_addr[11], request->ip_addr[12], request->ip_addr[13],
- request->ip_addr[14], request->ip_addr[15]);
- }
- }
- if (context->do_force_soa == 0) {
- ret |= _dns_rrs_add_all_best_ip(context);
- }
- if (context->qtype == DNS_T_A || context->qtype == DNS_T_AAAA) {
- if (context->ip_num > 0) {
- has_soa = 0;
- }
- }
- /* add SOA record */
- if (has_soa) {
- ret |= dns_add_SOA(context->packet, DNS_RRS_NS, domain, request->ip_ttl, &request->soa);
- tlog(TLOG_DEBUG, "result: %s, qtype: %d, return SOA", request->domain, context->qtype);
- } else if (context->do_force_soa == 1) {
- _dns_server_setup_soa(request);
- ret |= dns_add_SOA(context->packet, DNS_RRS_NS, domain, request->ip_ttl, &request->soa);
- }
- if (request->has_ecs) {
- ret |= dns_add_OPT_ECS(context->packet, &request->ecs);
- }
- if (request->srv_records != NULL) {
- ret |= _dns_server_add_srv(context);
- }
- if (request->rcode != DNS_RC_NOERROR) {
- tlog(TLOG_INFO, "result: %s, qtype: %d, rtcode: %d, id: %d", domain, context->qtype, request->rcode,
- request->id);
- }
- return ret;
- }
- static int _dns_setup_dns_packet(struct dns_server_post_context *context)
- {
- struct dns_head head;
- struct dns_request *request = context->request;
- int ret = 0;
- memset(&head, 0, sizeof(head));
- head.id = request->id;
- head.qr = DNS_QR_ANSWER;
- head.opcode = DNS_OP_QUERY;
- head.rd = 1;
- head.ra = 1;
- head.aa = 0;
- head.tc = 0;
- head.rcode = request->rcode;
- /* init a new DNS packet */
- ret = dns_packet_init(context->packet, context->packet_maxlen, &head);
- if (ret != 0) {
- return -1;
- }
- if (request->domain[0] == '\0') {
- return 0;
- }
- /* add request domain */
- ret = dns_add_domain(context->packet, request->domain, context->qtype, request->qclass);
- if (ret != 0) {
- return -1;
- }
- /* add RECORDs */
- ret = _dns_add_rrs(context);
- if (ret != 0) {
- return -1;
- }
- return 0;
- }
- static int _dns_setup_dns_raw_packet(struct dns_server_post_context *context)
- {
- /* encode to binary data */
- int encode_len = dns_encode(context->inpacket, context->inpacket_maxlen, context->packet);
- if (encode_len <= 0) {
- tlog(TLOG_DEBUG, "encode raw packet failed for %s", context->request->domain);
- return -1;
- }
- context->inpacket_len = encode_len;
- return 0;
- }
- static int _dns_result_callback(struct dns_server_post_context *context)
- {
- struct dns_result result;
- char ip[DNS_MAX_CNAME_LEN];
- unsigned int ping_time = -1;
- struct dns_request *request = context->request;
- if (request->result_callback == NULL) {
- return 0;
- }
- if (atomic_inc_return(&request->do_callback) != 1) {
- return 0;
- }
- ip[0] = 0;
- memset(&result, 0, sizeof(result));
- ping_time = request->ping_time;
- result.domain = request->domain;
- result.rtcode = request->rcode;
- result.addr_type = request->qtype;
- result.ip = ip;
- result.has_soa = request->has_soa | context->do_force_soa;
- result.ping_time = ping_time;
- result.ip_num = 0;
- if (request->has_ip != 0 && context->do_force_soa == 0) {
- for (int i = 0; i < context->ip_num && i < MAX_IP_NUM; i++) {
- result.ip_addr[i] = context->ip_addr[i];
- result.ip_num++;
- }
- if (request->qtype == DNS_T_A) {
- snprintf(ip, sizeof(ip), "%d.%d.%d.%d", request->ip_addr[0], request->ip_addr[1], request->ip_addr[2],
- request->ip_addr[3]);
- } else if (request->qtype == DNS_T_AAAA) {
- snprintf(ip, sizeof(ip), "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
- request->ip_addr[0], request->ip_addr[1], request->ip_addr[2], request->ip_addr[3],
- request->ip_addr[4], request->ip_addr[5], request->ip_addr[6], request->ip_addr[7],
- request->ip_addr[8], request->ip_addr[9], request->ip_addr[10], request->ip_addr[11],
- request->ip_addr[12], request->ip_addr[13], request->ip_addr[14], request->ip_addr[15]);
- }
- }
- return request->result_callback(&result, request->user_ptr);
- }
- static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context *context)
- {
- int ttl = 0;
- struct dns_request *request = context->request;
- char name[DNS_MAX_CNAME_LEN] = {0};
- int rr_count = 0;
- int timeout_value = 0;
- int ipset_timeout_value = 0;
- int nftset_timeout_value = 0;
- int i = 0;
- int j = 0;
- struct dns_conf_group *conf;
- struct dns_rrs *rrs = NULL;
- struct dns_ipset_rule *rule = NULL;
- struct dns_ipset_rule *ipset_rule = NULL;
- struct dns_ipset_rule *ipset_rule_v4 = NULL;
- struct dns_ipset_rule *ipset_rule_v6 = NULL;
- struct dns_nftset_rule *nftset_ip = NULL;
- struct dns_nftset_rule *nftset_ip6 = NULL;
- struct dns_rule_flags *rule_flags = NULL;
- int check_no_speed_rule = 0;
- if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_IPSET) == 0) {
- return 0;
- }
- if (context->do_ipset == 0) {
- return 0;
- }
- if (context->ip_num <= 0) {
- return 0;
- }
- if (request->ping_time < 0 && request->has_ip > 0 && request->passthrough == 0) {
- check_no_speed_rule = 1;
- }
- conf = request->conf;
- /* check ipset rule */
- rule_flags = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS);
- if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
- ipset_rule = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET);
- if (ipset_rule == NULL) {
- ipset_rule = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET);
- }
- if (ipset_rule == NULL && check_no_speed_rule && conf->ipset_nftset.ipset_no_speed.inet_enable) {
- ipset_rule_v4 = &conf->ipset_nftset.ipset_no_speed.inet;
- }
- }
- if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
- ipset_rule_v4 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV4);
- if (ipset_rule_v4 == NULL) {
- ipset_rule_v4 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET_IPV4);
- }
- if (ipset_rule_v4 == NULL && check_no_speed_rule && conf->ipset_nftset.ipset_no_speed.ipv4_enable) {
- ipset_rule_v4 = &conf->ipset_nftset.ipset_no_speed.ipv4;
- }
- }
- if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV6_IGN) == 0) {
- ipset_rule_v6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV6);
- if (ipset_rule_v6 == NULL) {
- ipset_rule_v6 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_IPSET_IPV6);
- }
- if (ipset_rule_v6 == NULL && check_no_speed_rule && conf->ipset_nftset.ipset_no_speed.ipv6_enable) {
- ipset_rule_v6 = &conf->ipset_nftset.ipset_no_speed.ipv6;
- }
- }
- if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP_IGN) == 0) {
- nftset_ip = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP);
- if (nftset_ip == NULL) {
- nftset_ip = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_NFTSET_IP);
- }
- if (nftset_ip == NULL && check_no_speed_rule && conf->ipset_nftset.nftset_no_speed.ip_enable) {
- nftset_ip = &conf->ipset_nftset.nftset_no_speed.ip;
- }
- }
- if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP6_IGN) == 0) {
- nftset_ip6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP6);
- if (nftset_ip6 == NULL) {
- nftset_ip6 = _dns_server_get_bind_ipset_nftset_rule(request, DOMAIN_RULE_NFTSET_IP6);
- }
- if (nftset_ip6 == NULL && check_no_speed_rule && conf->ipset_nftset.nftset_no_speed.ip6_enable) {
- nftset_ip6 = &conf->ipset_nftset.nftset_no_speed.ip6;
- }
- }
- if (!(ipset_rule || ipset_rule_v4 || ipset_rule_v6 || nftset_ip || nftset_ip6)) {
- return 0;
- }
- timeout_value = request->ip_ttl * 3;
- if (timeout_value == 0) {
- timeout_value = _dns_server_get_conf_ttl(request, 0) * 3;
- }
- if (conf->ipset_nftset.ipset_timeout_enable) {
- ipset_timeout_value = timeout_value;
- }
- if (conf->ipset_nftset.nftset_timeout_enable) {
- nftset_timeout_value = timeout_value;
- }
- for (j = 1; j < DNS_RRS_OPT; j++) {
- rrs = dns_get_rrs_start(context->packet, j, &rr_count);
- for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(context->packet, rrs)) {
- switch (rrs->type) {
- case DNS_T_A: {
- unsigned char addr[4];
- if (context->qtype != DNS_T_A) {
- break;
- }
- /* get A result */
- dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
- rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
- _dns_server_add_ipset_nftset(request, rule, nftset_ip, addr, DNS_RR_A_LEN, ipset_timeout_value,
- nftset_timeout_value);
- } break;
- case DNS_T_AAAA: {
- unsigned char addr[16];
- if (context->qtype != DNS_T_AAAA) {
- /* ignore non-matched query type */
- break;
- }
- dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
- rule = ipset_rule_v6 ? ipset_rule_v6 : ipset_rule;
- _dns_server_add_ipset_nftset(request, rule, nftset_ip6, addr, DNS_RR_AAAA_LEN, ipset_timeout_value,
- nftset_timeout_value);
- } break;
- case DNS_T_HTTPS: {
- char target[DNS_MAX_CNAME_LEN] = {0};
- struct dns_https_param *p = NULL;
- int priority = 0;
- int ret = dns_get_HTTPS_svcparm_start(rrs, &p, name, DNS_MAX_CNAME_LEN, &ttl, &priority, target,
- DNS_MAX_CNAME_LEN);
- if (ret != 0) {
- tlog(TLOG_WARN, "get HTTPS svcparm failed");
- return -1;
- }
- for (; p; p = dns_get_HTTPS_svcparm_next(rrs, p)) {
- switch (p->key) {
- case DNS_HTTPS_T_IPV4HINT: {
- unsigned char *addr;
- for (int k = 0; k < p->len / 4; k++) {
- addr = p->value + k * 4;
- rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
- _dns_server_add_ipset_nftset(request, rule, nftset_ip, addr, DNS_RR_A_LEN,
- ipset_timeout_value, nftset_timeout_value);
- }
- } break;
- case DNS_HTTPS_T_IPV6HINT: {
- unsigned char *addr;
- for (int k = 0; k < p->len / 16; k++) {
- addr = p->value + k * 16;
- rule = ipset_rule_v6 ? ipset_rule_v6 : ipset_rule;
- _dns_server_add_ipset_nftset(request, rule, nftset_ip6, addr, DNS_RR_AAAA_LEN,
- ipset_timeout_value, nftset_timeout_value);
- }
- } break;
- default:
- break;
- }
- }
- } break;
- default:
- break;
- }
- }
- }
- return 0;
- }
- static int _dns_result_child_post(struct dns_server_post_context *context)
- {
- struct dns_request *request = context->request;
- struct dns_request *parent_request = request->parent_request;
- DNS_CHILD_POST_RESULT child_ret = DNS_CHILD_POST_FAIL;
- /* not a child request */
- if (parent_request == NULL) {
- return 0;
- }
- if (request->child_callback) {
- int is_first_resp = context->no_release_parent;
- child_ret = request->child_callback(parent_request, request, is_first_resp);
- }
- if (context->do_reply == 1 && child_ret == DNS_CHILD_POST_SUCCESS) {
- struct dns_server_post_context parent_context;
- _dns_server_post_context_init(&parent_context, parent_request);
- parent_context.do_cache = context->do_cache;
- parent_context.do_ipset = context->do_ipset;
- parent_context.do_force_soa = context->do_force_soa;
- parent_context.do_audit = context->do_audit;
- parent_context.do_reply = context->do_reply;
- parent_context.reply_ttl = context->reply_ttl;
- parent_context.cache_ttl = context->cache_ttl;
- parent_context.skip_notify_count = context->skip_notify_count;
- parent_context.select_all_best_ip = 1;
- parent_context.no_release_parent = context->no_release_parent;
- _dns_request_post(&parent_context);
- _dns_server_reply_all_pending_list(parent_request, &parent_context);
- }
- if (context->no_release_parent == 0) {
- tlog(TLOG_DEBUG, "query %s with child %s done", parent_request->domain, request->domain);
- request->parent_request = NULL;
- parent_request->request_wait--;
- _dns_server_request_release(parent_request);
- }
- if (child_ret == DNS_CHILD_POST_FAIL) {
- return -1;
- }
- return 0;
- }
- static int _dns_request_update_id_ttl(struct dns_server_post_context *context)
- {
- int ttl = context->reply_ttl;
- struct dns_request *request = context->request;
- if (request->conf->dns_rr_ttl_reply_max > 0) {
- if (request->ip_ttl > request->conf->dns_rr_ttl_reply_max && ttl == 0) {
- ttl = request->ip_ttl;
- }
- if (ttl > request->conf->dns_rr_ttl_reply_max) {
- ttl = request->conf->dns_rr_ttl_reply_max;
- }
- if (ttl == 0) {
- ttl = request->conf->dns_rr_ttl_reply_max;
- }
- }
- if (ttl == 0) {
- ttl = request->ip_ttl;
- if (ttl == 0) {
- ttl = _dns_server_get_conf_ttl(request, ttl);
- }
- }
- struct dns_update_param param;
- param.id = request->id;
- param.cname_ttl = ttl;
- param.ip_ttl = ttl;
- if (dns_packet_update(context->inpacket, context->inpacket_len, ¶m) != 0) {
- tlog(TLOG_DEBUG, "update packet info failed.");
- }
- return 0;
- }
- int _dns_request_post(struct dns_server_post_context *context)
- {
- struct dns_request *request = context->request;
- char clientip[DNS_MAX_CNAME_LEN] = {0};
- int ret = 0;
- tlog(TLOG_DEBUG, "reply %s qtype: %d, rcode: %d, reply: %d", request->domain, request->qtype,
- context->packet->head.rcode, context->do_reply);
- /* init a new DNS packet */
- ret = _dns_setup_dns_packet(context);
- if (ret != 0) {
- tlog(TLOG_ERROR, "setup dns packet failed.");
- return -1;
- }
- ret = _dns_setup_dns_raw_packet(context);
- if (ret != 0) {
- tlog(TLOG_ERROR, "set dns raw packet failed.");
- return -1;
- }
- /* cache reply packet */
- ret = _dns_cache_reply_packet(context);
- if (ret != 0) {
- tlog(TLOG_WARN, "cache packet for %s failed.", request->domain);
- }
- /* setup ipset */
- _dns_server_setup_ipset_nftset_packet(context);
- /* reply child request */
- _dns_result_child_post(context);
- if (context->do_reply == 0) {
- return 0;
- }
- if (context->skip_notify_count == 0) {
- if (atomic_inc_return(&request->notified) != 1) {
- tlog(TLOG_DEBUG, "skip reply %s %d", request->domain, request->qtype);
- return 0;
- }
- }
- /* log audit log */
- _dns_server_audit_log(context);
- /* reply API callback */
- _dns_result_callback(context);
- if (request->conn == NULL) {
- return 0;
- }
- ret = _dns_request_update_id_ttl(context);
- if (ret != 0) {
- tlog(TLOG_ERROR, "update packet ttl failed.");
- return -1;
- }
- tlog(TLOG_INFO, "result: %s, client: %s, qtype: %d, id: %d, group: %s, time: %lums", request->domain,
- get_host_by_addr(clientip, sizeof(clientip), (struct sockaddr *)&request->addr), request->qtype, request->id,
- request->dns_group_name[0] != '\0' ? request->dns_group_name : DNS_SERVER_GROUP_DEFAULT,
- get_tick_count() - request->send_tick);
- ret = _dns_reply_inpacket(request, context->inpacket, context->inpacket_len);
- if (ret != 0) {
- tlog(TLOG_DEBUG, "reply raw packet to client failed.");
- return -1;
- }
- return 0;
- }
- int _dns_server_get_answer(struct dns_server_post_context *context)
- {
- int i = 0;
- int j = 0;
- int ttl = 0;
- struct dns_rrs *rrs = NULL;
- int rr_count = 0;
- struct dns_request *request = context->request;
- struct dns_packet *packet = context->packet;
- for (j = 1; j < DNS_RRS_OPT; j++) {
- rrs = dns_get_rrs_start(packet, j, &rr_count);
- for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
- switch (rrs->type) {
- case DNS_T_A: {
- unsigned char addr[4];
- char name[DNS_MAX_CNAME_LEN] = {0};
- struct dns_ip_address *addr_map = NULL;
- if (request->qtype != DNS_T_A) {
- continue;
- }
- /* get A result */
- dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
- if (strncasecmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
- strncasecmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
- continue;
- }
- if (context->no_check_add_ip == 0 &&
- _dns_ip_address_check_add(request, name, addr, DNS_T_A, request->ping_time, &addr_map) != 0) {
- continue;
- }
- if (addr_map != NULL) {
- _dns_server_context_add_ip(context, addr_map->ip_addr);
- }
- if (request->has_ip == 1) {
- continue;
- }
- memcpy(request->ip_addr, addr, DNS_RR_A_LEN);
- /* add this ip to request */
- request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
- request->has_ip = 1;
- request->rcode = packet->head.rcode;
- } break;
- case DNS_T_AAAA: {
- unsigned char addr[16];
- char name[DNS_MAX_CNAME_LEN] = {0};
- struct dns_ip_address *addr_map = NULL;
- if (request->qtype != DNS_T_AAAA) {
- /* ignore non-matched query type */
- continue;
- }
- dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
- if (strncasecmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
- strncasecmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
- continue;
- }
- if (context->no_check_add_ip == 0 &&
- _dns_ip_address_check_add(request, name, addr, DNS_T_AAAA, request->ping_time, &addr_map) != 0) {
- continue;
- }
- if (addr_map != NULL) {
- _dns_server_context_add_ip(context, addr_map->ip_addr);
- }
- if (request->has_ip == 1) {
- continue;
- }
- memcpy(request->ip_addr, addr, DNS_RR_AAAA_LEN);
- request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
- request->has_ip = 1;
- request->rcode = packet->head.rcode;
- } break;
- case DNS_T_NS: {
- char cname[DNS_MAX_CNAME_LEN];
- char name[DNS_MAX_CNAME_LEN] = {0};
- dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
- tlog(TLOG_DEBUG, "NS: %s, ttl: %d, cname: %s\n", name, ttl, cname);
- } break;
- case DNS_T_CNAME: {
- char cname[DNS_MAX_CNAME_LEN];
- char name[DNS_MAX_CNAME_LEN] = {0};
- if (request->conf->dns_force_no_cname) {
- continue;
- }
- dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
- tlog(TLOG_DEBUG, "name: %s, ttl: %d, cname: %s\n", name, ttl, cname);
- if (strncasecmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
- strncasecmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
- continue;
- }
- safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
- request->ttl_cname = _dns_server_get_conf_ttl(request, ttl);
- request->has_cname = 1;
- } break;
- case DNS_T_SOA: {
- char name[DNS_MAX_CNAME_LEN] = {0};
- request->has_soa = 1;
- if (request->rcode != DNS_RC_NOERROR) {
- request->rcode = packet->head.rcode;
- }
- dns_get_SOA(rrs, name, 128, &ttl, &request->soa);
- tlog(TLOG_DEBUG,
- "domain: %s, qtype: %d, SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, "
- "expire: "
- "%d, minimum: %d",
- request->domain, request->qtype, request->soa.mname, request->soa.rname, request->soa.serial,
- request->soa.refresh, request->soa.retry, request->soa.expire, request->soa.minimum);
- request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
- } break;
- default:
- break;
- }
- }
- }
- return 0;
- }
- int _dns_cache_reply_packet(struct dns_server_post_context *context)
- {
- struct dns_request *request = context->request;
- int speed = -1;
- if (context->do_cache == 0 || request->no_cache == 1) {
- return 0;
- }
- if (context->packet->head.rcode == DNS_RC_SERVFAIL || context->packet->head.rcode == DNS_RC_NXDOMAIN ||
- context->packet->head.rcode == DNS_RC_NOTIMP) {
- context->reply_ttl = DNS_SERVER_FAIL_TTL;
- /* Do not cache record if cannot connect to remote */
- if (request->remote_server_fail == 0 && context->packet->head.rcode == DNS_RC_SERVFAIL) {
- /* Try keep old cache if server fail */
- _dns_cache_try_keep_old_cache(request);
- return 0;
- }
- if (context->packet->head.rcode == DNS_RC_NOTIMP) {
- return 0;
- }
- return _dns_cache_packet(context);
- }
- if (context->qtype != DNS_T_AAAA && context->qtype != DNS_T_A && context->qtype != DNS_T_HTTPS) {
- return _dns_cache_specify_packet(context);
- }
- struct dns_cache_data *cache_packet = dns_cache_new_data_packet(context->inpacket, context->inpacket_len);
- if (cache_packet == NULL) {
- return -1;
- }
- speed = request->ping_time;
- if (context->do_force_soa) {
- speed = -1;
- }
- if (_dns_server_request_update_cache(request, speed, context->qtype, cache_packet, context->cache_ttl) != 0) {
- tlog(TLOG_WARN, "update packet cache failed.");
- }
- _dns_cache_cname_packet(context);
- return 0;
- }
- int _dns_server_reply_passthrough(struct dns_server_post_context *context)
- {
- struct dns_request *request = context->request;
- if (atomic_inc_return(&request->notified) != 1) {
- return 0;
- }
- _dns_server_get_answer(context);
- _dns_cache_reply_packet(context);
- if (_dns_server_setup_ipset_nftset_packet(context) != 0) {
- tlog(TLOG_DEBUG, "setup ipset failed.");
- }
- _dns_result_callback(context);
- _dns_server_audit_log(context);
- /* reply child request */
- _dns_result_child_post(context);
- if (request->conn && context->do_reply == 1) {
- char clientip[DNS_MAX_CNAME_LEN] = {0};
- /* When passthrough, modify the id to be the id of the client request. */
- int ret = _dns_request_update_id_ttl(context);
- if (ret != 0) {
- tlog(TLOG_ERROR, "update packet ttl failed.");
- return -1;
- }
- _dns_reply_inpacket(request, context->inpacket, context->inpacket_len);
- tlog(TLOG_INFO, "result: %s, client: %s, qtype: %d, id: %d, group: %s, time: %lums", request->domain,
- get_host_by_addr(clientip, sizeof(clientip), (struct sockaddr *)&request->addr), request->qtype,
- request->id, request->dns_group_name[0] != '\0' ? request->dns_group_name : DNS_SERVER_GROUP_DEFAULT,
- get_tick_count() - request->send_tick);
- }
- return _dns_server_reply_all_pending_list(request, context);
- }
|