Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f50e4dd081 | ||
|
|
ca6a9613d9 | ||
|
|
c88b334902 | ||
|
|
017cd5cdc1 | ||
|
|
0e89d05ee7 | ||
|
|
772229c826 | ||
|
|
7f1dc8a311 | ||
|
|
eff1f1b4c7 | ||
|
|
ea8c1f47f8 | ||
|
|
106ec6789c | ||
|
|
8c271e34c1 | ||
|
|
756029f5e9 | ||
|
|
6338f1257c | ||
|
|
b77cea63e9 | ||
|
|
f1ce462989 | ||
|
|
e5eb562dee | ||
|
|
c53a87b8d9 | ||
|
|
f2fc970561 | ||
|
|
328f44e800 | ||
|
|
11cf7b614c | ||
|
|
51e1e6565f | ||
|
|
3ba8c418f7 | ||
|
|
3e3859cfb1 | ||
|
|
ac0ab0c916 | ||
|
|
98be18f926 | ||
|
|
ed63c617bc | ||
|
|
81ce05e6af | ||
|
|
4e5248ebf3 | ||
|
|
ccd0f203fb | ||
|
|
29d61d9373 | ||
|
|
4dcfd2c729 | ||
|
|
42b3e98b2a | ||
|
|
81ecfa5dab | ||
|
|
baa1397fb0 |
17
.github/workflows/c-cpp.yml
vendored
Normal file
17
.github/workflows/c-cpp.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: make
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
.vscode
|
||||
.o
|
||||
*.o
|
||||
.DS_Store
|
||||
.swp.
|
||||
*.swp.
|
||||
|
||||
41
ReadMe.md
41
ReadMe.md
@@ -11,19 +11,26 @@ SmartDNS是一个运行在本地的DNS服务器,SmartDNS接受本地客户端
|
||||
|
||||
## 目录
|
||||
|
||||
1. [软件效果展示](#软件效果展示)
|
||||
1. [特性](#特性)
|
||||
1. [架构](#架构)
|
||||
1. [使用](#使用)
|
||||
1. [下载配套安装包](#下载配套安装包)
|
||||
1. [标准Linux系统安装](#标准linux系统安装树莓派x86_64系统)
|
||||
1. [openwrt/LEDE](#openwrtlede)
|
||||
1. [华硕路由器原生固件/梅林固件](#华硕路由器原生固件梅林固件)
|
||||
1. [optware/entware](#optwareentware)
|
||||
1. [Windows 10 WSL安装/WSL ubuntu](#windows-10-wsl安装wsl-ubuntu)
|
||||
1. [配置参数](#配置参数)
|
||||
1. [捐助](#donate)
|
||||
1. [FAQ](#faq)
|
||||
- [SmartDNS](#smartdns)
|
||||
- [目录](#目录)
|
||||
- [软件效果展示](#软件效果展示)
|
||||
- [特性](#特性)
|
||||
- [架构](#架构)
|
||||
- [使用](#使用)
|
||||
- [下载配套安装包](#下载配套安装包)
|
||||
- [标准Linux系统安装/树莓派/X86_64系统](#标准linux系统安装树莓派x86_64系统)
|
||||
- [openwrt](#openwrt)
|
||||
- [华硕路由器原生固件/梅林固件](#华硕路由器原生固件梅林固件)
|
||||
- [optware/entware](#optwareentware)
|
||||
- [Windows 10 WSL安装/WSL ubuntu](#windows-10-wsl安装wsl-ubuntu)
|
||||
- [配置参数](#配置参数)
|
||||
- [FAQ](#faq)
|
||||
- [编译](#编译)
|
||||
- [Donate](#donate)
|
||||
- [PayPal](#paypal)
|
||||
- [Alipay 支付宝](#alipay-支付宝)
|
||||
- [Wechat 微信](#wechat-微信)
|
||||
- [开源声明](#开源声明)
|
||||
|
||||
## 软件效果展示
|
||||
|
||||
@@ -117,7 +124,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
|
||||
## 架构
|
||||
|
||||

|
||||

|
||||
|
||||
1. SmartDNS接收本地网络设备的DNS查询请求,如PC,手机的查询请求。
|
||||
2. SmartDNS将查询请求发送到多个上游DNS服务器,可采用标准UDP查询,非标准端口UDP查询,及TCP查询。
|
||||
@@ -504,7 +511,7 @@ https://github.com/pymumu/smartdns/releases
|
||||
|bind|DNS监听端口号|[::]:53|可绑定多个端口<br>`IP:PORT`: 服务器IP,端口号。<br>`[-group]`: 请求时使用的DNS服务器组。<br>`[-no-rule-addr]`:跳过address规则。<br>`[-no-rule-nameserver]`:跳过Nameserver规则。<br>`[-no-rule-ipset]`:跳过Ipset规则。<br>`[no-rule-soa]`:跳过SOA(#)规则.<br>`[no-dualstack-selection]`:停用双栈测速。<br>`[-no-speed-check]`:停用测速。<br>`[-no-cache]`:停止缓存|bind :53
|
||||
|bind-tcp|TCP DNS监听端口号|[::]:53|可绑定多个端口<br>`IP:PORT`: 服务器IP,端口号。<br>`[-group]`: 请求时使用的DNS服务器组。<br>`[-no-rule-addr]`:跳过address规则。<br>`[-no-rule-nameserver]`:跳过Nameserver规则。<br>`[-no-rule-ipset]`:跳过Ipset规则。<br>`[no-rule-soa]`:跳过SOA(#)规则.<br>`[no-dualstack-selection]`:停用双栈测速。<br>`[-no-speed-check]`:停用测速。<br>`[-no-cache]`:停止缓存|bind-tcp :53
|
||||
|cache-size|域名结果缓存个数|512|数字|cache-size 512
|
||||
|cache-persist|是否持久化缓存|no|[yes\|no]|cache-persist yes
|
||||
|cache-persist|是否持久化缓存|自动<br>当 `cache-file` 所在的位置有超过 128MB 的可用空间时启用,否则禁用。|[yes\|no]|cache-persist yes
|
||||
|cache-file|缓存持久化文件路径|/tmp/smartdns.cache|路径|cache-file /tmp/smartdns.cache
|
||||
|tcp-idle-time|TCP链接空闲超时时间|120|数字|tcp-idle-time 120
|
||||
|rr-ttl|域名结果TTL|远程查询结果|大于0的数字|rr-ttl 600
|
||||
@@ -526,9 +533,9 @@ https://github.com/pymumu/smartdns/releases
|
||||
|speed-check-mode|测速模式选择|无|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:80
|
||||
|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|None|ipset /domain/[ipset\|-], `-`表示忽略|ipset /www.example.com/pass
|
||||
|ipset|域名IPSET|None|ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]], `-`表示忽略|ipset /www.example.com/#4:dns4,#6:-
|
||||
|ipset-timeout|设置IPSET超时功能启用|auto|[yes]|ipset-timeout yes
|
||||
|domain-rules|设置域名规则|无|domain-rules /domain/ [-rules...]<br>`[-speed-check-mode]`: 测速模式,参考`speed-check-mode`配置<br>`[-address]`: 参考`address`配置<br>`[-nameserver]`: 参考`nameserver`配置<br>`[-ipset]`:参考`ipset`配置|domain-rules /www.example.com/ -speed-check-mode none
|
||||
|domain-rules|设置域名规则|无|domain-rules /domain/ [-rules...]<br>`[-c\|-speed-check-mode]`: 测速模式,参考`speed-check-mode`配置<br>`[-a\|-address]`: 参考`address`配置<br>`[-n\|-nameserver]`: 参考`nameserver`配置<br>`[-p\|-ipset]`:参考`ipset`配置<br>`[-d\|-dualstack-ip-selection]`: 参考`dualstack-ip-selection`|domain-rules /www.example.com/ -speed-check-mode none
|
||||
|bogus-nxdomain|假冒IP地址过滤|无|[ip/subnet],可重复| bogus-nxdomain 1.2.3.4/16
|
||||
|ignore-ip|忽略IP地址|无|[ip/subnet],可重复| ignore-ip 1.2.3.4/16
|
||||
|whitelist-ip|白名单IP地址|无|[ip/subnet],可重复| whitelist-ip 1.2.3.4/16
|
||||
|
||||
@@ -498,7 +498,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|bind|DNS listening port number|[::]:53|Support binding multiple ports<br>`IP:PORT`: server IP, port number. <br>`[-group]`: The DNS server group used when requesting. <br>`[-no-rule-addr]`: Skip the address rule. <br>`[-no-rule-nameserver]`: Skip the Nameserver rule. <br>`[-no-rule-ipset]`: Skip the Ipset rule. <br>`[-no-rule-soa]`: Skip address SOA(#) rules.<br>`[-no-dualstack-selection]`: Disable dualstack ip selection.<br>`[-no-speed-check]`: Disable speed measurement. <br>`[-no-cache]`: stop caching |bind :53
|
||||
|bind-tcp|TCP mode DNS listening port number|[::]:53|Support binding multiple ports<br>`IP:PORT`: server IP, port number. <br>`[-group]`: The DNS server group used when requesting. <br>`[-no-rule-addr]`: Skip the address rule. <br>`[-no-rule-nameserver]`: Skip the Nameserver rule. <br>`[-no-rule-ipset]`: Skip the Ipset rule. <br>`[-no-rule-soa]`: Skip address SOA(#) rules.<br>`[-no-dualstack-selection]`: Disable dualstack ip selection.<br>`[-no-speed-check]`: Disable speed measurement. <br>`[-no-cache]`: stop caching |bind-tcp :53
|
||||
|cache-size|Domain name result cache number|512|integer|cache-size 512
|
||||
|cache-persist|enable persist cache|no|[yes\|no]|cache-persist yes
|
||||
|cache-persist|enable persist cache|Auto: Enabled if the location of `cache-file` has more than 128MB of free space.|[yes\|no]|cache-persist yes
|
||||
|cache-file|cache persist file|/tmp/smartdns.cache|路径|cache-file /tmp/smartdns.cache
|
||||
|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
|
||||
@@ -520,9 +520,9 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:443
|
||||
|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\|-], `-` for ignore|ipset /www.example.com/pass
|
||||
|ipset|Domain IPSet|None|ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]], `-` for ignore|ipset /www.example.com/#4:dns4,#6:-
|
||||
|ipset-timeout|ipset timeout enable|auto|[yes]|ipset-timeout yes
|
||||
|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br>`[-speed-check-mode]`: set speed check mode,same as parameter `speed-check-mode`<br>`[-address]`: same as parameter `address` <br>`[-nameserver]`: same as parameter `nameserver`<br>`[-ipset]`: same as parameter `ipset`|domain-rules /www.example.com/ -speed-check-mode none
|
||||
|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br>`[-c\|-speed-check-mode]`: set speed check mode,same as parameter `speed-check-mode`<br>`[-a\|-address]`: same as parameter `address` <br>`[-n\|-nameserver]`: same as parameter `nameserver`<br>`[-p\|-ipset]`: same as parameter `ipset`<br>`[-d\|-dualstack-ip-selection]`: same as parameter `dualstack-ip-selection`|domain-rules /www.example.com/ -speed-check-mode none
|
||||
|bogus-nxdomain|bogus IP address|None|[IP/subnet], Repeatable| bogus-nxdomain 1.2.3.4/16
|
||||
|ignore-ip|ignore ip address|None|[ip/subnet], Repeatable| ignore-ip 1.2.3.4/16
|
||||
|whitelist-ip|ip whitelist|None|[ip/subnet], Repeatable,When the filtering server responds IPs in the IP whitelist, only result in whitelist will be accepted| whitelist-ip 1.2.3.4/16
|
||||
|
||||
@@ -189,8 +189,9 @@ log-level info
|
||||
# set domain rules
|
||||
# domain-rules /domain/ [-speed-check-mode [...]]
|
||||
# rules:
|
||||
# -speed-check-mode [mode]: speed check mode
|
||||
# [-c] -speed-check-mode [mode]: speed check mode
|
||||
# speed-check-mode [ping|tcp:port|none|,]
|
||||
# -address [address|-]: same as address option
|
||||
# -nameserver [group|-]: same as nameserver option
|
||||
# -ipset [ipset|-]: same as ipset option
|
||||
# [-a] -address [address|-]: same as address option
|
||||
# [-n] -nameserver [group|-]: same as nameserver option
|
||||
# [-p] -ipset [ipset|-]: same as ipset option
|
||||
# [-d] -dualstack-ip-selection [yes|no]: same as dualstack-ip-selection option
|
||||
|
||||
0
package/build-pkg.sh
Normal file → Executable file
0
package/build-pkg.sh
Normal file → Executable file
0
package/debian/make.sh
Normal file → Executable file
0
package/debian/make.sh
Normal file → Executable file
0
package/linux/make.sh
Normal file → Executable file
0
package/linux/make.sh
Normal file → Executable file
@@ -104,13 +104,13 @@ msgid "Cache Size"
|
||||
msgstr "缓存大小"
|
||||
|
||||
msgid "DNS domain result cache size"
|
||||
msgstr "缓存DNS的结果,缓存大小,配置零则不缓存"
|
||||
msgstr "缓存DNS的结果,缓存大小,配置零则不缓存(单位:条)"
|
||||
|
||||
msgid "Domain TTL"
|
||||
msgstr "域名TTL"
|
||||
|
||||
msgid "TTL for all domain result."
|
||||
msgstr "设置所有域名的TTL值"
|
||||
msgstr "设置所有域名的TTL值(单位:秒,下同)"
|
||||
|
||||
msgid "Domain TTL Min"
|
||||
msgstr "域名TTL最小值"
|
||||
|
||||
0
package/luci-compat/make.sh
Normal file → Executable file
0
package/luci-compat/make.sh
Normal file → Executable file
@@ -110,13 +110,13 @@ msgid "Cache Size"
|
||||
msgstr "缓存大小"
|
||||
|
||||
msgid "DNS domain result cache size"
|
||||
msgstr "缓存DNS的结果,缓存大小,配置零则不缓存"
|
||||
msgstr "缓存DNS的结果,缓存大小,配置零则不缓存(单位:条)"
|
||||
|
||||
msgid "Domain TTL"
|
||||
msgstr "域名TTL"
|
||||
|
||||
msgid "TTL for all domain result."
|
||||
msgstr "设置所有域名的TTL值"
|
||||
msgstr "设置所有域名的TTL值(单位:秒,下同)"
|
||||
|
||||
msgid "Domain TTL Min"
|
||||
msgstr "域名TTL最小值"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"path": "smartdns/smartdns"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-smartdns" ],
|
||||
"uci": { "smartdns": true }
|
||||
}
|
||||
}
|
||||
|
||||
0
package/luci/make.sh
Normal file → Executable file
0
package/luci/make.sh
Normal file → Executable file
2
package/openwrt/make.sh
Normal file → Executable file
2
package/openwrt/make.sh
Normal file → Executable file
@@ -74,7 +74,7 @@ build()
|
||||
cd $ROOT
|
||||
|
||||
tar zcf $ROOT/data.tar.gz -C root --owner=0 --group=0 .
|
||||
tar zcf $OUTPUTDIR/smartdns.$VER.$FILEARCH.ipk --owner=0 --group=0 control.tar.gz data.tar.gz debian-binary
|
||||
tar zcf $OUTPUTDIR/smartdns.$VER.$FILEARCH.ipk --owner=0 --group=0 ./control.tar.gz ./data.tar.gz ./debian-binary
|
||||
rm -fr $ROOT/
|
||||
}
|
||||
|
||||
|
||||
0
package/optware/make.sh
Normal file → Executable file
0
package/optware/make.sh
Normal file → Executable file
@@ -1,21 +1,24 @@
|
||||
Name: smartdns
|
||||
Version: 31
|
||||
Release: 1%{?dist}
|
||||
Version: 1.2020.09.08
|
||||
Release: 2235%{?dist}
|
||||
Summary: smartdns
|
||||
|
||||
License: GPL 3.0
|
||||
URL: https://github.com/pymumu/smartdns
|
||||
Source0: smartdns-Release31.tar.gz
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
BuildRequires: glibc
|
||||
BuildRequires: centos-release >= 7
|
||||
BuildRequires: openssl-devel
|
||||
Requires: glibc
|
||||
Requires: openssl
|
||||
Requires: systemd
|
||||
|
||||
%description
|
||||
A local DNS server to obtain the fastest website IP for the best Internet experience.
|
||||
|
||||
%prep
|
||||
%setup -q -n smartdns-Release31
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
cd src
|
||||
|
||||
5
src/.gitignore
vendored
Normal file
5
src/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.vscode
|
||||
.o
|
||||
.DS_Store
|
||||
.swp.
|
||||
smartdns
|
||||
@@ -20,7 +20,7 @@ OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_co
|
||||
|
||||
# cflags
|
||||
ifndef CFLAGS
|
||||
CFLAGS =-O2 -g -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing
|
||||
CFLAGS =-O2 -g -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing -funwind-tables
|
||||
endif
|
||||
override CFLAGS +=-Iinclude
|
||||
override CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
|
||||
@@ -35,7 +35,7 @@ override CXXFLAGS +=-Iinclude
|
||||
ifeq ($(STATIC), yes)
|
||||
override LDFLAGS += -lssl -lcrypto -Wl,--whole-archive -lpthread -Wl,--no-whole-archive -ldl -static
|
||||
else
|
||||
override LDFLAGS += -lssl -lcrypto -lpthread
|
||||
override LDFLAGS += -lssl -lcrypto -lpthread -ldl
|
||||
endif
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
36
src/dns.c
36
src/dns.c
@@ -253,11 +253,8 @@ static int _dns_add_qr_head(struct dns_data_context *data_context, char *domain,
|
||||
return -1;
|
||||
}
|
||||
|
||||
*((unsigned short *)(data_context->ptr)) = qtype;
|
||||
data_context->ptr += 2;
|
||||
|
||||
*((unsigned short *)(data_context->ptr)) = qclass;
|
||||
data_context->ptr += 2;
|
||||
_dns_write_short(&data_context->ptr, qtype);
|
||||
_dns_write_short(&data_context->ptr, qclass);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -266,6 +263,10 @@ static int _dns_get_qr_head(struct dns_data_context *data_context, char *domain,
|
||||
{
|
||||
int i;
|
||||
int is_read_all = 0;
|
||||
|
||||
if (domain == NULL || data_context == NULL) {
|
||||
return -1;
|
||||
}
|
||||
/* question head */
|
||||
/* |domain |
|
||||
* |qtype | qclass |
|
||||
@@ -296,11 +297,8 @@ static int _dns_get_qr_head(struct dns_data_context *data_context, char *domain,
|
||||
return -1;
|
||||
}
|
||||
|
||||
*qtype = *((unsigned short *)(data_context->ptr));
|
||||
data_context->ptr += 2;
|
||||
|
||||
*qclass = *((unsigned short *)(data_context->ptr));
|
||||
data_context->ptr += 2;
|
||||
*qtype = _dns_read_short(&data_context->ptr);
|
||||
*qclass = _dns_read_short(&data_context->ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -325,11 +323,8 @@ static int _dns_add_rr_head(struct dns_data_context *data_context, char *domain,
|
||||
return -1;
|
||||
}
|
||||
|
||||
*((unsigned int *)(data_context->ptr)) = ttl;
|
||||
data_context->ptr += 4;
|
||||
|
||||
*((unsigned short *)(data_context->ptr)) = rr_len;
|
||||
data_context->ptr += 2;
|
||||
_dns_write_int(&data_context->ptr, ttl);
|
||||
_dns_write_short(&data_context->ptr, rr_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -351,11 +346,8 @@ static int _dns_get_rr_head(struct dns_data_context *data_context, char *domain,
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ttl = *((unsigned int *)(data_context->ptr));
|
||||
data_context->ptr += 4;
|
||||
|
||||
*rr_len = *((unsigned short *)(data_context->ptr));
|
||||
data_context->ptr += 2;
|
||||
*ttl = _dns_read_int(&data_context->ptr);
|
||||
*rr_len = _dns_read_short(&data_context->ptr);
|
||||
|
||||
return len;
|
||||
}
|
||||
@@ -940,7 +932,7 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz
|
||||
|
||||
/*[len]string[len]string...[0]0 */
|
||||
while (1) {
|
||||
if (ptr > context->data + context->maxsize || ptr < context->data || output_len >= size - 1 || ptr_jump > 4) {
|
||||
if (ptr >= context->data + context->maxsize || ptr < context->data || output_len >= size - 1 || ptr_jump > 4) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1363,7 +1355,7 @@ static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *
|
||||
len = (ecs->source_prefix / 8);
|
||||
len += (ecs->source_prefix % 8 > 0) ? 1 : 0;
|
||||
|
||||
if (_dns_left_len(context) < len) {
|
||||
if (_dns_left_len(context) < len || len > sizeof(ecs->addr)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -142,8 +142,7 @@ void dns_cache_data_free(struct dns_cache_data *data)
|
||||
free(data);
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, int cname_ttl, unsigned char *addr,
|
||||
int addr_len)
|
||||
struct dns_cache_data *dns_cache_new_data(void)
|
||||
{
|
||||
struct dns_cache_addr *cache_addr = malloc(sizeof(struct dns_cache_addr));
|
||||
memset(cache_addr, 0, sizeof(struct dns_cache_addr));
|
||||
@@ -151,6 +150,50 @@ struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cache_addr->head.cache_type = CACHE_TYPE_NONE;
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
|
||||
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)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache;
|
||||
if (cache_addr == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memset(cache_addr->addr_data.addr, 0, sizeof(cache_addr->addr_data.addr));
|
||||
|
||||
if (cname) {
|
||||
safe_strncpy(cache_addr->addr_data.cname, cname, DNS_MAX_CNAME_LEN);
|
||||
cache_addr->addr_data.cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
cache_addr->head.cache_flag = cache_flag;
|
||||
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);
|
||||
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)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache;
|
||||
if (cache_addr == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (addr_len == DNS_RR_A_LEN) {
|
||||
memcpy(cache_addr->addr_data.addr, addr, DNS_RR_A_LEN);
|
||||
} else if (addr_len != DNS_RR_AAAA_LEN) {
|
||||
@@ -167,16 +210,8 @@ struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname,
|
||||
cache_addr->head.cache_flag = cache_flag;
|
||||
cache_addr->head.cache_type = CACHE_TYPE_ADDR;
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
|
||||
return (struct dns_cache_data *)cache_addr;
|
||||
|
||||
errout:
|
||||
if (cache_addr) {
|
||||
free(cache_addr);
|
||||
cache_addr = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len)
|
||||
@@ -298,6 +333,7 @@ int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
}
|
||||
|
||||
if (dns_cache_head.size <= 0) {
|
||||
dns_cache_data_free(cache_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -376,6 +412,18 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache)
|
||||
return ttl;
|
||||
}
|
||||
|
||||
int dns_cache_is_soa(struct dns_cache *dns_cache) {
|
||||
if (dns_cache == NULL) {
|
||||
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) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache)
|
||||
{
|
||||
return dns_cache->cache_data;
|
||||
@@ -467,7 +515,7 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
}
|
||||
|
||||
if (ttl < 0) {
|
||||
if (dns_cache_head.enable_inactive) {
|
||||
if (dns_cache_head.enable_inactive && (dns_cache_is_soa(dns_cache) == 0)) {
|
||||
_dns_cache_move_inactive(dns_cache);
|
||||
} else {
|
||||
_dns_cache_remove(dns_cache);
|
||||
|
||||
@@ -62,6 +62,7 @@ struct dns_cache_addr {
|
||||
struct dns_cache_data_head head;
|
||||
struct dns_cache_addr_data {
|
||||
unsigned int cname_ttl;
|
||||
char soa;
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
union {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
@@ -116,9 +117,6 @@ uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data);
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data);
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, int cname_ttl, unsigned char *addr,
|
||||
int addr_len);
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len);
|
||||
|
||||
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
|
||||
@@ -145,8 +143,17 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre);
|
||||
|
||||
int dns_cache_get_ttl(struct dns_cache *dns_cache);
|
||||
|
||||
int dns_cache_is_soa(struct dns_cache *dns_cache);
|
||||
|
||||
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_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl);
|
||||
|
||||
void dns_cache_destroy(void);
|
||||
|
||||
int dns_cache_load(const char *file);
|
||||
|
||||
162
src/dns_client.c
162
src/dns_client.c
@@ -184,6 +184,9 @@ struct dns_client {
|
||||
struct list_head dns_server_list;
|
||||
struct dns_server_group *default_group;
|
||||
|
||||
SSL_CTX *ssl_ctx;
|
||||
int ssl_verify_skip;
|
||||
|
||||
/* query list */
|
||||
pthread_mutex_t dns_request_lock;
|
||||
struct list_head dns_request_list;
|
||||
@@ -253,6 +256,9 @@ static int dns_client_has_bootstrap_dns = 0;
|
||||
int _ssl_read(struct dns_server_info *server, void *buff, int num)
|
||||
{
|
||||
int ret = 0;
|
||||
if (server == NULL || buff == NULL) {
|
||||
return SSL_ERROR_SYSCALL;
|
||||
}
|
||||
pthread_mutex_lock(&server->lock);
|
||||
ret = SSL_read(server->ssl, buff, num);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
@@ -262,6 +268,10 @@ int _ssl_read(struct dns_server_info *server, void *buff, int num)
|
||||
int _ssl_write(struct dns_server_info *server, const void *buff, int num)
|
||||
{
|
||||
int ret = 0;
|
||||
if (server == NULL || buff == NULL || server->ssl == NULL) {
|
||||
return SSL_ERROR_SYSCALL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&server->lock);
|
||||
ret = SSL_write(server->ssl, buff, num);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
@@ -271,6 +281,10 @@ int _ssl_write(struct dns_server_info *server, const void *buff, int num)
|
||||
int _ssl_shutdown(struct dns_server_info *server)
|
||||
{
|
||||
int ret = 0;
|
||||
if (server == NULL || server->ssl == NULL) {
|
||||
return SSL_ERROR_SYSCALL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&server->lock);
|
||||
ret = SSL_shutdown(server->ssl);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
@@ -280,6 +294,10 @@ int _ssl_shutdown(struct dns_server_info *server)
|
||||
int _ssl_get_error(struct dns_server_info *server, int ret)
|
||||
{
|
||||
int err = 0;
|
||||
if (server == NULL || server->ssl == NULL) {
|
||||
return SSL_ERROR_SYSCALL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&server->lock);
|
||||
err = SSL_get_error(server->ssl, ret);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
@@ -289,6 +307,10 @@ int _ssl_get_error(struct dns_server_info *server, int ret)
|
||||
int _ssl_do_handshake(struct dns_server_info *server)
|
||||
{
|
||||
int err = 0;
|
||||
if (server == NULL || server->ssl == NULL) {
|
||||
return SSL_ERROR_SYSCALL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&server->lock);
|
||||
err = SSL_do_handshake(server->ssl);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
@@ -298,6 +320,10 @@ int _ssl_do_handshake(struct dns_server_info *server)
|
||||
int _ssl_session_reused(struct dns_server_info *server)
|
||||
{
|
||||
int err = 0;
|
||||
if (server == NULL || server->ssl == NULL) {
|
||||
return SSL_ERROR_SYSCALL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&server->lock);
|
||||
err = SSL_session_reused(server->ssl);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
@@ -307,6 +333,10 @@ int _ssl_session_reused(struct dns_server_info *server)
|
||||
SSL_SESSION *_ssl_get1_session(struct dns_server_info *server)
|
||||
{
|
||||
SSL_SESSION *ret = 0;
|
||||
if (server == NULL || server->ssl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&server->lock);
|
||||
ret = SSL_get1_session(server->ssl);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
@@ -407,6 +437,10 @@ static struct dns_server_info *_dns_client_get_server(char *server_ip, int port,
|
||||
struct dns_server_info *server_info, *tmp;
|
||||
struct dns_server_info *server_info_return = NULL;
|
||||
|
||||
if (server_ip == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&client.server_list_lock);
|
||||
list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list)
|
||||
{
|
||||
@@ -509,6 +543,10 @@ static int _dns_client_add_to_pending_group(char *group_name, char *server_ip, i
|
||||
struct dns_server_pending *pending = NULL;
|
||||
struct dns_server_pending_group *group = NULL;
|
||||
|
||||
if (group_name == NULL || server_ip == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&pending_server_mutex);
|
||||
list_for_each_entry_safe(item, tmp, &pending_servers, list)
|
||||
{
|
||||
@@ -550,6 +588,10 @@ static int _dns_client_add_to_group_pending(char *group_name, char *server_ip, i
|
||||
{
|
||||
struct dns_server_info *server_info = NULL;
|
||||
|
||||
if (group_name == NULL || server_ip == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
server_info = _dns_client_get_server(server_ip, port, server_type);
|
||||
if (server_info == NULL) {
|
||||
if (ispending == 0) {
|
||||
@@ -630,6 +672,10 @@ int dns_client_add_group(char *group_name)
|
||||
unsigned long key;
|
||||
struct dns_server_group *group = NULL;
|
||||
|
||||
if (group_name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_dns_client_get_group(group_name) != NULL) {
|
||||
tlog(TLOG_ERROR, "add group %s failed, group already exists", group_name);
|
||||
return -1;
|
||||
@@ -661,6 +707,10 @@ static int _dns_client_remove_group(struct dns_server_group *group)
|
||||
struct dns_server_group_member *group_member;
|
||||
struct dns_server_group_member *tmp;
|
||||
|
||||
if (group == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(group_member, tmp, &group->head, list)
|
||||
{
|
||||
_dns_client_remove_member(group_member);
|
||||
@@ -678,6 +728,10 @@ int dns_client_remove_group(char *group_name)
|
||||
struct dns_server_group *group = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
|
||||
if (group_name == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
key = hash_string(group_name);
|
||||
hash_for_each_possible_safe(client.group, group, tmp, node, key)
|
||||
{
|
||||
@@ -786,6 +840,10 @@ static int _dns_client_set_trusted_cert(SSL_CTX *ssl_ctx)
|
||||
char *capath = NULL;
|
||||
int cert_path_set = 0;
|
||||
|
||||
if (ssl_ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dns_conf_ca_file[0]) {
|
||||
cafile = dns_conf_ca_file;
|
||||
}
|
||||
@@ -796,15 +854,19 @@ static int _dns_client_set_trusted_cert(SSL_CTX *ssl_ctx)
|
||||
|
||||
if (cafile == NULL && capath == NULL) {
|
||||
if (SSL_CTX_set_default_verify_paths(ssl_ctx)) {
|
||||
cert_path_set = 1;
|
||||
}
|
||||
|
||||
const STACK_OF(X509_NAME) *cas = SSL_CTX_get_client_CA_list(ssl_ctx);
|
||||
if (cas && sk_X509_NAME_num(cas) == 0) {
|
||||
cafile = "/etc/ssl/certs/ca-certificates.crt";
|
||||
capath = "/etc/ssl/certs";
|
||||
} else {
|
||||
cert_path_set = 1;
|
||||
cert_path_set = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (cert_path_set == 0) {
|
||||
if (!SSL_CTX_load_verify_locations(ssl_ctx, cafile, capath)) {
|
||||
if (SSL_CTX_load_verify_locations(ssl_ctx, cafile, capath) == 0) {
|
||||
tlog(TLOG_WARN, "load certificate from %s:%s failed.", cafile, capath);
|
||||
return -1;
|
||||
}
|
||||
@@ -813,6 +875,47 @@ static int _dns_client_set_trusted_cert(SSL_CTX *ssl_ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SSL_CTX *_ssl_ctx_get(void)
|
||||
{
|
||||
pthread_mutex_lock(&client.server_list_lock);
|
||||
SSL_CTX *ssl_ctx = client.ssl_ctx;
|
||||
if (ssl_ctx) {
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||
#else
|
||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
#endif
|
||||
|
||||
if (ssl_ctx == NULL) {
|
||||
tlog(TLOG_ERROR, "init ssl failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT);
|
||||
SSL_CTX_sess_set_cache_size(ssl_ctx, DNS_MAX_SERVERS);
|
||||
if (_dns_client_set_trusted_cert(ssl_ctx) != 0) {
|
||||
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
|
||||
client.ssl_verify_skip = 1;
|
||||
}
|
||||
|
||||
client.ssl_ctx = ssl_ctx;
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
return client.ssl_ctx;
|
||||
errout:
|
||||
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
if (ssl_ctx) {
|
||||
SSL_CTX_free(ssl_ctx);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* add dns server information */
|
||||
static int _dns_client_server_add(char *server_ip, char *server_host, int port, dns_server_type_t server_type,
|
||||
struct client_dns_server_flags *flags)
|
||||
@@ -914,24 +1017,14 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
|
||||
|
||||
/* if server type is TLS, create ssl context */
|
||||
if (server_type == DNS_SERVER_TLS || server_type == DNS_SERVER_HTTPS) {
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
server_info->ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||
#else
|
||||
server_info->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
#endif
|
||||
|
||||
server_info->ssl_ctx = _ssl_ctx_get();
|
||||
if (server_info->ssl_ctx == NULL) {
|
||||
tlog(TLOG_ERROR, "init ssl failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
SSL_CTX_set_options(server_info->ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
SSL_CTX_set_session_cache_mode(server_info->ssl_ctx, SSL_SESS_CACHE_CLIENT);
|
||||
SSL_CTX_sess_set_cache_size(server_info->ssl_ctx, 32);
|
||||
if (_dns_client_set_trusted_cert(server_info->ssl_ctx) != 0) {
|
||||
tlog(TLOG_WARN, "disable check certificate for %s.", server_info->ip);
|
||||
if (client.ssl_verify_skip) {
|
||||
server_info->skip_check_cert = 1;
|
||||
SSL_CTX_set_verify(server_info->ssl_ctx, SSL_VERIFY_NONE, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,11 +1069,6 @@ errout:
|
||||
fast_ping_stop(server_info->ping_host);
|
||||
}
|
||||
|
||||
if (server_info->ssl_ctx) {
|
||||
SSL_CTX_free(server_info->ssl_ctx);
|
||||
server_info->ssl_ctx = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&server_info->lock);
|
||||
free(server_info);
|
||||
}
|
||||
@@ -1066,10 +1154,7 @@ static void _dns_client_server_close(struct dns_server_info *server_info)
|
||||
server_info->ssl_session = NULL;
|
||||
}
|
||||
|
||||
if (server_info->ssl_ctx) {
|
||||
SSL_CTX_free(server_info->ssl_ctx);
|
||||
server_info->ssl_ctx = NULL;
|
||||
}
|
||||
server_info->ssl_ctx = NULL;
|
||||
}
|
||||
|
||||
/* remove all servers information */
|
||||
@@ -1663,19 +1748,19 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
|
||||
const int ip_tos = SOCKET_IP_TOS;
|
||||
|
||||
if (server_info->ssl_ctx == NULL) {
|
||||
tlog(TLOG_ERROR, "create ssl ctx failed.");
|
||||
tlog(TLOG_ERROR, "create ssl ctx failed, %s", server_info->ip);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ssl = SSL_new(server_info->ssl_ctx);
|
||||
if (ssl == NULL) {
|
||||
tlog(TLOG_ERROR, "new ssl failed.");
|
||||
tlog(TLOG_ERROR, "new ssl failed, %s", server_info->ip);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
fd = socket(server_info->ai_family, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
tlog(TLOG_ERROR, "create socket failed.");
|
||||
tlog(TLOG_ERROR, "create socket failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -2307,7 +2392,7 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
|
||||
pthread_mutex_unlock(&server_info->lock);
|
||||
peer_CN[0] = '\0';
|
||||
_dns_client_tls_get_cert_CN(cert, peer_CN, sizeof(peer_CN));
|
||||
tlog(TLOG_WARN, "peer server %s certificate verify failed", server_info->ip);
|
||||
tlog(TLOG_WARN, "peer server %s certificate verify failed, ret = %ld", server_info->ip, res);
|
||||
tlog(TLOG_WARN, "peer CN: %s", peer_CN);
|
||||
goto errout;
|
||||
}
|
||||
@@ -2577,7 +2662,7 @@ static int _dns_client_send_tcp(struct dns_server_info *server_info, void *packe
|
||||
/* save data to buffer, and retry when EPOLLOUT is available */
|
||||
return _dns_client_send_data_to_buffer(server_info, inpacket, len);
|
||||
} else if (errno == EPIPE) {
|
||||
shutdown(server_info->fd, SHUT_RDWR);
|
||||
_dns_client_shutdown_socket(server_info);
|
||||
}
|
||||
return -1;
|
||||
} else if (send_len < len) {
|
||||
@@ -2621,7 +2706,7 @@ static int _dns_client_send_tls(struct dns_server_info *server_info, void *packe
|
||||
/* save data to buffer, and retry when EPOLLOUT is available */
|
||||
return _dns_client_send_data_to_buffer(server_info, inpacket, len);
|
||||
} else if (server_info->ssl && errno != ENOMEM) {
|
||||
SSL_shutdown(server_info->ssl);
|
||||
_dns_client_shutdown_socket(server_info);
|
||||
}
|
||||
return -1;
|
||||
} else if (send_len < len) {
|
||||
@@ -2672,7 +2757,7 @@ static int _dns_client_send_https(struct dns_server_info *server_info, void *pac
|
||||
/* save data to buffer, and retry when EPOLLOUT is available */
|
||||
return _dns_client_send_data_to_buffer(server_info, inpacket, http_len);
|
||||
} else if (server_info->ssl && errno != ENOMEM) {
|
||||
_ssl_shutdown(server_info);
|
||||
_dns_client_shutdown_socket(server_info);
|
||||
}
|
||||
return -1;
|
||||
} else if (send_len < http_len) {
|
||||
@@ -2691,15 +2776,19 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
int ret = 0;
|
||||
int send_err = 0;
|
||||
int i = 0;
|
||||
int total_server = 0;
|
||||
|
||||
query->send_tick = get_tick_count();
|
||||
|
||||
/* send query to all dns servers */
|
||||
for (i = 0; i < 2; i++) {
|
||||
total_server = 0;
|
||||
pthread_mutex_lock(&client.server_list_lock);
|
||||
list_for_each_entry_safe(group_member, tmp, &query->server_group->head, list)
|
||||
{
|
||||
server_info = group_member->server;
|
||||
total_server++;
|
||||
tlog(TLOG_DEBUG, "send query to server %s", server_info->ip);
|
||||
if (server_info->fd <= 0) {
|
||||
ret = _dns_client_create_socket(server_info);
|
||||
if (ret != 0) {
|
||||
@@ -2765,7 +2854,7 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
}
|
||||
|
||||
if (atomic_read(&query->dns_request_sent) <= 0) {
|
||||
tlog(TLOG_ERROR, "Send query to upstream server failed.");
|
||||
tlog(TLOG_ERROR, "Send query to upstream server failed, total server number %d", total_server);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -2851,6 +2940,10 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void
|
||||
int ret = 0;
|
||||
uint32_t key = 0;
|
||||
|
||||
if (domain == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
query = malloc(sizeof(*query));
|
||||
if (query == NULL) {
|
||||
goto errout;
|
||||
@@ -3045,6 +3138,7 @@ static void _dns_client_add_pending_servers(void)
|
||||
if (add_success == 0) {
|
||||
tlog(TLOG_WARN, "add pending DNS server %s failed.", pending->host);
|
||||
}
|
||||
list_del_init(&pending->list);
|
||||
_dns_client_server_pending_release_lck(pending);
|
||||
} else {
|
||||
tlog(TLOG_DEBUG, "add pending DNS server %s failed, retry %d...", pending->host, pending->retry_cnt);
|
||||
@@ -3247,4 +3341,8 @@ void dns_client_exit(void)
|
||||
|
||||
pthread_mutex_destroy(&client.server_list_lock);
|
||||
pthread_mutex_destroy(&client.domain_map_lock);
|
||||
if (client.ssl_ctx) {
|
||||
SSL_CTX_free(client.ssl_ctx);
|
||||
client.ssl_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
113
src/dns_conf.c
113
src/dns_conf.c
@@ -482,7 +482,7 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _config_domain_rule_flag_set(char *domain, unsigned int flag)
|
||||
static int _config_domain_rule_flag_set(char *domain, unsigned int flag, unsigned int is_clear)
|
||||
{
|
||||
struct dns_domain_rule *domain_rule = NULL;
|
||||
struct dns_domain_rule *old_domain_rule = NULL;
|
||||
@@ -516,12 +516,18 @@ static int _config_domain_rule_flag_set(char *domain, unsigned int flag)
|
||||
/* add new rule to domain */
|
||||
if (domain_rule->rules[DOMAIN_RULE_FLAGS] == NULL) {
|
||||
rule_flags = malloc(sizeof(*rule_flags));
|
||||
memset(rule_flags, 0, sizeof(*rule_flags));
|
||||
rule_flags->flags = 0;
|
||||
domain_rule->rules[DOMAIN_RULE_FLAGS] = rule_flags;
|
||||
}
|
||||
|
||||
rule_flags = domain_rule->rules[DOMAIN_RULE_FLAGS];
|
||||
rule_flags->flags |= flag;
|
||||
if (is_clear == false) {
|
||||
rule_flags->flags |= flag;
|
||||
} else {
|
||||
rule_flags->flags &= ~flag;
|
||||
}
|
||||
rule_flags->is_flag_set |= flag;
|
||||
|
||||
/* update domain rule */
|
||||
if (add_domain_rule) {
|
||||
@@ -589,11 +595,40 @@ static int _conf_domain_rule_ipset(char *domain, const char *ipsetname)
|
||||
{
|
||||
struct dns_ipset_rule *ipset_rule = NULL;
|
||||
const char *ipset = NULL;
|
||||
char *copied_name = NULL;
|
||||
enum domain_rule type;
|
||||
int ignore_flag;
|
||||
|
||||
copied_name = strdup(ipsetname);
|
||||
|
||||
if (copied_name == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
for (char *tok = strtok(copied_name, ","); tok; tok = strtok(NULL, ",")) {
|
||||
if (tok[0] == '#') {
|
||||
if (strncmp(tok, "#6:", 3u) == 0) {
|
||||
type = DOMAIN_RULE_IPSET_IPV6;
|
||||
ignore_flag = DOMAIN_FLAG_IPSET_IPV6_IGN;
|
||||
} else if (strncmp(tok, "#4:", 3u) == 0) {
|
||||
type = DOMAIN_RULE_IPSET_IPV4;
|
||||
ignore_flag = DOMAIN_FLAG_IPSET_IPV4_IGN;
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
tok += 3;
|
||||
} else {
|
||||
type = DOMAIN_RULE_IPSET;
|
||||
ignore_flag = DOMAIN_FLAG_IPSET_IGN;
|
||||
}
|
||||
|
||||
if (strncmp(tok, "-", 1) == 0) {
|
||||
_config_domain_rule_flag_set(domain, ignore_flag, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Process domain option */
|
||||
if (strncmp(ipsetname, "-", sizeof("-")) != 0) {
|
||||
/* new ipset domain */
|
||||
ipset = _dns_conf_get_ipset(ipsetname);
|
||||
ipset = _dns_conf_get_ipset(tok);
|
||||
if (ipset == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
@@ -604,26 +639,26 @@ static int _conf_domain_rule_ipset(char *domain, const char *ipsetname)
|
||||
}
|
||||
|
||||
ipset_rule->ipsetname = ipset;
|
||||
} else {
|
||||
/* ignore this domain */
|
||||
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_IPSET_IGNORE) != 0) {
|
||||
|
||||
if (_config_domain_rule_add(domain, type, ipset_rule) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_config_domain_rule_add(domain, DOMAIN_RULE_IPSET, ipset_rule) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
goto clear;
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
tlog(TLOG_ERROR, "add ipset %s failed", ipsetname);
|
||||
|
||||
if (ipset_rule) {
|
||||
free(ipset_rule);
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "add ipset %s failed", ipsetname);
|
||||
clear:
|
||||
if (copied_name) {
|
||||
free(copied_name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -670,7 +705,7 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
|
||||
}
|
||||
|
||||
/* add SOA rule */
|
||||
if (_config_domain_rule_flag_set(domain, flag) != 0) {
|
||||
if (_config_domain_rule_flag_set(domain, flag, 0) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -687,7 +722,7 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
|
||||
}
|
||||
|
||||
/* ignore rule */
|
||||
if (_config_domain_rule_flag_set(domain, flag) != 0) {
|
||||
if (_config_domain_rule_flag_set(domain, flag, 0) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -1008,7 +1043,7 @@ static int _conf_domain_rule_nameserver(char *domain, const char *group_name)
|
||||
nameserver_rule->group_name = group;
|
||||
} else {
|
||||
/* ignore this domain */
|
||||
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_NAMESERVER_IGNORE) != 0) {
|
||||
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_NAMESERVER_IGNORE, 0) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -1029,6 +1064,26 @@ errout:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _conf_domain_rule_dualstack_selection(char *domain, const char *yesno)
|
||||
{
|
||||
if (strncmp(yesno, "yes", sizeof("yes")) == 0 || strncmp(yesno, "Yes", sizeof("Yes")) == 0) {
|
||||
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_DUALSTACK_SELECT, 0) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
/* ignore this domain */
|
||||
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_DUALSTACK_SELECT, 1) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
tlog(TLOG_ERROR, "set dualstack for %s failed. ", domain);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_nameserver(void *data, int argc, char *argv[])
|
||||
{
|
||||
char domain[DNS_MAX_CONF_CNAME_LEN];
|
||||
@@ -1239,6 +1294,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
{"address", required_argument, NULL, 'a'},
|
||||
{"ipset", required_argument, NULL, 'p'},
|
||||
{"nameserver", required_argument, NULL, 'n'},
|
||||
{"dualstack-ip-selection", required_argument, NULL, 'd'},
|
||||
{NULL, no_argument, NULL, 0}
|
||||
};
|
||||
/* clang-format on */
|
||||
@@ -1255,7 +1311,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
/* process extra options */
|
||||
optind = 1;
|
||||
while (1) {
|
||||
opt = getopt_long_only(argc, argv, "", long_options, NULL);
|
||||
opt = getopt_long_only(argc, argv, "c:a:p:n:d:", long_options, NULL);
|
||||
if (opt == -1) {
|
||||
break;
|
||||
}
|
||||
@@ -1313,6 +1369,15 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
const char *yesno = optarg;
|
||||
if (_conf_domain_rule_dualstack_selection(domain, yesno) != 0) {
|
||||
tlog(TLOG_ERROR, "set dualstack selection rule failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1419,8 +1484,14 @@ int config_addtional_file(void *data, int argc, char *argv[])
|
||||
if (conf_file[0] != '/') {
|
||||
safe_strncpy(file_path_dir, conf_get_conf_file(), DNS_MAX_PATH);
|
||||
dirname(file_path_dir);
|
||||
if (snprintf(file_path, DNS_MAX_PATH, "%s/%s", file_path_dir, conf_file) < 0) {
|
||||
return -1;
|
||||
if (strncmp(file_path_dir, conf_get_conf_file(), sizeof(file_path_dir)) == 0) {
|
||||
if (snprintf(file_path, DNS_MAX_PATH, "%s", conf_file) < 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (snprintf(file_path, DNS_MAX_PATH, "%s/%s", file_path_dir, conf_file) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
safe_strncpy(file_path, conf_file, DNS_MAX_PATH);
|
||||
|
||||
@@ -56,6 +56,8 @@ enum domain_rule {
|
||||
DOMAIN_RULE_ADDRESS_IPV4,
|
||||
DOMAIN_RULE_ADDRESS_IPV6,
|
||||
DOMAIN_RULE_IPSET,
|
||||
DOMAIN_RULE_IPSET_IPV4,
|
||||
DOMAIN_RULE_IPSET_IPV6,
|
||||
DOMAIN_RULE_NAMESERVER,
|
||||
DOMAIN_RULE_CHECKSPEED,
|
||||
DOMAIN_RULE_MAX,
|
||||
@@ -78,8 +80,11 @@ typedef enum {
|
||||
#define DOMAIN_FLAG_ADDR_IGN (1 << 3)
|
||||
#define DOMAIN_FLAG_ADDR_IPV4_IGN (1 << 4)
|
||||
#define DOMAIN_FLAG_ADDR_IPV6_IGN (1 << 5)
|
||||
#define DOMAIN_FLAG_IPSET_IGNORE (1 << 6)
|
||||
#define DOMAIN_FLAG_NAMESERVER_IGNORE (1 << 7)
|
||||
#define DOMAIN_FLAG_IPSET_IGN (1 << 6)
|
||||
#define DOMAIN_FLAG_IPSET_IPV4_IGN (1 << 7)
|
||||
#define DOMAIN_FLAG_IPSET_IPV6_IGN (1 << 8)
|
||||
#define DOMAIN_FLAG_NAMESERVER_IGNORE (1 << 9)
|
||||
#define DOMAIN_FLAG_DUALSTACK_SELECT (1 << 10)
|
||||
|
||||
#define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0)
|
||||
|
||||
@@ -95,6 +100,7 @@ typedef enum {
|
||||
|
||||
struct dns_rule_flags {
|
||||
unsigned int flags;
|
||||
unsigned int is_flag_set;
|
||||
};
|
||||
|
||||
struct dns_address_IPV4 {
|
||||
|
||||
209
src/dns_server.c
209
src/dns_server.c
@@ -258,6 +258,21 @@ static int _dns_server_epoll_ctl(struct dns_server_conn_head *head, int op, uint
|
||||
|
||||
static void _dns_server_set_dualstack_selection(struct dns_request *request)
|
||||
{
|
||||
struct dns_rule_flags *rule_flag = NULL;
|
||||
|
||||
rule_flag = request->domain_rule.rules[DOMAIN_RULE_FLAGS];
|
||||
if (rule_flag) {
|
||||
if (rule_flag->flags & DOMAIN_FLAG_DUALSTACK_SELECT) {
|
||||
request->dualstack_selection = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (rule_flag->is_flag_set & DOMAIN_FLAG_DUALSTACK_SELECT) {
|
||||
request->dualstack_selection = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_DUALSTACK_SELECTION) == 0) {
|
||||
request->dualstack_selection = 0;
|
||||
return;
|
||||
@@ -666,7 +681,7 @@ static int _dns_server_reply_SOA(int rcode, struct dns_request *request)
|
||||
/* add ip to specific ipset */
|
||||
static int _dns_setup_ipset(struct dns_request *request)
|
||||
{
|
||||
struct dns_ipset_rule *ipset_rule = NULL;
|
||||
struct dns_ipset_rule *rule = NULL, *ipset_rule = NULL, *ipset_rule_v4 = NULL, *ipset_rule_v6 = NULL;
|
||||
struct dns_rule_flags *rule_flags = NULL;
|
||||
int ret = 0;
|
||||
|
||||
@@ -676,32 +691,56 @@ static int _dns_setup_ipset(struct dns_request *request)
|
||||
|
||||
/* check ipset rule */
|
||||
rule_flags = request->domain_rule.rules[DOMAIN_RULE_FLAGS];
|
||||
if (rule_flags) {
|
||||
if (rule_flags->flags & DOMAIN_FLAG_IPSET_IGNORE) {
|
||||
return 0;
|
||||
}
|
||||
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
|
||||
ipset_rule = request->domain_rule.rules[DOMAIN_RULE_IPSET];
|
||||
}
|
||||
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
|
||||
ipset_rule_v4 = request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV4];
|
||||
}
|
||||
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV6_IGN) == 0) {
|
||||
ipset_rule_v6 = request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV6];
|
||||
}
|
||||
|
||||
ipset_rule = request->domain_rule.rules[DOMAIN_RULE_IPSET];
|
||||
if (ipset_rule == NULL) {
|
||||
if (!(ipset_rule || ipset_rule_v4 || ipset_rule_v6)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add IPV4 to ipset */
|
||||
if (request->has_ipv4 && request->qtype == DNS_T_A) {
|
||||
ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
|
||||
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
|
||||
if (rule) {
|
||||
ret |= ipset_add(rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH: domain:%s, ipset:%s, IP: %d.%d.%d.%d, result: %d", request->domain,
|
||||
rule->ipsetname, request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2],
|
||||
request->ipv4_addr[3], ret);
|
||||
}
|
||||
}
|
||||
|
||||
/* add IPV6 to ipset */
|
||||
if (request->has_ipv6 && request->qtype == DNS_T_AAAA) {
|
||||
if (request->has_ipv4) {
|
||||
ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
|
||||
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
|
||||
if (rule) {
|
||||
ret |= ipset_add(rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH: domain:%s, ipset:%s, IP: %d.%d.%d.%d, result: %d", request->domain,
|
||||
rule->ipsetname, request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2],
|
||||
request->ipv4_addr[3], ret);
|
||||
}
|
||||
}
|
||||
rule = ipset_rule_v6 ? ipset_rule_v6 : ipset_rule;
|
||||
if (rule) {
|
||||
ret |= ipset_add(rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
|
||||
tlog(TLOG_DEBUG,
|
||||
"IPSET-MATCH: domain:%s, ipset:%s, IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x, result: %d",
|
||||
request->domain, rule->ipsetname, request->ipv6_addr[0], request->ipv6_addr[1], request->ipv6_addr[2],
|
||||
request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5], request->ipv6_addr[6],
|
||||
request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10],
|
||||
request->ipv6_addr[11], request->ipv6_addr[12], request->ipv6_addr[13], request->ipv6_addr[14],
|
||||
request->ipv6_addr[15], ret);
|
||||
}
|
||||
ret |= ipset_add(ipset_rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH: domain:%s, ipset:%s, result: %d", request->domain, ipset_rule->ipsetname, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -721,6 +760,10 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (request->has_soa) {
|
||||
ttl = dns_conf_rr_ttl;
|
||||
}
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
if (request->prefetch) {
|
||||
if (dns_cache_replace(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
@@ -744,7 +787,7 @@ errout:
|
||||
static int _dns_server_request_complete_A(struct dns_request *request)
|
||||
{
|
||||
char *cname = NULL;
|
||||
int cname_ttl = 0;
|
||||
int cname_ttl = dns_conf_rr_ttl;
|
||||
struct dns_cache_data *cache_data = NULL;
|
||||
|
||||
if (request->has_cname) {
|
||||
@@ -752,27 +795,29 @@ static int _dns_server_request_complete_A(struct dns_request *request)
|
||||
cname_ttl = request->ttl_cname;
|
||||
}
|
||||
|
||||
if (request->has_ipv4 == 0) {
|
||||
return 0;
|
||||
cache_data = dns_cache_new_data();
|
||||
if (cache_data == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0],
|
||||
request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
if (request->has_ipv4 != 0) {
|
||||
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0],
|
||||
request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
|
||||
request->has_soa = 0;
|
||||
if (request->has_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) {
|
||||
request->ttl_v4 = DNS_SERVER_TMOUT_TTL;
|
||||
request->has_soa = 0;
|
||||
if (request->has_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) {
|
||||
request->ttl_v4 = DNS_SERVER_TMOUT_TTL;
|
||||
}
|
||||
dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_RR_A_LEN);
|
||||
} else {
|
||||
dns_cache_set_data_soa(cache_data, request->server_flags, cname, cname_ttl);
|
||||
}
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) == 0) {
|
||||
dns_cache_data_free(cache_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cache_data = dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_RR_A_LEN);
|
||||
if (cache_data == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
@@ -792,7 +837,7 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
|
||||
{
|
||||
int ret = -1;
|
||||
char *cname = NULL;
|
||||
int cname_ttl = 0;
|
||||
int cname_ttl = dns_conf_rr_ttl;
|
||||
struct dns_cache_data *cache_data = NULL;
|
||||
|
||||
if (request->has_cname) {
|
||||
@@ -800,6 +845,11 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
|
||||
cname_ttl = request->ttl_cname;
|
||||
}
|
||||
|
||||
cache_data = dns_cache_new_data();
|
||||
if (cache_data == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (request->has_ipv6) {
|
||||
tlog(TLOG_INFO,
|
||||
"result: %s, rcode: %d, %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
@@ -814,19 +864,21 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
|
||||
}
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
|
||||
cache_data =
|
||||
dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv6_addr, DNS_T_AAAA);
|
||||
if (cache_data == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_server_request_update_cache(request, DNS_T_AAAA, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv6_addr, DNS_T_AAAA);
|
||||
|
||||
request->has_soa = 0;
|
||||
} else {
|
||||
dns_cache_set_data_soa(cache_data, request->server_flags, cname, cname_ttl);
|
||||
}
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
|
||||
if (_dns_server_request_update_cache(request, DNS_T_AAAA, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
cache_data = NULL;
|
||||
} else {
|
||||
dns_cache_data_free(cache_data);
|
||||
cache_data = NULL;
|
||||
}
|
||||
|
||||
if (request->has_ipv4 && (request->ping_ttl_v4 > 0)) {
|
||||
@@ -838,15 +890,17 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
|
||||
request->ping_ttl_v6 < 0) {
|
||||
tlog(TLOG_DEBUG, "Force IPV4 perfered.");
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
|
||||
cache_data =
|
||||
dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_T_A);
|
||||
cache_data = dns_cache_new_data();
|
||||
if (cache_data == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv4_addr,
|
||||
DNS_T_A);
|
||||
if (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
cache_data = NULL;
|
||||
}
|
||||
|
||||
if (request->dualstack_selection) {
|
||||
@@ -866,7 +920,7 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (cache_data == NULL) {
|
||||
if (cache_data != NULL) {
|
||||
dns_cache_data_free(cache_data);
|
||||
cache_data = NULL;
|
||||
}
|
||||
@@ -1775,7 +1829,7 @@ static int _dns_server_setup_ipset_packet(struct dns_request *request, struct dn
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
struct dns_rrs *rrs = NULL;
|
||||
struct dns_ipset_rule *ipset_rule = NULL;
|
||||
struct dns_ipset_rule *rule = NULL, *ipset_rule = NULL, *ipset_rule_v4 = NULL, *ipset_rule_v6 = NULL;
|
||||
struct dns_rule_flags *rule_flags = NULL;
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_IPSET) == 0) {
|
||||
@@ -1783,14 +1837,17 @@ static int _dns_server_setup_ipset_packet(struct dns_request *request, struct dn
|
||||
}
|
||||
/* check ipset rule */
|
||||
rule_flags = request->domain_rule.rules[DOMAIN_RULE_FLAGS];
|
||||
if (rule_flags) {
|
||||
if (rule_flags->flags & DOMAIN_FLAG_IPSET_IGNORE) {
|
||||
return 0;
|
||||
}
|
||||
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
|
||||
ipset_rule = request->domain_rule.rules[DOMAIN_RULE_IPSET];
|
||||
}
|
||||
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
|
||||
ipset_rule_v4 = request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV4];
|
||||
}
|
||||
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV6_IGN) == 0) {
|
||||
ipset_rule_v6 = request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV6];
|
||||
}
|
||||
|
||||
ipset_rule = request->domain_rule.rules[DOMAIN_RULE_IPSET];
|
||||
if (ipset_rule == NULL) {
|
||||
if (!(ipset_rule || ipset_rule_v4 || ipset_rule_v6)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1809,11 +1866,14 @@ static int _dns_server_setup_ipset_packet(struct dns_request *request, struct dn
|
||||
/* get A result */
|
||||
dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
|
||||
/* add IPV4 to ipset */
|
||||
ipset_add(ipset_rule->ipsetname, addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
|
||||
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
|
||||
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: %d.%d.%d.%d", request->domain,
|
||||
ipset_rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
|
||||
if (rule) {
|
||||
/* add IPV4 to ipset */
|
||||
ipset_add(rule->ipsetname, addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: %d.%d.%d.%d", request->domain,
|
||||
rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
|
||||
}
|
||||
} break;
|
||||
case DNS_T_AAAA: {
|
||||
unsigned char addr[16];
|
||||
@@ -1826,16 +1886,25 @@ static int _dns_server_setup_ipset_packet(struct dns_request *request, struct dn
|
||||
/* add IPV6 to ipset */
|
||||
if (request->has_ipv6) {
|
||||
if (request->has_ipv4) {
|
||||
ipset_add(ipset_rule->ipsetname, addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
|
||||
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
|
||||
if (rule) {
|
||||
/* add IPV4 to ipset */
|
||||
ipset_add(rule->ipsetname, addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: %d.%d.%d.%d",
|
||||
request->domain, rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
|
||||
}
|
||||
}
|
||||
rule = ipset_rule_v6 ? ipset_rule_v6 : ipset_rule;
|
||||
if (rule) {
|
||||
ipset_add(rule->ipsetname, addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
|
||||
tlog(TLOG_DEBUG,
|
||||
"IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, rule->ipsetname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
|
||||
addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14],
|
||||
addr[15]);
|
||||
}
|
||||
ipset_add(ipset_rule->ipsetname, addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG,
|
||||
"IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, ipset_rule->ipsetname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
|
||||
addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
@@ -2062,10 +2131,18 @@ static void _dns_server_update_rule_by_flags(struct dns_request *request)
|
||||
request->domain_rule.rules[DOMAIN_RULE_ADDRESS_IPV6] = NULL;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_IPSET_IGNORE) {
|
||||
if (flags & DOMAIN_FLAG_IPSET_IGN) {
|
||||
request->domain_rule.rules[DOMAIN_RULE_IPSET] = NULL;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_IPSET_IPV4_IGN) {
|
||||
request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV4] = NULL;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_IPSET_IPV6_IGN) {
|
||||
request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV6] = NULL;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_NAMESERVER_IGNORE) {
|
||||
request->domain_rule.rules[DOMAIN_RULE_NAMESERVER] = NULL;
|
||||
}
|
||||
@@ -2400,7 +2477,7 @@ static int _dns_server_process_cache(struct dns_request *request)
|
||||
if (dns_cache == NULL) {
|
||||
if (request->dualstack_selection && request->qtype == DNS_T_AAAA) {
|
||||
dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A);
|
||||
if (dns_cache_A) {
|
||||
if (dns_cache_A && dns_cache_is_soa(dns_cache_A) == 0 && dns_cache_is_soa(dns_cache)) {
|
||||
tlog(TLOG_DEBUG, "No IPV6 Found, Force IPV4 perfered.");
|
||||
if (dns_cache_get_ttl(dns_cache_A) == 0) {
|
||||
uint32_t server_flags = request->server_flags;
|
||||
@@ -2420,9 +2497,14 @@ static int _dns_server_process_cache(struct dns_request *request)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (dns_cache_is_soa(dns_cache)) {
|
||||
ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (request->dualstack_selection && request->qtype == DNS_T_AAAA) {
|
||||
dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A);
|
||||
if (dns_cache_A && (dns_cache_A->info.speed > 0)) {
|
||||
if (dns_cache_A && dns_cache_is_soa(dns_cache_A) == 0 && (dns_cache_A->info.speed > 0)) {
|
||||
if ((dns_cache_A->info.speed + (dns_conf_dualstack_ip_selection_threshold * 10)) < dns_cache->info.speed ||
|
||||
dns_cache->info.speed < 0) {
|
||||
tlog(TLOG_DEBUG, "Force IPV4 perfered.");
|
||||
@@ -2591,6 +2673,8 @@ static int _dns_server_do_query(struct dns_request *request, const char *domain,
|
||||
group_name = dns_group;
|
||||
}
|
||||
|
||||
_dns_server_set_dualstack_selection(request);
|
||||
|
||||
if (_dns_server_process_special_query(request) == 0) {
|
||||
goto clean_exit;
|
||||
}
|
||||
@@ -2717,7 +2801,6 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
|
||||
_dns_server_request_set_client(request, conn);
|
||||
_dns_server_request_set_client_addr(request, from, from_len);
|
||||
_dns_server_request_set_id(request, packet->head.id);
|
||||
_dns_server_set_dualstack_selection(request);
|
||||
ret = _dns_server_do_query(request, domain, qtype);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "do query %s failed.\n", domain);
|
||||
|
||||
@@ -365,7 +365,12 @@ static void _fast_ping_close_host_sock(struct ping_host_struct *ping_host)
|
||||
|
||||
static void _fast_ping_host_put(struct ping_host_struct *ping_host)
|
||||
{
|
||||
if (!atomic_dec_and_test(&ping_host->ref)) {
|
||||
int ref_cnt = atomic_dec_and_test(&ping_host->ref);
|
||||
if (!ref_cnt) {
|
||||
if (ref_cnt < 0) {
|
||||
tlog(TLOG_ERROR, "invalid refcount of ping_host %s", ping_host->host);
|
||||
abort();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1081,15 +1086,19 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c
|
||||
pthread_mutex_unlock(&ping.map_lock);
|
||||
|
||||
_fast_ping_host_get(ping_host);
|
||||
_fast_ping_host_get(ping_host);
|
||||
// for ping race condition, get reference count twice
|
||||
if (_fast_ping_sendping(ping_host) != 0) {
|
||||
goto errout_remove;
|
||||
}
|
||||
|
||||
ping_host->run = 1;
|
||||
freeaddrinfo(gai);
|
||||
_fast_ping_host_put(ping_host);
|
||||
return ping_host;
|
||||
errout_remove:
|
||||
fast_ping_stop(ping_host);
|
||||
_fast_ping_host_put(ping_host);
|
||||
ping_host = NULL;
|
||||
errout:
|
||||
if (gai) {
|
||||
|
||||
@@ -363,7 +363,7 @@ static void _sig_error_exit(int signo, siginfo_t *siginfo, void *ct)
|
||||
"%s %s)\n",
|
||||
signo, siginfo->si_code, siginfo->si_errno, siginfo->si_pid, getpid(), PC, (unsigned long)siginfo->si_addr,
|
||||
__DATE__, __TIME__, arch);
|
||||
|
||||
print_stack();
|
||||
sleep(1);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
209
src/tlog.c
209
src/tlog.c
@@ -10,6 +10,7 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
@@ -21,7 +22,6 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef likely
|
||||
@@ -40,6 +40,8 @@
|
||||
#define TLOG_BUFF_LEN (PATH_MAX + TLOG_LOG_NAME_LEN * 3)
|
||||
#define TLOG_SUFFIX_GZ ".gz"
|
||||
#define TLOG_SUFFIX_LOG ""
|
||||
#define TLOG_MAX_LINE_SIZE_SET (1024 * 8)
|
||||
#define TLOG_MIN_LINE_SIZE_SET (128)
|
||||
|
||||
#define TLOG_SEGMENT_MAGIC 0xFF446154
|
||||
|
||||
@@ -57,6 +59,9 @@ struct tlog_log {
|
||||
char logdir[PATH_MAX];
|
||||
char logname[TLOG_LOG_NAME_LEN];
|
||||
char suffix[TLOG_LOG_NAME_LEN];
|
||||
char pending_logfile[PATH_MAX];
|
||||
int rename_pending;
|
||||
int fail;
|
||||
int logsize;
|
||||
int logcount;
|
||||
int block;
|
||||
@@ -66,12 +71,15 @@ struct tlog_log {
|
||||
int multi_log;
|
||||
int logscreen;
|
||||
int segment_log;
|
||||
|
||||
unsigned int max_line_size;
|
||||
|
||||
tlog_output_func output_func;
|
||||
void *private_data;
|
||||
|
||||
time_t last_try;
|
||||
time_t last_waitpid;
|
||||
mode_t file_perm;
|
||||
mode_t archive_perm;
|
||||
|
||||
int waiters;
|
||||
int is_exit;
|
||||
@@ -97,13 +105,13 @@ struct tlog_segment_log_head {
|
||||
struct tlog_loginfo info;
|
||||
unsigned short len;
|
||||
char data[0];
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
|
||||
struct tlog_segment_head {
|
||||
unsigned int magic;
|
||||
unsigned short len;
|
||||
char data[0];
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed));
|
||||
|
||||
struct oldest_log {
|
||||
char name[TLOG_LOG_NAME_LEN];
|
||||
@@ -166,8 +174,8 @@ static int _tlog_mkdir(const char *path)
|
||||
if (access(path, F_OK) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(*path == ' ' && *path != '\0') {
|
||||
|
||||
while (*path == ' ' && *path != '\0') {
|
||||
path++;
|
||||
}
|
||||
|
||||
@@ -283,11 +291,37 @@ static int _tlog_gettime(struct tlog_time *cur_time)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tlog_set_maxline_size(struct tlog_log *log, int size)
|
||||
{
|
||||
if (log == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (size < TLOG_MIN_LINE_SIZE_SET) {
|
||||
size = TLOG_MIN_LINE_SIZE_SET;
|
||||
} else if (size > TLOG_MAX_LINE_SIZE_SET) {
|
||||
size = TLOG_MAX_LINE_SIZE_SET;
|
||||
}
|
||||
|
||||
log->max_line_size = size;
|
||||
}
|
||||
|
||||
void tlog_set_permission(struct tlog_log *log, unsigned int file, unsigned int archive)
|
||||
{
|
||||
log->file_perm = file;
|
||||
log->archive_perm = archive;
|
||||
}
|
||||
|
||||
int tlog_localtime(struct tlog_time *tm)
|
||||
{
|
||||
return _tlog_gettime(tm);
|
||||
}
|
||||
|
||||
tlog_log *tlog_get_root()
|
||||
{
|
||||
return tlog.root;
|
||||
}
|
||||
|
||||
void tlog_set_private(tlog_log *log, void *private_data)
|
||||
{
|
||||
if (log == NULL) {
|
||||
@@ -311,19 +345,19 @@ static int _tlog_format(char *buff, int maxlen, struct tlog_loginfo *info, void
|
||||
int len = 0;
|
||||
int total_len = 0;
|
||||
struct tlog_time *tm = &info->time;
|
||||
void* unused __attribute__ ((unused));
|
||||
void *unused __attribute__((unused));
|
||||
|
||||
unused = userptr;
|
||||
|
||||
if (tlog.root->multi_log) {
|
||||
/* format prefix */
|
||||
len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5d][%4s][%17s:%-4d] ",
|
||||
tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000, getpid(),
|
||||
len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5d][%4s][%17s:%-4d] ",
|
||||
tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000, getpid(),
|
||||
tlog_get_level_string(info->level), info->file, info->line);
|
||||
} else {
|
||||
/* format prefix */
|
||||
len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5s][%17s:%-4d] ",
|
||||
tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000,
|
||||
len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5s][%17s:%-4d] ",
|
||||
tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000,
|
||||
tlog_get_level_string(info->level), info->file, info->line);
|
||||
}
|
||||
|
||||
@@ -359,7 +393,7 @@ static int _tlog_root_log_buffer(char *buff, int maxlen, void *userptr, const ch
|
||||
}
|
||||
|
||||
if (tlog.root->segment_log) {
|
||||
log_head = (struct tlog_segment_log_head *) buff;
|
||||
log_head = (struct tlog_segment_log_head *)buff;
|
||||
len += sizeof(*log_head);
|
||||
memcpy(&log_head->info, &info_inter->info, sizeof(log_head->info));
|
||||
}
|
||||
@@ -400,7 +434,7 @@ static int _tlog_print_buffer(char *buff, int maxlen, void *userptr, const char
|
||||
{
|
||||
int len;
|
||||
int total_len = 0;
|
||||
void* unused __attribute__ ((unused));
|
||||
void *unused __attribute__((unused));
|
||||
|
||||
unused = userptr;
|
||||
|
||||
@@ -438,7 +472,7 @@ static int _tlog_need_drop(struct tlog_log *log)
|
||||
}
|
||||
|
||||
/* if free buffer length is less than min line length */
|
||||
if (maxlen < TLOG_MAX_LINE_LEN) {
|
||||
if (maxlen < log->max_line_size) {
|
||||
log->dropped++;
|
||||
ret = 0;
|
||||
}
|
||||
@@ -450,14 +484,14 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
|
||||
{
|
||||
int len;
|
||||
int maxlen = 0;
|
||||
char buff[TLOG_MAX_LINE_LEN];
|
||||
|
||||
struct tlog_segment_head *segment_head = NULL;
|
||||
|
||||
if (log == NULL || format == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buff[log->max_line_size];
|
||||
|
||||
if (log->buff == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -469,7 +503,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
|
||||
len = print_callback(buff, sizeof(buff), userptr, format, ap);
|
||||
if (len <= 0) {
|
||||
return -1;
|
||||
} else if (len >= TLOG_MAX_LINE_LEN) {
|
||||
} else if (len >= log->max_line_size) {
|
||||
strncpy(buff, "[LOG TOO LONG, DISCARD]\n", sizeof(buff));
|
||||
buff[sizeof(buff) - 1] = '\0';
|
||||
len = strnlen(buff, sizeof(buff));
|
||||
@@ -490,7 +524,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
|
||||
}
|
||||
|
||||
/* if free buffer length is less than min line length */
|
||||
if (maxlen < TLOG_MAX_LINE_LEN) {
|
||||
if (maxlen < log->max_line_size) {
|
||||
if (log->end != log->start) {
|
||||
tlog.notify_log = log;
|
||||
pthread_cond_signal(&tlog.cond);
|
||||
@@ -502,7 +536,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
pthread_mutex_lock(&log->lock);
|
||||
log->waiters++;
|
||||
@@ -516,7 +550,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
|
||||
|
||||
pthread_mutex_lock(&tlog.lock);
|
||||
}
|
||||
} while (maxlen < TLOG_MAX_LINE_LEN);
|
||||
} while (maxlen < log->max_line_size);
|
||||
|
||||
if (log->segment_log) {
|
||||
segment_head = (struct tlog_segment_head *)(log->buff + log->end);
|
||||
@@ -532,7 +566,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
|
||||
}
|
||||
|
||||
/* if remain buffer is not enough for a line, move end to start of buffer. */
|
||||
if (log->end > log->buffsize - TLOG_MAX_LINE_LEN) {
|
||||
if (log->end > log->buffsize - log->max_line_size) {
|
||||
log->ext_end = log->end;
|
||||
log->end = 0;
|
||||
}
|
||||
@@ -562,12 +596,12 @@ int tlog_printf(struct tlog_log *log, const char *format, ...)
|
||||
return len;
|
||||
}
|
||||
|
||||
static int _tlog_early_print(const char *format, va_list ap)
|
||||
static int _tlog_early_print(const char *format, va_list ap)
|
||||
{
|
||||
char log_buf[TLOG_MAX_LINE_LEN];
|
||||
size_t len = 0;
|
||||
size_t out_len = 0;
|
||||
int unused __attribute__ ((unused));
|
||||
int unused __attribute__((unused));
|
||||
|
||||
if (tlog_disable_early_print) {
|
||||
return 0;
|
||||
@@ -643,13 +677,13 @@ static int _tlog_rename_logfile(struct tlog_log *log, const char *log_file)
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(archive_file, sizeof(archive_file), "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d%s",
|
||||
snprintf(archive_file, sizeof(archive_file), "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d%s",
|
||||
log->logdir, log->logname, logtime.year, logtime.mon, logtime.mday,
|
||||
logtime.hour, logtime.min, logtime.sec, log->suffix);
|
||||
|
||||
while (access(archive_file, F_OK) == 0) {
|
||||
i++;
|
||||
snprintf(archive_file, sizeof(archive_file), "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d-%d%s",
|
||||
snprintf(archive_file, sizeof(archive_file), "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d-%d%s",
|
||||
log->logdir, log->logname, logtime.year, logtime.mon,
|
||||
logtime.mday, logtime.hour, logtime.min, logtime.sec, i, log->suffix);
|
||||
}
|
||||
@@ -658,6 +692,8 @@ static int _tlog_rename_logfile(struct tlog_log *log, const char *log_file)
|
||||
return -1;
|
||||
}
|
||||
|
||||
chmod(archive_file, log->archive_perm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -666,7 +702,7 @@ static int _tlog_list_dir(const char *path, list_callback callback, void *userpt
|
||||
DIR *dir = NULL;
|
||||
struct dirent *ent;
|
||||
int ret = 0;
|
||||
const char* unused __attribute__ ((unused)) = path;
|
||||
const char *unused __attribute__((unused)) = path;
|
||||
|
||||
dir = opendir(path);
|
||||
if (dir == NULL) {
|
||||
@@ -699,7 +735,7 @@ static int _tlog_count_log_callback(const char *path, struct dirent *entry, void
|
||||
struct count_log *count_log = (struct count_log *)userptr;
|
||||
struct tlog_log *log = count_log->log;
|
||||
char logname[TLOG_LOG_NAME_LEN * 2];
|
||||
const char* unused __attribute__ ((unused)) = path;
|
||||
const char *unused __attribute__((unused)) = path;
|
||||
|
||||
if (strstr(entry->d_name, log->suffix) == NULL) {
|
||||
return 0;
|
||||
@@ -1023,16 +1059,41 @@ static int _tlog_archive_log(struct tlog_log *log)
|
||||
}
|
||||
}
|
||||
|
||||
void _tlog_get_log_name_dir(struct tlog_log *log)
|
||||
{
|
||||
char log_file[PATH_MAX];
|
||||
if (log->fd > 0) {
|
||||
close(log->fd);
|
||||
log->fd = -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&tlog.lock);
|
||||
strncpy(log_file, log->pending_logfile, sizeof(log_file) - 1);
|
||||
log_file[sizeof(log_file) - 1] = '\0';
|
||||
strncpy(log->logdir, dirname(log_file), sizeof(log->logdir));
|
||||
log->logdir[sizeof(log->logdir) - 1] = '\0';
|
||||
strncpy(log_file, log->pending_logfile, PATH_MAX);
|
||||
log_file[sizeof(log_file) - 1] = '\0';
|
||||
strncpy(log->logname, basename(log_file), sizeof(log->logname));
|
||||
log->logname[sizeof(log->logname) - 1] = '\0';
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
}
|
||||
|
||||
static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
{
|
||||
int len;
|
||||
int unused __attribute__ ((unused));
|
||||
int unused __attribute__((unused));
|
||||
|
||||
if (bufflen <= 0) {
|
||||
if (bufflen <= 0 || log->fail) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* output log to screen */
|
||||
if (log->rename_pending) {
|
||||
_tlog_get_log_name_dir(log);
|
||||
log->rename_pending = 0;
|
||||
}
|
||||
|
||||
/* output log to screen */
|
||||
if (log->logscreen) {
|
||||
unused = write(STDOUT_FILENO, buff, bufflen);
|
||||
}
|
||||
@@ -1072,7 +1133,7 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
}
|
||||
snprintf(logfile, sizeof(logfile), "%s/%s", log->logdir, log->logname);
|
||||
log->filesize = 0;
|
||||
log->fd = open(logfile, O_APPEND | O_CREAT | O_WRONLY | O_CLOEXEC, 0640);
|
||||
log->fd = open(logfile, O_APPEND | O_CREAT | O_WRONLY | O_CLOEXEC, log->file_perm);
|
||||
if (log->fd < 0) {
|
||||
if (print_errmsg == 0) {
|
||||
return -1;
|
||||
@@ -1131,7 +1192,6 @@ static int _tlog_any_has_data_locked(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int _tlog_any_has_data(void)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -1162,7 +1222,7 @@ static int _tlog_wait_pids(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
last_log = next;
|
||||
last_log = next;
|
||||
next->last_waitpid = now;
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
_tlog_wait_pid(next, 0);
|
||||
@@ -1263,7 +1323,6 @@ static void _tlog_wakeup_waiters(struct tlog_log *log)
|
||||
pthread_mutex_unlock(&log->lock);
|
||||
}
|
||||
|
||||
|
||||
static void _tlog_write_one_segment_log(struct tlog_log *log, char *buff, int bufflen)
|
||||
{
|
||||
struct tlog_segment_head *segment_head = NULL;
|
||||
@@ -1345,10 +1404,10 @@ static void *_tlog_work(void *arg)
|
||||
int log_dropped = 0;
|
||||
struct tlog_log *log = NULL;
|
||||
struct tlog_log *loop_log = NULL;
|
||||
void* unused __attribute__ ((unused));
|
||||
void *unused __attribute__((unused));
|
||||
|
||||
unused = arg;
|
||||
|
||||
|
||||
while (1) {
|
||||
log_len = 0;
|
||||
log_extlen = 0;
|
||||
@@ -1430,7 +1489,7 @@ static void *_tlog_work(void *arg)
|
||||
|
||||
void tlog_set_early_printf(int enable)
|
||||
{
|
||||
tlog_disable_early_print = (enable == 0) ? 1 : 0;
|
||||
tlog_disable_early_print = (enable == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
const char *tlog_get_level_string(tlog_level level)
|
||||
@@ -1518,10 +1577,14 @@ tlog_level tlog_getlevel(void)
|
||||
return tlog_set_level;
|
||||
}
|
||||
|
||||
void tlog_set_logfile(const char *logfile)
|
||||
{
|
||||
tlog_rename_logfile(tlog.root, logfile);
|
||||
}
|
||||
|
||||
tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag)
|
||||
{
|
||||
struct tlog_log *log = NULL;
|
||||
char log_file[PATH_MAX];
|
||||
|
||||
if (tlog.run == 0) {
|
||||
fprintf(stderr, "tlog is not initialized.");
|
||||
@@ -1546,22 +1609,19 @@ tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int bu
|
||||
log->filesize = 0;
|
||||
log->zip_pid = -1;
|
||||
log->is_exit = 0;
|
||||
log->fail = 0;
|
||||
log->waiters = 0;
|
||||
log->block = ((flag & TLOG_NONBLOCK) == 0) ? 1 : 0;
|
||||
log->nocompress = ((flag & TLOG_NOCOMPRESS) == 0) ? 0 : 1;
|
||||
log->logscreen = ((flag & TLOG_SCREEN) == 0) ? 0 : 1;
|
||||
log->multi_log = ((flag & TLOG_MULTI_WRITE) == 0) ? 0 : 1;
|
||||
log->segment_log = ((flag & TLOG_SEGMENT) == 0) ? 0 : 1;
|
||||
log->max_line_size = TLOG_MAX_LINE_LEN;
|
||||
log->output_func = _tlog_write;
|
||||
log->file_perm = S_IRUSR | S_IWUSR | S_IRGRP;
|
||||
log->archive_perm = S_IRUSR | S_IRGRP;
|
||||
|
||||
strncpy(log_file, logfile, sizeof(log_file) - 1);
|
||||
log_file[sizeof(log_file) - 1] = '\0';
|
||||
strncpy(log->logdir, dirname(log_file), sizeof(log->logdir));
|
||||
log->logdir[sizeof(log->logdir) - 1] = '\0';
|
||||
strncpy(log_file, logfile, PATH_MAX);
|
||||
log_file[sizeof(log_file) - 1] = '\0';
|
||||
strncpy(log->logname, basename(log_file), sizeof(log->logname));
|
||||
log->logname[sizeof(log->logname) - 1] = '\0';
|
||||
tlog_rename_logfile(log, logfile);
|
||||
if (log->nocompress) {
|
||||
strncpy(log->suffix, TLOG_SUFFIX_LOG, sizeof(log->suffix));
|
||||
} else {
|
||||
@@ -1605,6 +1665,58 @@ void tlog_close(tlog_log *log)
|
||||
log->is_exit = 1;
|
||||
}
|
||||
|
||||
void tlog_rename_logfile(struct tlog_log *log, const char *logfile)
|
||||
{
|
||||
pthread_mutex_lock(&tlog.lock);
|
||||
strncpy(log->pending_logfile, logfile, sizeof(log->pending_logfile) - 1);
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
log->rename_pending = 1;
|
||||
}
|
||||
|
||||
static void tlog_fork_prepare(void)
|
||||
{
|
||||
if (tlog.root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&tlog.lock);
|
||||
}
|
||||
|
||||
static void tlog_fork_parent(void)
|
||||
{
|
||||
if (tlog.root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
}
|
||||
|
||||
static void tlog_fork_child(void)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
tlog_log *next;
|
||||
if (tlog.root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
int ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "create tlog work thread failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
goto out;
|
||||
errout:
|
||||
next = tlog.log;
|
||||
while (next) {
|
||||
next->fail = 1;
|
||||
next = next->next;
|
||||
}
|
||||
out:
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
}
|
||||
|
||||
int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
@@ -1616,7 +1728,7 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffsize > 0 && buffsize < TLOG_MAX_LINE_LEN * 2) {
|
||||
if (buffsize > 0 && buffsize < TLOG_MAX_LINE_SIZE_SET * 2) {
|
||||
fprintf(stderr, "buffer size is invalid.\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -1645,6 +1757,9 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
|
||||
}
|
||||
|
||||
tlog.root = log;
|
||||
if (flag & TLOG_SUPPORT_FORK) {
|
||||
pthread_atfork(&tlog_fork_prepare, &tlog_fork_parent, &tlog_fork_child);
|
||||
}
|
||||
return 0;
|
||||
errout:
|
||||
if (tlog.tid > 0) {
|
||||
|
||||
116
src/tlog.h
116
src/tlog.h
@@ -1,19 +1,20 @@
|
||||
/*
|
||||
* tinylog
|
||||
* Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>
|
||||
* Copyright (C) 2018-2021 Ruilin Peng (Nick) <pymumu@gmail.com>
|
||||
* https://github.com/pymumu/tinylog
|
||||
*/
|
||||
|
||||
#ifndef TLOG_H
|
||||
#define TLOG_H
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
extern "C" {
|
||||
#endif /*__cplusplus */
|
||||
|
||||
@@ -60,6 +61,9 @@ struct tlog_time {
|
||||
/* enable log to screen */
|
||||
#define TLOG_SCREEN (1 << 4)
|
||||
|
||||
/* enable suppport fork process */
|
||||
#define TLOG_SUPPORT_FORK (1 << 5)
|
||||
|
||||
struct tlog_loginfo {
|
||||
tlog_level level;
|
||||
const char *file;
|
||||
@@ -79,7 +83,7 @@ format: Log formats
|
||||
#define tlog(level, format, ...) tlog_ext(level, BASE_FILE_NAME, __LINE__, __func__, NULL, format, ##__VA_ARGS__)
|
||||
|
||||
extern int tlog_ext(tlog_level level, const char *file, int line, const char *func, void *userptr, const char *format, ...)
|
||||
__attribute__((format(printf, 6, 7))) __attribute__((nonnull (6)));
|
||||
__attribute__((format(printf, 6, 7))) __attribute__((nonnull(6)));
|
||||
extern int tlog_vext(tlog_level level, const char *file, int line, const char *func, void *userptr, const char *format, va_list ap);
|
||||
|
||||
/* write buff to log file */
|
||||
@@ -91,6 +95,9 @@ extern int tlog_setlevel(tlog_level level);
|
||||
/* get log level */
|
||||
extern tlog_level tlog_getlevel(void);
|
||||
|
||||
/* set log file */
|
||||
extern void tlog_set_logfile(const char *logfile);
|
||||
|
||||
/* enalbe log to screen */
|
||||
extern void tlog_setlogscreen(int enable);
|
||||
|
||||
@@ -132,6 +139,10 @@ extern int tlog_reg_log_output_func(tlog_log_output_func output, void *private_d
|
||||
|
||||
struct tlog_log;
|
||||
typedef struct tlog_log tlog_log;
|
||||
|
||||
/* get root log handler */
|
||||
extern tlog_log *tlog_get_root(void);
|
||||
|
||||
/*
|
||||
Function: open a new log stream, handler should close by tlog_close
|
||||
logfile: log file.
|
||||
@@ -149,12 +160,15 @@ extern int tlog_write(struct tlog_log *log, const char *buff, int bufflen);
|
||||
/* close log stream */
|
||||
extern void tlog_close(tlog_log *log);
|
||||
|
||||
/* change log file */
|
||||
extern void tlog_rename_logfile(struct tlog_log *log, const char *logfile);
|
||||
|
||||
/*
|
||||
Function: Print log to log stream
|
||||
log: log stream
|
||||
format: Log formats
|
||||
*/
|
||||
extern int tlog_printf(tlog_log *log, const char *format, ...) __attribute__((format(printf, 2, 3))) __attribute__((nonnull (1, 2)));
|
||||
extern int tlog_printf(tlog_log *log, const char *format, ...) __attribute__((format(printf, 2, 3))) __attribute__((nonnull(1, 2)));
|
||||
|
||||
/*
|
||||
Function: Print log to log stream with ap
|
||||
@@ -180,49 +194,78 @@ extern void *tlog_get_private(tlog_log *log);
|
||||
/* get local time */
|
||||
extern int tlog_localtime(struct tlog_time *tm);
|
||||
|
||||
/* set max line size */
|
||||
extern void tlog_set_maxline_size(struct tlog_log *log, int size);
|
||||
|
||||
/*
|
||||
Function: set log file and archive permission
|
||||
log: log stream
|
||||
file: log file permission, default is 640
|
||||
archive: archive file permission, default is 440
|
||||
*/
|
||||
|
||||
extern void tlog_set_permission(struct tlog_log *log, mode_t file, mode_t archive);
|
||||
|
||||
#ifdef __cplusplus
|
||||
class Tlog {
|
||||
using Stream = std::ostringstream;
|
||||
using Buffer = std::unique_ptr<Stream, std::function<void(Stream*)>>;
|
||||
public:
|
||||
Tlog(){}
|
||||
~Tlog(){}
|
||||
|
||||
static Tlog &Instance() {
|
||||
static Tlog logger;
|
||||
return logger;
|
||||
Tlog(tlog_level level, const char *file, int line, const char *func, void *userptr)
|
||||
{
|
||||
level_ = level;
|
||||
file_ = file;
|
||||
line_ = line;
|
||||
func_ = func;
|
||||
userptr_ = userptr;
|
||||
}
|
||||
|
||||
Buffer LogStream(tlog_level level, const char *file, int line, const char *func, void *userptr) {
|
||||
return Buffer(new Stream, [=](Stream *st) {
|
||||
tlog_ext(level, file, line, func, userptr, "%s", st->str().c_str());
|
||||
delete st;
|
||||
});
|
||||
~Tlog()
|
||||
{
|
||||
tlog_ext(level_, file_, line_, func_, userptr_, "%s", msg_.str().c_str());
|
||||
}
|
||||
|
||||
std::ostream &Stream()
|
||||
{
|
||||
return msg_;
|
||||
}
|
||||
|
||||
private:
|
||||
tlog_level level_;
|
||||
const char *file_;
|
||||
int line_;
|
||||
const char *func_;
|
||||
void *userptr_;
|
||||
std::ostringstream msg_;
|
||||
};
|
||||
|
||||
class TlogOut {
|
||||
using Stream = std::ostringstream;
|
||||
using Buffer = std::unique_ptr<Stream, std::function<void(Stream*)>>;
|
||||
public:
|
||||
TlogOut(){}
|
||||
~TlogOut(){}
|
||||
|
||||
static TlogOut &Instance() {
|
||||
static TlogOut logger;
|
||||
return logger;
|
||||
TlogOut(tlog_log *log)
|
||||
{
|
||||
log_ = log;
|
||||
}
|
||||
|
||||
Buffer Out(tlog_log *log) {
|
||||
return Buffer(new Stream, [=](Stream *st) {
|
||||
tlog_printf(log, "%s", st->str().c_str());
|
||||
delete st;
|
||||
});
|
||||
~TlogOut()
|
||||
{
|
||||
if (log_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
tlog_printf(log_, "%s", msg_.str().c_str());
|
||||
}
|
||||
|
||||
std::ostream &Stream()
|
||||
{
|
||||
return msg_;
|
||||
}
|
||||
|
||||
private:
|
||||
tlog_log *log_;
|
||||
std::ostringstream msg_;
|
||||
};
|
||||
|
||||
#define Tlog_logger (Tlog::Instance())
|
||||
#define Tlog_stream(level) if (tlog_getlevel() <= level) *Tlog_logger.LogStream(level, BASE_FILE_NAME, __LINE__, __func__, NULL)
|
||||
#define Tlog_stream(level) \
|
||||
if (tlog_getlevel() <= level) \
|
||||
Tlog(level, BASE_FILE_NAME, __LINE__, __func__, NULL).Stream()
|
||||
#define tlog_debug Tlog_stream(TLOG_DEBUG)
|
||||
#define tlog_info Tlog_stream(TLOG_INFO)
|
||||
#define tlog_notice Tlog_stream(TLOG_NOTICE)
|
||||
@@ -230,8 +273,7 @@ public:
|
||||
#define tlog_error Tlog_stream(TLOG_ERROR)
|
||||
#define tlog_fatal Tlog_stream(TLOG_FATAL)
|
||||
|
||||
#define Tlog_out_logger (TlogOut::Instance())
|
||||
#define tlog_out(stream) (*Tlog_out_logger.Out(stream))
|
||||
#define tlog_out(stream) TlogOut(stream).Stream()
|
||||
|
||||
} /*__cplusplus */
|
||||
#else
|
||||
@@ -241,5 +283,5 @@ public:
|
||||
#define tlog_warn(...) tlog(TLOG_WARN, ##__VA_ARGS__)
|
||||
#define tlog_error(...) tlog(TLOG_ERROR, ##__VA_ARGS__)
|
||||
#define tlog_fatal(...) tlog(TLOG_FATAL, ##__VA_ARGS__)
|
||||
#endif
|
||||
#endif
|
||||
#endif // !TLOG_H
|
||||
|
||||
52
src/util.c
52
src/util.c
@@ -21,7 +21,9 @@
|
||||
#endif
|
||||
#include "util.h"
|
||||
#include "dns_conf.h"
|
||||
#include "tlog.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
@@ -39,6 +41,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#define TMP_BUFF_LEN_32 32
|
||||
|
||||
@@ -936,7 +939,7 @@ void get_compiled_time(struct tm *tm)
|
||||
int hour, min, sec;
|
||||
static const char *month_names = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
|
||||
sscanf(__DATE__, "%5s %d %d", s_month, &day, &year);
|
||||
sscanf(__DATE__, "%4s %d %d", s_month, &day, &year);
|
||||
month = (strstr(month_names, s_month) - month_names) / 3;
|
||||
sscanf(__TIME__, "%d:%d:%d", &hour, &min, &sec);
|
||||
tm->tm_year = year - 1900;
|
||||
@@ -1009,3 +1012,50 @@ uint64_t get_free_space(const char *path)
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
struct backtrace_state {
|
||||
void **current;
|
||||
void **end;
|
||||
};
|
||||
|
||||
static _Unwind_Reason_Code unwind_callback(struct _Unwind_Context *context, void *arg)
|
||||
{
|
||||
struct backtrace_state *state = (struct backtrace_state *)(arg);
|
||||
uintptr_t pc = _Unwind_GetIP(context);
|
||||
if (pc) {
|
||||
if (state->current == state->end) {
|
||||
return _URC_END_OF_STACK;
|
||||
} else {
|
||||
*state->current++ = (void *)(pc);
|
||||
}
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
void print_stack(void)
|
||||
{
|
||||
const size_t max_buffer = 30;
|
||||
void *buffer[max_buffer];
|
||||
|
||||
struct backtrace_state state = {buffer, buffer + max_buffer};
|
||||
_Unwind_Backtrace(unwind_callback, &state);
|
||||
int frame_num = state.current - buffer;
|
||||
if (frame_num == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
tlog(TLOG_FATAL, "Stack:");
|
||||
for (int idx = 0; idx < frame_num; ++idx) {
|
||||
const void *addr = buffer[idx];
|
||||
const char *symbol = "";
|
||||
|
||||
Dl_info info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (dladdr(addr, &info) && info.dli_sname) {
|
||||
symbol = info.dli_sname;
|
||||
}
|
||||
|
||||
void *offset = (void *)((char *)(addr) - (char *)(info.dli_fbase));
|
||||
tlog(TLOG_FATAL, "#%.2d: %p %s from %s+%p", idx + 1, addr, symbol, info.dli_fname, offset);
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,8 @@ int set_sock_lingertime(int fd, int time);
|
||||
|
||||
uint64_t get_free_space(const char *path);
|
||||
|
||||
void print_stack(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus */
|
||||
|
||||
19
systemd/smartdns.service
Normal file
19
systemd/smartdns.service
Normal file
@@ -0,0 +1,19 @@
|
||||
[Unit]
|
||||
Description=SmartDNS Server
|
||||
After=network.target
|
||||
StartLimitBurst=0
|
||||
StartLimitIntervalSec=60
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
PIDFile=/var/run/smartdns.pid
|
||||
EnvironmentFile=/etc/default/smartdns
|
||||
ExecStart=/usr/sbin/smartdns -p /var/run/smartdns.pid $SMART_DNS_OPTS
|
||||
KillMode=process
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
TimeoutStopSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Alias=smartdns.service
|
||||
@@ -1,9 +1,8 @@
|
||||
[Unit]
|
||||
Description=smartdns server
|
||||
Description=SmartDNS Server
|
||||
After=network.target
|
||||
StartLimitBurst=0
|
||||
StartLimitIntervalSec=60
|
||||
TimeoutStopSec=5
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
@@ -13,6 +12,7 @@ ExecStart=@SBINDIR@/smartdns -p @RUNSTATEDIR@/smartdns.pid $SMART_DNS_OPTS
|
||||
KillMode=process
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
TimeoutStopSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
Reference in New Issue
Block a user