Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
756029f5e9 | ||
|
|
6338f1257c | ||
|
|
b77cea63e9 | ||
|
|
f1ce462989 | ||
|
|
e5eb562dee | ||
|
|
c53a87b8d9 | ||
|
|
f2fc970561 | ||
|
|
328f44e800 | ||
|
|
11cf7b614c | ||
|
|
51e1e6565f | ||
|
|
3ba8c418f7 | ||
|
|
3e3859cfb1 | ||
|
|
ac0ab0c916 | ||
|
|
98be18f926 | ||
|
|
ed63c617bc | ||
|
|
81ce05e6af | ||
|
|
4e5248ebf3 | ||
|
|
ccd0f203fb | ||
|
|
29d61d9373 | ||
|
|
4dcfd2c729 | ||
|
|
42b3e98b2a | ||
|
|
81ecfa5dab | ||
|
|
baa1397fb0 | ||
|
|
86902d2e34 | ||
|
|
6f30fe6d05 | ||
|
|
0b45da29c7 | ||
|
|
2b81fffb7e | ||
|
|
7af6f475da | ||
|
|
c3b6560b46 | ||
|
|
a3d3364a32 | ||
|
|
b8a36ccb8c | ||
|
|
aee19be262 | ||
|
|
98429e88f1 | ||
|
|
80cb27c795 | ||
|
|
cb73eadf01 | ||
|
|
69ba3f8789 | ||
|
|
c380bbe0e3 | ||
|
|
da74e877c5 | ||
|
|
a300873b3f | ||
|
|
a9829f6155 | ||
|
|
1923271630 | ||
|
|
c23ec7ea8f | ||
|
|
aad751c1f5 | ||
|
|
138df2fd5d | ||
|
|
297ea29639 | ||
|
|
bc0d6b89ca | ||
|
|
2148efd262 | ||
|
|
ce46ac58a7 | ||
|
|
c1f9941427 | ||
|
|
770ce9e8bc | ||
|
|
60d0fc856e | ||
|
|
95472129ee | ||
|
|
f79ceeac43 | ||
|
|
54801e1ed6 | ||
|
|
304e94bc6f | ||
|
|
3985ea8269 | ||
|
|
c2c418ed89 | ||
|
|
b78c9eb6fe | ||
|
|
0aec326d55 | ||
|
|
29e4d4b48b | ||
|
|
a6fe329105 | ||
|
|
c824c0abc5 | ||
|
|
3ad7cd7f45 |
@@ -7,3 +7,4 @@ UseTab: ForContinuationAndIndentation
|
||||
MaxEmptyLinesToKeep: 1
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
BreakBeforeBraces: Linux
|
||||
ColumnLimit: 120
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
.vscode
|
||||
.o
|
||||
*.o
|
||||
.DS_Store
|
||||
.swp.
|
||||
*.swp.
|
||||
|
||||
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
||||
FROM debian:buster-slim
|
||||
|
||||
RUN apt update && \
|
||||
apt install -y git make gcc libssl-dev && \
|
||||
git clone https://github.com/pymumu/smartdns.git --depth 1 && \
|
||||
cd smartdns && \
|
||||
sh ./package/build-pkg.sh --platform debian --arch `dpkg --print-architecture` && \
|
||||
dpkg -i package/*.deb && \
|
||||
cd / && \
|
||||
rm -rf smartdns/ && \
|
||||
apt autoremove -y git make gcc libssl-dev && \
|
||||
apt clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
EXPOSE 53/udp
|
||||
VOLUME "/etc/smartdns/"
|
||||
|
||||
CMD ["/usr/sbin/smartdns", "-f"]
|
||||
47
Makefile
Normal file
47
Makefile
Normal file
@@ -0,0 +1,47 @@
|
||||
# Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
#
|
||||
# smartdns is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# smartdns is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
PKG_CONFIG := pkg-config
|
||||
DESTDIR :=
|
||||
PREFIX := /usr
|
||||
SBINDIR := $(PREFIX)/sbin
|
||||
SYSCONFDIR := /etc
|
||||
RUNSTATEDIR := /var/run
|
||||
SYSTEMDSYSTEMUNITDIR := $(shell ${PKG_CONFIG} --variable=systemdsystemunitdir systemd)
|
||||
SMARTDNS_SYSTEMD = systemd/smartdns.service
|
||||
|
||||
.PHONY: all clean install SMARTDNS_BIN
|
||||
all: SMARTDNS_BIN
|
||||
|
||||
SMARTDNS_BIN: $(SMARTDNS_SYSTEMD)
|
||||
$(MAKE) $(MFLAGS) -C src all
|
||||
|
||||
$(SMARTDNS_SYSTEMD): systemd/smartdns.service.in
|
||||
cp $< $@
|
||||
sed -i 's|@SBINDIR@|$(SBINDIR)|' $@
|
||||
sed -i 's|@SYSCONFDIR@|$(SYSCONFDIR)|' $@
|
||||
sed -i 's|@RUNSTATEDIR@|$(RUNSTATEDIR)|' $@
|
||||
|
||||
clean:
|
||||
$(MAKE) $(MFLAGS) -C src clean
|
||||
$(RM) $(SMARTDNS_SYSTEMD)
|
||||
|
||||
install: SMARTDNS_BIN
|
||||
install -v -m 0640 -D -t $(DESTDIR)$(SYSCONFDIR)/default etc/default/smartdns
|
||||
install -v -m 0755 -D -t $(DESTDIR)$(SYSCONFDIR)/init.d etc/init.d/smartdns
|
||||
install -v -m 0640 -D -t $(DESTDIR)$(SYSCONFDIR)/smartdns etc/smartdns/smartdns.conf
|
||||
install -v -m 0755 -D -t $(DESTDIR)$(SBINDIR) src/smartdns
|
||||
install -v -m 0644 -D -t $(DESTDIR)$(SYSTEMDSYSTEMUNITDIR) systemd/smartdns.service
|
||||
|
||||
23
ReadMe.md
23
ReadMe.md
@@ -2,7 +2,7 @@
|
||||
|
||||
**[English](ReadMe_en.md)**
|
||||
|
||||

|
||||

|
||||
SmartDNS是一个运行在本地的DNS服务器,SmartDNS接受本地客户端的DNS查询请求,从多个上游DNS服务器获取DNS查询结果,并将访问速度最快的结果返回给客户端,提高网络访问速度。
|
||||
同时支持指定特定域名IP地址,并高性匹配,达到过滤广告的效果。
|
||||
与dnsmasq的all-servers不同,smartdns返回的是访问速度最快的解析结果。 (详细差异请看[FAQ](#faq))
|
||||
@@ -17,7 +17,7 @@ SmartDNS是一个运行在本地的DNS服务器,SmartDNS接受本地客户端
|
||||
1. [使用](#使用)
|
||||
1. [下载配套安装包](#下载配套安装包)
|
||||
1. [标准Linux系统安装](#标准linux系统安装树莓派x86_64系统)
|
||||
1. [openwrt/LEDE](#openwrtlede)
|
||||
1. [openwrt/LEDE](#openwrt)
|
||||
1. [华硕路由器原生固件/梅林固件](#华硕路由器原生固件梅林固件)
|
||||
1. [optware/entware](#optwareentware)
|
||||
1. [Windows 10 WSL安装/WSL ubuntu](#windows-10-wsl安装wsl-ubuntu)
|
||||
@@ -117,7 +117,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,6 +504,8 @@ 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|是否持久化缓存|自动<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
|
||||
|rr-ttl-min|允许的最小TTL值|远程查询结果|大于0的数字|rr-ttl-min 60
|
||||
@@ -519,14 +521,14 @@ https://github.com/pymumu/smartdns/releases
|
||||
|conf-file|附加配置文件|无|文件路径|conf-file /etc/smartdns/smartdns.more.conf
|
||||
|server|上游UDP DNS|无|可重复<br>`[ip][:port]`:服务器IP,端口可选。<br>`[-blacklist-ip]`:blacklist-ip参数指定使用blacklist-ip配置IP过滤结果。<br>`[-whitelist-ip]`:whitelist-ip参数指定仅接受whitelist-ip中配置IP范围。<br>`[-group [group] ...]`:DNS服务器所属组,比如office, foreign,和nameserver配套使用。<br>`[-exclude-default-group]`:将DNS服务器从默认组中排除| server 8.8.8.8:53 -blacklist-ip -group g1
|
||||
|server-tcp|上游TCP DNS|无|可重复<br>`[ip][:port]`:服务器IP,端口可选。<br>`[-blacklist-ip]`:blacklist-ip参数指定使用blacklist-ip配置IP过滤结果。<br>`[-whitelist-ip]`:whitelist-ip参数指定仅接受whitelist-ip中配置IP范围。<br>`[-group [group] ...]`:DNS服务器所属组,比如office, foreign,和nameserver配套使用。<br>`[-exclude-default-group]`:将DNS服务器从默认组中排除| server-tcp 8.8.8.8:53
|
||||
|server-tls|上游TLS DNS|无|可重复<br>`[ip][:port]`:服务器IP,端口可选。<br>`[-spki-pin [sha256-pin]]`: TLS合法性校验SPKI值,base64编码的sha256 SPKI pin值<br>`[-host-name]`:TLS SNI名称。<br>`[-tls-host-verify]`: TLS证书主机名校验。<br>`[-blacklist-ip]`:blacklist-ip参数指定使用blacklist-ip配置IP过滤结果。<br>`[-whitelist-ip]`:whitelist-ip参数指定仅接受whitelist-ip中配置IP范围。<br>`[-group [group] ...]`:DNS服务器所属组,比如office, foreign,和nameserver配套使用。<br>`[-exclude-default-group]`:将DNS服务器从默认组中排除| server-tls 8.8.8.8:853
|
||||
|server-https|上游HTTPS DNS|无|可重复<br>`https://[host][:port]/path`:服务器IP,端口可选。<br>`[-spki-pin [sha256-pin]]`: TLS合法性校验SPKI值,base64编码的sha256 SPKI pin值<br>`[-host-name]`:TLS SNI名称<br>`[-http-host]`:http协议头主机名。<br>`[-tls-host-verify]`: TLS证书主机名校验。<br>`[-blacklist-ip]`:blacklist-ip参数指定使用blacklist-ip配置IP过滤结果。<br>`[-whitelist-ip]`:whitelist-ip参数指定仅接受whitelist-ip中配置IP范围。<br>`[-group [group] ...]`:DNS服务器所属组,比如office, foreign,和nameserver配套使用。<br>`[-exclude-default-group]`:将DNS服务器从默认组中排除| server-https https://cloudflare-dns.com/dns-query
|
||||
|server-tls|上游TLS DNS|无|可重复<br>`[ip][:port]`:服务器IP,端口可选。<br>`[-spki-pin [sha256-pin]]`: TLS合法性校验SPKI值,base64编码的sha256 SPKI pin值<br>`[-host-name]`:TLS SNI名称。<br>`[-tls-host-verify]`: TLS证书主机名校验。<br> `-no-check-certificate:`:跳过证书校验。<br>`[-blacklist-ip]`:blacklist-ip参数指定使用blacklist-ip配置IP过滤结果。<br>`[-whitelist-ip]`:whitelist-ip参数指定仅接受whitelist-ip中配置IP范围。<br>`[-group [group] ...]`:DNS服务器所属组,比如office, foreign,和nameserver配套使用。<br>`[-exclude-default-group]`:将DNS服务器从默认组中排除| server-tls 8.8.8.8:853
|
||||
|server-https|上游HTTPS DNS|无|可重复<br>`https://[host][:port]/path`:服务器IP,端口可选。<br>`[-spki-pin [sha256-pin]]`: TLS合法性校验SPKI值,base64编码的sha256 SPKI pin值<br>`[-host-name]`:TLS SNI名称<br>`[-http-host]`:http协议头主机名。<br>`[-tls-host-verify]`: TLS证书主机名校验。<br> `-no-check-certificate:`:跳过证书校验。<br>`[-blacklist-ip]`:blacklist-ip参数指定使用blacklist-ip配置IP过滤结果。<br>`[-whitelist-ip]`:whitelist-ip参数指定仅接受whitelist-ip中配置IP范围。<br>`[-group [group] ...]`:DNS服务器所属组,比如office, foreign,和nameserver配套使用。<br>`[-exclude-default-group]`:将DNS服务器从默认组中排除| server-https https://cloudflare-dns.com/dns-query
|
||||
|speed-check-mode|测速模式选择|无|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:80
|
||||
|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
|
||||
@@ -535,8 +537,11 @@ https://github.com/pymumu/smartdns/releases
|
||||
|prefetch-domain|域名预先获取功能|no|[yes\|no]|prefetch-domain yes
|
||||
|serve-expired|过期缓存服务功能|no|[yes\|no],开启此功能后,如果有请求时尝试回应TTL为0的过期记录,并并发查询记录,以避免查询等待|serve-expired yes
|
||||
|serve-expired-ttl|过期缓存服务最长超时时间|0|秒,0:表示停用超时,> 0表示指定的超时的秒数|serve-expired-ttl 0
|
||||
|serve-expired-reply-ttl|回应的过期缓存TTL|5|秒,0:表示停用超时,> 0表示指定的超时的秒数|serve-expired-reply-ttl 30
|
||||
|dualstack-ip-selection|双栈IP优选|no|[yes\|no]|dualstack-ip-selection yes
|
||||
|dualstack-ip-selection-threshold|双栈IP优选阈值|30ms|毫秒|dualstack-ip-selection-threshold [0-1000]
|
||||
|ca-file|证书文件|/etc/ssl/certs/ca-certificates.crt|路径|ca-file /etc/ssl/certs/ca-certificates.crt
|
||||
|ca-path|证书文件路径|/etc/ssl/certs|路径|ca-path /etc/ssl/certs
|
||||
|
||||
## FAQ
|
||||
|
||||
@@ -659,11 +664,11 @@ smartdns包含了编译软件包的脚本,支持编译luci,debian,openwrt
|
||||
|
||||
### Alipay 支付宝
|
||||
|
||||

|
||||

|
||||
|
||||
### Wechat 微信
|
||||
|
||||

|
||||

|
||||
|
||||
## 开源声明
|
||||
|
||||
|
||||
13
ReadMe_en.md
13
ReadMe_en.md
@@ -498,6 +498,8 @@ 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|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
|
||||
|rr-ttl-min|Domain name Minimum TTL|Remote query result|number greater than 0|rr-ttl-min 60
|
||||
@@ -513,14 +515,14 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|conf-file|additional conf file|None|File path|conf-file /etc/smartdns/smartdns.more.conf
|
||||
|server|Upstream UDP DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server 8.8.8.8:53 -blacklist-ip
|
||||
|server-tcp|Upstream TCP DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-tcp 8.8.8.8:53
|
||||
|server-tls|Upstream TLS DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name. <br>`[-tls-host-verify]`: TLS cert hostname to verify.<br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-tls 8.8.8.8:853
|
||||
|server-https|Upstream HTTPS DNS server|None|Repeatable <br>`https://[host][:port]/path`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name<br>`[-http-host]`:http header host. <br>`[-tls-host-verify]`: TLS cert hostname to verify.<br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-https https://cloudflare-dns.com/dns-query
|
||||
|server-tls|Upstream TLS DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name. <br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-tls 8.8.8.8:853
|
||||
|server-https|Upstream HTTPS DNS server|None|Repeatable <br>`https://[host][:port]/path`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name<br>`[-http-host]`:http header host. <br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-https https://cloudflare-dns.com/dns-query
|
||||
|speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp: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
|
||||
@@ -529,8 +531,11 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|prefetch-domain|domain prefetch feature|no|[yes\|no]|prefetch-domain yes
|
||||
|serve-expired|Cache serve expired feature|no|[yes\|no], Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish.|serve-expired yes
|
||||
|serve-expired-ttl|Cache serve expired limite TTL|0|second,0:disable,> 0 seconds after expiration|serve-expired-ttl 0
|
||||
|serve-expired-reply-ttl|TTL value to use when replying with expired data|5|second,0:disable,> 0 seconds after expiration|serve-expired-reply-ttl 30
|
||||
|dualstack-ip-selection|Dualstack ip selection|no|[yes\|no]|dualstack-ip-selection yes
|
||||
|dualstack-ip-selection-threshold|Dualstack ip select threadhold|30ms|millisecond|dualstack-ip-selection-threshold [0-1000]
|
||||
|ca-file|certificate file|/etc/ssl/certs/ca-certificates.crt|path|ca-file /etc/ssl/certs/ca-certificates.crt
|
||||
|ca-path|certificates path|/etc/ssl/certs|path|ca-path /etc/ssl/certs
|
||||
|
||||
## FAQ
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 52 KiB |
@@ -38,7 +38,13 @@ bind [::]:53
|
||||
# dns cache size
|
||||
# cache-size [number]
|
||||
# 0: for no cache
|
||||
cache-size 512
|
||||
cache-size 4096
|
||||
|
||||
# enable persist cache when restart
|
||||
# cache-persist yes
|
||||
|
||||
# cache persist file
|
||||
# cache-file /tmp/smartdns.cache
|
||||
|
||||
# prefetch domain
|
||||
# prefetch-domain [yes|no]
|
||||
@@ -52,6 +58,10 @@ cache-size 512
|
||||
# serve-expired-ttl [num]
|
||||
# serve-expired-ttl 0
|
||||
|
||||
# reply TTL value to use when replying with expired data
|
||||
# serve-expired-reply-ttl [num]
|
||||
# serve-expired-reply-ttl 30
|
||||
|
||||
# List of hosts that supply bogus NX domain results
|
||||
# bogus-nxdomain [ip/subnet]
|
||||
|
||||
@@ -112,6 +122,14 @@ log-level info
|
||||
# audit-size 128k
|
||||
# audit-num 2
|
||||
|
||||
# certificate file
|
||||
# ca-file [file]
|
||||
# ca-file /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
# certificate path
|
||||
# ca-path [path]
|
||||
# ca-path /etc/ss/certs
|
||||
|
||||
# remote udp dns server list
|
||||
# server [IP]:[PORT] [-blacklist-ip] [-whitelist-ip] [-check-edns] [-group [group] ...] [-exclude-default-group]
|
||||
# default port is 53
|
||||
@@ -130,8 +148,9 @@ log-level info
|
||||
# remote tls dns server list
|
||||
# server-tls [IP]:[PORT] [-blacklist-ip] [-whitelist-ip] [-spki-pin [sha256-pin]] [-group [group] ...] [-exclude-default-group]
|
||||
# -spki-pin: TLS spki pin to verify.
|
||||
# -tls-host-check: cert hostname to verify.
|
||||
# -hostname: TLS sni hostname.
|
||||
# -tls-host-verify: cert hostname to verify.
|
||||
# -host-name: TLS sni hostname.
|
||||
# -no-check-certificate: no check certificate.
|
||||
# Get SPKI with this command:
|
||||
# echo | openssl s_client -connect '[ip]:853' | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
|
||||
# default port is 853
|
||||
@@ -141,9 +160,10 @@ log-level info
|
||||
# remote https dns server list
|
||||
# server-https https://[host]:[port]/path [-blacklist-ip] [-whitelist-ip] [-spki-pin [sha256-pin]] [-group [group] ...] [-exclude-default-group]
|
||||
# -spki-pin: TLS spki pin to verify.
|
||||
# -tls-host-check: cert hostname to verify.
|
||||
# -hostname: TLS sni hostname.
|
||||
# -tls-host-verify: cert hostname to verify.
|
||||
# -host-name: TLS sni hostname.
|
||||
# -http-host: http host.
|
||||
# -no-check-certificate: no check certificate.
|
||||
# default port is 443
|
||||
# server-https https://cloudflare-dns.com/dns-query
|
||||
|
||||
@@ -169,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
|
||||
|
||||
@@ -43,8 +43,8 @@ showhelp()
|
||||
build_smartdns()
|
||||
{
|
||||
if [ "$PLATFORM" != "luci" ]; then
|
||||
make -C $CODE_DIR/src clean
|
||||
make -C $CODE_DIR/src all -j8 VER=$VER $MAKE_ARGS
|
||||
make -C $CODE_DIR clean $MAKE_ARGS
|
||||
make -C $CODE_DIR all -j8 VER=$VER $MAKE_ARGS
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "make smartdns failed"
|
||||
exit 1
|
||||
|
||||
@@ -77,14 +77,18 @@ install_files()
|
||||
return 1
|
||||
fi
|
||||
|
||||
install -v -m 0755 -t $PREFIX/usr/sbin src/smartdns
|
||||
install -v -m 0755 -t $PREFIX/usr/sbin usr/sbin/smartdns
|
||||
if [ $? -ne 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
install -v -m 0640 -t $PREFIX$SMARTDNS_CONF_DIR etc/smartdns/smartdns.conf
|
||||
if [ $? -ne 0 ]; then
|
||||
return 1
|
||||
if [ -e "$PREFIX$SMARTDNS_CONF_DIR/smartdns.conf" ]; then
|
||||
cp etc/smartdns/smartdns.conf $PREFIX$SMARTDNS_CONF_DIR/smartdns.conf.pkg
|
||||
else
|
||||
install -v -m 0640 -t $PREFIX$SMARTDNS_CONF_DIR etc/smartdns/smartdns.conf
|
||||
if [ $? -ne 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
install -v -m 0640 -t $PREFIX/etc/default etc/default/smartdns
|
||||
@@ -118,7 +122,6 @@ uninstall_smartdns()
|
||||
if [ -z "$PREFIX" ]; then
|
||||
stop_service 2>/dev/null
|
||||
fi
|
||||
rm -f $PREFIX$SMARTDNS_CONF_DIR/smartdns.conf
|
||||
rmdir $PREFIX$SMARTDNS_CONF_DIR 2>/dev/null
|
||||
rm -f $PREFIX/usr/sbin/smartdns
|
||||
rm -f $PREFIX/etc/default/smartdns
|
||||
@@ -23,12 +23,17 @@ build()
|
||||
cd $PKG_ROOT/
|
||||
|
||||
# Generic x86_64
|
||||
mkdir $PKG_ROOT/smartdns/src -p
|
||||
mkdir $PKG_ROOT/smartdns/usr/sbin -p
|
||||
mkdir $PKG_ROOT/smartdns/package -p
|
||||
mkdir $PKG_ROOT/smartdns/systemd -p
|
||||
|
||||
cd $SMARTDNS_DIR
|
||||
cp package/windows $PKG_ROOT/smartdns/package/ -a
|
||||
cp etc systemd *.md LICENSE install $PKG_ROOT/smartdns/ -a
|
||||
cp src/smartdns $PKG_ROOT/smartdns/src -a
|
||||
cp etc *.md LICENSE package/linux/install $PKG_ROOT/smartdns/ -a
|
||||
cp systemd/smartdns.service $PKG_ROOT/smartdns/systemd
|
||||
cp src/smartdns $PKG_ROOT/smartdns/usr/sbin -a
|
||||
chmod +x $PKG_ROOT/smartdns/install
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "copy smartdns file failed"
|
||||
rm -fr $PKG_ROOT
|
||||
|
||||
@@ -214,6 +214,12 @@ msgstr "校验TLS主机名"
|
||||
msgid "Set TLS hostname to verify."
|
||||
msgstr "设置校验TLS主机名。"
|
||||
|
||||
msgid "No check certificate"
|
||||
msgstr "停用证书校验"
|
||||
|
||||
msgid "Do not check certificate."
|
||||
msgstr "不校验证书的合法性。"
|
||||
|
||||
msgid "TLS SNI name"
|
||||
msgstr "TLS SNI名称"
|
||||
|
||||
|
||||
@@ -78,6 +78,16 @@ o.rempty = true
|
||||
o:depends("type", "tls")
|
||||
o:depends("type", "https")
|
||||
|
||||
---- certificate verify
|
||||
o = s:option(Flag, "no_check_certificate", translate("No check certificate"), translate("Do not check certificate."))
|
||||
o.rmempty = false
|
||||
o.default = o.disabled
|
||||
o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "0"
|
||||
end
|
||||
o:depends("type", "tls")
|
||||
o:depends("type", "https")
|
||||
|
||||
---- SNI host name
|
||||
o = s:option(Value, "host_name", translate("TLS SNI name"), translate("Sets the server name indication for query."))
|
||||
o.default = ""
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
--
|
||||
-- Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
--
|
||||
-- smartdns is free software: you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation, either version 3 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- smartdns is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License
|
||||
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
module("luci.controller.smartdns", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/smartdns") then
|
||||
return
|
||||
end
|
||||
|
||||
local page
|
||||
page = entry({"admin", "services", "smartdns"}, view("smartdns/smartdns"), _("SmartDNS"), 60)
|
||||
page.dependent = true
|
||||
end
|
||||
@@ -226,6 +226,12 @@ msgstr "校验TLS主机名"
|
||||
msgid "Set TLS hostname to verify."
|
||||
msgstr "设置校验TLS主机名。"
|
||||
|
||||
msgid "No check certificate"
|
||||
msgstr "停用证书校验"
|
||||
|
||||
msgid "Do not check certificate."
|
||||
msgstr "不校验证书的合法性。"
|
||||
|
||||
msgid "TLS SNI name"
|
||||
msgstr "TLS SNI名称"
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"admin/services/smartdns": {
|
||||
"title": "SmartDNS",
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "smartdns/smartdns"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-smartdns" ],
|
||||
"uci": { "smartdns": true }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,20 @@
|
||||
"read": {
|
||||
"file": {
|
||||
"/etc/smartdns/*": [ "read" ],
|
||||
"/usr/sbin/iptables": [ "exec" ],
|
||||
"/usr/sbin/ip6tables": [ "exec" ],
|
||||
"/usr/sbin/iptables -t nat -nL PREROUTING": [ "exec" ],
|
||||
"/usr/sbin/ip6tables -t nat -nL PREROUTING": [ "exec" ],
|
||||
"/usr/sbin/smartdns": [ "exec" ]
|
||||
},
|
||||
"ubus": {
|
||||
"service": [ "list" ]
|
||||
}
|
||||
},
|
||||
"uci": [ "smartdns" ]
|
||||
},
|
||||
"write": {
|
||||
"file": {
|
||||
"/etc/smartdns/*": [ "write" ]
|
||||
}
|
||||
},
|
||||
"uci": [ "smartdns" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,7 +201,7 @@ return L.view.extend({
|
||||
_("Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish."));
|
||||
o.rmempty = false;
|
||||
o.default = o.disabled;
|
||||
|
||||
|
||||
// Redirect;
|
||||
o = s.taboption("settings", form.ListValue, "redirect", _("Redirect"), _("SmartDNS redirect mode"));
|
||||
o.placeholder = "none";
|
||||
@@ -253,7 +253,7 @@ return L.view.extend({
|
||||
|
||||
// dns server group;
|
||||
o = s.taboption("seconddns", form.Value, "seconddns_server_group", _("Server Group"),
|
||||
_("Query DNS through specific dns server group, such as office, home."));
|
||||
_("Query DNS through specific dns server group, such as office, home."));
|
||||
o.rmempty = true;
|
||||
o.placeholder = "default";
|
||||
o.datatype = "hostname";
|
||||
@@ -305,8 +305,7 @@ return L.view.extend({
|
||||
|
||||
// custom settings;
|
||||
o = s.taboption("custom", form.TextValue, "custom_conf",
|
||||
_(""),
|
||||
_("smartdns custom settings"));
|
||||
"", _("smartdns custom settings"));
|
||||
|
||||
o.rows = 20;
|
||||
o.cfgvalue = function (section_id) {
|
||||
@@ -390,6 +389,15 @@ return L.view.extend({
|
||||
o.depends("type", "tls")
|
||||
o.depends("type", "https")
|
||||
|
||||
// certificate verify
|
||||
o = s.taboption("advanced", form.Flag, "no_check_certificate", _("No check certificate"),
|
||||
_("Do not check certificate."))
|
||||
o.rmempty = false
|
||||
o.default = o.disabled
|
||||
o.modalonly = true;
|
||||
o.depends("type", "tls")
|
||||
o.depends("type", "https")
|
||||
|
||||
// SNI host name
|
||||
o = s.taboption("advanced", form.Value, "host_name", _("TLS SNI name"),
|
||||
_("Sets the server name indication for query."))
|
||||
@@ -482,4 +490,3 @@ return L.view.extend({
|
||||
return m.render();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -53,21 +53,15 @@ build()
|
||||
cd $ROOT/
|
||||
build_tool
|
||||
|
||||
mkdir $ROOT/root/usr/lib/lua/ -p
|
||||
mkdir $ROOT/root/usr/lib/lua/luci/controller/ -p
|
||||
mkdir $ROOT/root/usr/lib/lua/luci -p
|
||||
mkdir $ROOT/root/usr/share/rpcd/acl.d/ -p
|
||||
cp $ROOT/files/luci/controller/* $ROOT/root/usr/lib/lua/luci/controller/ -avf
|
||||
cp $ROOT/files/luci/i18n $ROOT/root/usr/lib/lua/luci/ -avf
|
||||
cp $ROOT/files/luci/view $ROOT/root/usr/lib/lua/luci/ -avf
|
||||
|
||||
mkdir $ROOT/root/www/luci-static/resources/view -p
|
||||
cp $ROOT/files/luci/htdocs/luci-static/resources/view/* $ROOT/root/www/luci-static/resources/view/ -avf
|
||||
|
||||
#Generate Language
|
||||
$PO2LMO $ROOT/files/luci/i18n/smartdns.zh-cn.po $ROOT/root/usr/lib/lua/luci/i18n/smartdns.zh-cn.lmo
|
||||
rm $ROOT/root/usr/lib/lua/luci/i18n/smartdns.zh-cn.po
|
||||
|
||||
cp $ROOT/files/usr $ROOT/root/ -avf
|
||||
cp $ROOT/files/root/* $ROOT/root/ -avf
|
||||
INST_SIZE="`du -sb $ROOT/root/ | awk '{print $1}'`"
|
||||
|
||||
sed -i "s/^Architecture.*/Architecture: all/g" $ROOT/control/control
|
||||
|
||||
@@ -9,6 +9,9 @@ PKG_NAME:=smartdns
|
||||
PKG_VERSION:=1.2019.28
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
|
||||
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://www.github.com/pymumu/smartdns.git
|
||||
PKG_SOURCE_VERSION:=982002e836e486fb4e360bc10e84e7e7197caf46
|
||||
|
||||
@@ -46,7 +46,6 @@ set_forward_dnsmasq()
|
||||
[ "$server" = "$addr" ] && continue
|
||||
uci add_list dhcp.@dnsmasq[0].server="$server"
|
||||
done
|
||||
uci delete dhcp.@dnsmasq[0].resolvfile 2>/dev/null
|
||||
uci set dhcp.@dnsmasq[0].noresolv=1
|
||||
uci commit dhcp
|
||||
/etc/init.d/dnsmasq restart
|
||||
@@ -57,14 +56,13 @@ stop_forward_dnsmasq()
|
||||
local OLD_PORT="$1"
|
||||
addr="127.0.0.1#$OLD_PORT"
|
||||
OLD_SERVER="$(uci get dhcp.@dnsmasq[0].server 2>/dev/null)"
|
||||
if echo "$OLD_SERVER" | grep "^$addr" >/dev/null 2>&1; then
|
||||
if ! echo "$OLD_SERVER" | grep "^$addr" >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
uci del_list dhcp.@dnsmasq[0].server="$addr" 2>/dev/null
|
||||
addrlist="$(uci get dhcp.@dnsmasq[0].server 2>/dev/null)"
|
||||
[ -z "$addrlist" ] && {
|
||||
uci set dhcp.@dnsmasq[0].resolvfile=/tmp/resolv.conf.auto 2>/dev/null
|
||||
uci delete dhcp.@dnsmasq[0].noresolv 2>/dev/null
|
||||
}
|
||||
uci commit dhcp
|
||||
@@ -125,7 +123,6 @@ service_triggers() {
|
||||
procd_add_reload_trigger smartdns
|
||||
}
|
||||
|
||||
|
||||
conf_append()
|
||||
{
|
||||
echo "$1 $2" >> $SMARTDNS_CONF_TMP
|
||||
@@ -159,6 +156,7 @@ load_server()
|
||||
config_get type "$section" "type" "udp"
|
||||
config_get ip "$section" "ip" ""
|
||||
config_get tls_host_verify "$section" "tls_host_verify" ""
|
||||
config_get no_check_certificate "$section" "no_check_certificate" "0"
|
||||
config_get host_name "$section" "host_name" ""
|
||||
config_get http_host "$section" "http_host" ""
|
||||
config_get server_group "$section" "server_group" ""
|
||||
@@ -189,6 +187,7 @@ load_server()
|
||||
fi
|
||||
|
||||
[ -z "$tls_host_verify" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -tls-host-verify $tls_host_verify"
|
||||
[ "$no_check_certificate" = "0" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -no-check-certificate"
|
||||
[ -z "$host_name" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -host-name $host_name"
|
||||
[ -z "$http_host" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -http-host $http_host"
|
||||
[ -z "$server_group" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -group $server_group"
|
||||
|
||||
@@ -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/
|
||||
}
|
||||
|
||||
|
||||
@@ -332,9 +332,28 @@ case "$1" in
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -d "/proc/$pid" ]; then
|
||||
return 0;
|
||||
kill -15 "$pid" 2>/dev/null
|
||||
SLEEP=`which usleep`
|
||||
SLEEPTIME=200000
|
||||
if [ -z "$SLEEP" ]; then
|
||||
SLEEP="sleep"
|
||||
SLEEPTIME=0.2
|
||||
fi
|
||||
N=30
|
||||
while [ $N -gt 0 ]
|
||||
do
|
||||
pid="$(cat "$SMARTDNS_PID" | head -n 1 2>/dev/null)"
|
||||
if [ -z "$pid" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -d "/proc/$pid" ]; then
|
||||
return 0;
|
||||
fi
|
||||
|
||||
$SLEEP $SLEEPTIME 2>/dev/null
|
||||
N=$((N-1))
|
||||
done
|
||||
|
||||
kill -9 "$pid" 2>/dev/null
|
||||
;;
|
||||
|
||||
66
package/redhat/smartdns.spec
Normal file
66
package/redhat/smartdns.spec
Normal file
@@ -0,0 +1,66 @@
|
||||
Name: smartdns
|
||||
Version: 1.2020.09.08
|
||||
Release: 2235%{?dist}
|
||||
Summary: smartdns
|
||||
|
||||
License: GPL 3.0
|
||||
URL: https://github.com/pymumu/smartdns
|
||||
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
|
||||
|
||||
%build
|
||||
cd src
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%{__install} -D -m 755 src/smartdns $RPM_BUILD_ROOT%{_sbindir}/smartdns
|
||||
%{__install} -D -m 644 etc/smartdns/smartdns.conf $RPM_BUILD_ROOT%{_sysconfdir}/smartdns/smartdns.conf
|
||||
%{__install} -D -m 644 systemd/smartdns.service.in $RPM_BUILD_ROOT%{_unitdir}/smartdns.service
|
||||
|
||||
|
||||
cat > $RPM_BUILD_ROOT%{_unitdir}/smartdns.service <<EOF
|
||||
[Unit]
|
||||
Description=smartdns
|
||||
ConditionFileIsExecutable=/usr/sbin/smartdns
|
||||
After=syslog.target network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/sbin/smartdns -c /etc/smartdns/smartdns.conf -f
|
||||
PIDFile=/run/smartdns.pid
|
||||
Restart=on-failure
|
||||
KillMode=process
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{_sbindir}/smartdns
|
||||
%config(noreplace) %{_sysconfdir}/smartdns/smartdns.conf
|
||||
%{_unitdir}/smartdns.service
|
||||
|
||||
%post
|
||||
%systemd_post %{name}.service
|
||||
|
||||
%preun
|
||||
%systemd_preun %{name}.service
|
||||
|
||||
%postun
|
||||
%systemd_postun_with_restart %{name}.service
|
||||
@@ -38,7 +38,7 @@ else
|
||||
override LDFLAGS += -lssl -lcrypto -lpthread
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
|
||||
85
src/dns.c
85
src/dns.c
@@ -18,15 +18,15 @@
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "dns.h"
|
||||
#include "tlog.h"
|
||||
#include "stringutil.h"
|
||||
#include "tlog.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define QR_MASK 0x8000
|
||||
#define OPCODE_MASK 0x7800
|
||||
@@ -37,9 +37,9 @@
|
||||
#define RCODE_MASK 0x000F
|
||||
#define DNS_RR_END (0XFFFF)
|
||||
|
||||
#define UNUSED(expr) \
|
||||
do { \
|
||||
(void)(expr); \
|
||||
#define UNUSED(expr) \
|
||||
do { \
|
||||
(void)(expr); \
|
||||
} while (0)
|
||||
|
||||
/* read short and move pointer */
|
||||
@@ -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,16 +297,14 @@ 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;
|
||||
}
|
||||
|
||||
static int _dns_add_rr_head(struct dns_data_context *data_context, char *domain, int qtype, int qclass, int ttl, int rr_len)
|
||||
static int _dns_add_rr_head(struct dns_data_context *data_context, char *domain, int qtype, int qclass, int ttl,
|
||||
int rr_len)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
@@ -324,16 +323,14 @@ 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;
|
||||
}
|
||||
|
||||
static int _dns_get_rr_head(struct dns_data_context *data_context, char *domain, int maxsize, int *qtype, int *qclass, int *ttl, int *rr_len)
|
||||
static int _dns_get_rr_head(struct dns_data_context *data_context, char *domain, int maxsize, int *qtype, int *qclass,
|
||||
int *ttl, int *rr_len)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
@@ -349,16 +346,14 @@ 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;
|
||||
}
|
||||
|
||||
static int _dns_add_RAW(struct dns_packet *packet, dns_rr_type rrtype, dns_type_t rtype, char *domain, int ttl, void *raw, int raw_len)
|
||||
static int _dns_add_RAW(struct dns_packet *packet, dns_rr_type rrtype, dns_type_t rtype, char *domain, int ttl,
|
||||
void *raw, int raw_len)
|
||||
{
|
||||
int maxlen = 0;
|
||||
int len = 0;
|
||||
@@ -451,14 +446,16 @@ static int _dns_add_opt_RAW(struct dns_packet *packet, dns_opt_code_t opt_rrtype
|
||||
return _dns_add_RAW(packet, DNS_RRS_OPT, DNS_OPT_T_TCP_KEEPALIVE, "", 0, opt_data, len);
|
||||
}
|
||||
|
||||
static int _dns_get_opt_RAW(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct dns_opt *dns_opt, int *dns_optlen)
|
||||
static int _dns_get_opt_RAW(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct dns_opt *dns_opt,
|
||||
int *dns_optlen)
|
||||
{
|
||||
*dns_optlen = DNS_MAX_OPT_LEN;
|
||||
|
||||
return _dns_get_RAW(rrs, domain, maxsize, ttl, dns_opt, dns_optlen);
|
||||
}
|
||||
|
||||
static int __attribute__((unused)) _dns_add_OPT(struct dns_packet *packet, dns_rr_type type, unsigned short opt_code, unsigned short opt_len, struct dns_opt *opt)
|
||||
static int __attribute__((unused)) _dns_add_OPT(struct dns_packet *packet, dns_rr_type type, unsigned short opt_code,
|
||||
unsigned short opt_len, struct dns_opt *opt)
|
||||
{
|
||||
// TODO
|
||||
|
||||
@@ -508,7 +505,8 @@ static int __attribute__((unused)) _dns_add_OPT(struct dns_packet *packet, dns_
|
||||
return _dns_rr_add_end(packet, type, DNS_T_OPT, len);
|
||||
}
|
||||
|
||||
static int __attribute__((unused)) _dns_get_OPT(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, struct dns_opt *opt, int *opt_maxlen)
|
||||
static int __attribute__((unused)) _dns_get_OPT(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len,
|
||||
struct dns_opt *opt, int *opt_maxlen)
|
||||
{
|
||||
// TODO
|
||||
|
||||
@@ -593,7 +591,8 @@ int dns_get_NS(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *c
|
||||
return _dns_get_RAW(rrs, domain, maxsize, ttl, cname, &len);
|
||||
}
|
||||
|
||||
int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, unsigned char addr[DNS_RR_AAAA_LEN])
|
||||
int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl,
|
||||
unsigned char addr[DNS_RR_AAAA_LEN])
|
||||
{
|
||||
return _dns_add_RAW(packet, type, DNS_T_AAAA, domain, ttl, addr, DNS_RR_AAAA_LEN);
|
||||
}
|
||||
@@ -749,7 +748,8 @@ int dns_add_OPT_TCP_KEEYALIVE(struct dns_packet *packet, unsigned short timeout)
|
||||
return _dns_add_opt_RAW(packet, DNS_OPT_T_TCP_KEEPALIVE, &timeout_net, data_len);
|
||||
}
|
||||
|
||||
int dns_get_OPT_TCP_KEEYALIVE(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, unsigned short *timeout)
|
||||
int dns_get_OPT_TCP_KEEYALIVE(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len,
|
||||
unsigned short *timeout)
|
||||
{
|
||||
unsigned char opt_data[DNS_MAX_OPT_LEN];
|
||||
struct dns_opt *opt = (struct dns_opt *)opt_data;
|
||||
@@ -932,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;
|
||||
}
|
||||
|
||||
@@ -961,7 +961,8 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz
|
||||
}
|
||||
ptr = context->data + len;
|
||||
if (ptr > context->data + context->maxsize) {
|
||||
tlog(TLOG_DEBUG, "length is not enough %u:%ld, %p, %p", context->maxsize, (long)(ptr - context->data), context->ptr, context->data);
|
||||
tlog(TLOG_DEBUG, "length is not enough %u:%ld, %p, %p", context->maxsize, (long)(ptr - context->data),
|
||||
context->ptr, context->data);
|
||||
return -1;
|
||||
}
|
||||
is_compressed = 1;
|
||||
@@ -979,7 +980,8 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz
|
||||
}
|
||||
|
||||
if (ptr > context->data + context->maxsize) {
|
||||
tlog(TLOG_DEBUG, "length is not enough %u:%ld, %p, %p", context->maxsize, (long)(ptr - context->data), context->ptr, context->data);
|
||||
tlog(TLOG_DEBUG, "length is not enough %u:%ld, %p, %p", context->maxsize, (long)(ptr - context->data),
|
||||
context->ptr, context->data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -988,7 +990,8 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz
|
||||
/* copy sub string */
|
||||
copy_len = (len < size - output_len) ? len : size - 1 - output_len;
|
||||
if ((ptr + copy_len) > (context->data + context->maxsize)) {
|
||||
tlog(TLOG_DEBUG, "length is not enough %u:%ld, %p, %p", context->maxsize, (long)(ptr - context->data), context->ptr, context->data);
|
||||
tlog(TLOG_DEBUG, "length is not enough %u:%ld, %p, %p", context->maxsize, (long)(ptr - context->data),
|
||||
context->ptr, context->data);
|
||||
return -1;
|
||||
}
|
||||
memcpy(output, ptr, copy_len);
|
||||
@@ -1089,7 +1092,8 @@ static int _dns_encode_qr_head(struct dns_context *context, char *domain, int qt
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_decode_rr_head(struct dns_context *context, char *domain, int domain_size, int *qtype, int *qclass, int *ttl, int *rr_len)
|
||||
static int _dns_decode_rr_head(struct dns_context *context, char *domain, int domain_size, int *qtype, int *qclass,
|
||||
int *ttl, int *rr_len)
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
@@ -1351,14 +1355,15 @@ 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;
|
||||
}
|
||||
|
||||
memcpy(ecs->addr, context->ptr, len);
|
||||
context->ptr += len;
|
||||
|
||||
tlog(TLOG_DEBUG, "ECS: family:%d, source_prefix:%d, scope_prefix:%d, len:%d", ecs->family, ecs->source_prefix, ecs->scope_prefix, len);
|
||||
tlog(TLOG_DEBUG, "ECS: family:%d, source_prefix:%d, scope_prefix:%d, len:%d", ecs->family, ecs->source_prefix,
|
||||
ecs->scope_prefix, len);
|
||||
tlog(TLOG_DEBUG, "%d.%d.%d.%d", ecs->addr[0], ecs->addr[1], ecs->addr[2], ecs->addr[3]);
|
||||
|
||||
return 0;
|
||||
|
||||
19
src/dns.h
19
src/dns.h
@@ -44,7 +44,10 @@ typedef enum dns_rr_type {
|
||||
DNS_RRS_END,
|
||||
} dns_rr_type;
|
||||
|
||||
typedef enum dns_class { DNS_C_IN = 1, DNS_C_ANY = 255 } dns_class_t;
|
||||
typedef enum dns_class {
|
||||
DNS_C_IN = 1, // DNS C IN
|
||||
DNS_C_ANY = 255
|
||||
} dns_class_t;
|
||||
|
||||
typedef enum dns_type {
|
||||
DNS_T_A = 1,
|
||||
@@ -63,10 +66,10 @@ typedef enum dns_type {
|
||||
DNS_T_ALL = 255
|
||||
} dns_type_t;
|
||||
|
||||
typedef enum dns_opt_code {
|
||||
DNS_OPT_T_ECS = 8,
|
||||
typedef enum dns_opt_code {
|
||||
DNS_OPT_T_ECS = 8, // OPT ECS
|
||||
DNS_OPT_T_TCP_KEEPALIVE = 11,
|
||||
DNS_OPT_T_ALL = 255
|
||||
DNS_OPT_T_ALL = 255
|
||||
} dns_opt_code_t;
|
||||
|
||||
typedef enum dns_opcode {
|
||||
@@ -107,7 +110,7 @@ struct dns_head {
|
||||
unsigned short ancount; /* number of answer entries */
|
||||
unsigned short nscount; /* number of authority entries */
|
||||
unsigned short nrcount; /* number of addititional resource entries */
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed, aligned(2)));
|
||||
|
||||
struct dns_rrs {
|
||||
unsigned short next;
|
||||
@@ -196,7 +199,8 @@ int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned
|
||||
int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname);
|
||||
int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size);
|
||||
|
||||
int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, unsigned char addr[DNS_RR_AAAA_LEN]);
|
||||
int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl,
|
||||
unsigned char addr[DNS_RR_AAAA_LEN]);
|
||||
int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[DNS_RR_AAAA_LEN]);
|
||||
|
||||
int dns_add_SOA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, struct dns_soa *soa);
|
||||
@@ -212,7 +216,8 @@ int dns_add_OPT_ECS(struct dns_packet *packet, struct dns_opt_ecs *ecs);
|
||||
int dns_get_OPT_ECS(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, struct dns_opt_ecs *ecs);
|
||||
|
||||
int dns_add_OPT_TCP_KEEYALIVE(struct dns_packet *packet, unsigned short timeout);
|
||||
int dns_get_OPT_TCP_KEEYALIVE(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, unsigned short *timeout);
|
||||
int dns_get_OPT_TCP_KEEYALIVE(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len,
|
||||
unsigned short *timeout);
|
||||
/*
|
||||
* Packet operation
|
||||
*/
|
||||
|
||||
505
src/dns_cache.c
505
src/dns_cache.c
@@ -19,7 +19,11 @@
|
||||
#include "dns_cache.h"
|
||||
#include "stringutil.h"
|
||||
#include "tlog.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define DNS_CACHE_MAX_HITNUM 5000
|
||||
#define DNS_CACHE_HITNUM_STEP 2
|
||||
@@ -65,7 +69,7 @@ static __attribute__((unused)) struct dns_cache *_dns_cache_last(void)
|
||||
return list_last_entry(&dns_cache_head.cache_list, struct dns_cache, list);
|
||||
}
|
||||
|
||||
static struct dns_cache *_dns_cache_first(void)
|
||||
static struct dns_cache *_dns_inactive_cache_first(void)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
@@ -82,6 +86,7 @@ static void _dns_cache_delete(struct dns_cache *dns_cache)
|
||||
hash_del(&dns_cache->node);
|
||||
list_del_init(&dns_cache->list);
|
||||
atomic_dec(&dns_cache_head.num);
|
||||
dns_cache_data_free(dns_cache->cache_data);
|
||||
free(dns_cache);
|
||||
}
|
||||
|
||||
@@ -118,9 +123,124 @@ static void _dns_cache_move_inactive(struct dns_cache *dns_cache)
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list);
|
||||
}
|
||||
|
||||
int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr, int addr_len, int speed)
|
||||
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data)
|
||||
{
|
||||
return cache_data->head.cache_type;
|
||||
}
|
||||
|
||||
uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data)
|
||||
{
|
||||
return cache_data->head.cache_flag;
|
||||
}
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data)
|
||||
{
|
||||
if (data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
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));
|
||||
if (cache_addr == NULL) {
|
||||
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) {
|
||||
memcpy(cache_addr->addr_data.addr, addr, DNS_RR_AAAA_LEN);
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
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->head.cache_type = CACHE_TYPE_ADDR;
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
errout:
|
||||
return;
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len)
|
||||
{
|
||||
struct dns_cache_packet *cache_packet = NULL;
|
||||
size_t data_size = 0;
|
||||
if (packet == NULL || packet_len <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data_size = sizeof(*cache_packet) + packet_len;
|
||||
cache_packet = malloc(data_size);
|
||||
if (cache_packet == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(cache_packet->data, packet, packet_len);
|
||||
|
||||
cache_packet->head.cache_flag = cache_flag;
|
||||
cache_packet->head.cache_type = CACHE_TYPE_PACKET;
|
||||
cache_packet->head.size = packet_len;
|
||||
|
||||
return (struct dns_cache_data *)cache_packet;
|
||||
}
|
||||
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache_data *old_cache_data = NULL;
|
||||
|
||||
if (dns_cache_head.size <= 0) {
|
||||
return 0;
|
||||
@@ -129,7 +249,7 @@ int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_typ
|
||||
/* lookup existing cache */
|
||||
dns_cache = dns_cache_lookup(domain, qtype);
|
||||
if (dns_cache == NULL) {
|
||||
return 0;
|
||||
return dns_cache_insert(domain, ttl, qtype, speed, cache_data);
|
||||
}
|
||||
|
||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||
@@ -138,57 +258,30 @@ int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_typ
|
||||
|
||||
/* update cache data */
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
dns_cache->ttl = ttl;
|
||||
dns_cache->qtype = qtype;
|
||||
dns_cache->ttl = ttl;
|
||||
dns_cache->del_pending = 0;
|
||||
dns_cache->speed = speed;
|
||||
time(&dns_cache->insert_time);
|
||||
if (qtype == DNS_T_A) {
|
||||
if (addr_len != DNS_RR_A_LEN) {
|
||||
goto errout_unlock;
|
||||
}
|
||||
memcpy(dns_cache->addr, addr, DNS_RR_A_LEN);
|
||||
} else if (qtype == DNS_T_AAAA) {
|
||||
if (addr_len != DNS_RR_AAAA_LEN) {
|
||||
goto errout_unlock;
|
||||
}
|
||||
memcpy(dns_cache->addr, addr, DNS_RR_AAAA_LEN);
|
||||
} else {
|
||||
goto errout_unlock;
|
||||
}
|
||||
|
||||
if (cname) {
|
||||
safe_strncpy(dns_cache->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
dns_cache->cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
dns_cache->info.ttl = ttl;
|
||||
dns_cache->info.qtype = qtype;
|
||||
dns_cache->info.ttl = ttl;
|
||||
dns_cache->info.speed = speed;
|
||||
time(&dns_cache->info.insert_time);
|
||||
old_cache_data = dns_cache->cache_data;
|
||||
dns_cache->cache_data = cache_data;
|
||||
list_del_init(&dns_cache->list);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
dns_cache_data_free(old_cache_data);
|
||||
dns_cache_release(dns_cache);
|
||||
return 0;
|
||||
errout_unlock:
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
// errout:
|
||||
if (dns_cache) {
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr, int addr_len, int speed)
|
||||
int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data *cache_data, struct list_head *head)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
if (dns_cache_head.size <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if cache already exists, free */
|
||||
dns_cache = dns_cache_lookup(domain, qtype);
|
||||
dns_cache = dns_cache_lookup(info->domain, info->qtype);
|
||||
if (dns_cache) {
|
||||
dns_cache_delete(dns_cache);
|
||||
dns_cache_release(dns_cache);
|
||||
@@ -200,50 +293,22 @@ int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||
ttl = DNS_CACHE_TTL_MIN;
|
||||
}
|
||||
|
||||
key = hash_string(domain);
|
||||
key = jhash(&qtype, sizeof(qtype), key);
|
||||
safe_strncpy(dns_cache->domain, domain, DNS_MAX_CNAME_LEN);
|
||||
dns_cache->cname[0] = 0;
|
||||
dns_cache->qtype = qtype;
|
||||
dns_cache->ttl = ttl;
|
||||
atomic_set(&dns_cache->hitnum, 3);
|
||||
dns_cache->hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
||||
dns_cache->del_pending = 0;
|
||||
dns_cache->speed = speed;
|
||||
memset(dns_cache, 0, sizeof(*dns_cache));
|
||||
key = hash_string(info->domain);
|
||||
key = jhash(&info->qtype, sizeof(info->qtype), key);
|
||||
atomic_set(&dns_cache->ref, 1);
|
||||
time(&dns_cache->insert_time);
|
||||
if (qtype == DNS_T_A) {
|
||||
if (addr_len != DNS_RR_A_LEN) {
|
||||
goto errout;
|
||||
}
|
||||
memcpy(dns_cache->addr, addr, DNS_RR_A_LEN);
|
||||
} else if (qtype == DNS_T_AAAA) {
|
||||
if (addr_len != DNS_RR_AAAA_LEN) {
|
||||
goto errout;
|
||||
}
|
||||
memcpy(dns_cache->addr, addr, DNS_RR_AAAA_LEN);
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cname) {
|
||||
safe_strncpy(dns_cache->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
dns_cache->cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
memcpy(&dns_cache->info, info, sizeof(*info));
|
||||
dns_cache->del_pending = 0;
|
||||
dns_cache->cache_data = cache_data;
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_add(dns_cache_head.cache_hash, &dns_cache->node, key);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
list_add_tail(&dns_cache->list, head);
|
||||
INIT_LIST_HEAD(&dns_cache->check_list);
|
||||
|
||||
/* Release extra cache, remove oldest cache record */
|
||||
if (atomic_inc_return(&dns_cache_head.num) > dns_cache_head.size) {
|
||||
struct dns_cache *del_cache;
|
||||
del_cache = _dns_cache_first();
|
||||
del_cache = _dns_inactive_cache_first();
|
||||
if (del_cache) {
|
||||
_dns_cache_remove(del_cache);
|
||||
}
|
||||
@@ -259,6 +324,34 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache_info info;
|
||||
|
||||
if (cache_data == NULL || domain == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dns_cache_head.size <= 0) {
|
||||
dns_cache_data_free(cache_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||
ttl = DNS_CACHE_TTL_MIN;
|
||||
}
|
||||
|
||||
info.hitnum = 3;
|
||||
safe_strncpy(info.domain, domain, DNS_MAX_CNAME_LEN);
|
||||
info.qtype = qtype;
|
||||
info.ttl = ttl;
|
||||
info.hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
||||
info.speed = speed;
|
||||
time(&info.insert_time);
|
||||
|
||||
return _dns_cache_insert(&info, cache_data, &dns_cache_head.cache_list);
|
||||
}
|
||||
|
||||
struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
@@ -278,11 +371,11 @@ struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_for_each_possible(dns_cache_head.cache_hash, dns_cache, node, key)
|
||||
{
|
||||
if (dns_cache->qtype != qtype) {
|
||||
if (dns_cache->info.qtype != qtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(domain, dns_cache->domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||
if (strncmp(domain, dns_cache->info.domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -292,7 +385,7 @@ struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
|
||||
if (dns_cache_ret) {
|
||||
/* Return NULL if the cache times out */
|
||||
if (dns_cache_head.enable_inactive == 0 && (now - dns_cache_ret->insert_time > dns_cache_ret->ttl)) {
|
||||
if (dns_cache_head.enable_inactive == 0 && (now - dns_cache_ret->info.insert_time > dns_cache_ret->info.ttl)) {
|
||||
_dns_cache_remove(dns_cache_ret);
|
||||
dns_cache_ret = NULL;
|
||||
} else {
|
||||
@@ -311,7 +404,7 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache)
|
||||
int ttl = 0;
|
||||
time(&now);
|
||||
|
||||
ttl = dns_cache->insert_time + dns_cache->ttl - now;
|
||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - now;
|
||||
if (ttl < 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -319,6 +412,23 @@ 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->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;
|
||||
}
|
||||
|
||||
void dns_cache_delete(struct dns_cache *dns_cache)
|
||||
{
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
@@ -328,15 +438,14 @@ void dns_cache_delete(struct dns_cache *dns_cache)
|
||||
|
||||
int dns_cache_hitnum_dec_get(struct dns_cache *dns_cache)
|
||||
{
|
||||
int hitnum = 0;
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hitnum = atomic_dec_return(&dns_cache->hitnum);
|
||||
if (dns_cache->hitnum_update_add > DNS_CACHE_HITNUM_STEP) {
|
||||
dns_cache->hitnum_update_add--;
|
||||
dns_cache->info.hitnum--;
|
||||
if (dns_cache->info.hitnum_update_add > DNS_CACHE_HITNUM_STEP) {
|
||||
dns_cache->info.hitnum_update_add--;
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
return hitnum;
|
||||
return dns_cache->info.hitnum;
|
||||
}
|
||||
|
||||
void dns_cache_update(struct dns_cache *dns_cache)
|
||||
@@ -345,13 +454,13 @@ void dns_cache_update(struct dns_cache *dns_cache)
|
||||
if (!list_empty(&dns_cache->list)) {
|
||||
list_del_init(&dns_cache->list);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
atomic_add(dns_cache->hitnum_update_add, &dns_cache->hitnum);
|
||||
if (atomic_read(&dns_cache->hitnum) > DNS_CACHE_MAX_HITNUM) {
|
||||
atomic_set(&dns_cache->hitnum, DNS_CACHE_MAX_HITNUM);
|
||||
dns_cache->info.hitnum += dns_cache->info.hitnum_update_add;
|
||||
if (dns_cache->info.hitnum > DNS_CACHE_MAX_HITNUM) {
|
||||
dns_cache->info.hitnum = DNS_CACHE_MAX_HITNUM;
|
||||
}
|
||||
|
||||
if (dns_cache->hitnum_update_add < DNS_CACHE_HITNUM_STEP_MAX) {
|
||||
dns_cache->hitnum_update_add++;
|
||||
if (dns_cache->info.hitnum_update_add < DNS_CACHE_HITNUM_STEP_MAX) {
|
||||
dns_cache->info.hitnum_update_add++;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
@@ -365,7 +474,7 @@ void _dns_cache_remove_expired_ttl(time_t *now)
|
||||
|
||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.inactive_list, list)
|
||||
{
|
||||
ttl = dns_cache->insert_time + dns_cache->ttl - *now;
|
||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - *now;
|
||||
if (ttl > 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -394,7 +503,7 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list)
|
||||
{
|
||||
ttl = dns_cache->insert_time + dns_cache->ttl - now;
|
||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - now;
|
||||
if (ttl > 0 && ttl < ttl_pre) {
|
||||
/* If the TTL time is in the pre-timeout range, call callback function */
|
||||
if (callback && dns_cache->del_pending == 0) {
|
||||
@@ -406,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);
|
||||
@@ -430,6 +539,216 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
}
|
||||
}
|
||||
|
||||
static int _dns_cache_read_record(int fd, uint32_t cache_number)
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
struct dns_cache_record cache_record;
|
||||
struct dns_cache_data_head data_head;
|
||||
struct dns_cache_data *cache_data = NULL;
|
||||
struct list_head *head = NULL;
|
||||
|
||||
for (i = 0; i < cache_number; i++) {
|
||||
ret = read(fd, &cache_record, sizeof(cache_record));
|
||||
if (ret != sizeof(cache_record)) {
|
||||
tlog(TLOG_ERROR, "read cache failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cache_record.magic != MAGIC_CACHE_DATA) {
|
||||
tlog(TLOG_ERROR, "magic is invalid.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cache_record.type == CACHE_RECORD_TYPE_ACTIVE) {
|
||||
head = &dns_cache_head.cache_list;
|
||||
} else {
|
||||
head = &dns_cache_head.inactive_list;
|
||||
}
|
||||
|
||||
ret = read(fd, &data_head, sizeof(data_head));
|
||||
if (ret != sizeof(data_head)) {
|
||||
tlog(TLOG_ERROR, "read data head failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (data_head.size > 1024 * 8) {
|
||||
tlog(TLOG_ERROR, "data may invalid, skip load cache.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
cache_data = malloc(data_head.size + sizeof(data_head));
|
||||
if (cache_data == NULL) {
|
||||
tlog(TLOG_ERROR, "malloc cache data failed %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memcpy(&cache_data->head, &data_head, sizeof(data_head));
|
||||
ret = read(fd, cache_data->data, data_head.size);
|
||||
if (ret != data_head.size) {
|
||||
tlog(TLOG_ERROR, "read cache data failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_cache_insert(&cache_record.info, cache_data, head) != 0) {
|
||||
tlog(TLOG_ERROR, "insert cache data failed.");
|
||||
cache_data = NULL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
cache_data = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (cache_data) {
|
||||
free(cache_data);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_cache_load(const char *file)
|
||||
{
|
||||
int fd = -1;
|
||||
int ret = 0;
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_cache_file cache_file;
|
||||
ret = read(fd, &cache_file, sizeof(cache_file));
|
||||
if (ret != sizeof(cache_file)) {
|
||||
tlog(TLOG_ERROR, "read cache head failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cache_file.magic != MAGIC_NUMBER) {
|
||||
tlog(TLOG_ERROR, "cache file is invalid.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (strncmp(cache_file.version, __TIMESTAMP__, DNS_CACHE_VERSION_LEN) != 0) {
|
||||
tlog(TLOG_WARN, "cache version is different, skip load cache.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_cache_read_record(fd, cache_file.cache_number) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
errout:
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_cache_write_record(int fd, uint32_t *cache_number, enum CACHE_RECORD_TYPE type, struct list_head *head)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *tmp = NULL;
|
||||
struct dns_cache_record cache_record;
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
list_for_each_entry_safe_reverse(dns_cache, tmp, head, list)
|
||||
{
|
||||
cache_record.magic = MAGIC_CACHE_DATA;
|
||||
cache_record.type = type;
|
||||
memcpy(&cache_record.info, &dns_cache->info, sizeof(struct dns_cache_info));
|
||||
int ret = write(fd, &cache_record, sizeof(cache_record));
|
||||
if (ret != sizeof(cache_record)) {
|
||||
tlog(TLOG_ERROR, "write cache failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
struct dns_cache_data *cache_data = dns_cache->cache_data;
|
||||
ret = write(fd, cache_data, sizeof(*cache_data) + cache_data->head.size);
|
||||
if (ret != sizeof(*cache_data) + cache_data->head.size) {
|
||||
tlog(TLOG_ERROR, "write cache data failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
(*cache_number)++;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_cache_write_records(int fd, uint32_t *cache_number)
|
||||
{
|
||||
|
||||
if (_dns_cache_write_record(fd, cache_number, CACHE_RECORD_TYPE_ACTIVE, &dns_cache_head.cache_list) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_dns_cache_write_record(fd, cache_number, CACHE_RECORD_TYPE_INACTIVE, &dns_cache_head.inactive_list) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_cache_save(const char *file)
|
||||
{
|
||||
int fd = -1;
|
||||
uint32_t cache_number = 0;
|
||||
tlog(TLOG_DEBUG, "write cache file %s", file);
|
||||
|
||||
fd = open(file, O_TRUNC | O_CREAT | O_WRONLY, 0640);
|
||||
if (fd < 0) {
|
||||
tlog(TLOG_ERROR, "create file %s failed, %s", file, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
struct dns_cache_file cache_file;
|
||||
memset(&cache_file, 0, sizeof(cache_file));
|
||||
cache_file.magic = MAGIC_NUMBER;
|
||||
safe_strncpy(cache_file.version, __TIMESTAMP__, DNS_CACHE_VERSION_LEN);
|
||||
cache_file.cache_number = 0;
|
||||
|
||||
if (lseek(fd, sizeof(cache_file), SEEK_SET) < 0) {
|
||||
tlog(TLOG_ERROR, "seek file %s failed, %s", file, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_cache_write_records(fd, &cache_number) != 0) {
|
||||
tlog(TLOG_ERROR, "write record to file %s failed.", file);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (lseek(fd, 0, SEEK_SET) < 0) {
|
||||
tlog(TLOG_ERROR, "seek file %s failed, %s", file, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
cache_file.cache_number = cache_number;
|
||||
if (write(fd, &cache_file, sizeof(cache_file)) != sizeof(cache_file)) {
|
||||
tlog(TLOG_ERROR, "write file head %s failed, %s, %d", file, strerror(errno), fd);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "wrote total %d records.", cache_number);
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
errout:
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void dns_cache_destroy(void)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
111
src/dns_cache.h
111
src/dns_cache.h
@@ -32,34 +32,98 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define DNS_CACHE_TTL_MIN 30
|
||||
#define DNS_CACHE_VERSION_LEN 32
|
||||
#define MAGIC_NUMBER 0x6548634163536e44
|
||||
#define MAGIC_CACHE_DATA 0x44615461
|
||||
|
||||
enum CACHE_TYPE {
|
||||
CACHE_TYPE_NONE,
|
||||
CACHE_TYPE_ADDR,
|
||||
CACHE_TYPE_PACKET,
|
||||
};
|
||||
|
||||
enum CACHE_RECORD_TYPE {
|
||||
CACHE_RECORD_TYPE_ACTIVE,
|
||||
CACHE_RECORD_TYPE_INACTIVE,
|
||||
};
|
||||
|
||||
struct dns_cache_data_head {
|
||||
uint32_t cache_flag;
|
||||
enum CACHE_TYPE cache_type;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct dns_cache_data {
|
||||
struct dns_cache_data_head head;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
struct dns_cache_addr {
|
||||
struct dns_cache_data_head head;
|
||||
struct dns_cache_addr_data {
|
||||
unsigned int cname_ttl;
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
char soa;
|
||||
union {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
||||
unsigned char addr[0];
|
||||
};
|
||||
} addr_data;
|
||||
};
|
||||
|
||||
struct dns_cache_packet {
|
||||
struct dns_cache_data_head head;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
struct dns_cache_info {
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
int ttl;
|
||||
int hitnum;
|
||||
int speed;
|
||||
int hitnum_update_add;
|
||||
time_t insert_time;
|
||||
dns_type_t qtype;
|
||||
};
|
||||
|
||||
struct dns_cache_record {
|
||||
uint32_t magic;
|
||||
enum CACHE_RECORD_TYPE type;
|
||||
struct dns_cache_info info;
|
||||
};
|
||||
|
||||
struct dns_cache {
|
||||
struct hlist_node node;
|
||||
struct list_head list;
|
||||
struct list_head check_list;
|
||||
|
||||
atomic_t ref;
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
unsigned int cname_ttl;
|
||||
unsigned int ttl;
|
||||
int speed;
|
||||
atomic_t hitnum;
|
||||
int hitnum_update_add;
|
||||
int del_pending;
|
||||
time_t insert_time;
|
||||
dns_type_t qtype;
|
||||
union {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
||||
unsigned char addr[0];
|
||||
};
|
||||
|
||||
struct dns_cache_info info;
|
||||
struct dns_cache_data *cache_data;
|
||||
};
|
||||
|
||||
struct dns_cache_file {
|
||||
uint64_t magic;
|
||||
char version[DNS_CACHE_VERSION_LEN];
|
||||
uint32_t cache_number;
|
||||
};
|
||||
|
||||
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data);
|
||||
|
||||
uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data);
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data);
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len);
|
||||
|
||||
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
|
||||
|
||||
int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr, int addr_len, int speed);
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr, int addr_len, int speed);
|
||||
int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype);
|
||||
|
||||
@@ -79,8 +143,23 @@ 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);
|
||||
|
||||
int dns_cache_save(const char *file);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
763
src/dns_client.c
763
src/dns_client.c
File diff suppressed because it is too large
Load Diff
@@ -52,8 +52,9 @@ int dns_client_init(void);
|
||||
int dns_client_set_ecs(char *ip, int subnet);
|
||||
|
||||
/* query result notify function */
|
||||
typedef int (*dns_client_callback)(char *domain, dns_result_type rtype, unsigned int result_flag, struct dns_packet *packet, unsigned char *inpacket,
|
||||
int inpacket_len, void *user_ptr);
|
||||
typedef int (*dns_client_callback)(char *domain, dns_result_type rtype, unsigned int result_flag,
|
||||
struct dns_packet *packet, unsigned char *inpacket, int inpacket_len,
|
||||
void *user_ptr);
|
||||
|
||||
/* query domain */
|
||||
int dns_client_query(char *domain, int qtype, dns_client_callback callback, void *user_ptr, const char *group_name);
|
||||
@@ -69,6 +70,7 @@ struct client_dns_server_flag_tls {
|
||||
int spi_len;
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
char tls_host_verify[DNS_MAX_CNAME_LEN];
|
||||
char skip_check_cert;
|
||||
};
|
||||
|
||||
struct client_dns_server_flag_https {
|
||||
@@ -78,6 +80,7 @@ struct client_dns_server_flag_https {
|
||||
char httphost[DNS_MAX_CNAME_LEN];
|
||||
char path[DNS_MAX_CNAME_LEN];
|
||||
char tls_host_verify[DNS_MAX_CNAME_LEN];
|
||||
char skip_check_cert;
|
||||
};
|
||||
|
||||
struct client_dns_server_flags {
|
||||
@@ -95,7 +98,8 @@ struct client_dns_server_flags {
|
||||
int dns_client_spki_decode(const char *spki, unsigned char *spki_data_out);
|
||||
|
||||
/* add remote dns server */
|
||||
int dns_client_add_server(char *server_ip, int port, dns_server_type_t server_type, struct client_dns_server_flags *flags);
|
||||
int dns_client_add_server(char *server_ip, int port, dns_server_type_t server_type,
|
||||
struct client_dns_server_flags *flags);
|
||||
|
||||
/* remove remote dns server */
|
||||
int dns_client_remove_server(char *server_ip, int port, dns_server_type_t server_type);
|
||||
|
||||
140
src/dns_conf.c
140
src/dns_conf.c
@@ -50,6 +50,7 @@ int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
|
||||
int dns_conf_prefetch = 0;
|
||||
int dns_conf_serve_expired = 0;
|
||||
int dns_conf_serve_expired_ttl = 0;
|
||||
int dns_conf_serve_expired_reply_ttl = 5;
|
||||
|
||||
/* upstream servers */
|
||||
struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
@@ -68,6 +69,13 @@ char dns_conf_log_file[DNS_MAX_PATH];
|
||||
size_t dns_conf_log_size = 1024 * 1024;
|
||||
int dns_conf_log_num = 8;
|
||||
|
||||
/* CA file */
|
||||
char dns_conf_ca_file[DNS_MAX_PATH];
|
||||
char dns_conf_ca_path[DNS_MAX_PATH];
|
||||
|
||||
char dns_conf_cache_file[DNS_MAX_PATH];
|
||||
int dns_conf_cache_persist = 2;
|
||||
|
||||
/* auditing */
|
||||
int dns_conf_audit_enable = 0;
|
||||
int dns_conf_audit_log_SOA;
|
||||
@@ -103,6 +111,10 @@ static int _get_domain(char *value, char *domain, int max_dmain_size, char **ptr
|
||||
char *end = NULL;
|
||||
int len = 0;
|
||||
|
||||
if (value == NULL || domain == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* first field */
|
||||
begin = strstr(value, "/");
|
||||
if (begin == NULL) {
|
||||
@@ -246,6 +258,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
{"spki-pin", required_argument, NULL, 'p'}, /* check SPKI pin */
|
||||
{"host-name", required_argument, NULL, 'h'}, /* host name */
|
||||
{"http-host", required_argument, NULL, 'H'}, /* http host */
|
||||
{"no-check-certificate", no_argument, NULL, 'N'}, /* do not check certificate */
|
||||
{"tls-host-verify", required_argument, NULL, 'V' }, /* verify tls hostname */
|
||||
{"group", required_argument, NULL, 'g'}, /* add to group */
|
||||
{"exclude-default-group", no_argument, NULL, 'E'}, /* ecluse this from default group */
|
||||
@@ -257,6 +270,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
return -1;
|
||||
}
|
||||
|
||||
ip = argv[1];
|
||||
if (index >= DNS_MAX_SERVERS) {
|
||||
tlog(TLOG_WARN, "exceeds max server number, %s", ip);
|
||||
return 0;
|
||||
@@ -269,8 +283,6 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
server->httphost[0] = '\0';
|
||||
server->tls_host_verify[0] = '\0';
|
||||
|
||||
ip = argv[1];
|
||||
|
||||
if (type == DNS_SERVER_HTTPS) {
|
||||
if (parse_uri(ip, NULL, server->server, &port, server->path) != 0) {
|
||||
return -1;
|
||||
@@ -340,6 +352,10 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
safe_strncpy(server->tls_host_verify, optarg, DNS_MAX_CNAME_LEN);
|
||||
break;
|
||||
}
|
||||
case 'N': {
|
||||
server->skip_check_cert = 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -466,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;
|
||||
@@ -500,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) {
|
||||
@@ -573,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;
|
||||
}
|
||||
@@ -588,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;
|
||||
}
|
||||
|
||||
@@ -654,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;
|
||||
}
|
||||
|
||||
@@ -671,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;
|
||||
}
|
||||
|
||||
@@ -862,6 +913,7 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ip = argv[1];
|
||||
if (index >= DNS_MAX_SERVERS) {
|
||||
tlog(TLOG_WARN, "exceeds max server number, %s", ip);
|
||||
return 0;
|
||||
@@ -870,7 +922,6 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
|
||||
bind_ip = &dns_conf_bind_ip[index];
|
||||
bind_ip->type = type;
|
||||
bind_ip->flags = 0;
|
||||
ip = argv[1];
|
||||
safe_strncpy(bind_ip->ip, ip, DNS_MAX_IPLEN);
|
||||
|
||||
/* process extra options */
|
||||
@@ -992,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;
|
||||
}
|
||||
|
||||
@@ -1013,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];
|
||||
@@ -1223,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 */
|
||||
@@ -1239,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;
|
||||
}
|
||||
@@ -1297,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;
|
||||
}
|
||||
@@ -1346,9 +1427,12 @@ static struct config_item _config_item[] = {
|
||||
CONF_CUSTOM("speed-check-mode", _config_speed_check_mode, NULL),
|
||||
CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),
|
||||
CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX),
|
||||
CONF_STRING("cache-file", (char *)&dns_conf_cache_file, DNS_MAX_PATH),
|
||||
CONF_YESNO("cache-persist", &dns_conf_cache_persist),
|
||||
CONF_YESNO("prefetch-domain", &dns_conf_prefetch),
|
||||
CONF_YESNO("serve-expired", &dns_conf_serve_expired),
|
||||
CONF_INT("serve-expired-ttl", &dns_conf_serve_expired_ttl, 0, CONF_INT_MAX),
|
||||
CONF_INT("serve-expired-reply-ttl", &dns_conf_serve_expired_reply_ttl, 0, CONF_INT_MAX),
|
||||
CONF_YESNO("dualstack-ip-selection", &dns_conf_dualstack_ip_selection),
|
||||
CONF_INT("dualstack-ip-selection-threshold", &dns_conf_dualstack_ip_selection_threshold, 0, 1000),
|
||||
CONF_CUSTOM("log-level", _config_log_level, NULL),
|
||||
@@ -1370,6 +1454,8 @@ static struct config_item _config_item[] = {
|
||||
CONF_CUSTOM("ignore-ip", _conf_ip_ignore, NULL),
|
||||
CONF_CUSTOM("edns-client-subnet", _conf_edns_client_subnet, NULL),
|
||||
CONF_CUSTOM("domain-rules", _conf_domain_rules, NULL),
|
||||
CONF_STRING("ca-file", (char *)&dns_conf_ca_file, DNS_MAX_PATH),
|
||||
CONF_STRING("ca-path", (char *)&dns_conf_ca_path, DNS_MAX_PATH),
|
||||
CONF_CUSTOM("conf-file", config_addtional_file, NULL),
|
||||
CONF_END(),
|
||||
};
|
||||
@@ -1398,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);
|
||||
|
||||
@@ -49,12 +49,15 @@ extern "C" {
|
||||
#define SMARTDNS_CONF_FILE "/etc/smartdns/smartdns.conf"
|
||||
#define SMARTDNS_LOG_FILE "/var/log/smartdns.log"
|
||||
#define SMARTDNS_AUDIT_FILE "/var/log/smartdns-audit.log"
|
||||
#define SMARTDNS_CACHE_FILE "/tmp/smartdns.cache"
|
||||
|
||||
enum domain_rule {
|
||||
DOMAIN_RULE_FLAGS = 0,
|
||||
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,
|
||||
@@ -77,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)
|
||||
|
||||
@@ -90,10 +96,11 @@ typedef enum {
|
||||
#define BIND_FLAG_NO_SPEED_CHECK (1 << 5)
|
||||
#define BIND_FLAG_NO_CACHE (1 << 6)
|
||||
#define BIND_FLAG_NO_DUALSTACK_SELECTION (1 << 7)
|
||||
#define BIND_FLAG_FORCE_AAAA_SOA (1 << 8)
|
||||
#define BIND_FLAG_FORCE_AAAA_SOA (1 << 8)
|
||||
|
||||
struct dns_rule_flags {
|
||||
unsigned int flags;
|
||||
unsigned int is_flag_set;
|
||||
};
|
||||
|
||||
struct dns_address_IPV4 {
|
||||
@@ -145,6 +152,7 @@ struct dns_servers {
|
||||
unsigned int server_flag;
|
||||
int ttl;
|
||||
dns_server_type_t type;
|
||||
char skip_check_cert;
|
||||
char spki[DNS_MAX_SPKI_LEN];
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
char httphost[DNS_MAX_CNAME_LEN];
|
||||
@@ -203,6 +211,7 @@ extern int dns_conf_cachesize;
|
||||
extern int dns_conf_prefetch;
|
||||
extern int dns_conf_serve_expired;
|
||||
extern int dns_conf_serve_expired_ttl;
|
||||
extern int dns_conf_serve_expired_reply_ttl;
|
||||
extern struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
extern int dns_conf_server_num;
|
||||
|
||||
@@ -211,6 +220,12 @@ extern char dns_conf_log_file[DNS_MAX_PATH];
|
||||
extern size_t dns_conf_log_size;
|
||||
extern int dns_conf_log_num;
|
||||
|
||||
extern char dns_conf_ca_file[DNS_MAX_PATH];
|
||||
extern char dns_conf_ca_path[DNS_MAX_PATH];
|
||||
|
||||
extern char dns_conf_cache_file[DNS_MAX_PATH];
|
||||
extern int dns_conf_cache_persist;
|
||||
|
||||
extern struct dns_domain_check_order dns_conf_check_order;
|
||||
|
||||
extern struct dns_server_groups dns_conf_server_groups[DNS_NAX_GROUP_NUMBER];
|
||||
|
||||
971
src/dns_server.c
971
src/dns_server.c
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@
|
||||
#define _SMART_DNS_SERVER_H
|
||||
|
||||
#include "dns.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C" {
|
||||
@@ -36,10 +37,11 @@ void dns_server_stop(void);
|
||||
void dns_server_exit(void);
|
||||
|
||||
/* query result notify function */
|
||||
typedef int (*dns_result_callback)(char *domain, dns_rtcode_t rtcode, dns_type_t addr_type, char *ip, unsigned int ping_time, void *user_ptr);
|
||||
typedef int (*dns_result_callback)(char *domain, dns_rtcode_t rtcode, dns_type_t addr_type, char *ip,
|
||||
unsigned int ping_time, void *user_ptr);
|
||||
|
||||
/* query domain */
|
||||
int dns_server_query(char *domain, int qtype, dns_result_callback callback, void *user_ptr);
|
||||
int dns_server_query(char *domain, int qtype, uint32_t server_flags, dns_result_callback callback, void *user_ptr);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
|
||||
104
src/fast_ping.c
104
src/fast_ping.c
@@ -219,7 +219,8 @@ static void _fast_ping_install_filter_v4(int sock)
|
||||
}
|
||||
}
|
||||
|
||||
static int _fast_ping_sockaddr_ip_cmp(struct sockaddr *first_addr, socklen_t first_addr_len, struct sockaddr *second_addr, socklen_t second_addr_len)
|
||||
static int _fast_ping_sockaddr_ip_cmp(struct sockaddr *first_addr, socklen_t first_addr_len,
|
||||
struct sockaddr *second_addr, socklen_t second_addr_len)
|
||||
{
|
||||
if (first_addr_len != second_addr_len) {
|
||||
return -1;
|
||||
@@ -379,8 +380,8 @@ static void _fast_ping_host_put(struct ping_host_struct *ping_host)
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len, ping_host->seq, ping_host->ttl, &tv,
|
||||
ping_host->userptr);
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len,
|
||||
ping_host->seq, ping_host->ttl, &tv, ping_host->userptr);
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "ping end, id %d", ping_host->sid);
|
||||
@@ -407,8 +408,8 @@ static void _fast_ping_host_remove(struct ping_host_struct *ping_host)
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len, ping_host->seq, ping_host->ttl, &tv,
|
||||
ping_host->userptr);
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len,
|
||||
ping_host->seq, ping_host->ttl, &tv, ping_host->userptr);
|
||||
}
|
||||
|
||||
_fast_ping_host_put(ping_host);
|
||||
@@ -435,7 +436,8 @@ static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
|
||||
packet->msg.seq = ping_host->seq;
|
||||
icmp6->icmp6_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
|
||||
|
||||
len = sendto(ping.fd_icmp6, &ping_host->packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
||||
len = sendto(ping.fd_icmp6, &ping_host->packet, sizeof(struct fast_ping_packet), 0,
|
||||
(struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
||||
if (len < 0 || len != sizeof(struct fast_ping_packet)) {
|
||||
int err = errno;
|
||||
if (errno == ENETUNREACH || errno == EINVAL) {
|
||||
@@ -450,8 +452,9 @@ static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
|
||||
}
|
||||
|
||||
char ping_host_name[PING_MAX_HOSTLEN];
|
||||
tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, sizeof(ping_host_name), (struct sockaddr *)&ping_host->addr), ping_host->sid,
|
||||
strerror(err));
|
||||
tlog(TLOG_ERROR, "sendto %s, id %d, %s",
|
||||
gethost_by_addr(ping_host_name, sizeof(ping_host_name), (struct sockaddr *)&ping_host->addr),
|
||||
ping_host->sid, strerror(err));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -482,15 +485,17 @@ static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
|
||||
packet->msg.cookie = ping_host->cookie;
|
||||
icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
|
||||
|
||||
len = sendto(ping.fd_icmp, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
||||
len = sendto(ping.fd_icmp, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr,
|
||||
ping_host->addr_len);
|
||||
if (len < 0 || len != sizeof(struct fast_ping_packet)) {
|
||||
int err = errno;
|
||||
if (errno == ENETUNREACH || errno == EINVAL) {
|
||||
goto errout;
|
||||
}
|
||||
char ping_host_name[PING_MAX_HOSTLEN];
|
||||
tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, sizeof(ping_host_name), (struct sockaddr *)&ping_host->addr), ping_host->sid,
|
||||
strerror(err));
|
||||
tlog(TLOG_ERROR, "sendto %s, id %d, %s",
|
||||
gethost_by_addr(ping_host_name, sizeof(ping_host_name), (struct sockaddr *)&ping_host->addr),
|
||||
ping_host->sid, strerror(err));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -535,8 +540,9 @@ static int _fast_ping_sendping_udp(struct ping_host_struct *ping_host)
|
||||
goto errout;
|
||||
}
|
||||
char ping_host_name[PING_MAX_HOSTLEN];
|
||||
tlog(TLOG_ERROR, "sendto %s, id %d, %s", gethost_by_addr(ping_host_name, sizeof(ping_host_name), (struct sockaddr *)&ping_host->addr), ping_host->sid,
|
||||
strerror(err));
|
||||
tlog(TLOG_ERROR, "sendto %s, id %d, %s",
|
||||
gethost_by_addr(ping_host_name, sizeof(ping_host_name), (struct sockaddr *)&ping_host->addr),
|
||||
ping_host->sid, strerror(err));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -567,6 +573,11 @@ static int _fast_ping_sendping_tcp(struct ping_host_struct *ping_host)
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes));
|
||||
setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority));
|
||||
setsockopt(fd, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos));
|
||||
set_sock_keepalive(fd, 0, 0, 0);
|
||||
/* Set the socket lingering so we will RST connections instead of wasting
|
||||
* bandwidth with the four-step close
|
||||
*/
|
||||
set_sock_lingertime(fd, 0);
|
||||
|
||||
ping_host->seq++;
|
||||
if (connect(fd, (struct sockaddr *)&ping_host->addr, ping_host->addr_len) != 0) {
|
||||
@@ -583,7 +594,8 @@ static int _fast_ping_sendping_tcp(struct ping_host_struct *ping_host)
|
||||
bool_print_log = 0;
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "connect %s, id %d, %s", gethost_by_addr(ping_host_name, sizeof(ping_host_name), (struct sockaddr *)&ping_host->addr),
|
||||
tlog(TLOG_ERROR, "connect %s, id %d, %s",
|
||||
gethost_by_addr(ping_host_name, sizeof(ping_host_name), (struct sockaddr *)&ping_host->addr),
|
||||
ping_host->sid, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
@@ -671,8 +683,8 @@ static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type)
|
||||
}
|
||||
|
||||
struct icmp_filter filt;
|
||||
filt.data = ~((1 << ICMP_SOURCE_QUENCH) | (1 << ICMP_DEST_UNREACH) | (1 << ICMP_TIME_EXCEEDED) | (1 << ICMP_PARAMETERPROB) | (1 << ICMP_REDIRECT) |
|
||||
(1 << ICMP_ECHOREPLY));
|
||||
filt.data = ~((1 << ICMP_SOURCE_QUENCH) | (1 << ICMP_DEST_UNREACH) | (1 << ICMP_TIME_EXCEEDED) |
|
||||
(1 << ICMP_PARAMETERPROB) | (1 << ICMP_REDIRECT) | (1 << ICMP_ECHOREPLY));
|
||||
setsockopt(fd, SOL_RAW, ICMP_FILTER, &filt, sizeof filt);
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char *)&buffsize, optlen);
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char *)&buffsize, optlen);
|
||||
@@ -829,8 +841,9 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _fast_ping_print_result(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len,
|
||||
int seqno, int ttl, struct timeval *tv, void *userptr)
|
||||
static void _fast_ping_print_result(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result,
|
||||
struct sockaddr *addr, socklen_t addr_len, int seqno, int ttl, struct timeval *tv,
|
||||
void *userptr)
|
||||
{
|
||||
if (result == PING_RESULT_RESPONSE) {
|
||||
double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0;
|
||||
@@ -842,7 +855,8 @@ static void _fast_ping_print_result(struct ping_host_struct *ping_host, const ch
|
||||
}
|
||||
}
|
||||
|
||||
static int _fast_ping_get_addr_by_icmp(const char *ip_str, int port, struct addrinfo **out_gai, FAST_PING_TYPE *out_ping_type)
|
||||
static int _fast_ping_get_addr_by_icmp(const char *ip_str, int port, struct addrinfo **out_gai,
|
||||
FAST_PING_TYPE *out_ping_type)
|
||||
{
|
||||
struct addrinfo *gai = NULL;
|
||||
int socktype = 0;
|
||||
@@ -891,7 +905,8 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _fast_ping_get_addr_by_tcp(const char *ip_str, int port, struct addrinfo **out_gai, FAST_PING_TYPE *out_ping_type)
|
||||
static int _fast_ping_get_addr_by_tcp(const char *ip_str, int port, struct addrinfo **out_gai,
|
||||
FAST_PING_TYPE *out_ping_type)
|
||||
{
|
||||
struct addrinfo *gai = NULL;
|
||||
int socktype = 0;
|
||||
@@ -926,7 +941,8 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _fast_ping_get_addr_by_dns(const char *ip_str, int port, struct addrinfo **out_gai, FAST_PING_TYPE *out_ping_type)
|
||||
static int _fast_ping_get_addr_by_dns(const char *ip_str, int port, struct addrinfo **out_gai,
|
||||
FAST_PING_TYPE *out_ping_type)
|
||||
{
|
||||
struct addrinfo *gai = NULL;
|
||||
int socktype = 0;
|
||||
@@ -982,7 +998,8 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _fast_ping_get_addr_by_type(PING_TYPE type, const char *ip_str, int port, struct addrinfo **out_gai, FAST_PING_TYPE *out_ping_type)
|
||||
static int _fast_ping_get_addr_by_type(PING_TYPE type, const char *ip_str, int port, struct addrinfo **out_gai,
|
||||
FAST_PING_TYPE *out_ping_type)
|
||||
{
|
||||
switch (type) {
|
||||
case PING_TYPE_ICMP:
|
||||
@@ -1001,14 +1018,15 @@ static int _fast_ping_get_addr_by_type(PING_TYPE type, const char *ip_str, int p
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int count, int interval, int timeout, fast_ping_result ping_callback, void *userptr)
|
||||
struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int count, int interval, int timeout,
|
||||
fast_ping_result ping_callback, void *userptr)
|
||||
{
|
||||
struct ping_host_struct *ping_host = NULL;
|
||||
struct addrinfo *gai = NULL;
|
||||
uint32_t addrkey;
|
||||
char ip_str[PING_MAX_HOSTLEN];
|
||||
int port = -1;
|
||||
FAST_PING_TYPE ping_type;
|
||||
FAST_PING_TYPE ping_type = FAST_PING_END;
|
||||
unsigned int seed;
|
||||
int ret = 0;
|
||||
|
||||
@@ -1106,7 +1124,8 @@ static void tv_sub(struct timeval *out, struct timeval *in)
|
||||
out->tv_sec -= in->tv_sec;
|
||||
}
|
||||
|
||||
static struct fast_ping_packet *_fast_ping_icmp6_packet(struct ping_host_struct *ping_host, struct msghdr *msg, u_char *packet_data, int data_len)
|
||||
static struct fast_ping_packet *_fast_ping_icmp6_packet(struct ping_host_struct *ping_host, struct msghdr *msg,
|
||||
u_char *packet_data, int data_len)
|
||||
{
|
||||
int icmp_len;
|
||||
struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data;
|
||||
@@ -1148,7 +1167,8 @@ static struct fast_ping_packet *_fast_ping_icmp6_packet(struct ping_host_struct
|
||||
return packet;
|
||||
}
|
||||
|
||||
static struct fast_ping_packet *_fast_ping_icmp_packet(struct ping_host_struct *ping_host, struct msghdr *msg, u_char *packet_data, int data_len)
|
||||
static struct fast_ping_packet *_fast_ping_icmp_packet(struct ping_host_struct *ping_host, struct msghdr *msg,
|
||||
u_char *packet_data, int data_len)
|
||||
{
|
||||
struct ip *ip = (struct ip *)packet_data;
|
||||
struct fast_ping_packet *packet;
|
||||
@@ -1185,8 +1205,8 @@ static struct fast_ping_packet *_fast_ping_icmp_packet(struct ping_host_struct *
|
||||
return packet;
|
||||
}
|
||||
|
||||
static struct fast_ping_packet *_fast_ping_recv_packet(struct ping_host_struct *ping_host, struct msghdr *msg, u_char *inpacket, int len,
|
||||
struct timeval *tvrecv)
|
||||
static struct fast_ping_packet *_fast_ping_recv_packet(struct ping_host_struct *ping_host, struct msghdr *msg,
|
||||
u_char *inpacket, int len, struct timeval *tvrecv)
|
||||
{
|
||||
struct fast_ping_packet *packet = NULL;
|
||||
|
||||
@@ -1248,7 +1268,8 @@ static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct ti
|
||||
packet = _fast_ping_recv_packet(ping_host, &msg, inpacket, len, now);
|
||||
if (packet == NULL) {
|
||||
char name[PING_MAX_HOSTLEN];
|
||||
tlog(TLOG_DEBUG, "recv ping packet from %s failed.", gethost_by_addr(name, sizeof(name), (struct sockaddr *)&from));
|
||||
tlog(TLOG_DEBUG, "recv ping packet from %s failed.",
|
||||
gethost_by_addr(name, sizeof(name), (struct sockaddr *)&from));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -1260,7 +1281,8 @@ static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct ti
|
||||
pthread_mutex_lock(&ping.map_lock);
|
||||
hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey)
|
||||
{
|
||||
if (_fast_ping_sockaddr_ip_cmp(&recv_ping_host->addr, recv_ping_host->addr_len, (struct sockaddr *)&from, from_len) == 0 &&
|
||||
if (_fast_ping_sockaddr_ip_cmp(&recv_ping_host->addr, recv_ping_host->addr_len, (struct sockaddr *)&from,
|
||||
from_len) == 0 &&
|
||||
recv_ping_host->sid == sid && recv_ping_host->cookie == cookie) {
|
||||
_fast_ping_host_get(recv_ping_host);
|
||||
break;
|
||||
@@ -1282,8 +1304,9 @@ static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct ti
|
||||
recv_ping_host->ttl = packet->ttl;
|
||||
tv_sub(&tvresult, tvsend);
|
||||
if (recv_ping_host->ping_callback) {
|
||||
recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr, recv_ping_host->addr_len,
|
||||
recv_ping_host->seq, recv_ping_host->ttl, &tvresult, recv_ping_host->userptr);
|
||||
recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr,
|
||||
recv_ping_host->addr_len, recv_ping_host->seq, recv_ping_host->ttl, &tvresult,
|
||||
recv_ping_host->userptr);
|
||||
}
|
||||
|
||||
recv_ping_host->send = 0;
|
||||
@@ -1316,8 +1339,8 @@ static int _fast_ping_process_tcp(struct ping_host_struct *ping_host, struct epo
|
||||
}
|
||||
tv_sub(&tvresult, tvsend);
|
||||
if (ping_host->ping_callback) {
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr, ping_host->addr_len, ping_host->seq, ping_host->ttl,
|
||||
&tvresult, ping_host->userptr);
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr,
|
||||
ping_host->addr_len, ping_host->seq, ping_host->ttl, &tvresult, ping_host->userptr);
|
||||
}
|
||||
|
||||
ping_host->send = 0;
|
||||
@@ -1393,7 +1416,8 @@ static int _fast_ping_process_udp(struct ping_host_struct *ping_host, struct tim
|
||||
pthread_mutex_lock(&ping.map_lock);
|
||||
hash_for_each_possible(ping.addrmap, recv_ping_host, addr_node, addrkey)
|
||||
{
|
||||
if (_fast_ping_sockaddr_ip_cmp(&recv_ping_host->addr, recv_ping_host->addr_len, (struct sockaddr *)&from, from_len) == 0 &&
|
||||
if (_fast_ping_sockaddr_ip_cmp(&recv_ping_host->addr, recv_ping_host->addr_len, (struct sockaddr *)&from,
|
||||
from_len) == 0 &&
|
||||
recv_ping_host->sid == sid) {
|
||||
_fast_ping_host_get(recv_ping_host);
|
||||
break;
|
||||
@@ -1410,8 +1434,9 @@ static int _fast_ping_process_udp(struct ping_host_struct *ping_host, struct tim
|
||||
tvsend = &recv_ping_host->last;
|
||||
tv_sub(&tvresult, tvsend);
|
||||
if (recv_ping_host->ping_callback) {
|
||||
recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr, recv_ping_host->addr_len,
|
||||
recv_ping_host->seq, recv_ping_host->ttl, &tvresult, recv_ping_host->userptr);
|
||||
recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr,
|
||||
recv_ping_host->addr_len, recv_ping_host->seq, recv_ping_host->ttl, &tvresult,
|
||||
recv_ping_host->userptr);
|
||||
}
|
||||
|
||||
recv_ping_host->send = 0;
|
||||
@@ -1518,8 +1543,9 @@ static void _fast_ping_period_run(void)
|
||||
tv_sub(&interval, &ping_host->last);
|
||||
millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000;
|
||||
if (millisecond >= ping_host->timeout && ping_host->send == 1) {
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr, ping_host->addr_len, ping_host->seq, ping_host->ttl,
|
||||
&interval, ping_host->userptr);
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr,
|
||||
ping_host->addr_len, ping_host->seq, ping_host->ttl, &interval,
|
||||
ping_host->userptr);
|
||||
ping_host->send = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,13 @@ typedef enum {
|
||||
} FAST_PING_RESULT;
|
||||
|
||||
struct ping_host_struct;
|
||||
typedef void (*fast_ping_result)(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len,
|
||||
int seqno, int ttl, struct timeval *tv, void *userptr);
|
||||
typedef void (*fast_ping_result)(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result,
|
||||
struct sockaddr *addr, socklen_t addr_len, int seqno, int ttl, struct timeval *tv,
|
||||
void *userptr);
|
||||
|
||||
/* start ping */
|
||||
struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int count, int interval, int timeout, fast_ping_result ping_callback, void *userptr);
|
||||
struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int count, int interval, int timeout,
|
||||
fast_ping_result ping_callback, void *userptr);
|
||||
|
||||
/* stop ping */
|
||||
int fast_ping_stop(struct ping_host_struct *ping_host);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "http_parse.h"
|
||||
#include "hash.h"
|
||||
#include "hashtable.h"
|
||||
#include "util.h"
|
||||
#include "jhash.h"
|
||||
#include "list.h"
|
||||
#include <stdlib.h>
|
||||
@@ -214,7 +215,7 @@ static int _http_head_parse_response(struct http_head *http_head, char *key, cha
|
||||
{
|
||||
char *field_start = NULL;
|
||||
char *tmp_ptr = NULL;
|
||||
char *result = NULL;
|
||||
char *ret_msg = NULL;
|
||||
char *ret_code = NULL;
|
||||
|
||||
if (strstr(key, "HTTP/") == NULL) {
|
||||
@@ -226,29 +227,27 @@ static int _http_head_parse_response(struct http_head *http_head, char *key, cha
|
||||
field_start = tmp_ptr;
|
||||
}
|
||||
|
||||
if (*tmp_ptr == ' ') {
|
||||
*tmp_ptr = '\0';
|
||||
if (ret_code == NULL) {
|
||||
ret_code = field_start;
|
||||
} else if (result == NULL) {
|
||||
result = field_start;
|
||||
break;
|
||||
}
|
||||
|
||||
field_start = NULL;
|
||||
if (*tmp_ptr != ' ') {
|
||||
continue;
|
||||
}
|
||||
|
||||
*tmp_ptr = '\0';
|
||||
ret_code = field_start;
|
||||
ret_msg = tmp_ptr + 1;
|
||||
field_start = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (field_start && result == NULL) {
|
||||
result = field_start;
|
||||
if (ret_code == NULL || ret_msg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret_code == NULL || result == NULL) {
|
||||
if (is_numeric(ret_code) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
http_head->code = atol(ret_code);
|
||||
http_head->code_msg = result;
|
||||
http_head->code_msg = ret_msg;
|
||||
http_head->version = key;
|
||||
http_head->head_type = HTTP_HEAD_RESPONSE;
|
||||
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
#ifndef _GENERIC_ATOMIC_H
|
||||
#define _GENERIC_ATOMIC_H
|
||||
|
||||
|
||||
/* Check GCC version, just to be safe */
|
||||
#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC_MINOR__ < 1)
|
||||
# error atomic.h works only with GCC newer than version 4.1
|
||||
#endif /* GNUC >= 4.1 */
|
||||
|
||||
/**
|
||||
* Atomic type.
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _GENERIC_CONF_H
|
||||
#define _GENERIC_CONF_H
|
||||
|
||||
@@ -27,9 +26,9 @@
|
||||
#define CONF_INT_MAX (~(1 << 31))
|
||||
#define CONF_INT_MIN (1 << 31)
|
||||
|
||||
#define CONF_RET_OK 0
|
||||
#define CONF_RET_ERR -1
|
||||
#define CONF_RET_WARN -2
|
||||
#define CONF_RET_OK 0
|
||||
#define CONF_RET_ERR -1
|
||||
#define CONF_RET_WARN -2
|
||||
#define CONF_RET_NOENT -3
|
||||
|
||||
struct config_item {
|
||||
@@ -64,48 +63,48 @@ struct config_item_size {
|
||||
size_t max;
|
||||
};
|
||||
|
||||
#define CONF_INT(key, value, min_value, max_value) \
|
||||
{ \
|
||||
key, conf_int, &(struct config_item_int) \
|
||||
{ \
|
||||
.data = value, .min = min_value, .max = max_value \
|
||||
} \
|
||||
#define CONF_INT(key, value, min_value, max_value) \
|
||||
{ \
|
||||
key, conf_int, &(struct config_item_int) \
|
||||
{ \
|
||||
.data = value, .min = min_value, .max = max_value \
|
||||
} \
|
||||
}
|
||||
#define CONF_STRING(key, value, len_value) \
|
||||
{ \
|
||||
key, conf_string, &(struct config_item_string) \
|
||||
{ \
|
||||
.data = value, .size = len_value \
|
||||
} \
|
||||
#define CONF_STRING(key, value, len_value) \
|
||||
{ \
|
||||
key, conf_string, &(struct config_item_string) \
|
||||
{ \
|
||||
.data = value, .size = len_value \
|
||||
} \
|
||||
}
|
||||
#define CONF_YESNO(key, value) \
|
||||
{ \
|
||||
key, conf_yesno, &(struct config_item_yesno) \
|
||||
{ \
|
||||
.data = value \
|
||||
} \
|
||||
#define CONF_YESNO(key, value) \
|
||||
{ \
|
||||
key, conf_yesno, &(struct config_item_yesno) \
|
||||
{ \
|
||||
.data = value \
|
||||
} \
|
||||
}
|
||||
#define CONF_SIZE(key, value, min_value, max_value) \
|
||||
{ \
|
||||
key, conf_size, &(struct config_item_size) \
|
||||
{ \
|
||||
.data = value, .min = min_value, .max = max_value \
|
||||
} \
|
||||
#define CONF_SIZE(key, value, min_value, max_value) \
|
||||
{ \
|
||||
key, conf_size, &(struct config_item_size) \
|
||||
{ \
|
||||
.data = value, .min = min_value, .max = max_value \
|
||||
} \
|
||||
}
|
||||
/*
|
||||
* func: int (*func)(void *data, int argc, char *argv[]);
|
||||
*/
|
||||
#define CONF_CUSTOM(key, func, data) \
|
||||
{ \
|
||||
key, conf_custom, &(struct config_item_custom) \
|
||||
{ \
|
||||
.custom_data = data, .custom_func = func \
|
||||
} \
|
||||
#define CONF_CUSTOM(key, func, data) \
|
||||
{ \
|
||||
key, conf_custom, &(struct config_item_custom) \
|
||||
{ \
|
||||
.custom_data = data, .custom_func = func \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CONF_END() \
|
||||
{ \
|
||||
NULL, NULL, NULL \
|
||||
#define CONF_END() \
|
||||
{ \
|
||||
NULL, NULL, NULL \
|
||||
}
|
||||
|
||||
extern int conf_custom(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
@@ -79,7 +79,8 @@ static void _show_version(void)
|
||||
#else
|
||||
struct tm tm;
|
||||
get_compiled_time(&tm);
|
||||
snprintf(str_ver, sizeof(str_ver), "1.%.4d%.2d%.2d-%.2d%.2d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min);
|
||||
snprintf(str_ver, sizeof(str_ver), "1.%.4d%.2d%.2d-%.2d%.2d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min);
|
||||
#endif
|
||||
printf("smartdns %s\n", str_ver);
|
||||
}
|
||||
@@ -157,13 +158,18 @@ static int _smartdns_add_servers(void)
|
||||
safe_strncpy(flag_http->hostname, dns_conf_servers[i].hostname, sizeof(flag_http->hostname));
|
||||
safe_strncpy(flag_http->path, dns_conf_servers[i].path, sizeof(flag_http->path));
|
||||
safe_strncpy(flag_http->httphost, dns_conf_servers[i].httphost, sizeof(flag_http->httphost));
|
||||
safe_strncpy(flag_http->tls_host_verify, dns_conf_servers[i].tls_host_verify, sizeof(flag_http->tls_host_verify));
|
||||
safe_strncpy(flag_http->tls_host_verify, dns_conf_servers[i].tls_host_verify,
|
||||
sizeof(flag_http->tls_host_verify));
|
||||
flag_http->skip_check_cert = dns_conf_servers[i].skip_check_cert;
|
||||
} break;
|
||||
case DNS_SERVER_TLS: {
|
||||
struct client_dns_server_flag_tls *flag_tls = &flags.tls;
|
||||
flag_tls->spi_len = dns_client_spki_decode(dns_conf_servers[i].spki, (unsigned char *)flag_tls->spki);
|
||||
safe_strncpy(flag_tls->hostname, dns_conf_servers[i].hostname, sizeof(flag_tls->hostname));
|
||||
safe_strncpy(flag_tls->tls_host_verify, dns_conf_servers[i].tls_host_verify, sizeof(flag_tls->tls_host_verify));
|
||||
safe_strncpy(flag_tls->tls_host_verify, dns_conf_servers[i].tls_host_verify,
|
||||
sizeof(flag_tls->tls_host_verify));
|
||||
flag_tls->skip_check_cert = dns_conf_servers[i].skip_check_cert;
|
||||
|
||||
} break;
|
||||
case DNS_SERVER_TCP:
|
||||
break;
|
||||
@@ -175,7 +181,8 @@ static int _smartdns_add_servers(void)
|
||||
flags.type = dns_conf_servers[i].type;
|
||||
flags.server_flag = dns_conf_servers[i].server_flag;
|
||||
flags.result_flag = dns_conf_servers[i].result_flag;
|
||||
ret = dns_client_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type, &flags);
|
||||
ret = dns_client_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type,
|
||||
&flags);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "add server failed, %s:%d", dns_conf_servers[i].server, dns_conf_servers[i].port);
|
||||
return -1;
|
||||
@@ -259,7 +266,8 @@ static int _smartdns_init(void)
|
||||
tlog_setlogscreen(verbose_screen);
|
||||
tlog_setlevel(dns_conf_log_level);
|
||||
|
||||
tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <pymumu@gmail.com>, build:%s %s)", __DATE__, __TIME__);
|
||||
tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <pymumu@gmail.com>, build:%s %s)", __DATE__,
|
||||
__TIME__);
|
||||
|
||||
if (_smartdns_init_ssl() != 0) {
|
||||
tlog(TLOG_ERROR, "init ssl failed.");
|
||||
@@ -331,21 +339,30 @@ static void _sig_error_exit(int signo, siginfo_t *siginfo, void *ct)
|
||||
{
|
||||
unsigned long PC = 0;
|
||||
ucontext_t *context = ct;
|
||||
const char *arch = NULL;
|
||||
#if defined(__i386__)
|
||||
int *pgregs = (int *)(&(context->uc_mcontext.gregs));
|
||||
PC = pgregs[REG_EIP];
|
||||
arch = "i386";
|
||||
#elif defined(__x86_64__)
|
||||
int *pgregs = (int *)(&(context->uc_mcontext.gregs));
|
||||
PC = pgregs[REG_RIP];
|
||||
arch = "x86_64";
|
||||
#elif defined(__arm__)
|
||||
PC = context->uc_mcontext.arm_pc;
|
||||
arch = "arm";
|
||||
#elif defined(__aarch64__)
|
||||
PC = context->uc_mcontext.pc;
|
||||
arch = "arm64";
|
||||
#elif defined(__mips__)
|
||||
PC = context->uc_mcontext.pc;
|
||||
arch = "mips";
|
||||
#endif
|
||||
tlog(TLOG_FATAL, "process exit with signal %d, code = %d, errno = %d, pid = %d, self = %d, pc = %#lx, addr = %#lx, build(%s %s)\n", signo, siginfo->si_code,
|
||||
siginfo->si_errno, siginfo->si_pid, getpid(), PC, (unsigned long)siginfo->si_addr, __DATE__, __TIME__);
|
||||
tlog(TLOG_FATAL,
|
||||
"process exit with signal %d, code = %d, errno = %d, pid = %d, self = %d, pc = %#lx, addr = %#lx, build(%s "
|
||||
"%s %s)\n",
|
||||
signo, siginfo->si_code, siginfo->si_errno, siginfo->si_pid, getpid(), PC, (unsigned long)siginfo->si_addr,
|
||||
__DATE__, __TIME__, arch);
|
||||
|
||||
sleep(1);
|
||||
_exit(0);
|
||||
@@ -422,6 +439,7 @@ int main(int argc, char *argv[])
|
||||
goto errout;
|
||||
}
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
if (dns_server_load_conf(config_file) != 0) {
|
||||
fprintf(stderr, "load config failed.\n");
|
||||
goto errout;
|
||||
@@ -434,7 +452,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
signal(SIGINT, _sig_exit);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGTERM, _sig_exit);
|
||||
atexit(_smartdns_exit);
|
||||
|
||||
return _smartdns_run();
|
||||
|
||||
246
src/tlog.c
246
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;
|
||||
@@ -94,16 +102,16 @@ struct tlog {
|
||||
};
|
||||
|
||||
struct tlog_segment_log_head {
|
||||
struct tlog_info info;
|
||||
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];
|
||||
@@ -117,7 +125,7 @@ struct count_log {
|
||||
};
|
||||
|
||||
struct tlog_info_inter {
|
||||
struct tlog_info info;
|
||||
struct tlog_loginfo info;
|
||||
void *userptr;
|
||||
};
|
||||
|
||||
@@ -167,6 +175,10 @@ static int _tlog_mkdir(const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*path == ' ' && *path != '\0') {
|
||||
path++;
|
||||
}
|
||||
|
||||
strncpy(path_c, path, sizeof(path_c) - 1);
|
||||
path_c[sizeof(path_c) - 1] = '\0';
|
||||
len = strnlen(path_c, sizeof(path_c) - 1);
|
||||
@@ -181,6 +193,11 @@ static int _tlog_mkdir(const char *path)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (path_end == path_c) {
|
||||
path_end++;
|
||||
continue;
|
||||
}
|
||||
|
||||
str = *path_end;
|
||||
*path_end = '\0';
|
||||
if (access(path_c, F_OK) == 0) {
|
||||
@@ -203,8 +220,8 @@ static int _tlog_mkdir(const char *path)
|
||||
|
||||
static struct tm *_tlog_localtime(time_t *timep, struct tm *tm)
|
||||
{
|
||||
static time_t last_time = {0};
|
||||
static struct tm last_tm = {0};
|
||||
static time_t last_time;
|
||||
static struct tm last_tm;
|
||||
|
||||
/* localtime_r has a global timezone lock, it's about 8 times slower than gmtime
|
||||
* this code is used to speed up localtime_r call.
|
||||
@@ -274,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) {
|
||||
@@ -297,21 +340,24 @@ void *tlog_get_private(tlog_log *log)
|
||||
return log->private_data;
|
||||
}
|
||||
|
||||
static int _tlog_format(char *buff, int maxlen, struct tlog_info *info, void *userptr, const char *format, va_list ap)
|
||||
static int _tlog_format(char *buff, int maxlen, struct tlog_loginfo *info, void *userptr, const char *format, va_list ap)
|
||||
{
|
||||
int len = 0;
|
||||
int total_len = 0;
|
||||
struct tlog_time *tm = &info->time;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -347,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));
|
||||
}
|
||||
@@ -388,6 +434,9 @@ static int _tlog_print_buffer(char *buff, int maxlen, void *userptr, const char
|
||||
{
|
||||
int len;
|
||||
int total_len = 0;
|
||||
void *unused __attribute__((unused));
|
||||
|
||||
unused = userptr;
|
||||
|
||||
/* format log message */
|
||||
len = vsnprintf(buff, maxlen, format, ap);
|
||||
@@ -423,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;
|
||||
}
|
||||
@@ -435,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;
|
||||
}
|
||||
@@ -454,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));
|
||||
@@ -475,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);
|
||||
@@ -487,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++;
|
||||
@@ -501,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);
|
||||
@@ -517,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;
|
||||
}
|
||||
@@ -547,11 +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];
|
||||
int len = 0;
|
||||
int out_len = 0;
|
||||
size_t len = 0;
|
||||
size_t out_len = 0;
|
||||
int unused __attribute__((unused));
|
||||
|
||||
if (tlog_disable_early_print) {
|
||||
return 0;
|
||||
@@ -565,9 +615,9 @@ static int _tlog_early_print(const char *format, va_list ap)
|
||||
out_len = sizeof(log_buf);
|
||||
}
|
||||
|
||||
write(STDOUT_FILENO, log_buf, out_len);
|
||||
unused = write(STDOUT_FILENO, log_buf, out_len);
|
||||
if (log_buf[out_len - 1] != '\n') {
|
||||
write(STDOUT_FILENO, "\n", 1);
|
||||
unused = write(STDOUT_FILENO, "\n", 1);
|
||||
}
|
||||
|
||||
return len;
|
||||
@@ -627,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);
|
||||
}
|
||||
@@ -642,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;
|
||||
}
|
||||
|
||||
@@ -650,6 +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;
|
||||
|
||||
dir = opendir(path);
|
||||
if (dir == NULL) {
|
||||
@@ -682,6 +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;
|
||||
|
||||
if (strstr(entry->d_name, log->suffix) == NULL) {
|
||||
return 0;
|
||||
@@ -1005,17 +1059,43 @@ static int _tlog_archive_log(struct tlog_log *log)
|
||||
}
|
||||
}
|
||||
|
||||
static int _tlog_write(struct tlog_log *log, char *buff, int bufflen)
|
||||
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));
|
||||
|
||||
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) {
|
||||
write(STDOUT_FILENO, buff, bufflen);
|
||||
unused = write(STDOUT_FILENO, buff, bufflen);
|
||||
}
|
||||
|
||||
/* if log file size exceeds threshold, start to compress */
|
||||
@@ -1027,7 +1107,7 @@ static int _tlog_write(struct tlog_log *log, char *buff, int bufflen)
|
||||
if (log->filesize < lseek(log->fd, 0, SEEK_END) && log->multi_log == 0) {
|
||||
const char *msg = "[Auto enable multi-process write mode, log may be lost, please enable multi-process write mode manually]\n";
|
||||
log->multi_log = 1;
|
||||
write(log->fd, msg, strlen(msg));
|
||||
unused = write(log->fd, msg, strlen(msg));
|
||||
}
|
||||
close(log->fd);
|
||||
log->fd = -1;
|
||||
@@ -1053,7 +1133,7 @@ static int _tlog_write(struct tlog_log *log, 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;
|
||||
@@ -1083,7 +1163,7 @@ static int _tlog_write(struct tlog_log *log, char *buff, int bufflen)
|
||||
return len;
|
||||
}
|
||||
|
||||
int tlog_write(struct tlog_log *log, char *buff, int bufflen)
|
||||
int tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
{
|
||||
return _tlog_write(log, buff, bufflen);
|
||||
}
|
||||
@@ -1112,7 +1192,6 @@ static int _tlog_any_has_data_locked(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int _tlog_any_has_data(void)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -1143,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);
|
||||
@@ -1244,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;
|
||||
@@ -1297,7 +1375,7 @@ static void _tlog_work_write(struct tlog_log *log, int log_len, int log_extlen,
|
||||
}
|
||||
}
|
||||
|
||||
static int _tlog_root_write_log(struct tlog_log *log, char *buff, int bufflen)
|
||||
static int _tlog_root_write_log(struct tlog_log *log, const char *buff, int bufflen)
|
||||
{
|
||||
struct tlog_segment_log_head *head = NULL;
|
||||
static struct tlog_segment_log_head empty_info;
|
||||
@@ -1326,6 +1404,9 @@ 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));
|
||||
|
||||
unused = arg;
|
||||
|
||||
while (1) {
|
||||
log_len = 0;
|
||||
@@ -1355,7 +1436,7 @@ static void *_tlog_work(void *arg)
|
||||
log = _tlog_wait_log_locked(log);
|
||||
if (log == NULL) {
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
if (errno != ETIMEDOUT) {
|
||||
if (errno != ETIMEDOUT && tlog.run) {
|
||||
sleep(1);
|
||||
}
|
||||
continue;
|
||||
@@ -1408,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)
|
||||
@@ -1491,10 +1572,19 @@ int tlog_setlevel(tlog_level level)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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.");
|
||||
@@ -1519,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 {
|
||||
@@ -1578,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;
|
||||
@@ -1589,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;
|
||||
}
|
||||
@@ -1618,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) {
|
||||
|
||||
131
src/tlog.h
131
src/tlog.h
@@ -1,14 +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 <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
extern "C" {
|
||||
#endif /*__cplusplus */
|
||||
|
||||
@@ -55,7 +61,10 @@ struct tlog_time {
|
||||
/* enable log to screen */
|
||||
#define TLOG_SCREEN (1 << 4)
|
||||
|
||||
struct tlog_info {
|
||||
/* enable suppport fork process */
|
||||
#define TLOG_SUPPORT_FORK (1 << 5)
|
||||
|
||||
struct tlog_loginfo {
|
||||
tlog_level level;
|
||||
const char *file;
|
||||
const char *func;
|
||||
@@ -74,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 */
|
||||
@@ -83,6 +92,12 @@ extern int tlog_write_log(char *buff, int bufflen);
|
||||
/* set log level */
|
||||
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);
|
||||
|
||||
@@ -113,17 +128,21 @@ steps:
|
||||
|
||||
read _tlog_format for example.
|
||||
*/
|
||||
typedef int (*tlog_format_func)(char *buff, int maxlen, struct tlog_info *info, void *userptr, const char *format, va_list ap);
|
||||
typedef int (*tlog_format_func)(char *buff, int maxlen, struct tlog_loginfo *info, void *userptr, const char *format, va_list ap);
|
||||
extern int tlog_reg_format_func(tlog_format_func func);
|
||||
|
||||
/* register log output callback
|
||||
Note: info is invalid when flag TLOG_SEGMENT is not set.
|
||||
*/
|
||||
typedef int (*tlog_log_output_func)(struct tlog_info *info, char *buff, int bufflen, void *private_data);
|
||||
typedef int (*tlog_log_output_func)(struct tlog_loginfo *info, const char *buff, int bufflen, void *private_data);
|
||||
extern int tlog_reg_log_output_func(tlog_log_output_func output, void *private_data);
|
||||
|
||||
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.
|
||||
@@ -132,21 +151,24 @@ maxlogcount: Number of archived logs.
|
||||
buffsize: Buffer size, zero for default (128K)
|
||||
flag: read tlog flags
|
||||
return: log stream handler.
|
||||
*/
|
||||
*/
|
||||
extern tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag);
|
||||
|
||||
/* write buff to log file */
|
||||
extern int tlog_write(struct tlog_log *log, char *buff, int bufflen);
|
||||
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
|
||||
@@ -160,7 +182,7 @@ extern int tlog_vprintf(tlog_log *log, const char *format, va_list ap);
|
||||
extern void tlog_logscreen(tlog_log *log, int enable);
|
||||
|
||||
/* register output callback */
|
||||
typedef int (*tlog_output_func)(struct tlog_log *log, char *buff, int bufflen);
|
||||
typedef int (*tlog_output_func)(struct tlog_log *log, const char *buff, int bufflen);
|
||||
extern int tlog_reg_output_func(tlog_log *log, tlog_output_func output);
|
||||
|
||||
/* set private data */
|
||||
@@ -172,7 +194,94 @@ 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
|
||||
}
|
||||
#endif /*__cplusplus */
|
||||
class Tlog {
|
||||
public:
|
||||
Tlog(tlog_level level, const char *file, int line, const char *func, void *userptr)
|
||||
{
|
||||
level_ = level;
|
||||
file_ = file;
|
||||
line_ = line;
|
||||
func_ = func;
|
||||
userptr_ = userptr;
|
||||
}
|
||||
|
||||
~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 {
|
||||
public:
|
||||
TlogOut(tlog_log *log)
|
||||
{
|
||||
log_ = log;
|
||||
}
|
||||
|
||||
~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_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)
|
||||
#define tlog_warn Tlog_stream(TLOG_WARN)
|
||||
#define tlog_error Tlog_stream(TLOG_ERROR)
|
||||
#define tlog_fatal Tlog_stream(TLOG_FATAL)
|
||||
|
||||
#define tlog_out(stream) TlogOut(stream).Stream()
|
||||
|
||||
} /*__cplusplus */
|
||||
#else
|
||||
#define tlog_debug(...) tlog(TLOG_DEBUG, ##__VA_ARGS__)
|
||||
#define tlog_info(...) tlog(TLOG_INFO, ##__VA_ARGS__)
|
||||
#define tlog_notice(...) tlog(TLOG_NOTICE, ##__VA_ARGS__)
|
||||
#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 // !TLOG_H
|
||||
|
||||
91
src/util.c
91
src/util.c
@@ -24,20 +24,21 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <pthread.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#define TMP_BUFF_LEN_32 32
|
||||
|
||||
@@ -285,14 +286,14 @@ int parse_ip(const char *value, char *ip, int *port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _check_is_ipv4(const char *ip)
|
||||
static int _check_is_ipv4(const char *ip)
|
||||
{
|
||||
const char *ptr = ip;
|
||||
char c = 0;
|
||||
int dot_num = 0;
|
||||
int dig_num = 0;
|
||||
|
||||
while ( (c = *ptr++) != '\0') {
|
||||
while ((c = *ptr++) != '\0') {
|
||||
if (c == '.') {
|
||||
dot_num++;
|
||||
dig_num = 0;
|
||||
@@ -326,7 +327,7 @@ static int _check_is_ipv6(const char *ip)
|
||||
int colon_num = 0;
|
||||
int dig_num = 0;
|
||||
|
||||
while ( (c = *ptr++) != '\0') {
|
||||
while ((c = *ptr++) != '\0') {
|
||||
if (c == '[' || c == ']') {
|
||||
continue;
|
||||
}
|
||||
@@ -420,7 +421,7 @@ int parse_uri(char *value, char *scheme, char *host, int *port, char *path)
|
||||
|
||||
if (path) {
|
||||
strncpy(path, process_ptr, PATH_MAX);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -456,8 +457,8 @@ char *reverse_string(char *output, const char *input, int len, int to_lower_case
|
||||
if (to_lower_case) {
|
||||
if (*output >= 'A' && *output <= 'Z') {
|
||||
/* To lower case */
|
||||
*output = *output + 32;
|
||||
}
|
||||
*output = *output + 32;
|
||||
}
|
||||
}
|
||||
output++;
|
||||
len--;
|
||||
@@ -502,7 +503,8 @@ static int _ipset_support_timeout(const char *ipsetname)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout, int operate)
|
||||
static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout,
|
||||
int operate)
|
||||
{
|
||||
struct nlmsghdr *netlink_head;
|
||||
struct ipset_netlink_msg *netlink_msg;
|
||||
@@ -560,7 +562,9 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int
|
||||
netlink_head->nlmsg_len += NETLINK_ALIGN(sizeof(struct ipset_netlink_attr));
|
||||
nested[1]->type = NLA_F_NESTED | IPSET_ATTR_IP;
|
||||
|
||||
_ipset_add_attr(netlink_head, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, addr_len, addr);
|
||||
_ipset_add_attr(netlink_head,
|
||||
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, addr_len,
|
||||
addr);
|
||||
nested[1]->len = (void *)buffer + NETLINK_ALIGN(netlink_head->nlmsg_len) - (void *)nested[1];
|
||||
|
||||
if (timeout > 0 && _ipset_support_timeout(ipsetname) == 0) {
|
||||
@@ -925,25 +929,35 @@ static int parse_server_name_extension(const char *data, size_t data_len, char *
|
||||
return -2;
|
||||
}
|
||||
|
||||
void get_compiled_time(struct tm *tm)
|
||||
{
|
||||
char s_month[5];
|
||||
int month, day, year;
|
||||
void get_compiled_time(struct tm *tm)
|
||||
{
|
||||
char s_month[5];
|
||||
int month, day, year;
|
||||
int hour, min, sec;
|
||||
static const char *month_names = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
static const char *month_names = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
|
||||
sscanf(__DATE__, "%5s %d %d", s_month, &day, &year);
|
||||
month = (strstr(month_names, s_month) - month_names) / 3;
|
||||
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;
|
||||
tm->tm_mon = month;
|
||||
tm->tm_mday = day;
|
||||
tm->tm_isdst = -1;
|
||||
tm->tm_year = year - 1900;
|
||||
tm->tm_mon = month;
|
||||
tm->tm_mday = day;
|
||||
tm->tm_isdst = -1;
|
||||
tm->tm_hour = hour;
|
||||
tm->tm_min = min;
|
||||
tm->tm_sec = sec;
|
||||
}
|
||||
|
||||
int is_numeric(const char *str)
|
||||
{
|
||||
while (*str != '\0') {
|
||||
if (*str < '0' || *str > '9')
|
||||
return -1;
|
||||
str++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int has_network_raw_cap(void)
|
||||
{
|
||||
int fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||
@@ -958,7 +972,7 @@ int has_network_raw_cap(void)
|
||||
int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt)
|
||||
{
|
||||
const int yes = 1;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes))!= 0) {
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -967,4 +981,31 @@ int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt)
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepcnt, sizeof(keepcnt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int set_sock_lingertime(int fd, int time)
|
||||
{
|
||||
struct linger l;
|
||||
|
||||
l.l_onoff = 1;
|
||||
l.l_linger = 0;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (const char *)&l, sizeof(l)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t get_free_space(const char *path)
|
||||
{
|
||||
uint64_t size = 0;
|
||||
struct statvfs buf;
|
||||
if (statvfs(path, &buf) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = (uint64_t)buf.f_frsize * buf.f_bavail;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
14
src/util.h
14
src/util.h
@@ -19,27 +19,27 @@
|
||||
#ifndef SMART_DNS_UTIL_H
|
||||
#define SMART_DNS_UTIL_H
|
||||
|
||||
#include "stringutil.h"
|
||||
#include <netdb.h>
|
||||
#include <time.h>
|
||||
#include "stringutil.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /*__cplusplus */
|
||||
|
||||
#ifndef TCP_FASTOPEN
|
||||
#define TCP_FASTOPEN 23
|
||||
#define TCP_FASTOPEN 23
|
||||
#endif
|
||||
|
||||
#ifndef TCP_FASTOPEN_CONNECT
|
||||
#define TCP_FASTOPEN_CONNECT 30
|
||||
#endif
|
||||
#ifndef TCP_THIN_LINEAR_TIMEOUTS
|
||||
#define TCP_THIN_LINEAR_TIMEOUTS 16
|
||||
#define TCP_THIN_LINEAR_TIMEOUTS 16
|
||||
#endif
|
||||
|
||||
#ifndef TCP_THIN_DUPACK
|
||||
#define TCP_THIN_DUPACK 17
|
||||
#define TCP_THIN_DUPACK 17
|
||||
#endif
|
||||
|
||||
#define PORT_NOT_DEFINED -1
|
||||
@@ -98,10 +98,16 @@ int parse_tls_header(const char *data, size_t data_len, char *hostname, const ch
|
||||
|
||||
void get_compiled_time(struct tm *tm);
|
||||
|
||||
int is_numeric(const char *str);
|
||||
|
||||
int has_network_raw_cap(void);
|
||||
|
||||
int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt);
|
||||
|
||||
int set_sock_lingertime(int fd, int time);
|
||||
|
||||
uint64_t get_free_space(const char *path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus */
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
[Unit]
|
||||
Description=smart dns server
|
||||
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 $SMART_DNS_OPTS
|
||||
PIDFile=@RUNSTATEDIR@/smartdns.pid
|
||||
EnvironmentFile=@SYSCONFDIR@/default/smartdns
|
||||
ExecStart=@SBINDIR@/smartdns -p @RUNSTATEDIR@/smartdns.pid $SMART_DNS_OPTS
|
||||
KillMode=process
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
StartLimitBurst=0
|
||||
StartLimitIntervalSec=60
|
||||
TimeoutStopSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user