Compare commits

..

12 Commits

Author SHA1 Message Date
Nick Peng
64e5b326cc luci: fix status section not working issue and add some options 2022-08-28 17:30:24 +08:00
Nick Peng
f659cf3725 dns_conf: support relative path for dnsmasq-lease-file 2022-08-28 10:22:14 +08:00
Nick Peng
83c8105312 dns_server: fix only cache on ip address result issue 2022-08-24 20:05:35 +08:00
Nick Peng
fecc313e03 dns_server: fix SERVERFAIL when A is 127.0.0.1 2022-08-23 22:49:41 +08:00
Nick Peng
145f7cfa42 dns_server: make the TTL of the first request to 2s & fix hostname issue. 2022-08-21 18:29:44 +08:00
Nick Peng
464f2adaa7 fast_ping: fix race condition 2022-08-21 18:29:44 +08:00
Zhong Lufan
7c9288f887 Readme: Fix typo 2022-08-19 19:36:46 +08:00
Nick Peng
96d3deb595 conf: add local-ttl option 2022-08-15 21:35:08 +08:00
Nick Peng
584480dda1 fix: malformed packet crash issue 2022-08-12 20:47:27 +08:00
Nick Peng
2848aa0ac7 server_group: fix server group not working issue. 2022-08-11 23:57:33 +08:00
Nick Peng
c156595f61 optware-script: fix optware init script issue 2022-08-11 23:56:17 +08:00
Thiasap
9dfe51c5ed wsl: Fix the problem of incorrect identification of WSL 2022-08-11 11:54:07 +08:00
20 changed files with 301 additions and 90 deletions

View File

@@ -563,6 +563,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
| rr-ttl-min | 允许的最小 TTL 值 | 远程查询结果 | 大于 0 的数字 | rr-ttl-min 60 |
| rr-ttl-max | 允许的最大 TTL 值 | 远程查询结果 | 大于 0 的数字 | rr-ttl-max 600 |
| rr-ttl-reply-max | 允许返回给客户端的最大 TTL 值 | 远程查询结果 | 大于 0 的数字 | rr-ttl-reply-max 60 |
| local-ttl | 本地HOSTaddress的TTL值 | rr-ttl-min | 大于 0 的数字 | local-ttl 60 |
| max-reply-ip-num | 允许返回给客户的最大IP数量 | IP数量 | 大于 0 的数字 | max-reply-ip-num 1 |
| log-level | 设置日志级别 | error | fatal、error、warn、notice、info 或 debug | log-level error |
| log-file | 日志文件路径 | /var/log/smartdns/smartdns.log | 合法路径字符串 | log-file /var/log/smartdns/smartdns.log |
@@ -578,7 +579,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
| server-tls | 上游 TLS DNS | 无 | 可重复。<br>[ip][:port]:服务器 IP:端口(可选)<br>[-spki-pin [sha256-pin]]TLS 合法性校验 SPKI 值base64 编码的 sha256 SPKI pin 值<br>[-host-name]TLS SNI 名称<br>[-tls-host-verify]TLS 证书主机名校验<br> [-no-check-certificate]:跳过证书校验<br>[-blacklist-ip]:配置 IP 过滤结果<br>[-whitelist-ip]:仅接受参数中配置的 IP 范围<br>[-group [group] ...]DNS 服务器所属组,比如 office 和 foreign和 nameserver 配套使用<br>[-exclude-default-group]:将 DNS 服务器从默认组中排除 | server-tls 8.8.8.8:853 |
| server-https | 上游 HTTPS DNS | 无 | 可重复。<br>https://[host][:port]/path服务器 IP:端口(可选)<br>[-spki-pin [sha256-pin]]TLS 合法性校验 SPKI 值base64 编码的 sha256 SPKI pin 值<br>[-host-name]TLS SNI 名称<br>[-http-host]http 协议头主机名<br>[-tls-host-verify]TLS 证书主机名校验<br> [-no-check-certificate]:跳过证书校验<br>[-blacklist-ip]:配置 IP 过滤结果<br>[-whitelist-ip]:仅接受参数中配置的 IP 范围。<br>[-group [group] ...]DNS 服务器所属组,比如 office 和 foreign和 nameserver 配套使用<br>[-exclude-default-group]:将 DNS 服务器从默认组中排除 | server-https https://cloudflare-dns.com/dns-query |
| speed-check-mode | 测速模式选择 | 无 | [ping\|tcp:[80]\|none] | speed-check-mode ping,tcp:80,tcp:443 |
| response-mode | 首次查询响应模式 | first-ping |模式:[fisrt-ping\|fastest-ip\|first-response]<br> [first-ping]: 最快ping响应地址模式DNS上游最快查询时延+ping时延最短查询等待与链接体验最佳;<br>[fastest-ip]: 最快IP地址模式查询到的所有IP地址中ping最短的IP。需等待IP测速; <br>[first-response]: 最快响应的DNS结果DNS查询等待时间最短返回的IP地址可能不是最快。| response-mode first-ping |
| response-mode | 首次查询响应模式 | first-ping |模式:[fisrt-ping\|fastest-ip\|fastest-response]<br> [first-ping]: 最快ping响应地址模式DNS上游最快查询时延+ping时延最短查询等待与链接体验最佳;<br>[fastest-ip]: 最快IP地址模式查询到的所有IP地址中ping最短的IP。需等待IP测速; <br>[fastest-response]: 最快响应的DNS结果DNS查询等待时间最短返回的IP地址可能不是最快。| response-mode first-ping |
| address | 指定域名 IP 地址 | 无 | address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6] <br>- 表示忽略 <br># 表示返回 SOA <br>4 表示 IPv4 <br>6 表示 IPv6 | address /www.example.com/1.2.3.4 |
| nameserver | 指定域名使用 server 组解析 | 无 | nameserver /domain/[group\|-], group 为组名,- 表示忽略此规则,配套 server 中的 -group 参数使用 | nameserver /www.example.com/office |
| ipset | 域名 ipset | 无 | ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]]-表示忽略 | ipset /www.example.com/#4:dns4,#6:- |

View File

@@ -497,6 +497,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|tcp-idle-time|TCP connection idle timeout|120|integer|tcp-idle-time 120
|rr-ttl|Domain name TTL|Remote query result|number greater than 0|rr-ttl 600
|rr-ttl-min|Domain name Minimum TTL|Remote query result|number greater than 0|rr-ttl-min 60
|local-ttl|ttl for address and host|rr-ttl-min|number greater than 0|local-ttl 600
|rr-ttl-reply-max|Domain name Minimum Reply TTL|Remote query result|number greater than 0|rr-ttl-reply-max 60
|rr-ttl-max|Domain name Maximum TTL|Remote query result|number greater than 0|rr-ttl-max 600
|max-reply-ip-num|Maximum number of IPs returned to the client|8|number of IPs, 1~16 |max-reply-ip-num 1
@@ -514,7 +515,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|server-tls|Upstream TLS DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name. <br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-tls 8.8.8.8:853
|server-https|Upstream HTTPS DNS server|None|Repeatable <br>`https://[host][:port]/path`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name<br>`[-http-host]`http header host. <br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-https https://cloudflare-dns.com/dns-query
|speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:80,tcp:443
|response-mode|First query response mode|first-ping|Mode: [fisrt-ping\|fastest-ip\|first-response]<br> [first-ping]: The fastest dns + ping response mode, DNS query delay + ping delay is the shortest;<br>[fastest-ip]: The fastest IP address mode, return the fastest ip address, may take some time to test speed. <br>[first-response]: The fastest response DNS result mode, the DNS query waiting time is the shortest. | response-mode first-ping |
|response-mode|First query response mode|first-ping|Mode: [fisrt-ping\|fastest-ip\|fastest-response]<br> [first-ping]: The fastest dns + ping response mode, DNS query delay + ping delay is the shortest;<br>[fastest-ip]: The fastest IP address mode, return the fastest ip address, may take some time to test speed. <br>[fastest-response]: The fastest response DNS result mode, the DNS query waiting time is the shortest. | response-mode first-ping |
|address|Domain IP address|None|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-` for ignore, `#` for return SOA, `4` for IPV4, `6` for IPV6| address /www.example.com/1.2.3.4
|nameserver|To query domain with specific server group|None|nameserver /domain/[group\|-], `group` is the group name, `-` means ignore this rule, use the `-group` parameter in the related server|nameserver /www.example.com/office
|ipset|Domain IPSet|None|ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]], `-` for ignore|ipset /www.example.com/#4:dns4,#6:-

View File

@@ -36,7 +36,9 @@
# IPV6:
# bind [::]:53
# bind-tcp [::]:53
bind [::]:53
bind [::]:7053
force-AAAA-SOA yes
# tcp connection idle timeout
# tcp-idle-time [second]

View File

@@ -187,7 +187,7 @@ init_dir()
which systemctl >/dev/null 2>&1
ISSYSTEMD="$?"
# Running under WSL (Windows Subsystem for Linux)?
cat /proc/version | grep Microsoft >/dev/null 2>&1;
cat /proc/version | grep -E '[Mm]icrosoft' >/dev/null 2>&1;
if [ $? -eq 0 ]; then
ISSYSTEMD=1
ISWSL=0

View File

@@ -109,6 +109,12 @@ msgstr "重定向53端口到SmartDNS"
msgid "Cache Size"
msgstr "缓存大小"
msgid "Resolve Local Hostnames"
msgstr "本地主机名解析"
msgid "Resolve local hostnames by reading Dnsmasq lease file"
msgstr "读取Dnsmasq的DHCP Lease文件解析本地主机名"
msgid "DNS domain result cache size"
msgstr "缓存DNS的结果缓存大小配置零则不缓存单位"
@@ -193,8 +199,8 @@ msgstr "跳过cache。"
msgid "Force AAAA SOA"
msgstr "停用IPV6地址解析"
msgid "Force AAAA SOA."
msgstr "停用IPV6地址解析。"
msgid "Force HTTPS SOA."
msgstr "停用HTTPS解析。"
msgid "Upstream Servers"
msgstr "上游服务器"

View File

@@ -31,7 +31,7 @@ var callServiceList = rpc.declare({
expect: { '': {} }
});
function getPidOfSmartdns() {
function getServiceStatus() {
return L.resolveDefault(callServiceList(conf), {})
.then(function (res) {
var isrunning = false;
@@ -49,6 +49,8 @@ function getIPTablesRedirect() {
} else {
return "";
}
}).catch(function (err) {
return "";
});
}
@@ -59,12 +61,14 @@ function getIP6TablesRedirect() {
} else {
return "";
}
});
}).catch(function (err) {
return "";
});;
}
function smartdnsServiceStatus() {
return Promise.all([
getPidOfSmartdns(),
getServiceStatus(),
getIPTablesRedirect(),
getIP6TablesRedirect()
]);
@@ -136,6 +140,10 @@ return L.view.extend({
L.Poll.add(function () {
return L.resolveDefault(smartdnsServiceStatus()).then(function (res) {
var view = document.getElementById("service_status");
if (view == null) {
return;
}
view.innerHTML = smartdnsRenderStatus(res);
});
});
@@ -215,6 +223,21 @@ return L.view.extend({
o = s.taboption("settings", form.Value, "cache_size", _("Cache Size"), _("DNS domain result cache size"));
o.rempty = true;
// cache-size;
o = s.taboption("settings", form.Flag, "resolve_local_hostnames", _("Resolve Local Hostnames"), _("Resolve local hostnames by reading Dnsmasq lease file"));
o.rmempty = false;
o.default = o.enabled;
// Force AAAA SOA
o = s.taboption("settings", form.Flag, "force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
o.rmempty = false;
o.default = o.disabled;
// Force HTTPS SOA
o = s.taboption("settings", form.Flag, "force_https_soa", _("Force HTTPS SOA"), _("Force HTTPS SOA."));
o.rmempty = false;
o.default = o.disabled;
// rr-ttl;
o = s.taboption("settings", form.Value, "rr_ttl", _("Domain TTL"), _("TTL for all domain result."));
o.rempty = true;

View File

@@ -260,6 +260,8 @@ load_service()
{
local section="$1"
args=""
dnsmase_lease_file="$(uci get dhcp.@dnsmasq[0].leasefile 2>/dev/null)"
qtype_soa_list=""
mkdir -p $SMARTDNS_VAR_CONF_DIR
rm -f $SMARTDNS_CONF_TMP
@@ -302,6 +304,15 @@ load_service()
config_get cache_size "$section" "cache_size" ""
[ -z "$cache_size" ] || conf_append "cache-size" "$cache_size"
config_get resolve_local_hostnames "$section" "resolve_local_hostnames" "1"
[ -z "$resolve_local_hostnames" ] || conf_append "dnsmasq-lease-file" "$dnsmase_lease_file"
config_get force_aaaa_soa "$section" "force_aaaa_soa" "0"
[ "$force_aaaa_soa" = "1" ] && qtype_soa_list="$qtype_soa_list 28"
config_get force_https_soa "$section" "force_https_soa" "0"
[ "$force_https_soa" = "1" ] && qtype_soa_list="$qtype_soa_list 65"
config_get rr_ttl "$section" "rr_ttl" ""
[ -z "$rr_ttl" ] || conf_append "rr-ttl" "$rr_ttl"
@@ -331,6 +342,8 @@ load_service()
config_get old_port "$section" "old_port" "0"
config_get old_enabled "$section" "old_enabled" "0"
[ -z "$qtype_soa_list" ] || conf_append "force-qtype-SOA" "$qtype_soa_list"
if [ "$old_redirect" != "$redirect" ] || [ "$old_port" != "$SMARTDNS_PORT" ] || [ "$old_enabled" = "1" -a "$enabled" = "0" ]; then
[ "$old_redirect" = "none" ] || {
[ "$old_port" = "0" ] || clear_iptable "$old_port" "$ipv6_server"

View File

@@ -22,6 +22,7 @@ SMARTDNS_PID=/var/run/smartdns.pid
SMARTDNS_PORT=535
SMARTDNS_OPT=/opt/etc/smartdns/smartdns-opt.conf
# workmode
# DO NOT CHANGE THIS, CHANGE MODE IN smartdns-opt.conf
# 0: run as port only
# 1: redirect port
# 2: replace
@@ -232,11 +233,11 @@ set_smartdns_port()
if [ "$SMARTDNS_WORKMODE" = "0" ]; then
return 0
elif [ "$SMARTDNS_WORKMODE" = "1" ]; then
sed -i "s/^\\(bind .*\\):53 *\\(.*\\)\$/\\1:$SMARTDNS_PORT \\2/g" $SMARTDNS_CONF
sed -i "s/^\\(bind-tcp .*\\):53 *\\(.*\\)\$/\\1:$SMARTDNS_PORT \\2/g" $SMARTDNS_CONF
sed -i "s/^\(bind .*\):53\( .*\)\?$/\1:$SMARTDNS_PORT \2/g" $SMARTDNS_CONF
sed -i "s/^\(bind-tcp .*\):53\( .*\)\?$/\1:$SMARTDNS_PORT \2/g" $SMARTDNS_CONF
elif [ "$SMARTDNS_WORKMODE" = "2" ]; then
sed -i "s/^\\(bind .*\\):$SMARTDNS_PORT *\\(.*\\)\$/\\1:53 \\2/g" $SMARTDNS_CONF
sed -i "s/^\\(bind-tcp .*\\):$SMARTDNS_PORT *\\(.*\\)\$/\\1:53 \\2/g" $SMARTDNS_CONF
sed -i "s/^\(bind .*\):$SMARTDNS_PORT\( .*\)\?$/\1:53 \2/g" $SMARTDNS_CONF
sed -i "s/^\(bind-tcp .*\):$SMARTDNS_PORT\( .*\)\?$/\1:53 \2/g" $SMARTDNS_CONF
else
return 1
fi

View File

@@ -43,7 +43,7 @@
} while (0)
/* read short and move pointer */
static short _dns_read_short(unsigned char **buffer)
static unsigned short _dns_read_short(unsigned char **buffer)
{
unsigned short value = 0;
@@ -549,6 +549,10 @@ static int _dns_add_RAW(struct dns_packet *packet, dns_rr_type rrtype, dns_type_
struct dns_context context;
int ret = 0;
if (raw_len < 0) {
return -1;
}
/* resource record */
/* |domain |
* |qtype | qclass |
@@ -1153,6 +1157,11 @@ static int _dns_decode_rr_head(struct dns_context *context, char *domain, int do
*ttl = _dns_read_int(&context->ptr);
*rr_len = _dns_read_short(&context->ptr);
if (*rr_len < 0 || *ttl < 0) {
tlog(TLOG_DEBUG, "rr len or ttl is invalid.");
return -1;
}
return 0;
}
@@ -1233,7 +1242,7 @@ static int _dns_encode_raw(struct dns_context *context, struct dns_rrs *rrs)
static int _dns_decode_raw(struct dns_context *context, unsigned char *raw, int len)
{
if (_dns_left_len(context) < len) {
if (_dns_left_len(context) < len || len < 0) {
return -1;
}
@@ -1595,6 +1604,11 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*/
if (rr_len < 0) {
tlog(TLOG_DEBUG, "opt len is invalid.");
return -1;
}
if (ercode != 0) {
tlog(TLOG_ERROR, "extend rcode invalid.");
return -1;
@@ -1682,7 +1696,7 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
/* decode rr head */
ret = _dns_decode_rr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
if (ret < 0) {
if (ret < 0 || qclass < 0) {
tlog(TLOG_DEBUG, "decode head failed.");
return -1;
}

View File

@@ -128,9 +128,14 @@ enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data)
return cache_data->head.cache_type;
}
uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data)
uint32_t dns_cache_get_query_flag(struct dns_cache_data *cache_data)
{
return cache_data->head.cache_flag;
return cache_data->head.query_flag;
}
const char *dns_cache_get_dns_group_name(struct dns_cache_data *cache_data)
{
return cache_data->head.dns_group_name;
}
void dns_cache_data_free(struct dns_cache_data *data)
@@ -156,7 +161,8 @@ struct dns_cache_data *dns_cache_new_data(void)
return (struct dns_cache_data *)cache_addr;
}
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl)
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
int cname_ttl)
{
if (dns_cache == NULL) {
goto errout;
@@ -179,7 +185,13 @@ void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag
cache_addr->addr_data.cname_ttl = cname_ttl;
}
cache_addr->head.cache_flag = cache_flag;
if (query_option) {
cache_addr->head.query_flag = query_option->query_flag;
if (query_option->dns_group_name) {
safe_strncpy(cache_addr->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN);
}
}
cache_addr->addr_data.soa = 1;
cache_addr->head.cache_type = CACHE_TYPE_ADDR;
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
@@ -187,8 +199,8 @@ errout:
return;
}
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl,
unsigned char *addr, int addr_len)
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
int cname_ttl, unsigned char *addr, int addr_len)
{
if (dns_cache == NULL) {
goto errout;
@@ -212,14 +224,21 @@ void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_fl
cache_addr->addr_data.cname_ttl = cname_ttl;
}
cache_addr->head.cache_flag = cache_flag;
if (query_option) {
cache_addr->head.query_flag = query_option->query_flag;
if (query_option->dns_group_name) {
safe_strncpy(cache_addr->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN);
}
}
cache_addr->head.cache_type = CACHE_TYPE_ADDR;
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
errout:
return;
}
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len)
struct dns_cache_data *dns_cache_new_data_packet(struct dns_cache_query_option *query_option, void *packet,
size_t packet_len)
{
struct dns_cache_packet *cache_packet = NULL;
size_t data_size = 0;
@@ -236,7 +255,12 @@ struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *pack
memcpy(cache_packet->data, packet, packet_len);
memset(&cache_packet->head, 0, sizeof(cache_packet->head));
cache_packet->head.cache_flag = cache_flag;
if (query_option) {
cache_packet->head.query_flag = query_option->query_flag;
if (query_option->dns_group_name) {
strncpy(cache_packet->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN - 1);
}
}
cache_packet->head.cache_type = CACHE_TYPE_PACKET;
cache_packet->head.size = packet_len;

View File

@@ -33,6 +33,7 @@ extern "C" {
#define DNS_CACHE_TTL_MIN 1
#define DNS_CACHE_VERSION_LEN 32
#define DNS_CACHE_GROUP_NAME_LEN 32
#define MAGIC_NUMBER 0x6548634163536e44
#define MAGIC_CACHE_DATA 0x44615461
@@ -47,9 +48,15 @@ enum CACHE_RECORD_TYPE {
CACHE_RECORD_TYPE_INACTIVE,
};
struct dns_cache_query_option {
uint32_t query_flag;
const char *dns_group_name;
};
struct dns_cache_data_head {
uint32_t cache_flag;
enum CACHE_TYPE cache_type;
uint32_t query_flag;
char dns_group_name[DNS_CACHE_GROUP_NAME_LEN];
int is_soa;
ssize_t size;
};
@@ -115,11 +122,14 @@ struct dns_cache_file {
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data);
uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data);
uint32_t dns_cache_get_query_flag(struct dns_cache_data *cache_data);
const char *dns_cache_get_dns_group_name(struct dns_cache_data *cache_data);
void dns_cache_data_free(struct dns_cache_data *data);
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len);
struct dns_cache_data *dns_cache_new_data_packet(struct dns_cache_query_option *query_option, void *packet,
size_t packet_len);
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
@@ -156,10 +166,11 @@ struct dns_cache_data *dns_cache_new_data(void);
struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache);
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl,
unsigned char *addr, int addr_len);
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
int cname_ttl, unsigned char *addr, int addr_len);
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl);
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
int cname_ttl);
void dns_cache_destroy(void);

View File

@@ -1416,10 +1416,6 @@ static void _dns_client_query_remove(struct dns_query_struct *query)
{
/* remove query from period check list, and release reference*/
pthread_mutex_lock(&client.domain_map_lock);
if (list_empty(&query->dns_request_list)) {
pthread_mutex_unlock(&client.domain_map_lock);
return;
}
list_del_init(&query->dns_request_list);
hash_del(&query->domain_node);
pthread_mutex_unlock(&client.domain_map_lock);

View File

@@ -124,6 +124,7 @@ int dns_conf_rr_ttl;
int dns_conf_rr_ttl_reply_max;
int dns_conf_rr_ttl_min = 600;
int dns_conf_rr_ttl_max;
int dns_conf_local_ttl;
int dns_conf_force_AAAA_SOA;
int dns_conf_force_no_cname;
int dns_conf_ipset_timeout_enable;
@@ -1749,8 +1750,8 @@ static int _conf_dhcp_lease_dnsmasq_file(void *data, int argc, char *argv[])
return -1;
}
safe_strncpy(dns_conf_dnsmasq_lease_file, argv[1], DNS_MAX_PATH);
if (_conf_dhcp_lease_dnsmasq_add(argv[1]) != 0) {
conf_get_conf_fullpath(argv[1], dns_conf_dnsmasq_lease_file, sizeof(dns_conf_dnsmasq_lease_file));
if (_conf_dhcp_lease_dnsmasq_add(dns_conf_dnsmasq_lease_file) != 0) {
return -1;
}
@@ -1907,6 +1908,7 @@ static struct config_item _config_item[] = {
CONF_INT("rr-ttl-min", &dns_conf_rr_ttl_min, 0, CONF_INT_MAX),
CONF_INT("rr-ttl-max", &dns_conf_rr_ttl_max, 0, CONF_INT_MAX),
CONF_INT("rr-ttl-reply-max", &dns_conf_rr_ttl_reply_max, 0, CONF_INT_MAX),
CONF_INT("local-ttl", &dns_conf_local_ttl, 0, CONF_INT_MAX),
CONF_INT("max-reply-ip-num", &dns_conf_max_reply_ip_num, 1, CONF_INT_MAX),
CONF_ENUM("response-mode", &dns_conf_response_mode, &dns_conf_response_mode_enum),
CONF_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA),
@@ -2091,6 +2093,19 @@ static int _dns_conf_load_post(void)
dns_conf_response_mode_enum[dns_conf_response_mode].name);
}
if ((dns_conf_rr_ttl_min > dns_conf_rr_ttl_max) && dns_conf_rr_ttl_max > 0) {
dns_conf_rr_ttl_min = dns_conf_rr_ttl_max;
}
if ((dns_conf_rr_ttl_max < dns_conf_rr_ttl_min) && dns_conf_rr_ttl_max > 0) {
dns_conf_rr_ttl_max = dns_conf_rr_ttl_min;
}
if (dns_conf_local_ttl == 0) {
dns_conf_local_ttl = dns_conf_rr_ttl_min;
}
return 0;
}

View File

@@ -312,6 +312,7 @@ extern int dns_conf_rr_ttl_min;
extern int dns_conf_rr_ttl_max;
extern int dns_conf_force_AAAA_SOA;
extern int dns_conf_ipset_timeout_enable;
extern int dns_conf_local_ttl;
extern int dns_conf_force_no_cname;

View File

@@ -163,6 +163,7 @@ struct dns_request {
struct dns_server_conn_head *conn;
uint32_t server_flags;
char dns_group_name[DNS_GROUP_NAME_LEN];
/* dns request list */
struct list_head list;
@@ -261,8 +262,8 @@ static tlog_log *dns_audit;
static int is_ipv6_ready;
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expired_domain, uint32_t server_flags,
struct dns_query_options *options);
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expired_domain,
struct dns_server_query_option *server_query_option);
static int _dns_server_get_answer(struct dns_server_post_context *context);
static void _dns_server_request_get(struct dns_request *request);
static void _dns_server_request_release(struct dns_request *request);
@@ -940,6 +941,8 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
speed = request->ping_time;
if (has_soa) {
struct dns_cache_query_option cache_option;
if (request->dualstack_selection && request->has_ip && request->qtype == DNS_T_AAAA) {
ttl = _dns_server_get_conf_ttl(request->ip_ttl);
} else {
@@ -948,7 +951,10 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
ttl = DNS_SERVER_TMOUT_TTL;
}
}
dns_cache_set_data_soa(cache_data, request->server_flags, request->cname, request->ttl_cname);
cache_option.query_flag = request->server_flags;
cache_option.dns_group_name = 0;
dns_cache_set_data_soa(cache_data, &cache_option, request->cname, request->ttl_cname);
}
tlog(TLOG_DEBUG, "cache %s qtype: %d ttl: %d\n", request->domain, qtype, ttl);
@@ -983,6 +989,7 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
{
struct dns_packet *packet = context->packet;
struct dns_packet *cname_packet = NULL;
struct dns_cache_query_option cache_option;
int ret = 0;
int i = 0;
int j = 0;
@@ -1080,7 +1087,10 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
if (inpacket_len <= 0) {
return -1;
}
cache_packet = dns_cache_new_data_packet(request->server_flags, inpacket_buff, inpacket_len);
cache_option.query_flag = request->server_flags;
cache_option.dns_group_name = request->dns_group_name;
cache_packet = dns_cache_new_data_packet(&cache_option, inpacket_buff, inpacket_len);
if (cache_packet == NULL) {
return -1;
}
@@ -1123,9 +1133,13 @@ errout:
static int _dns_cache_packet(struct dns_server_post_context *context)
{
struct dns_cache_query_option cache_option;
struct dns_request *request = context->request;
cache_option.query_flag = request->server_flags;
cache_option.dns_group_name = request->dns_group_name;
struct dns_cache_data *cache_packet =
dns_cache_new_data_packet(request->server_flags, context->inpacket, context->inpacket_len);
dns_cache_new_data_packet(&cache_option, context->inpacket, context->inpacket_len);
if (cache_packet == NULL) {
return -1;
}
@@ -1249,8 +1263,11 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
return _dns_cache_specify_packet(context);
}
struct dns_cache_query_option cache_option;
cache_option.query_flag = request->server_flags;
cache_option.dns_group_name = request->dns_group_name;
struct dns_cache_data *cache_packet =
dns_cache_new_data_packet(request->server_flags, context->inpacket, context->inpacket_len);
dns_cache_new_data_packet(&cache_option, context->inpacket, context->inpacket_len);
if (cache_packet == NULL) {
return -1;
}
@@ -1549,6 +1566,7 @@ static int _dns_server_force_dualstack(struct dns_request *request)
static int _dns_server_request_complete(struct dns_request *request)
{
int ttl = DNS_SERVER_TMOUT_TTL;
int reply_ttl = ttl;
if (request->rcode == DNS_RC_SERVFAIL || request->rcode == DNS_RC_NXDOMAIN) {
ttl = DNS_SERVER_FAIL_TTL;
@@ -1600,6 +1618,15 @@ out:
}
}
reply_ttl = ttl;
if (request->passthrough == 0 && dns_conf_cachesize > 0 &&
request->check_order_list->orders[0].type != DOMAIN_CHECK_NONE) {
reply_ttl = dns_conf_serve_expired_reply_ttl;
if (reply_ttl < 2) {
reply_ttl = 2;
}
}
struct dns_server_post_context context;
_dns_server_post_context_init(&context, request);
context.do_cache = 1;
@@ -1607,7 +1634,7 @@ out:
context.do_force_soa = request->dualstack_selection_force_soa;
context.do_audit = 1;
context.do_reply = 1;
context.reply_ttl = ttl;
context.reply_ttl = reply_ttl;
context.skip_notify_count = 1;
_dns_request_post(&context);
@@ -1788,10 +1815,6 @@ static void _dns_server_complete_with_multi_ipaddress(struct dns_request *reques
struct dns_server_post_context context;
int do_reply = 0;
if (request->passthrough) {
return;
}
if (atomic_read(&request->ip_map_num) > 0) {
request->has_soa = 0;
}
@@ -1801,6 +1824,10 @@ static void _dns_server_complete_with_multi_ipaddress(struct dns_request *reques
_dns_server_force_dualstack(request);
}
if (request->passthrough && do_reply == 0) {
return;
}
_dns_server_post_context_init(&context, request);
context.do_cache = 1;
context.do_ipset = 1;
@@ -2299,6 +2326,7 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
if (addr[0] == 0 || addr[0] == 127) {
/* If half of the servers return the same result, then ignore this address */
if (atomic_inc_return(&request->adblock) <= (dns_server_num() / 2 + dns_server_num() % 2)) {
request->rcode = DNS_RC_NOERROR;
_dns_server_request_release(request);
return -1;
}
@@ -2375,6 +2403,7 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
if (_dns_server_is_adblock_ipv6(addr) == 0) {
/* If half of the servers return the same result, then ignore this address */
if (atomic_inc_return(&request->adblock) <= (dns_server_num() / 2 + dns_server_num() % 2)) {
request->rcode = DNS_RC_NOERROR;
_dns_server_request_release(request);
return -1;
}
@@ -3010,7 +3039,7 @@ static int _dns_server_reply_request_eth_ip(struct dns_request *request)
}
request->rcode = DNS_RC_NOERROR;
request->ip_ttl = 600;
request->ip_ttl = dns_conf_local_ttl;
request->has_ip = 1;
struct dns_server_post_context context;
@@ -3400,7 +3429,7 @@ static int _dns_server_process_address(struct dns_request *request)
}
request->rcode = DNS_RC_NOERROR;
request->ip_ttl = 600;
request->ip_ttl = dns_conf_local_ttl;
request->has_ip = 1;
struct dns_server_post_context context;
@@ -3647,18 +3676,21 @@ reply_cache:
out_update_cache:
if (dns_cache_get_ttl(dns_cache) == 0) {
uint32_t server_flags = request->server_flags;
struct dns_query_options options;
struct dns_server_query_option dns_query_options;
dns_query_options.server_flags = request->server_flags;
dns_query_options.dns_group_name = request->dns_group_name;
if (request->conn == NULL) {
server_flags = dns_cache_get_cache_flag(dns_cache->cache_data);
dns_query_options.server_flags = dns_cache_get_query_flag(dns_cache->cache_data);
dns_query_options.dns_group_name = dns_cache_get_dns_group_name(dns_cache->cache_data);
}
options.enable_flag = 0;
dns_query_options.ecs_enable_flag = 0;
if (request->has_ecs) {
options.enable_flag |= DNS_QUEY_OPTION_ECS_DNS;
memcpy(&options.ecs_dns, &request->ecs, sizeof(options.ecs_dns));
dns_query_options.ecs_enable_flag |= DNS_QUEY_OPTION_ECS_DNS;
memcpy(&dns_query_options.ecs_dns, &request->ecs, sizeof(dns_query_options.ecs_dns));
}
_dns_server_prefetch_request(request->domain, request->qtype, 0, server_flags, &options);
_dns_server_prefetch_request(request->domain, request->qtype, 0, &dns_query_options);
} else {
dns_cache_update(dns_cache);
}
@@ -3797,10 +3829,6 @@ static int _dns_server_process_special_query(struct dns_request *request)
{
int ret = 0;
if (_dns_server_process_smartdns_domain(request) == 0) {
goto clean_exit;
}
switch (request->qtype) {
case DNS_T_PTR:
/* return PTR record */
@@ -3918,7 +3946,7 @@ static int _dns_server_process_host(struct dns_request *request)
}
request->rcode = DNS_RC_NOERROR;
request->ip_ttl = 600;
request->ip_ttl = dns_conf_local_ttl;
request->has_ip = 1;
struct dns_server_post_context context;
@@ -3969,6 +3997,7 @@ static int _dns_server_query_dualstack(struct dns_request *request)
}
request_dualstack->server_flags = request->server_flags;
safe_strncpy(request_dualstack->dns_group_name, request->dns_group_name, sizeof(request->dns_group_name));
safe_strncpy(request_dualstack->domain, request->domain, sizeof(request->domain));
request_dualstack->qtype = qtype;
request_dualstack->dualstack_selection_query = 1;
@@ -4013,14 +4042,16 @@ static int _dns_server_do_query(struct dns_request *request)
/* lookup domain rule */
_dns_server_get_domain_rule(request);
group_name = _dns_server_get_request_groupname(request);
if (group_name == NULL) {
group_name = dns_group;
group_name = request->dns_group_name;
if (request->dns_group_name[0] == '\0') {
group_name = _dns_server_get_request_groupname(request);
if (group_name == NULL) {
group_name = dns_group;
}
safe_strncpy(request->dns_group_name, group_name, DNS_GROUP_NAME_LEN);
}
if (_dns_server_process_host(request) == 0) {
goto clean_exit;
}
_dns_server_set_dualstack_selection(request);
@@ -4038,6 +4069,14 @@ static int _dns_server_do_query(struct dns_request *request)
goto clean_exit;
}
if (_dns_server_process_smartdns_domain(request) == 0) {
goto clean_exit;
}
if (_dns_server_process_host(request) == 0) {
goto clean_exit;
}
/* process qtype soa */
if (_dns_server_qtype_soa(request) == 0) {
goto clean_exit;
@@ -4206,22 +4245,28 @@ errout:
return ret;
}
static int _dns_server_prefetch_setup_options(struct dns_request *request, struct dns_query_options *options)
static int _dns_server_setup_server_query_options(struct dns_request *request,
struct dns_server_query_option *server_query_option)
{
if (options == NULL) {
if (server_query_option == NULL) {
return 0;
}
if (options->enable_flag & DNS_QUEY_OPTION_ECS_DNS) {
request->server_flags = server_query_option->server_flags;
if (server_query_option->dns_group_name) {
safe_strncpy(request->dns_group_name, server_query_option->dns_group_name, DNS_GROUP_NAME_LEN);
}
if (server_query_option->ecs_enable_flag & DNS_QUEY_OPTION_ECS_DNS) {
request->has_ecs = 1;
memcpy(&request->ecs, &options->ecs_dns, sizeof(request->ecs));
memcpy(&request->ecs, &server_query_option->ecs_dns, sizeof(request->ecs));
}
return 0;
}
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expired_domain, uint32_t server_flags,
struct dns_query_options *options)
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expired_domain,
struct dns_server_query_option *server_query_option)
{
int ret = -1;
struct dns_request *request = NULL;
@@ -4234,8 +4279,7 @@ static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expi
safe_strncpy(request->domain, domain, sizeof(request->domain));
request->qtype = qtype;
request->server_flags = server_flags;
_dns_server_prefetch_setup_options(request, options);
_dns_server_setup_server_query_options(request, server_query_option);
_dns_server_request_set_enable_prefetch(request, expired_domain);
ret = _dns_server_do_query(request);
if (ret != 0) {
@@ -4253,7 +4297,8 @@ errout:
return ret;
}
int dns_server_query(const char *domain, int qtype, uint32_t server_flags, dns_result_callback callback, void *user_ptr)
int dns_server_query(const char *domain, int qtype, struct dns_server_query_option *server_query_option,
dns_result_callback callback, void *user_ptr)
{
int ret = -1;
struct dns_request *request = NULL;
@@ -4264,9 +4309,9 @@ int dns_server_query(const char *domain, int qtype, uint32_t server_flags, dns_r
goto errout;
}
request->server_flags = server_flags;
safe_strncpy(request->domain, domain, sizeof(request->domain));
request->qtype = qtype;
_dns_server_setup_server_query_options(request, server_query_option);
_dns_server_request_set_callback(request, callback, user_ptr);
ret = _dns_server_do_query(request);
if (ret != 0) {
@@ -4662,6 +4707,7 @@ static int _dns_server_second_ping_check(struct dns_request *request)
static void _dns_server_prefetch_domain(struct dns_cache *dns_cache)
{
/* If there are still hits, continue pre-fetching */
struct dns_server_query_option server_query_option;
int hitnum = dns_cache_hitnum_dec_get(dns_cache);
if (hitnum <= 0) {
return;
@@ -4670,8 +4716,10 @@ static void _dns_server_prefetch_domain(struct dns_cache *dns_cache)
/* start prefetch domain */
tlog(TLOG_DEBUG, "prefetch by cache %s, qtype %d, ttl %d, hitnum %d", dns_cache->info.domain, dns_cache->info.qtype,
dns_cache->info.ttl, hitnum);
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 0,
dns_cache_get_cache_flag(dns_cache->cache_data), NULL) != 0) {
server_query_option.dns_group_name = dns_cache_get_dns_group_name(dns_cache->cache_data);
server_query_option.server_flags = dns_cache_get_query_flag(dns_cache->cache_data);
server_query_option.ecs_enable_flag = 0;
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 0, &server_query_option) != 0) {
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
}
}
@@ -4682,8 +4730,12 @@ static void _dns_server_prefetch_expired_domain(struct dns_cache *dns_cache)
tlog(TLOG_DEBUG, "expired domain, prefetch by cache %s, qtype %d, ttl %d", dns_cache->info.domain,
dns_cache->info.qtype, dns_cache->info.ttl);
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 1,
dns_cache_get_cache_flag(dns_cache->cache_data), NULL) != 0) {
struct dns_server_query_option server_query_option;
server_query_option.dns_group_name = dns_cache_get_dns_group_name(dns_cache->cache_data);
server_query_option.server_flags = dns_cache_get_query_flag(dns_cache->cache_data);
server_query_option.ecs_enable_flag = 0;
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 1, &server_query_option) != 0) {
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
}
}

View File

@@ -21,11 +21,20 @@
#include "dns.h"
#include <stdint.h>
#include "dns_client.h"
#ifdef __cpluscplus
extern "C" {
#endif
struct dns_server_query_option {
uint32_t server_flags;
const char *dns_group_name;
unsigned long ecs_enable_flag;
struct dns_opt_ecs ecs_dns;
struct dns_query_ecs_ip ecs_ip;
};
int dns_server_init(void);
int dns_server_run(void);
@@ -41,7 +50,8 @@ typedef int (*dns_result_callback)(const char *domain, dns_rtcode_t rtcode, dns_
unsigned int ping_time, void *user_ptr);
/* query domain */
int dns_server_query(const char *domain, int qtype, uint32_t server_flags, dns_result_callback callback, void *user_ptr);
int dns_server_query(const char *domain, int qtype, struct dns_server_query_option *server_query_option,
dns_result_callback callback, void *user_ptr);
#ifdef __cpluscplus
}

View File

@@ -1112,10 +1112,6 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c
tlog(TLOG_DEBUG, "ping %s, id = %d", host, ping_host->sid);
addrkey = _fast_ping_hash_key(ping_host->sid, &ping_host->addr);
pthread_mutex_lock(&ping.map_lock);
_fast_ping_host_get(ping_host);
hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
pthread_mutex_unlock(&ping.map_lock);
_fast_ping_host_get(ping_host);
_fast_ping_host_get(ping_host);
@@ -1124,7 +1120,11 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c
goto errout_remove;
}
pthread_mutex_lock(&ping.map_lock);
_fast_ping_host_get(ping_host);
hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
ping_host->run = 1;
pthread_mutex_unlock(&ping.map_lock);
freeaddrinfo(gai);
_fast_ping_host_put(ping_host);
return ping_host;

View File

@@ -160,4 +160,6 @@ void load_exit(void);
const char *conf_get_conf_file(void);
const char *conf_get_conf_fullpath(const char *path, char *fullpath, size_t path_len);
#endif // !_GENERIC_CONF_H

View File

@@ -24,6 +24,15 @@
static inline char *safe_strncpy(char *dest, const char *src, size_t n)
{
if (src == NULL) {
dest[0] = '\0';
return dest;
}
if (n <= 0) {
return NULL;
}
#if __GNUC__ > 7
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-truncation"

View File

@@ -18,16 +18,46 @@
#include "conf.h"
#include <getopt.h>
#include <libgen.h>
#include <linux/limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static const char *currrent_conf_file = NULL;
static const char *current_conf_file = NULL;
const char *conf_get_conf_file(void)
{
return currrent_conf_file;
return current_conf_file;
}
const char *conf_get_conf_fullpath(const char *path, char *fullpath, size_t path_len)
{
char file_path_dir[PATH_MAX];
if (path_len < 1) {
return NULL;
}
if (path[0] == '/') {
strncpy(fullpath, path, path_len);
return fullpath;
}
strncpy(file_path_dir, conf_get_conf_file(), PATH_MAX - 1);
file_path_dir[PATH_MAX - 1] = 0;
dirname(file_path_dir);
if (file_path_dir[0] == '\0') {
strncpy(fullpath, path, path_len);
return fullpath;
}
if (snprintf(fullpath, PATH_MAX, "%s/%s", file_path_dir, path) < 0) {
return NULL;
}
return fullpath;
}
int conf_custom(const char *item, void *data, int argc, char *argv[])
@@ -303,7 +333,7 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
conf_getopt_reset();
/* call item function */
currrent_conf_file = file;
current_conf_file = file;
call_ret = items[i].item_func(items[i].item, items[i].data, argc, argv);
ret = handler(file, line_no, call_ret);
if (ret != 0) {