Compare commits

..

16 Commits

Author SHA1 Message Date
Nick Peng
34691154fb passthrouth: fix passthrouth ttl 2022-05-03 10:25:33 +08:00
Nick Peng
29a5803860 Fix typo & ttl issue. 2022-05-03 09:00:30 +08:00
Nick Peng
ebd820bcbb dns_server: make max ttl no countdown 2022-05-02 22:53:51 +08:00
Nick Peng
1de5557430 client: support ECS 2022-04-30 20:22:57 +08:00
Nick Peng
c92615e6cd dual-stack: return soa when ipv4 exists in cache 2022-04-30 08:46:30 +08:00
Nick Peng
c561ae2fc5 Feature: Supports setting the maximum TTL value of the response to the client 2022-04-29 22:29:40 +08:00
Nick Peng
d30264ed08 script: force stop smartdns process 2022-04-29 10:09:40 +08:00
Nick Peng
22e13b40db dns_server: fix passthrouth ipset issue 2022-04-26 20:43:11 +08:00
Nick Peng
75dda9340d dns_conf: update default configuration. 2022-04-25 18:46:52 +08:00
Nick Peng
baf2be681d dns-server: Parallel query performance optimization for the same domain name 2022-04-25 18:46:40 +08:00
Nick Peng
5bd521c36b dns_server: Cache A record for AAAA query when dualstack select 2022-04-22 23:36:37 +08:00
Nick Peng
d0305f60f6 dns_server: make fastest ip first place & fix audit log and ipset for multi IPs. 2022-04-17 18:03:24 +08:00
Nick Peng
6e1363dca4 Feature: select all best ip 2022-04-10 19:47:00 +08:00
Nick Peng
23e9021d30 client: avoid retry query storm 2022-04-09 11:12:00 +08:00
Nick Peng
92af4c05c0 dns: support domain compress. 2022-04-05 21:21:33 +08:00
Nick Peng
24661c2419 Fix issue #903 TXT, SRV, record failed. 2022-04-04 10:34:55 +08:00
18 changed files with 1678 additions and 977 deletions

View File

@@ -560,6 +560,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
| `rr-ttl` | 域名结果 TTL | 远程查询结果 | 大于 `0` 的数字 | `rr-ttl 600` |
| `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` |
| `log-level` | 设置日志级别 | `error` | `fatal`、`error`、`warn`、`notice`、`info` 或 `debug` | `log-level error` |
| `log-file` | 日志文件路径 | `/var/log/smartdns.log` | 合法路径字符串 | `log-file /var/log/smartdns.log` |
| `log-size` | 日志大小 | `128K` | 数字 + `K`、`M` 或 `G` | `log-size 128K` |
@@ -586,11 +587,11 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
| `force-AAAA-SOA` | 强制 AAAA 地址返回 SOA | `no` | [`yes`\|`no`] | `force-AAAA-SOA yes` |
| `force-qtype-SOA` | 强制指定 qtype 返回 SOA | qtype id | [`<qtypeid>` \| ...] | `force-qtype-SOA 65 28`
| `prefetch-domain` | 域名预先获取功能 | `no` | [`yes`\|`no`] | `prefetch-domain yes` |
| `serve-expired` | 过期缓存服务功能 | `no` | [`yes`\|`no`],开启此功能后,如果有请求时尝试回应 TTL 为 0 的过期记录,并发查询记录,以避免查询等待 |
| `serve-expired` | 过期缓存服务功能 | `yes` | [`yes`\|`no`],开启此功能后,如果有请求时尝试回应 TTL 为 0 的过期记录,并发查询记录,以避免查询等待 |
| `serve-expired-ttl` | 过期缓存服务最长超时时间 | `0` | 秒,`0` 表示停用超时,大于 `0` 表示指定的超时的秒数 | `serve-expired-ttl 0` |
| `serve-expired-reply-ttl` | 回应的过期缓存 TTL | `5` | 秒,`0` 表示停用超时,大于 `0` 表示指定的超时的秒数 | `serve-expired-reply-ttl 30` |
| `dualstack-ip-selection` | 双栈 IP 优选 | `no` | [`yes`\|`no`] | `dualstack-ip-selection yes` |
| `dualstack-ip-selection-threshold` | 双栈 IP 优选阈值 | `30ms` | 单位为毫秒(`ms` | `dualstack-ip-selection-threshold [0-1000]` |
| `dualstack-ip-selection` | 双栈 IP 优选 | `yes` | [`yes`\|`no`] | `dualstack-ip-selection yes` |
| `dualstack-ip-selection-threshold` | 双栈 IP 优选阈值 | `15ms` | 单位为毫秒(`ms` | `dualstack-ip-selection-threshold [0-1000]` |
| `ca-file` | 证书文件 | `/etc/ssl/certs/ca-certificates.crt` | 合法路径字符串 | `ca-file /etc/ssl/certs/ca-certificates.crt` |
| `ca-path` | 证书文件路径 | `/etc/ssl/certs` | 合法路径字符串 | `ca-path /etc/ssl/certs` |

View File

@@ -503,6 +503,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
|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
|log-level|log level|error|fatal,error,warn,notice,info,debug|log-level error
|log-file|log path|/var/log/smartdns.log|File Pah|log-file /var/log/smartdns.log
@@ -530,11 +531,11 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|force-AAAA-SOA|force AAAA query return SOA|no|[yes\|no]|force-AAAA-SOA yes
|force-qtype-SOA|force specific qtype return SOA|qtype id|[qtypeid | ...]|force-qtype-SOA 65 28
|prefetch-domain|domain prefetch feature|no|[yes\|no]|prefetch-domain yes
|serve-expired|Cache serve expired feature|no|[yes\|no], Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish.|serve-expired yes
|serve-expired|Cache serve expired feature|yes|[yes\|no], Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish.|serve-expired yes
|serve-expired-ttl|Cache serve expired limite TTL|0|second0disable> 0 seconds after expiration|serve-expired-ttl 0
|serve-expired-reply-ttl|TTL value to use when replying with expired data|5|second0disable> 0 seconds after expiration|serve-expired-reply-ttl 30
|dualstack-ip-selection|Dualstack ip selection|no|[yes\|no]|dualstack-ip-selection yes
|dualstack-ip-selection-threshold|Dualstack ip select threadhold|30ms|millisecond|dualstack-ip-selection-threshold [0-1000]
|dualstack-ip-selection|Dualstack ip selection|yes|[yes\|no]|dualstack-ip-selection yes
|dualstack-ip-selection-threshold|Dualstack ip select threadhold|15ms|millisecond|dualstack-ip-selection-threshold [0-1000]
|ca-file|certificate file|/etc/ssl/certs/ca-certificates.crt|path|ca-file /etc/ssl/certs/ca-certificates.crt
|ca-path|certificates path|/etc/ssl/certs|path|ca-path /etc/ssl/certs

View File

@@ -68,11 +68,23 @@ case $1 in
echo "Stop smartdns server failed."
exit 1;
fi
rm -f "$PIDFILE"
LOOP=1
while true; do
if [ ! -d "/proc/$PID" ]; then
break;
fi
if [ $LOOP -gt 12 ]; then
kill -9 "$PID"
break;
fi
LOOP=$((LOOP+1))
sleep .5
done
echo "Stop smartdns server success."
;;
restart)
"$0" stop && sleep 1 && "$0" start
"$0" stop && "$0" start
;;
status)
PID="$(cat "$PIDFILE" 2>/dev/null)"

View File

@@ -102,10 +102,12 @@ cache-size 4096
# rr-ttl: ttl for all record
# rr-ttl-min: minimum ttl for resource record
# rr-ttl-max: maximum ttl for resource record
# tr-ttl-reply-max: maximum reply ttl for resource record
# example:
# rr-ttl 300
# rr-ttl-min 60
# rr-ttl-max 86400
# rr-ttl-reply-max 60
# set log level
# log-level: [level], level=fatal, error, warn, notice, info, debug

View File

@@ -124,6 +124,9 @@ msgstr "域名TTL最大值"
msgid "Maximum TTL for all domain result."
msgstr "设置所有域名的TTL最大值"
msgid "Maximum Reply TTL for all domain result."
msgstr "设置返回给客户端的TTL最大值"
msgid "smartdns custom settings"
msgstr "smartdns 自定义设置,具体配置参数参考指导"

View File

@@ -70,7 +70,7 @@ end
---- Support DualStack ip selection
o = s:taboption("settings", Flag, "dualstack_ip_selection", translate("Dual-stack IP Selection"), translate("Enable IP selection between IPV4 and IPV6"))
o.rmempty = false
o.default = o.disabled
o.default = o.enabled
o.cfgvalue = function(...)
return Flag.cfgvalue(...) or "0"
end
@@ -87,7 +87,7 @@ end
o = s:taboption("settings", Flag, "serve_expired", translate("Serve expired"),
translate("Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish."))
o.rmempty = false
o.default = o.disabled
o.default = o.enabled
o.cfgvalue = function(...)
return Flag.cfgvalue(...) or "0"
end
@@ -112,15 +112,19 @@ o.rempty = true
---- rr-ttl-min
o = s:taboption("settings", Value, "rr_ttl_min", translate("Domain TTL Min"), translate("Minimum TTL for all domain result."))
o.rempty = true
o.placeholder = "300"
o.default = 300
o.placeholder = "600"
o.default = 600
o.optional = true
---- second dns server
---- rr-ttl-max
o = s:taboption("settings", Value, "rr_ttl_max", translate("Domain TTL Max"), translate("Maximum TTL for all domain result."))
o.rempty = true
---- rr-ttl-reply-max
o = s:taboption("settings", Value, "rr_ttl_reply_max", translate("Domain TTL Max"), translate("Maximum Reply TTL for all domain result."))
o.rempty = true
---- second dns server
---- Eanble
o = s:taboption("seconddns", Flag, "seconddns_enabled", translate("Enable"), translate("Enable or disable second DNS server."))
o.default = o.disabled

View File

@@ -130,6 +130,9 @@ msgstr "域名TTL最大值"
msgid "Maximum TTL for all domain result."
msgstr "设置所有域名的TTL最大值"
msgid "Maximum Reply TTL for all domain result."
msgstr "设置返回给客户端的TTL最大值"
msgid "smartdns custom settings"
msgstr "smartdns 自定义设置,具体配置参数参考指导"

View File

@@ -188,7 +188,7 @@ return L.view.extend({
o = s.taboption("settings", form.Flag, "dualstack_ip_selection", _("Dual-stack IP Selection"),
_("Enable IP selection between IPV4 and IPV6"));
o.rmempty = false;
o.default = o.disabled;
o.default = o.enabled;
// Domain prefetch load ;
o = s.taboption("settings", form.Flag, "prefetch_domain", _("Domain prefetch"),
@@ -200,7 +200,7 @@ return L.view.extend({
o = s.taboption("settings", form.Flag, "serve_expired", _("Serve expired"),
_("Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish."));
o.rmempty = false;
o.default = o.disabled;
o.default = o.enabled;
// Redirect;
o = s.taboption("settings", form.ListValue, "redirect", _("Redirect"), _("SmartDNS redirect mode"));
@@ -223,16 +223,21 @@ return L.view.extend({
o = s.taboption("settings", form.Value, "rr_ttl_min", _("Domain TTL Min"),
_("Minimum TTL for all domain result."));
o.rempty = true;
o.placeholder = "300";
o.default = 300;
o.placeholder = "600";
o.default = 600;
o.optional = true;
// second dns server;
// rr-ttl-max;
o = s.taboption("settings", form.Value, "rr_ttl_max", _("Domain TTL Max"),
_("Maximum TTL for all domain result."));
_("Maximum TTL for all domain result."));
o.rempty = true;
// rr-ttl-reply-max;
o = s.taboption("settings", form.Value, "rr_ttl_reply_max", _("Domain Reply TTL Max"),
_("Maximum Reply TTL for all domain result."));
o.rempty = true;
// second dns server;
// Eanble;
o = s.taboption("seconddns", form.Flag, "seconddns_enabled", _("Enable"),
_("Enable or disable second DNS server."));

View File

@@ -311,6 +311,9 @@ load_service()
config_get rr_ttl_max "$section" "rr_ttl_max" ""
[ -z "$rr_ttl_max" ] || conf_append "rr-ttl-max" "$rr_ttl_max"
config_get rr_ttl_reply_max "$section" "rr_ttl_reply_max" ""
[ -z "$rr_ttl_reply_max" ] || conf_append "rr-ttl-reply-max" "$rr_ttl_reply_max"
config_get log_size "$section" "log_size" "64K"
[ -z "$log_size" ] || conf_append "log-size" "$log_size"

909
src/dns.c

File diff suppressed because it is too large Load Diff

View File

@@ -113,11 +113,15 @@ struct dns_head {
unsigned short nrcount; /* number of addititional resource entries */
} __attribute__((packed, aligned(2)));
struct dns_rrs {
unsigned short next;
unsigned short len;
dns_type_t type;
unsigned char data[0];
#define DNS_PACKET_DICT_SIZE 16
struct dns_packet_dict_item {
unsigned pos;
unsigned int hash;
};
struct dns_packet_dict {
short dict_count;
struct dns_packet_dict_item names[DNS_PACKET_DICT_SIZE];
};
/* packet haed */
@@ -130,21 +134,24 @@ struct dns_packet {
unsigned short optcount;
unsigned short optional;
unsigned short payloadsize;
struct dns_packet_dict namedict;
int size;
int len;
unsigned char data[0];
};
/* RRS encode/decode context */
struct dns_data_context {
unsigned char *data;
unsigned char *ptr;
unsigned int maxsize;
struct dns_rrs {
struct dns_packet *packet;
unsigned short next;
unsigned short len;
dns_type_t type;
unsigned char data[0];
};
/* packet encode/decode context */
struct dns_context {
struct dns_packet *packet;
struct dns_packet_dict *namedict;
unsigned char *data;
unsigned int maxsize;
unsigned char *ptr;
@@ -170,7 +177,7 @@ struct dns_opt_ecs {
unsigned char source_prefix;
unsigned char scope_prefix;
unsigned char addr[DNS_RR_AAAA_LEN];
};
} __attribute__((packed));;
/* OPT COOLIE */
struct dns_opt_cookie {
@@ -234,4 +241,12 @@ int dns_encode(unsigned char *data, int size, struct dns_packet *packet);
int dns_packet_init(struct dns_packet *packet, int size, struct dns_head *head);
struct dns_update_param {
int id;
int ip_ttl;
int cname_ttl;
};
int dns_packet_update(unsigned char *data, int size, struct dns_update_param *param);
#endif

View File

@@ -162,6 +162,11 @@ void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag
goto errout;
}
dns_cache->head.is_soa = 1;
if (dns_cache->head.cache_type == CACHE_TYPE_PACKET) {
return;
}
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache;
if (cache_addr == NULL) {
goto errout;
@@ -229,6 +234,7 @@ 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;
cache_packet->head.cache_type = CACHE_TYPE_PACKET;
@@ -447,10 +453,10 @@ int dns_cache_is_soa(struct dns_cache *dns_cache)
return 0;
}
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache_get_data(dns_cache);
if (cache_addr->head.cache_type == CACHE_TYPE_ADDR && cache_addr->addr_data.soa) {
if (dns_cache->cache_data->head.is_soa) {
return 1;
}
return 0;
}

View File

@@ -50,6 +50,7 @@ enum CACHE_RECORD_TYPE {
struct dns_cache_data_head {
uint32_t cache_flag;
enum CACHE_TYPE cache_type;
int is_soa;
size_t size;
};

View File

@@ -58,7 +58,7 @@
#define DNS_TCP_IDLE_TIMEOUT (60 * 10)
#define DNS_TCP_CONNECT_TIMEOUT (5)
#define DNS_QUERY_TIMEOUT (500)
#define DNS_QUERY_RETRY (6)
#define DNS_QUERY_RETRY (4)
#define DNS_PENDING_SERVER_RETRY 40
#define SOCKET_PRIORITY (6)
#define SOCKET_IP_TOS (IPTOS_LOWDELAY | IPTOS_RELIABILITY)
@@ -117,6 +117,7 @@ struct dns_server_info {
time_t last_send;
time_t last_recv;
int prohibit;
/* server addr info */
unsigned short ai_family;
@@ -1004,6 +1005,7 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
server_info->ttl = ttl;
server_info->ttl_range = 0;
server_info->skip_check_cert = skip_check_cert;
server_info->prohibit = 0;
pthread_mutex_init(&server_info->lock, NULL);
memcpy(&server_info->flags, flags, sizeof(server_info->flags));
@@ -2152,6 +2154,7 @@ static int _dns_client_process_tcp_buff(struct dns_server_info *server_info)
}
tlog(TLOG_DEBUG, "recv tcp packet from %s, len = %d", server_info->ip, len);
time(&server_info->last_recv);
/* process result */
if (_dns_client_recv(server_info, inpacket_data, dns_packet_len, &server_info->addr, server_info->ai_addrlen) !=
0) {
@@ -2230,7 +2233,6 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
return ret;
}
time(&server_info->last_recv);
server_info->recv_buff.len += len;
if (server_info->recv_buff.len <= 2) {
/* wait and recv */
@@ -2787,6 +2789,14 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
list_for_each_entry_safe(group_member, tmp, &query->server_group->head, list)
{
server_info = group_member->server;
if (server_info->prohibit) {
time_t now;
time(&now);
if ((now - 60 < server_info->last_send) && (now - 5 > server_info->last_recv)) {
continue;
}
server_info->prohibit = 0;
}
total_server++;
tlog(TLOG_DEBUG, "send query to server %s", server_info->ip);
if (server_info->fd <= 0) {
@@ -2838,6 +2848,8 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
time_t now;
time(&now);
if (now - 5 > server_info->last_recv || send_err != ENOMEM) {
server_info->prohibit = 1;
tlog(TLOG_INFO, "server %s not alive, prohibit", server_info->ip);
_dns_client_shutdown_socket(server_info);
}
@@ -3261,6 +3273,34 @@ static void *_dns_client_work(void *arg)
int dns_client_set_ecs(char *ip, int subnet)
{
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len);
switch (addr.ss_family) {
case AF_INET: {
struct sockaddr_in *addr_in;
addr_in = (struct sockaddr_in *)&addr;
memcpy(&client.ecs_ipv4.ipv4_addr, &addr_in->sin_addr.s_addr, 4);
client.ecs_ipv4.bitlen = subnet;
client.ecs_ipv4.enable = 1;
} break;
case AF_INET6: {
struct sockaddr_in6 *addr_in6;
addr_in6 = (struct sockaddr_in6 *)&addr;
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
memcpy(&client.ecs_ipv4.ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
client.ecs_ipv4.bitlen = subnet;
client.ecs_ipv4.enable = 1;
} else {
memcpy(&client.ecs_ipv6.ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
client.ecs_ipv6.bitlen = subnet;
client.ecs_ipv6.enable = 1;
}
} break;
default:
return -1;
}
return 0;
}

View File

@@ -50,7 +50,7 @@ int dns_conf_tcp_idle_time = 120;
/* cache */
int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
int dns_conf_prefetch = 0;
int dns_conf_serve_expired = 0;
int dns_conf_serve_expired = 1;
int dns_conf_serve_expired_ttl = 0;
int dns_conf_serve_expired_reply_ttl = 5;
@@ -90,12 +90,13 @@ art_tree dns_conf_domain_rule;
struct dns_conf_address_rule dns_conf_address_rule;
/* dual-stack selection */
int dns_conf_dualstack_ip_selection;
int dns_conf_dualstack_ip_selection_threshold = 30;
int dns_conf_dualstack_ip_selection = 1;
int dns_conf_dualstack_ip_selection_threshold = 15;
/* TTL */
int dns_conf_rr_ttl;
int dns_conf_rr_ttl_min;
int dns_conf_rr_ttl_reply_max;
int dns_conf_rr_ttl_min = 600;
int dns_conf_rr_ttl_max;
int dns_conf_force_AAAA_SOA;
@@ -1176,11 +1177,13 @@ static int _config_iplist_rule(char *subnet, enum address_rule rule)
static int _config_qtype_soa(void *data, int argc, char *argv[])
{
struct dns_qtype_soa_list *soa_list;
int i = 0;
if (argc <= 1) {
return -1;
}
for (int i = 1; i < argc; i++) {
for (i = 1; i < argc; i++) {
soa_list = malloc(sizeof(*soa_list));
if (soa_list == NULL) {
tlog(TLOG_ERROR, "cannot malloc memory");
@@ -1254,7 +1257,7 @@ static int _conf_edns_client_subnet(void *data, int argc, char *argv[])
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
if (argc <= 1 || data == NULL) {
if (argc <= 1) {
return -1;
}
@@ -1485,6 +1488,7 @@ static struct config_item _config_item[] = {
CONF_INT("rr-ttl", &dns_conf_rr_ttl, 0, CONF_INT_MAX),
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_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA),
CONF_CUSTOM("force-qtype-SOA", _config_qtype_soa, NULL),
CONF_CUSTOM("blacklist-ip", _config_blacklist_ip, NULL),

View File

@@ -255,6 +255,7 @@ extern int dns_conf_dualstack_ip_selection;
extern int dns_conf_dualstack_ip_selection_threshold;
extern int dns_conf_rr_ttl;
extern int dns_conf_rr_ttl_reply_max;
extern int dns_conf_rr_ttl_min;
extern int dns_conf_rr_ttl_max;
extern int dns_conf_force_AAAA_SOA;

File diff suppressed because it is too large Load Diff

View File

@@ -1049,6 +1049,7 @@ void print_stack(void)
{
const size_t max_buffer = 30;
void *buffer[max_buffer];
int idx = 0;
struct backtrace_state state = {buffer, buffer + max_buffer};
_Unwind_Backtrace(unwind_callback, &state);
@@ -1058,7 +1059,7 @@ void print_stack(void)
}
tlog(TLOG_FATAL, "Stack:");
for (int idx = 0; idx < frame_num; ++idx) {
for (idx = 0; idx < frame_num; ++idx) {
const void *addr = buffer[idx];
const char *symbol = "";