Compare commits

..

15 Commits

Author SHA1 Message Date
Nick Peng
60a3719ec7 dns_server: fix local ttl issue 2023-03-04 11:21:48 +08:00
Nick Peng
e897788098 readme: update readme 2023-03-03 21:31:11 +08:00
Nick Peng
1ef9da847d dns-server: fix cname rule issue 2023-03-03 21:09:27 +08:00
Nick Peng
66b86e1a8b dns-server: fix cname & dualstack issue 2023-03-02 23:20:25 +08:00
Nick Peng
95f843dc43 dns-server: fix rr-ttl-* priority issue 2023-03-01 19:53:22 +08:00
Nick Peng
6827554def dns-server: fix dns64 issue & cname dns-group-issue 2023-02-28 23:40:05 +08:00
Nick Peng
e8eddabc85 dns_client: force close server failure after 60s. 2023-02-27 00:09:33 +08:00
Nick Peng
15636c355a fast-ping: fix fast-ping issue 2023-02-26 22:59:57 +08:00
Nick Peng
b473b9c6e1 ReadMe: update some typo 2023-02-24 19:52:38 +08:00
Nick Peng
2ca4c92c9f dns-client: allow same upstream server with different proxy. 2023-02-22 21:55:07 +08:00
Nick Peng
e3271b07c4 tlog: update tlog 2023-02-22 21:54:16 +08:00
Nick Peng
c5ca3ccf43 luci: add dns64 option 2023-02-21 23:28:17 +08:00
Nick Peng
a6cb6061ec optware: fix optware init script issue 2023-02-21 22:59:50 +08:00
Nick Peng
995d5dce95 dns-client: fix tcp connect timeout issue. 2023-02-21 22:38:55 +08:00
Nick Peng
c21be04632 dns_server: update ttl issue for domain-rule 2023-02-18 21:10:44 +08:00
18 changed files with 510 additions and 148 deletions

View File

@@ -126,7 +126,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
1. **高性能、占用资源少** 1. **高性能、占用资源少**
多线程异步 IO 模式cache 缓存查询结果。 多线程异步 IO 模式cache 缓存查询结果。
1. **主流系统官方支持** 1. **主流系统官方支持**
主流路由系统官方软件源安装smartdns。 主流路由系统官方软件源安装smartdns。
## 架构 ## 架构
@@ -172,6 +172,8 @@ entware|ipkg update<br />ipkg install smartdns|软件源路径:<https://bin.en
| OpenWrtARM | smartdns.1.yyyy.MM.dd-REL.arm-openwrt-all.ipk | ARM 小端架构的 OpenWrt 系统 | | OpenWrtARM | smartdns.1.yyyy.MM.dd-REL.arm-openwrt-all.ipk | ARM 小端架构的 OpenWrt 系统 |
| OpenWrt LuCI | luci-app-smartdns.1.yyyy.MM.dd-REL.all.ipk | OpenWrt 管理界面 | | OpenWrt LuCI | luci-app-smartdns.1.yyyy.MM.dd-REL.all.ipk | OpenWrt 管理界面 |
| OpenWrt LuCI | luci-app-smartdns.1.yyyy.MM.dd-REL.all-luci-compat-all.ipk | OpenWrt 管理界面、OpenWrt 18.xx 及之前版本 | | OpenWrt LuCI | luci-app-smartdns.1.yyyy.MM.dd-REL.all-luci-compat-all.ipk | OpenWrt 管理界面、OpenWrt 18.xx 及之前版本 |
| Windows | smartdns-rs https://github.com/mokeyish/smartdns-rs | Rust版本SmartDNS | [Rust版本SmartDNS](https://github.com/mokeyish/smartdns-rs) |
| MacOS | smartdns-rs https://github.com/mokeyish/smartdns-rs | Rust版本SmartDNS |
**[前往 Release 页面下载](https://github.com/pymumu/smartdns/releases)。** **[前往 Release 页面下载](https://github.com/pymumu/smartdns/releases)。**
@@ -181,8 +183,6 @@ entware|ipkg update<br />ipkg install smartdns|软件源路径:<https://bin.en
- 静态编译的软件包未强制判断 CPU 架构,安装不正确的软件包将会导致服务无法启动,请确保正确安装对应的版本。 - 静态编译的软件包未强制判断 CPU 架构,安装不正确的软件包将会导致服务无法启动,请确保正确安装对应的版本。
- MacOSWindows可获取Rust语言实现的Smartdns: [SmartDNS-rs](https://github.com/mokeyish/smartdns-rs)。
## 安装和使用 ## 安装和使用
### 标准 Linux 系统 / 树莓派 ### 标准 Linux 系统 / 树莓派
@@ -612,7 +612,7 @@ entware|ipkg update<br />ipkg install smartdns|软件源路径:<https://bin.en
| nameserver | 指定域名使用 server 组解析 | 无 | nameserver /domain/[group\|-], group 为组名,- 表示忽略此规则,配套 server 中的 -group 参数使用 | nameserver /www.example.com/office | | nameserver | 指定域名使用 server 组解析 | 无 | nameserver /domain/[group\|-], group 为组名,- 表示忽略此规则,配套 server 中的 -group 参数使用 | nameserver /www.example.com/office |
| ipset | 域名 ipset | 无 | ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]]-表示忽略 | ipset /www.example.com/#4:dns4,#6:- <br />ipset /www.example.com/dns | | ipset | 域名 ipset | 无 | ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]]-表示忽略 | ipset /www.example.com/#4:dns4,#6:- <br />ipset /www.example.com/dns |
| ipset-timeout | 设置 ipset 超时功能启用 | no | [yes\|no] | ipset-timeout yes | | ipset-timeout | 设置 ipset 超时功能启用 | no | [yes\|no] | ipset-timeout yes |
| ipset-no-speed | 当测速失败时将域名结果设置到ipset集合中 | 无 | ipset \| #[4\|6]:ipset | ipset-no-speed #4:ipset4,#6:ipse6 <br /> ipset-no-speed ipset| | ipset-no-speed | 当测速失败时将域名结果设置到ipset集合中 | 无 | ipset \| #[4\|6]:ipset | ipset-no-speed #4:ipset4,#6:ipset6 <br /> ipset-no-speed ipset|
| nftset | 域名 nftset | 无 | nftset /domain/[#4\|#6\|-]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]]<br />-表示忽略;<br />ipv4 地址的 family 只支持 inet 和 ip<br />ipv6 地址的 family 只支持 inet 和 ip6<br />由于 nft 限制,两种地址只能分开存放于两个 set 中。| nftset /www.example.com/#4:inet#tab#dns4,#6:- | | nftset | 域名 nftset | 无 | nftset /domain/[#4\|#6\|-]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]]<br />-表示忽略;<br />ipv4 地址的 family 只支持 inet 和 ip<br />ipv6 地址的 family 只支持 inet 和 ip6<br />由于 nft 限制,两种地址只能分开存放于两个 set 中。| nftset /www.example.com/#4:inet#tab#dns4,#6:- |
| nftset-timeout | 设置 nftset 超时功能启用 | no | [yes\|no] | nftset-timeout yes | | nftset-timeout | 设置 nftset 超时功能启用 | no | [yes\|no] | nftset-timeout yes |
| nftset-no-speed | 当测速失败时将域名结果设置到nftset集合中 | 无 | nftset-no-speed [#4\|#6]:[family#nftable#nftset][,#[4\|6]:[family#nftable#nftset]]] <br />ipv4 地址的 family 只支持 inet 和 ip <br />ipv6 地址的 family 只支持 inet 和 ip6 <br />由于 nft 限制,两种地址只能分开存放于两个 set 中。| nftset-no-speed #4:inet#tab#set4| | nftset-no-speed | 当测速失败时将域名结果设置到nftset集合中 | 无 | nftset-no-speed [#4\|#6]:[family#nftable#nftset][,#[4\|6]:[family#nftable#nftset]]] <br />ipv4 地址的 family 只支持 inet 和 ip <br />ipv6 地址的 family 只支持 inet 和 ip6 <br />由于 nft 限制,两种地址只能分开存放于两个 set 中。| nftset-no-speed #4:inet#tab#set4|
@@ -630,8 +630,9 @@ entware|ipkg update<br />ipkg install smartdns|软件源路径:<https://bin.en
| serve-expired | 过期缓存服务功能 | yes | [yes\|no],开启此功能后,如果有请求时尝试回应 TTL 为 0 的过期记录,并发查询记录,以避免查询等待 | | serve-expired | 过期缓存服务功能 | yes | [yes\|no],开启此功能后,如果有请求时尝试回应 TTL 为 0 的过期记录,并发查询记录,以避免查询等待 |
| serve-expired-ttl | 过期缓存服务最长超时时间 | 0 | 秒0 表示停用超时,大于 0 表示指定的超时的秒数 | serve-expired-ttl 0 | | serve-expired-ttl | 过期缓存服务最长超时时间 | 0 | 秒0 表示停用超时,大于 0 表示指定的超时的秒数 | serve-expired-ttl 0 |
| serve-expired-reply-ttl | 回应的过期缓存 TTL | 5 | 秒0 表示停用超时,大于 0 表示指定的超时的秒数 | serve-expired-reply-ttl 30 | | serve-expired-reply-ttl | 回应的过期缓存 TTL | 5 | 秒0 表示停用超时,大于 0 表示指定的超时的秒数 | serve-expired-reply-ttl 30 |
| serve-expired-prefetch-time | 过期缓存预查询时间 | 28800 | 秒,到达对应超时时间后预查询时间 | serve-expired-prefetch-time 86400 |
| dualstack-ip-selection | 双栈 IP 优选 | yes | [yes\|no] | dualstack-ip-selection yes | | dualstack-ip-selection | 双栈 IP 优选 | yes | [yes\|no] | dualstack-ip-selection yes |
| dualstack-ip-selection-threshold | 双栈 IP 优选阈值 | 15ms | 单位为毫秒ms | dualstack-ip-selection-threshold [0-1000] | | dualstack-ip-selection-threshold | 双栈 IP 优选阈值 | 10ms | 单位为毫秒ms | dualstack-ip-selection-threshold [0-1000] |
| user | 进程运行用户 | root | user [username] | user nobody | | user | 进程运行用户 | root | user [username] | user nobody |
| ca-file | 证书文件 | /etc/ssl/<br />certs/ca-certificates.crt | 合法路径字符串 | ca-file /etc/ssl/certs/ca-certificates.crt | | ca-file | 证书文件 | /etc/ssl/<br />certs/ca-certificates.crt | 合法路径字符串 | ca-file /etc/ssl/certs/ca-certificates.crt |
| ca-path | 证书文件路径 | /etc/ssl/certs | 合法路径字符串 | ca-path /etc/ssl/certs | | ca-path | 证书文件路径 | /etc/ssl/certs | 合法路径字符串 | ca-path /etc/ssl/certs |

View File

@@ -121,7 +121,7 @@ From the comparison, smartdns found the fastest IP address to visit www.baidu.co
1. **High performance, low resource consumption** 1. **High performance, low resource consumption**
Multi-threaded asynchronous IO mode, cache cache query results. Multi-threaded asynchronous IO mode, cache cache query results.
1. **DNS domain forwarding** 1. **DNS domain forwarding**
Support DNS forwarding, ipset and nftables. Support setting the domain result to ipset and nftset set when speed check fails. Support DNS forwarding, ipset and nftables. Support setting the domain result to ipset and nftset set when speed check fails.
## Architecture ## Architecture
@@ -167,6 +167,8 @@ Download the matching version of the SmartDNS installation package. The correspo
|openwrt|smartdns.xxxxxxxx.arm-openwrt-all.ipk|Support the arm architecture for openwrt。 |openwrt|smartdns.xxxxxxxx.arm-openwrt-all.ipk|Support the arm architecture for openwrt。
|openwrt LUCI|luci-app-smartdns.xxxxxxxxx.all.ipk|Openwrt management interface. |openwrt LUCI|luci-app-smartdns.xxxxxxxxx.all.ipk|Openwrt management interface.
|openwrt LUCI|luci-app-smartdns.xxxxxxxxx.all-luci-compat-all|Compat Openwrt management interface for early openwrt. |openwrt LUCI|luci-app-smartdns.xxxxxxxxx.all-luci-compat-all|Compat Openwrt management interface for early openwrt.
|Windows|smartdns-rs https://github.com/mokeyish/smartdns-rs| Rust Version SmartDNS |
|MacOS|smartdns-rs https://github.com/mokeyish/smartdns-rs| Rust Version SmartDNS |
- The released packages are statically compiled. If you need a small size package, please compile it yourself or obtain it from the openwrt / entware repository. - The released packages are statically compiled. If you need a small size package, please compile it yourself or obtain it from the openwrt / entware repository.
@@ -176,7 +178,6 @@ Download the matching version of the SmartDNS installation package. The correspo
```shell ```shell
https://github.com/pymumu/smartdns/releases https://github.com/pymumu/smartdns/releases
``` ```
- For MacOS, Windows, you can try rust version of smartdns: [SmartDNS-rs](https://github.com/mokeyish/smartdns-rs)
- For the installation procedure, please refer to the following sections. - For the installation procedure, please refer to the following sections.
@@ -476,7 +477,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
1. Install smartdns 1. Install smartdns
download install package `smartdns.xxxxxxxx.x86_64-linux-all.tar.gz`and unzip to the `D:\` directory, after decompression, the directory is as follows: download install package `smartdns.xxxxxxxx.x86_64-linux-all.tar.gz`, and unzip to the `D:\` directory, after decompression, the directory is as follows:
```shell ```shell
D:\SMARTDNS D:\SMARTDNS
@@ -540,7 +541,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|--|--|--|--|--| |--|--|--|--|--|
|server-name|DNS name|host name/smartdns|any string like hostname|server-name smartdns |server-name|DNS name|host name/smartdns|any string like hostname|server-name smartdns
|bind|DNS listening port number|[::]:53|Support binding multiple ports<br />`IP:PORT@DEVICE`: server IP, port number, and device. <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 or nftset rules. <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@eth0 |bind|DNS listening port number|[::]:53|Support binding multiple ports<br />`IP:PORT@DEVICE`: server IP, port number, and device. <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 or nftset rules. <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@eth0
|bind-tcp|TCP mode DNS listening port number|[::]:53|Support binding multiple ports<br />`IP:PORT@DEVICE`: server IP, port number and device. <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 or nftset rules. <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 |bind-tcp|TCP mode DNS listening port number|[::]:53|Support binding multiple ports<br />`IP:PORT@DEVICE`: server IP, port number and device. <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 or nftset rules. <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-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-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/<br />smartdns.cache|path|cache-file /tmp/smartdns.cache |cache-file|cache persist file|/tmp/<br />smartdns.cache|path|cache-file /tmp/smartdns.cache
@@ -562,10 +563,10 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|audit-num|archived audit log number|2|Integer, 0 means turn off the log|audit-num 2 |audit-num|archived audit log number|2|Integer, 0 means turn off the log|audit-num 2
|audit-file-mode|archived audit log file mode|0640|Integer|audit-file-mode 644 |audit-file-mode|archived audit log file mode|0640|Integer|audit-file-mode 644
|conf-file|additional conf file|None|File path|conf-file /etc/smartdns/smartdns.more.conf |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]\|URL`: Server IP, port optional OR URL. <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. <br />`[-set-mark mark]`set mark on packets <br /> `[-proxy name]`: set proxy server| server 8.8.8.8:53 -blacklist-ip<br />server tls://8.8.8.8 |server|Upstream UDP DNS server|None|Repeatable <br />`[ip][:port]\|URL`: Server IP, port optional OR URL. <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. <br />`[-set-mark mark]`: set mark on packets <br /> `[-proxy name]`: set proxy server| server 8.8.8.8:53 -blacklist-ip<br />server tls://8.8.8.8
|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 <br />`[-set-mark mark]`set mark on packets <br /> `[-proxy name]`: set proxy server| server-tcp 8.8.8.8:53 |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 <br />`[-set-mark mark]`: set mark on packets <br /> `[-proxy name]`: set proxy server| 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. `-` to disable SNI 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 <br /> `[-set-mark mark]`set mark on packets <br /> `[-proxy name]`: set proxy server| server-tls 8.8.8.8:853 |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. `-` to disable SNI 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 <br /> `[-set-mark mark]`: set mark on packets <br /> `[-proxy name]`: set proxy server| 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 <br /> `[-set-mark mark]`set mark on packets <br /> `[-proxy name]`: set proxy server| server-https <https://cloudflare-dns.com/dns-query> |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 <br /> `[-set-mark mark]`: set mark on packets <br /> `[-proxy name]`: set proxy server| server-https <https://cloudflare-dns.com/dns-query>
|proxy-server| proxy server | None | Repeatable. <br />`proxy-server URL` <br />[URL]: `[socks5\|http]://[username:password@]host:port`<br />[-name]: proxy server name. |proxy-server socks5://user:pass@1.2.3.4:1080 -name proxy| |proxy-server| proxy server | None | Repeatable. <br />`proxy-server URL` <br />[URL]: `[socks5\|http]://[username:password@]host:port`<br />[-name]: proxy server name. |proxy-server socks5://user:pass@1.2.3.4:1080 -name proxy|
|speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:80,tcp:443 |speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:80,tcp:443
|response-mode|First query response mode|first-ping|Mode: [first-ping\|fastest-ip\|fastest-response]<br /> [first-ping]: The fastest dns + ping response mode, DNS query delay + ping delay is the shortest;<br />[fastest-ip]: The fastest IP address mode, return the fastest ip address, may take some time to test speed. <br />[fastest-response]: The fastest response DNS result mode, the DNS query waiting time is the shortest. | response-mode first-ping | |response-mode|First query response mode|first-ping|Mode: [first-ping\|fastest-ip\|fastest-response]<br /> [first-ping]: The fastest dns + ping response mode, DNS query delay + ping delay is the shortest;<br />[fastest-ip]: The fastest IP address mode, return the fastest ip address, may take some time to test speed. <br />[fastest-response]: The fastest response DNS result mode, the DNS query waiting time is the shortest. | response-mode first-ping |
@@ -575,26 +576,27 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|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 |nameserver|To query domain with specific server group|None|nameserver /domain/[group\|-], `group` is the group name, `-` means ignore this rule, use the `-group` parameter in the related server|nameserver /www.example.com/office
|ipset|Domain IPSet|None|ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]], `-` for ignore|ipset /www.example.com/#4:dns4,#6:- |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|no|[yes\|no]|ipset-timeout yes |ipset-timeout|ipset timeout enable|no|[yes\|no]|ipset-timeout yes
|ipset-no-speed|When speed check fails, set the ip address of the domain name to the ipset | None | ipset \| #[4\|6]:ipset | ipset-no-speed #4:ipset4,#6:ipse6 <br /> ipset-no-speed ipset| |ipset-no-speed|When speed check fails, set the ip address of the domain name to the ipset | None | ipset \| #[4\|6]:ipset | ipset-no-speed #4:ipset4,#6:ipset6 <br /> ipset-no-speed ipset|
|nftset|Domain nftset|None|nftset /domain/[#4\|#6\|-]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]]<br /> `-` to ignore<br />the valid families are inet and ip for ipv4 addresses while the valid ones are inet and ip6 for ipv6 addresses <br />due to the limitation of nftable <br />two types of addresses have to be stored in two sets|nftset /www.example.com/#4:inet#tab#dns4,#6:- |nftset|Domain nftset|None|nftset /domain/[#4\|#6\|-]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]]<br /> `-` to ignore<br />the valid families are inet and ip for ipv4 addresses while the valid ones are inet and ip6 for ipv6 addresses <br />due to the limitation of nftable <br />two types of addresses have to be stored in two sets|nftset /www.example.com/#4:inet#tab#dns4,#6:-
|nftset-timeout|nftset timeout enable|no|[yes\|no]|nftset-timeout yes |nftset-timeout|nftset timeout enable|no|[yes\|no]|nftset-timeout yes
|nftset-no-speed|When speed check fails, set the ip address of the domain name to the nftset | None | nftset-no-speed [#4\|#6]:[family#nftable#nftset][,#[4\|6]:[family#nftable#nftset]]] <br />the valid families are inet and ip for ipv4 addresses while the valid ones are inet and ip6 for ipv6 addresses <br />due to the limitation of nftable <br />two types of addresses have to be stored in two sets| nftset-no-speed #4:inet#tab#set4| |nftset-no-speed|When speed check fails, set the ip address of the domain name to the nftset | None | nftset-no-speed [#4\|#6]:[family#nftable#nftset][,#[4\|6]:[family#nftable#nftset]]] <br />the valid families are inet and ip for ipv4 addresses while the valid ones are inet and ip6 for ipv6 addresses <br />due to the limitation of nftable <br />two types of addresses have to be stored in two sets| nftset-no-speed #4:inet#tab#set4|
|nftset-debug|nftset debug enable|no|[yes\|no]|nftset-debug yes |nftset-debug|nftset debug enable|no|[yes\|no]|nftset-debug yes
|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br />[-c\|-speed-check-mode]: set speed check modesame 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 `nftset`<br />[-t\|-nftset]: same as parameter `nftset`<br />[-d\|-dualstack-ip-selection]: same as parameter `dualstack-ip-selection`<br /> [-no-serve-expired]disable serve expired<br />[-rr-ttl\|-rr-ttl-min\|-rr-ttl-max]: same as parameter: rr-ttl, rr-ttl-min, rr-ttl-max<br />[-delete]delete rule|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 `nftset`<br />[-t\|-nftset]: same as parameter `nftset`<br />[-d\|-dualstack-ip-selection]: same as parameter `dualstack-ip-selection`<br /> [-no-serve-expired]: disable serve expired<br />[-rr-ttl\|-rr-ttl-min\|-rr-ttl-max]: same as parameter: rr-ttl, rr-ttl-min, rr-ttl-max<br />[-delete]: delete rule|domain-rules /www.example.com/ -speed-check-mode none
| domain-set | collection of domains|None| domain-set [options...]<br />[-n\|-name]name of set <br />[-t\|-type] [list]: set type, only support list, one domain per line <br />[-f\|-file]file path of domain set<br /> used with address, nameserver, ipset, nftset, example: /domain-set:[name]/ | domain-set -name set -type list -file /path/to/list <br /> address /domain-set:set/1.2.4.8 | | domain-set | collection of domains|None| domain-set [options...]<br />[-n\|-name]: name of set <br />[-t\|-type] [list]: set type, only support list, one domain per line <br />[-f\|-file]: file path of domain set<br /> used with address, nameserver, ipset, nftset, example: /domain-set:[name]/ | domain-set -name set -type list -file /path/to/list <br /> address /domain-set:set/1.2.4.8 |
|bogus-nxdomain|bogus IP address|None|[IP/subnet], Repeatable| bogus-nxdomain 1.2.3.4/16 |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 |ignore-ip|ignore ip address|None|[ip/subnet], Repeatable| ignore-ip 1.2.3.4/16
|whitelist-ip|ip whitelist|None|[ip/subnet], RepeatableWhen the filtering server responds IPs in the IP whitelist, only result in whitelist will be accepted| whitelist-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
|blacklist-ip|ip blacklist|None|[ip/subnet], RepeatableWhen the filtering server responds IPs in the IP blacklist, The result will be discarded directly| blacklist-ip 1.2.3.4/16 |blacklist-ip|ip blacklist|None|[ip/subnet], Repeatable, When the filtering server responds IPs in the IP blacklist, The result will be discarded directly| blacklist-ip 1.2.3.4/16
|force-AAAA-SOA|force AAAA query return SOA|no|[yes\|no]|force-AAAA-SOA yes |force-AAAA-SOA|force AAAA query return SOA|no|[yes\|no]|force-AAAA-SOA yes
|force-qtype-SOA|force specific qtype return SOA|qtype id|[qtypeid \| ...]|force-qtype-SOA 65 28 |force-qtype-SOA|force specific qtype return SOA|qtype id|[qtypeid \| ...]|force-qtype-SOA 65 28
|prefetch-domain|domain prefetch feature|no|[yes\|no]|prefetch-domain yes |prefetch-domain|domain prefetch feature|no|[yes\|no]|prefetch-domain yes
|dnsmasq-lease-file|Support reading dnsmasq dhcp file to resolve local hostname|None|dnsmasq dhcp lease file| dnsmasq-lease-file /var/lib/misc/dnsmasq.leases |dnsmasq-lease-file|Support reading dnsmasq dhcp file to resolve local hostname|None|dnsmasq dhcp lease file| dnsmasq-lease-file /var/lib/misc/dnsmasq.leases
|serve-expired|Cache serve expired feature|yes|[yes\|no], Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish.|serve-expired yes |serve-expired|Cache serve expired feature|yes|[yes\|no], Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish.|serve-expired yes
|serve-expired-ttl|Cache serve expired limit TTL|0|second0disable> 0 seconds after expiration|serve-expired-ttl 0 |serve-expired-ttl|Cache serve expired limit 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|second0disable> 0 seconds after expiration|serve-expired-reply-ttl 30 |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
|serve-expired-prefetch-time| Prefetch time when serve expired | 28800 | secondprefetch time | serve-expired-prefetch-time 86400 |
|dualstack-ip-selection|Dualstack ip selection|yes|[yes\|no]|dualstack-ip-selection yes |dualstack-ip-selection|Dualstack ip selection|yes|[yes\|no]|dualstack-ip-selection yes
|dualstack-ip-selection-threshold|Dualstack ip select thresholds|15ms|millisecond|dualstack-ip-selection-threshold [0-1000] |dualstack-ip-selection-threshold|Dualstack ip select thresholds|10ms|millisecond|dualstack-ip-selection-threshold [0-1000]
|user|run as user|root|user [username]|user nobody |user|run as user|root|user [username]|user nobody
|ca-file|certificate file|/etc/ssl/certs/<br />ca-certificates.crt|path|ca-file /etc/ssl/certs/ca-certificates.crt |ca-file|certificate file|/etc/ssl/certs/<br />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 |ca-path|certificates path|/etc/ssl/certs|path|ca-path /etc/ssl/certs

View File

@@ -82,6 +82,9 @@ msgstr "协议类型"
msgid "DNS domain result cache size" msgid "DNS domain result cache size"
msgstr "缓存DNS的结果缓存大小配置零则不缓存" msgstr "缓存DNS的结果缓存大小配置零则不缓存"
msgid "DNS64 Server Settings"
msgstr "DNS64服务器配置"
msgid "Description" msgid "Description"
msgstr "描述" msgstr "描述"

View File

@@ -34,6 +34,7 @@ s.anonymous = true
s:tab("settings", translate("General Settings")) s:tab("settings", translate("General Settings"))
s:tab("advanced", translate('Advanced Settings')) s:tab("advanced", translate('Advanced Settings'))
s:tab("seconddns", translate("Second Server Settings")) s:tab("seconddns", translate("Second Server Settings"))
s:tab("dns64", translate("DNS64 Server Settings"))
s:tab("proxy", translate("Proxy Server Settings")) s:tab("proxy", translate("Proxy Server Settings"))
s:tab("custom", translate("Custom Settings")) s:tab("custom", translate("Custom Settings"))
@@ -371,6 +372,12 @@ function o.validate(self, value)
return value return value
end end
----- dns64 server settings
o = s:taboption("dns64", Value, "dns64", translate("DNS64"));
o.placeholder = "64:ff9b::/96"
o.datatype = 'ip6addr'
o.rmempty = true
----- custom settings ----- custom settings
custom = s:taboption("custom", Value, "Custom Settings", custom = s:taboption("custom", Value, "Custom Settings",
translate(""), translate(""),

View File

@@ -90,6 +90,9 @@ msgstr "协议类型"
msgid "DNS domain result cache size" msgid "DNS domain result cache size"
msgstr "缓存DNS的结果缓存大小配置零则不缓存" msgstr "缓存DNS的结果缓存大小配置零则不缓存"
msgid "DNS64 Server Settings"
msgstr "DNS64服务器配置"
msgid "default" msgid "default"
msgstr "默认" msgstr "默认"

View File

@@ -131,6 +131,7 @@ return view.extend({
s.tab("settings", _("General Settings")); s.tab("settings", _("General Settings"));
s.tab("advanced", _('Advanced Settings')); s.tab("advanced", _('Advanced Settings'));
s.tab("seconddns", _("Second Server Settings")); s.tab("seconddns", _("Second Server Settings"));
s.tab("dns64", _("DNS64 Server Settings"));
s.tab("files", _("Download Files Setting"), _("Download domain list files for domain-rule and include config files, please refresh the page after download to take effect.")); s.tab("files", _("Download Files Setting"), _("Download domain list files for domain-rule and include config files, please refresh the page after download to take effect."));
s.tab("proxy", _("Proxy Server Settings")); s.tab("proxy", _("Proxy Server Settings"));
s.tab("custom", _("Custom Settings")); s.tab("custom", _("Custom Settings"));
@@ -430,6 +431,14 @@ return view.extend({
o.rmempty = false; o.rmempty = false;
o.default = o.disabled; o.default = o.disabled;
///////////////////////////////////////
// DNS64 Settings
///////////////////////////////////////
o = s.taboption("dns64", form.Value, "dns64", _("DNS64"));
o.placeholder = "64:ff9b::/96";
o.datatype = "ip6addr";
o.rempty = true;
/////////////////////////////////////// ///////////////////////////////////////
// download Files Settings // download Files Settings
/////////////////////////////////////// ///////////////////////////////////////

View File

@@ -480,6 +480,7 @@ load_service()
config_get port "$section" "port" "53" config_get port "$section" "port" "53"
config_get ipv6_server "$section" "ipv6_server" "1" config_get ipv6_server "$section" "ipv6_server" "1"
config_get tcp_server "$section" "tcp_server" "1" config_get tcp_server "$section" "tcp_server" "1"
config_get server_flags "$section" "server_flags" ""
config_get speed_check_mode "$section" "speed_check_mode" "" config_get speed_check_mode "$section" "speed_check_mode" ""
[ ! -z "$speed_check_mode" ] && conf_append "speed-check-mode" "$speed_check_mode" [ ! -z "$speed_check_mode" ] && conf_append "speed-check-mode" "$speed_check_mode"
@@ -563,6 +564,9 @@ load_service()
config_get proxy_server "$section" "proxy_server" "" config_get proxy_server "$section" "proxy_server" ""
[ -z "$proxy_server" ] || conf_append "proxy-server" "$proxy_server -name default-proxy" [ -z "$proxy_server" ] || conf_append "proxy-server" "$proxy_server -name default-proxy"
config_get dns64 "$section" "dns64" ""
[ -z "$dns64" ] || conf_append "dns64" "$dns64"
config_get redirect "$section" "redirect" "" config_get redirect "$section" "redirect" ""
config_get old_port "$section" "old_port" "0" config_get old_port "$section" "old_port" "0"
config_get old_enabled "$section" "old_enabled" "0" config_get old_enabled "$section" "old_enabled" "0"
@@ -629,7 +633,7 @@ load_service()
[ "$auto_set_dnsmasq" = "0" ] && [ "$old_auto_set_dnsmasq" = "1" ] && stop_forward_dnsmasq "$old_port" "0" [ "$auto_set_dnsmasq" = "0" ] && [ "$old_auto_set_dnsmasq" = "1" ] && stop_forward_dnsmasq "$old_port" "0"
} }
conf_append_bind "$port" "$device" "$tcp_server" "$ipv6_server" "$ARGS" conf_append_bind "$port" "$device" "$tcp_server" "$ipv6_server" "$server_flags"
load_second_server "$section" load_second_server "$section"

View File

@@ -343,28 +343,28 @@ case "$1" in
$SMARTDNS_BIN -c "$SMARTDNS_CONF" -p $SMARTDNS_PID $SMARTDNS_BIN -c "$SMARTDNS_CONF" -p $SMARTDNS_PID
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
clear_rule clear_rule
exit 1
fi fi
;; ;;
status) status)
pid="$(cat $SMARTDNS_PID |head -n 1 2>/dev/null)" pid="$(cat $SMARTDNS_PID |head -n 1 2>/dev/null)"
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
echo "smartdns not running." echo "smartdns not running."
return 0 exit 0
fi fi
if [ -d "/proc/$pid" ]; then if [ -d "/proc/$pid" ]; then
echo "smartdns running" echo "smartdns is running"
return 0; exit 0
fi fi
echo "smartdns not running." echo "smartdns not running."
return 0; exit 0
;; ;;
stop) stop)
clear_rule
pid="$(cat "$SMARTDNS_PID" | head -n 1 2>/dev/null)" pid="$(cat "$SMARTDNS_PID" | head -n 1 2>/dev/null)"
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
echo "smartdns not running." echo "smartdns not running."
return 0 exit 0
fi fi
kill -15 "$pid" 2>/dev/null kill -15 "$pid" 2>/dev/null
@@ -379,17 +379,17 @@ case "$1" in
do do
pid="$(cat "$SMARTDNS_PID" | head -n 1 2>/dev/null)" pid="$(cat "$SMARTDNS_PID" | head -n 1 2>/dev/null)"
if [ -z "$pid" ]; then if [ -z "$pid" ]; then
return 0 break
fi fi
if [ ! -d "/proc/$pid" ]; then if [ ! -d "/proc/$pid" ]; then
return 0 break
fi fi
stat="$(cat /proc/${pid}/stat | awk '{print $3}' 2>/dev/null)" stat="$(cat /proc/${pid}/stat | awk '{print $3}' 2>/dev/null)"
if [ "$stat" = "Z" ]; then if [ "$stat" = "Z" ]; then
$SLEEP $SLEEPTIME $SLEEP $SLEEPTIME
return 0 break
fi fi
$SLEEP $SLEEPTIME 2>/dev/null $SLEEP $SLEEPTIME 2>/dev/null
@@ -397,11 +397,15 @@ case "$1" in
done done
kill -9 "$pid" 2>/dev/null kill -9 "$pid" 2>/dev/null
clear_rule
exit 0
;; ;;
restart) restart)
$0 stop $0 stop
$0 start $0 start
;; ;;
reload)
;;
enable) enable)
nvram set apps_state_enable=2 nvram set apps_state_enable=2
nvram set apps_state_error=0 nvram set apps_state_error=0

View File

@@ -23,7 +23,7 @@ ifndef CFLAGS
ifdef DEBUG ifdef DEBUG
CFLAGS = -g CFLAGS = -g
else else
CFLAGS = -O2 -g CFLAGS = -O2
endif endif
CFLAGS +=-Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing -funwind-tables -Wmissing-prototypes -Wshadow -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough CFLAGS +=-Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing -funwind-tables -Wmissing-prototypes -Wshadow -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough
endif endif

View File

@@ -1687,13 +1687,13 @@ static int _dns_decode_opt_cookie(struct dns_context *context, struct dns_opt_co
return 0; return 0;
} }
if (opt_len < (int)member_size(struct dns_opt_cookie, server_cookie)) { if (opt_len < 8 || opt_len > (int)member_size(struct dns_opt_cookie, server_cookie)) {
return -1; return -1;
} }
memcpy(cookie->server_cookie, context->ptr, len); memcpy(cookie->server_cookie, context->ptr, opt_len);
cookie->server_cookie_len = len; cookie->server_cookie_len = opt_len;
context->ptr += len; context->ptr += opt_len;
tlog(TLOG_DEBUG, "OPT COOKIE"); tlog(TLOG_DEBUG, "OPT COOKIE");
return 0; return 0;
@@ -1860,8 +1860,8 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
} }
if (errcode != 0) { if (errcode != 0) {
tlog(TLOG_ERROR, "extend rcode invalid."); tlog(TLOG_DEBUG, "extend rcode invalid, %d", errcode);
return -1; return 0;
} }
while (context->ptr - start < rr_len) { while (context->ptr - start < rr_len) {

View File

@@ -198,7 +198,7 @@ struct dns_opt_ecs {
unsigned char addr[DNS_RR_AAAA_LEN]; unsigned char addr[DNS_RR_AAAA_LEN];
} __attribute__((packed)); } __attribute__((packed));
/* OPT COOLIE */ /* OPT COOKIE */
struct dns_opt_cookie { struct dns_opt_cookie {
char server_cookie_len; char server_cookie_len;
unsigned char client_cookie[8]; unsigned char client_cookie[8];

View File

@@ -41,13 +41,14 @@
#include <netinet/ip_icmp.h> #include <netinet/ip_icmp.h>
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/rand.h> #include <openssl/rand.h>
#include <openssl/ssl.h>
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/epoll.h> #include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@@ -196,7 +197,6 @@ struct dns_client {
/* query list */ /* query list */
struct list_head dns_request_list; struct list_head dns_request_list;
pthread_cond_t run_cond;
atomic_t run_period; atomic_t run_period;
atomic_t dns_server_num; atomic_t dns_server_num;
@@ -208,6 +208,8 @@ struct dns_client {
pthread_mutex_t domain_map_lock; pthread_mutex_t domain_map_lock;
DECLARE_HASHTABLE(domain_map, 6); DECLARE_HASHTABLE(domain_map, 6);
DECLARE_HASHTABLE(group, 4); DECLARE_HASHTABLE(group, 4);
int fd_wakeup;
}; };
/* dns replied server info */ /* dns replied server info */
@@ -264,6 +266,8 @@ static pthread_mutex_t pending_server_mutex = PTHREAD_MUTEX_INITIALIZER;
static int dns_client_has_bootstrap_dns = 0; static int dns_client_has_bootstrap_dns = 0;
static int _dns_client_send_udp(struct dns_server_info *server_info, void *packet, int len); static int _dns_client_send_udp(struct dns_server_info *server_info, void *packet, int len);
static void _dns_client_clear_wakeup_event(void);
static void _dns_client_do_wakeup_event(void);
static ssize_t _ssl_read(struct dns_server_info *server, void *buff, int num) static ssize_t _ssl_read(struct dns_server_info *server, void *buff, int num)
{ {
@@ -443,7 +447,7 @@ errout:
} }
/* check whether server exists */ /* check whether server exists */
static int _dns_client_server_exist(const char *server_ip, int port, dns_server_type_t server_type) static int _dns_client_server_exist(const char *server_ip, int port, dns_server_type_t server_type, struct client_dns_server_flags *flags)
{ {
struct dns_server_info *server_info = NULL; struct dns_server_info *server_info = NULL;
struct dns_server_info *tmp = NULL; struct dns_server_info *tmp = NULL;
@@ -454,6 +458,10 @@ static int _dns_client_server_exist(const char *server_ip, int port, dns_server_
continue; continue;
} }
if (memcmp(&server_info->flags, flags, sizeof(*flags)) == 0) {
continue;
}
if (strncmp(server_info->ip, server_ip, DNS_HOSTNAME_LEN) != 0) { if (strncmp(server_info->ip, server_ip, DNS_HOSTNAME_LEN) != 0) {
continue; continue;
} }
@@ -1025,7 +1033,7 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
} }
/* if server exist, return */ /* if server exist, return */
if (_dns_client_server_exist(server_ip, port, server_type) == 0) { if (_dns_client_server_exist(server_ip, port, server_type, flags) == 0) {
return 0; return 0;
} }
@@ -1337,9 +1345,8 @@ static int _dns_client_server_pending(char *server_ip, int port, dns_server_type
atomic_set(&client.run_period, 1); atomic_set(&client.run_period, 1);
pthread_mutex_unlock(&pending_server_mutex); pthread_mutex_unlock(&pending_server_mutex);
pthread_mutex_lock(&client.domain_map_lock); _dns_client_do_wakeup_event();
pthread_cond_signal(&client.run_cond);
pthread_mutex_unlock(&client.domain_map_lock);
return 0; return 0;
errout: errout:
if (pending) { if (pending) {
@@ -1514,7 +1521,7 @@ static void _dns_client_check_tcp(void)
} }
if (server_info->status == DNS_SERVER_STATUS_CONNECTING) { if (server_info->status == DNS_SERVER_STATUS_CONNECTING) {
if (server_info->last_send + DNS_TCP_CONNECT_TIMEOUT < now) { if (server_info->last_recv + DNS_TCP_CONNECT_TIMEOUT < now) {
tlog(TLOG_DEBUG, "server %s connect timeout.", server_info->ip); tlog(TLOG_DEBUG, "server %s connect timeout.", server_info->ip);
_dns_client_close_socket(server_info); _dns_client_close_socket(server_info);
} }
@@ -2179,6 +2186,11 @@ static int _dns_client_process_udp_proxy(struct dns_server_info *server_info, st
return ret; return ret;
} }
int latency = get_tick_count() - server_info->send_tick;
if (latency < server_info->drop_packet_latency_ms) {
return 0;
}
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d", tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d",
get_host_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len); get_host_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len);
@@ -3273,6 +3285,9 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
continue; continue;
} }
server_info->prohibit = 0; server_info->prohibit = 0;
if (now - 60 > server_info->last_send) {
_dns_client_close_socket(server_info);
}
} }
total_server++; total_server++;
tlog(TLOG_DEBUG, "send query to server %s", server_info->ip); tlog(TLOG_DEBUG, "send query to server %s", server_info->ip);
@@ -3284,6 +3299,7 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
} }
atomic_inc(&query->dns_request_sent); atomic_inc(&query->dns_request_sent);
errno = 0;
switch (server_info->type) { switch (server_info->type) {
case DNS_SERVER_UDP: case DNS_SERVER_UDP:
/* udp query */ /* udp query */
@@ -3569,7 +3585,7 @@ int dns_client_query(const char *domain, int qtype, dns_client_callback callback
pthread_mutex_lock(&client.domain_map_lock); pthread_mutex_lock(&client.domain_map_lock);
if (hash_hashed(&query->domain_node)) { if (hash_hashed(&query->domain_node)) {
if (list_empty(&client.dns_request_list)) { if (list_empty(&client.dns_request_list)) {
pthread_cond_signal(&client.run_cond); _dns_client_do_wakeup_event();
} }
list_add_tail(&query->dns_request_list, &client.dns_request_list); list_add_tail(&query->dns_request_list, &client.dns_request_list);
@@ -3818,15 +3834,12 @@ static void _dns_client_period_run_second(void)
_dns_client_add_pending_servers(); _dns_client_add_pending_servers();
} }
static void _dns_client_period_run(void) static void _dns_client_period_run(unsigned int msec)
{ {
struct dns_query_struct *query = NULL; struct dns_query_struct *query = NULL;
struct dns_query_struct *tmp = NULL; struct dns_query_struct *tmp = NULL;
static unsigned int msec = 0;
msec++;
LIST_HEAD(check_list); LIST_HEAD(check_list);
unsigned long now = get_tick_count(); unsigned long now = get_tick_count();
/* get query which timed out to check list */ /* get query which timed out to check list */
@@ -3869,9 +3882,11 @@ static void *_dns_client_work(void *arg)
int i = 0; int i = 0;
unsigned long now = {0}; unsigned long now = {0};
unsigned long last = {0}; unsigned long last = {0};
unsigned int msec = 0;
unsigned int sleep = 100; unsigned int sleep = 100;
int sleep_time = 0; int sleep_time = 0;
unsigned long expect_time = 0; unsigned long expect_time = 0;
int unused __attribute__((unused));
sleep_time = sleep; sleep_time = sleep;
now = get_tick_count() - sleep; now = get_tick_count() - sleep;
@@ -3884,11 +3899,17 @@ static void *_dns_client_work(void *arg)
if (sleep_time <= 0) { if (sleep_time <= 0) {
sleep_time = 0; sleep_time = 0;
} }
int cnt = sleep_time / sleep;
msec -= cnt;
expect_time -= cnt * sleep;
sleep_time -= cnt * sleep;
} }
if (now >= expect_time) { if (now >= expect_time) {
msec++;
if (last != now) { if (last != now) {
_dns_client_period_run(); _dns_client_period_run(msec);
} }
sleep_time = sleep - (now - expect_time); sleep_time = sleep - (now - expect_time);
@@ -3896,19 +3917,21 @@ static void *_dns_client_work(void *arg)
sleep_time = 0; sleep_time = 0;
expect_time = now; expect_time = now;
} }
/* When client is idle, the sleep time is 1000ms, to reduce CPU usage */
pthread_mutex_lock(&client.domain_map_lock);
if (list_empty(&client.dns_request_list)) {
int cnt = 10 - (msec % 10) - 1;
sleep_time += sleep * cnt;
msec += cnt;
/* sleep to next second */
expect_time += sleep * cnt;
}
pthread_mutex_unlock(&client.domain_map_lock);
expect_time += sleep; expect_time += sleep;
} }
last = now; last = now;
pthread_mutex_lock(&client.domain_map_lock);
if (list_empty(&client.dns_request_list) && atomic_read(&client.run_period) == 0) {
pthread_cond_wait(&client.run_cond, &client.domain_map_lock);
expect_time = get_tick_count();
pthread_mutex_unlock(&client.domain_map_lock);
continue;
}
pthread_mutex_unlock(&client.domain_map_lock);
num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, sleep_time); num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, sleep_time);
if (num < 0) { if (num < 0) {
usleep(100000); usleep(100000);
@@ -3918,6 +3941,11 @@ static void *_dns_client_work(void *arg)
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
struct epoll_event *event = &events[i]; struct epoll_event *event = &events[i];
struct dns_server_info *server_info = (struct dns_server_info *)event->data.ptr; struct dns_server_info *server_info = (struct dns_server_info *)event->data.ptr;
if (event->data.fd == client.fd_wakeup) {
_dns_client_clear_wakeup_event();
continue;
}
if (server_info == NULL) { if (server_info == NULL) {
tlog(TLOG_WARN, "server info is invalid."); tlog(TLOG_WARN, "server info is invalid.");
continue; continue;
@@ -3971,10 +3999,71 @@ int dns_client_set_ecs(char *ip, int subnet)
return 0; return 0;
} }
static int _dns_client_create_wakeup_event(void)
{
int fd_wakeup = -1;
fd_wakeup = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
if (fd_wakeup < 0) {
tlog(TLOG_ERROR, "create eventfd failed, %s\n", strerror(errno));
goto errout;
}
struct epoll_event event;
memset(&event, 0, sizeof(event));
event.events = EPOLLIN;
event.data.fd = fd_wakeup;
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_ADD, fd_wakeup, &event) < 0) {
tlog(TLOG_ERROR, "add eventfd to epoll failed, %s\n", strerror(errno));
goto errout;
}
return fd_wakeup;
errout:
if (fd_wakeup > 0) {
close(fd_wakeup);
}
return -1;
}
static void _dns_client_close_wakeup_event(void)
{
if (client.fd_wakeup > 0) {
close(client.fd_wakeup);
client.fd_wakeup = -1;
}
}
static void _dns_client_clear_wakeup_event(void)
{
uint64_t val = 0;
int unused __attribute__((unused));
if (client.fd_wakeup <= 0) {
return;
}
unused = read(client.fd_wakeup, &val, sizeof(val));
}
static void _dns_client_do_wakeup_event(void)
{
uint64_t val = 1;
int unused __attribute__((unused));
if (client.fd_wakeup <= 0) {
return;
}
unused = write(client.fd_wakeup, &val, sizeof(val));
}
int dns_client_init(void) int dns_client_init(void)
{ {
pthread_attr_t attr; pthread_attr_t attr;
int epollfd = -1; int epollfd = -1;
int fd_wakeup = -1;
int ret = 0; int ret = 0;
if (client.epoll_fd > 0) { if (client.epoll_fd > 0) {
@@ -4002,8 +4091,6 @@ int dns_client_init(void)
hash_init(client.group); hash_init(client.group);
INIT_LIST_HEAD(&client.dns_request_list); INIT_LIST_HEAD(&client.dns_request_list);
pthread_cond_init(&client.run_cond, NULL);
if (dns_client_add_group(DNS_SERVER_GROUP_DEFAULT) != 0) { if (dns_client_add_group(DNS_SERVER_GROUP_DEFAULT) != 0) {
tlog(TLOG_ERROR, "add default server group failed."); tlog(TLOG_ERROR, "add default server group failed.");
goto errout; goto errout;
@@ -4020,6 +4107,14 @@ int dns_client_init(void)
goto errout; goto errout;
} }
fd_wakeup = _dns_client_create_wakeup_event();
if (fd_wakeup < 0) {
tlog(TLOG_ERROR, "create wakeup event failed, %s\n", strerror(errno));
goto errout;
}
client.fd_wakeup = fd_wakeup;
return 0; return 0;
errout: errout:
if (client.tid) { if (client.tid) {
@@ -4029,13 +4124,16 @@ errout:
client.tid = 0; client.tid = 0;
} }
if (epollfd) { if (epollfd > 0) {
close(epollfd); close(epollfd);
} }
if (fd_wakeup > 0) {
close(fd_wakeup);
}
pthread_mutex_destroy(&client.server_list_lock); pthread_mutex_destroy(&client.server_list_lock);
pthread_mutex_destroy(&client.domain_map_lock); pthread_mutex_destroy(&client.domain_map_lock);
pthread_cond_destroy(&client.run_cond);
return -1; return -1;
} }
@@ -4045,14 +4143,13 @@ void dns_client_exit(void)
if (client.tid) { if (client.tid) {
void *ret = NULL; void *ret = NULL;
atomic_set(&client.run, 0); atomic_set(&client.run, 0);
pthread_mutex_lock(&client.domain_map_lock); _dns_client_do_wakeup_event();
pthread_cond_signal(&client.run_cond);
pthread_mutex_unlock(&client.domain_map_lock);
pthread_join(client.tid, &ret); pthread_join(client.tid, &ret);
client.tid = 0; client.tid = 0;
} }
/* free all resources */ /* free all resources */
_dns_client_close_wakeup_event();
_dns_client_remove_all_pending_servers(); _dns_client_remove_all_pending_servers();
_dns_client_server_remove_all(); _dns_client_server_remove_all();
_dns_client_query_remove_all(); _dns_client_query_remove_all();
@@ -4060,7 +4157,6 @@ void dns_client_exit(void)
pthread_mutex_destroy(&client.server_list_lock); pthread_mutex_destroy(&client.server_list_lock);
pthread_mutex_destroy(&client.domain_map_lock); pthread_mutex_destroy(&client.domain_map_lock);
pthread_cond_destroy(&client.run_cond);
if (client.ssl_ctx) { if (client.ssl_ctx) {
SSL_CTX_free(client.ssl_ctx); SSL_CTX_free(client.ssl_ctx);
client.ssl_ctx = NULL; client.ssl_ctx = NULL;

View File

@@ -132,7 +132,7 @@ struct dns_conf_address_rule dns_conf_address_rule;
/* dual-stack selection */ /* dual-stack selection */
int dns_conf_dualstack_ip_selection = 1; int dns_conf_dualstack_ip_selection = 1;
int dns_conf_dualstack_ip_allow_force_AAAA; int dns_conf_dualstack_ip_allow_force_AAAA;
int dns_conf_dualstack_ip_selection_threshold = 15; int dns_conf_dualstack_ip_selection_threshold = 10;
/* TTL */ /* TTL */
int dns_conf_rr_ttl; int dns_conf_rr_ttl;
@@ -3283,10 +3283,6 @@ static int _dns_conf_load_post(void)
dns_conf_rr_ttl_max = dns_conf_rr_ttl_min; dns_conf_rr_ttl_max = dns_conf_rr_ttl_min;
} }
if (dns_conf_local_ttl == 0) {
dns_conf_local_ttl = dns_conf_rr_ttl_min;
}
if (dns_resolv_file[0] == '\0') { if (dns_resolv_file[0] == '\0') {
safe_strncpy(dns_resolv_file, DNS_RESOLV_FILE, sizeof(dns_resolv_file)); safe_strncpy(dns_resolv_file, DNS_RESOLV_FILE, sizeof(dns_resolv_file));
} }

View File

@@ -85,10 +85,12 @@ typedef enum {
DNS_BIND_TYPE_TLS, DNS_BIND_TYPE_TLS,
} DNS_BIND_TYPE; } DNS_BIND_TYPE;
#define DOMAIN_CHECK_NONE 0 typedef enum {
#define DOMAIN_CHECK_ICMP 1 DOMAIN_CHECK_NONE = 0,
#define DOMAIN_CHECK_TCP 2 DOMAIN_CHECK_ICMP = 1,
#define DOMAIN_CHECK_NUM 3 DOMAIN_CHECK_TCP = 2,
DOMAIN_CHECK_NUM = 3,
} DOMAIN_CHECK_TYPE;
#define DOMAIN_FLAG_ADDR_SOA (1 << 0) #define DOMAIN_FLAG_ADDR_SOA (1 << 0)
#define DOMAIN_FLAG_ADDR_IPV4_SOA (1 << 1) #define DOMAIN_FLAG_ADDR_IPV4_SOA (1 << 1)
@@ -215,7 +217,7 @@ struct dns_server_groups {
}; };
struct dns_domain_check_order { struct dns_domain_check_order {
char type; DOMAIN_CHECK_TYPE type;
unsigned short tcp_port; unsigned short tcp_port;
}; };

View File

@@ -52,6 +52,7 @@
#define DNS_SERVER_TMOUT_TTL (5 * 60) #define DNS_SERVER_TMOUT_TTL (5 * 60)
#define DNS_SERVER_FAIL_TTL (60) #define DNS_SERVER_FAIL_TTL (60)
#define DNS_SERVER_SOA_TTL (30) #define DNS_SERVER_SOA_TTL (30)
#define DNS_SERVER_ADDR_TTL (60)
#define DNS_CONN_BUFF_SIZE 4096 #define DNS_CONN_BUFF_SIZE 4096
#define DNS_REQUEST_MAX_TIMEOUT 950 #define DNS_REQUEST_MAX_TIMEOUT 950
#define DNS_PING_TIMEOUT (DNS_REQUEST_MAX_TIMEOUT) #define DNS_PING_TIMEOUT (DNS_REQUEST_MAX_TIMEOUT)
@@ -238,6 +239,7 @@ struct dns_request {
/* send original raw packet to server/client like proxy */ /* send original raw packet to server/client like proxy */
int passthrough; int passthrough;
int request_wait; int request_wait;
int prefetch; int prefetch;
int prefetch_expired_domain; int prefetch_expired_domain;
@@ -260,10 +262,14 @@ struct dns_request {
DECLARE_HASHTABLE(ip_map, 4); DECLARE_HASHTABLE(ip_map, 4);
struct dns_domain_rule domain_rule; struct dns_domain_rule domain_rule;
int skip_domain_rule;
struct dns_domain_check_orders *check_order_list; struct dns_domain_check_orders *check_order_list;
int check_order; int check_order;
struct dns_request_pending_list *request_pending_list; struct dns_request_pending_list *request_pending_list;
int no_select_possible_ip;
int no_cache_cname;
}; };
/* dns server data */ /* dns server data */
@@ -293,11 +299,13 @@ static int _dns_server_get_answer(struct dns_server_post_context *context);
static void _dns_server_request_get(struct dns_request *request); static void _dns_server_request_get(struct dns_request *request);
static void _dns_server_request_release(struct dns_request *request); static void _dns_server_request_release(struct dns_request *request);
static void _dns_server_request_release_complete(struct dns_request *request, int do_complete); static void _dns_server_request_release_complete(struct dns_request *request, int do_complete);
static int _dns_server_request_complete(struct dns_request *request);
static int _dns_server_reply_passthrough(struct dns_server_post_context *context); static int _dns_server_reply_passthrough(struct dns_server_post_context *context);
static int _dns_server_do_query(struct dns_request *request, int skip_notify_event); static int _dns_server_do_query(struct dns_request *request, int skip_notify_event);
static int _dns_request_post(struct dns_server_post_context *context); static int _dns_request_post(struct dns_server_post_context *context);
static int _dns_server_reply_all_pending_list(struct dns_request *request, struct dns_server_post_context *context); static int _dns_server_reply_all_pending_list(struct dns_request *request, struct dns_server_post_context *context);
static void *_dns_server_get_dns_rule(struct dns_request *request, enum domain_rule rule); static void *_dns_server_get_dns_rule(struct dns_request *request, enum domain_rule rule);
static const char *_dns_server_get_request_groupname(struct dns_request *request);
static void _dns_server_wakeup_thread(void) static void _dns_server_wakeup_thread(void)
{ {
@@ -308,7 +316,6 @@ static void _dns_server_wakeup_thread(void)
static int _dns_server_forward_request(unsigned char *inpacket, int inpacket_len) static int _dns_server_forward_request(unsigned char *inpacket, int inpacket_len)
{ {
tlog(TLOG_DEBUG, "forward request.\n");
return -1; return -1;
} }
@@ -333,12 +340,19 @@ static int _dns_server_get_conf_ttl(struct dns_request *request, int ttl)
rr_ttl = ttl_rule->ttl; rr_ttl = ttl_rule->ttl;
} }
/* make domain rule ttl high priority */
if (ttl_rule->ttl_min > 0) { if (ttl_rule->ttl_min > 0) {
rr_ttl_min = ttl_rule->ttl_min; rr_ttl_min = ttl_rule->ttl_min;
if (dns_conf_rr_ttl_max <= rr_ttl_min && dns_conf_rr_ttl_max > 0) {
rr_ttl_max = rr_ttl_min;
}
} }
if (ttl_rule->ttl_max > 0) { if (ttl_rule->ttl_max > 0) {
rr_ttl_max = ttl_rule->ttl_max; rr_ttl_max = ttl_rule->ttl_max;
if (dns_conf_rr_ttl_min >= rr_ttl_max && dns_conf_rr_ttl_min > 0 && ttl_rule->ttl_min <= 0) {
rr_ttl_min = rr_ttl_max;
}
} }
} }
@@ -346,9 +360,14 @@ static int _dns_server_get_conf_ttl(struct dns_request *request, int ttl)
return rr_ttl; return rr_ttl;
} }
if (rr_ttl_max > 0 && ttl > rr_ttl_max) { /* make rr_ttl_min first priority */
if (rr_ttl_max < rr_ttl_min && rr_ttl_max > 0) {
rr_ttl_max = rr_ttl_min;
}
if (rr_ttl_max > 0 && ttl >= rr_ttl_max) {
ttl = rr_ttl_max; ttl = rr_ttl_max;
} else if (rr_ttl_min > 0 && ttl < rr_ttl_min) { } else if (rr_ttl_min > 0 && ttl <= rr_ttl_min) {
ttl = rr_ttl_min; ttl = rr_ttl_min;
} }
@@ -388,6 +407,23 @@ static int _dns_server_is_dns_rule_extract_match(struct dns_request *request, en
return request->domain_rule.is_sub_rule[rule] == 0; return request->domain_rule.is_sub_rule[rule] == 0;
} }
static int _dns_server_is_dns64_request(struct dns_request *request)
{
if (request->qtype != DNS_T_AAAA) {
return 0;
}
if (request->dualstack_selection_query == 1) {
return 0;
}
if (dns_conf_dns_dns64.prefix_len <= 0) {
return 0;
}
return 1;
}
static void _dns_server_set_dualstack_selection(struct dns_request *request) static void _dns_server_set_dualstack_selection(struct dns_request *request)
{ {
struct dns_rule_flags *rule_flag = NULL; struct dns_rule_flags *rule_flag = NULL;
@@ -1096,7 +1132,7 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
} else { } else {
ttl = dns_conf_rr_ttl; ttl = dns_conf_rr_ttl;
if (ttl == 0) { if (ttl == 0) {
ttl = DNS_SERVER_TMOUT_TTL; ttl = _dns_server_get_conf_ttl(request, request->ip_ttl);
} }
} }
@@ -1159,7 +1195,7 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
struct dns_request *request = context->request; struct dns_request *request = context->request;
if (request->has_cname == 0) { if (request->has_cname == 0 || request->no_cache_cname == 1) {
return 0; return 0;
} }
@@ -1615,6 +1651,7 @@ static int _dns_result_child_post(struct dns_server_post_context *context)
parent_context.do_audit = context->do_audit; parent_context.do_audit = context->do_audit;
parent_context.do_reply = context->do_reply; parent_context.do_reply = context->do_reply;
parent_context.reply_ttl = context->reply_ttl; parent_context.reply_ttl = context->reply_ttl;
parent_context.cache_ttl = context->cache_ttl;
parent_context.skip_notify_count = context->skip_notify_count; parent_context.skip_notify_count = context->skip_notify_count;
parent_context.select_all_best_ip = 1; parent_context.select_all_best_ip = 1;
parent_context.no_release_parent = context->no_release_parent; parent_context.no_release_parent = context->no_release_parent;
@@ -1624,7 +1661,7 @@ static int _dns_result_child_post(struct dns_server_post_context *context)
} }
if (context->no_release_parent == 0) { if (context->no_release_parent == 0) {
tlog(TLOG_INFO, "query %s with child %s done", parent_request->domain, request->domain); tlog(TLOG_DEBUG, "query %s with child %s done", parent_request->domain, request->domain);
request->parent_request = NULL; request->parent_request = NULL;
parent_request->request_wait--; parent_request->request_wait--;
_dns_server_request_release(parent_request); _dns_server_request_release(parent_request);
@@ -1715,7 +1752,7 @@ static int _dns_server_reply_SOA(int rcode, struct dns_request *request)
{ {
/* return SOA record */ /* return SOA record */
request->rcode = rcode; request->rcode = rcode;
if (request->ip_ttl == 0) { if (request->ip_ttl <= 0) {
request->ip_ttl = DNS_SERVER_SOA_TTL; request->ip_ttl = DNS_SERVER_SOA_TTL;
} }
@@ -1769,7 +1806,7 @@ static int _dns_server_reply_all_pending_list(struct dns_request *request, struc
context_pending.do_force_soa = context->do_force_soa; context_pending.do_force_soa = context->do_force_soa;
context_pending.do_ipset = 0; context_pending.do_ipset = 0;
context_pending.reply_ttl = request->ip_ttl; context_pending.reply_ttl = request->ip_ttl;
context_pending.no_release_parent = context->no_release_parent; context_pending.no_release_parent = 0;
_dns_server_reply_passthrough(&context_pending); _dns_server_reply_passthrough(&context_pending);
req->request_pending_list = NULL; req->request_pending_list = NULL;
@@ -1783,6 +1820,34 @@ static int _dns_server_reply_all_pending_list(struct dns_request *request, struc
return ret; return ret;
} }
static void _dns_server_check_complete_dualstack(struct dns_request *request, struct dns_request *dualstack_request)
{
if (dualstack_request == NULL || request == NULL) {
return;
}
if (dualstack_request->qtype == DNS_T_A && dns_conf_dualstack_ip_allow_force_AAAA == 0) {
return;
}
if (dualstack_request->ping_time > 0) {
return;
}
if (dualstack_request->dualstack_selection_query == 1) {
return;
}
if (request->ping_time <= (dns_conf_dualstack_ip_selection_threshold * 10)) {
return;
}
dualstack_request->dualstack_selection_has_ip = request->has_ip;
dualstack_request->dualstack_selection_ping_time = request->ping_time;
dualstack_request->dualstack_selection_force_soa = 1;
_dns_server_request_complete(dualstack_request);
}
static int _dns_server_force_dualstack(struct dns_request *request) static int _dns_server_force_dualstack(struct dns_request *request)
{ {
/* for dualstack request as first pending request, check if need to choose another request*/ /* for dualstack request as first pending request, check if need to choose another request*/
@@ -1791,8 +1856,10 @@ static int _dns_server_force_dualstack(struct dns_request *request)
request->dualstack_selection_has_ip = dualstack_request->has_ip; request->dualstack_selection_has_ip = dualstack_request->has_ip;
request->dualstack_selection_ping_time = dualstack_request->ping_time; request->dualstack_selection_ping_time = dualstack_request->ping_time;
request->dualstack_selection = 1; request->dualstack_selection = 1;
/* if another request still waiting for ping, force complete another request */
_dns_server_check_complete_dualstack(request, dualstack_request);
} }
if (request->dualstack_selection_ping_time < 0 || request->dualstack_selection == 0) { if (request->dualstack_selection_ping_time < 0 || request->dualstack_selection == 0) {
return -1; return -1;
} }
@@ -2009,6 +2076,10 @@ static void _dns_server_select_possible_ipaddress(struct dns_request *request)
return; return;
} }
if (request->no_select_possible_ip != 0) {
return;
}
if (request->ping_time > 0) { if (request->ping_time > 0) {
return; return;
} }
@@ -2048,14 +2119,14 @@ static void _dns_server_select_possible_ipaddress(struct dns_request *request)
switch (request->qtype) { switch (request->qtype) {
case DNS_T_A: { case DNS_T_A: {
memcpy(request->ip_addr, selected_addr_map->ip_addr, DNS_RR_A_LEN); memcpy(request->ip_addr, selected_addr_map->ip_addr, DNS_RR_A_LEN);
request->ip_ttl = DNS_SERVER_TMOUT_TTL; request->ip_ttl = dns_conf_rr_ttl_min > 0 ? dns_conf_rr_ttl_min : DNS_SERVER_TMOUT_TTL;
tlog(TLOG_DEBUG, "possible result: %s, rcode: %d, hitnum: %d, %d.%d.%d.%d", request->domain, request->rcode, tlog(TLOG_DEBUG, "possible result: %s, rcode: %d, hitnum: %d, %d.%d.%d.%d", request->domain, request->rcode,
selected_addr_map->hitnum, request->ip_addr[0], request->ip_addr[1], request->ip_addr[2], selected_addr_map->hitnum, request->ip_addr[0], request->ip_addr[1], request->ip_addr[2],
request->ip_addr[3]); request->ip_addr[3]);
} break; } break;
case DNS_T_AAAA: { case DNS_T_AAAA: {
memcpy(request->ip_addr, selected_addr_map->ip_addr, DNS_RR_AAAA_LEN); memcpy(request->ip_addr, selected_addr_map->ip_addr, DNS_RR_AAAA_LEN);
request->ip_ttl = DNS_SERVER_TMOUT_TTL; request->ip_ttl = dns_conf_rr_ttl_min > 0 ? dns_conf_rr_ttl_min : DNS_SERVER_TMOUT_TTL;
tlog(TLOG_DEBUG, tlog(TLOG_DEBUG,
"possible result: %s, rcode: %d, hitnum: %d, " "possible result: %s, rcode: %d, hitnum: %d, "
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
@@ -2786,9 +2857,14 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
} }
safe_strncpy(cname, domain_cname, DNS_MAX_CNAME_LEN); safe_strncpy(cname, domain_cname, DNS_MAX_CNAME_LEN);
request->ttl_cname = _dns_server_get_conf_ttl(request, ttl); request->ttl_cname = _dns_server_get_conf_ttl(request, ttl);
tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", name, ttl, cname); tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", domain_name, ttl, cname);
} break; } break;
case DNS_T_SOA: { case DNS_T_SOA: {
/* if DNS64 enabled, skip check SOA. */
if (_dns_server_is_dns64_request(request)) {
break;
}
request->has_soa = 1; request->has_soa = 1;
if (request->rcode != DNS_RC_NOERROR) { if (request->rcode != DNS_RC_NOERROR) {
request->rcode = packet->head.rcode; request->rcode = packet->head.rcode;
@@ -2800,11 +2876,6 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
domain, request->qtype, request->soa.mname, request->soa.rname, request->soa.serial, domain, request->qtype, request->soa.mname, request->soa.rname, request->soa.serial,
request->soa.refresh, request->soa.retry, request->soa.expire, request->soa.minimum); request->soa.refresh, request->soa.retry, request->soa.expire, request->soa.minimum);
/* if DNS64 enabled, skip check SOA. */
if (request->qtype == DNS_T_AAAA && dns_conf_dns_dns64.prefix_len > 0) {
break;
}
int soa_num = atomic_inc_return(&request->soa_num); int soa_num = atomic_inc_return(&request->soa_num);
if ((soa_num >= (dns_server_num() / 3) + 1 || soa_num > 4) && atomic_read(&request->ip_map_num) <= 0) { if ((soa_num >= (dns_server_num() / 3) + 1 || soa_num > 4) && atomic_read(&request->ip_map_num) <= 0) {
request->ip_ttl = ttl; request->ip_ttl = ttl;
@@ -2948,6 +3019,12 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, const
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN); dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
} break; } break;
default: default:
if (ttl == 0) {
/* Get TTL */
char tmpname[DNS_MAX_CNAME_LEN];
char tmpbuf[DNS_MAX_CNAME_LEN];
dns_get_CNAME(rrs, tmpname, DNS_MAX_CNAME_LEN, &ttl, tmpbuf, DNS_MAX_CNAME_LEN);
}
break; break;
} }
} }
@@ -3037,7 +3114,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
char cname[DNS_MAX_CNAME_LEN]; char cname[DNS_MAX_CNAME_LEN];
char name[DNS_MAX_CNAME_LEN] = {0}; char name[DNS_MAX_CNAME_LEN] = {0};
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN); dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
tlog(TLOG_DEBUG, "NS: %s ttl: %d cname: %s\n", name, ttl, cname); tlog(TLOG_DEBUG, "NS: %s, ttl: %d, cname: %s\n", name, ttl, cname);
} break; } break;
case DNS_T_CNAME: { case DNS_T_CNAME: {
char cname[DNS_MAX_CNAME_LEN]; char cname[DNS_MAX_CNAME_LEN];
@@ -3047,7 +3124,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
} }
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN); dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", name, ttl, cname); tlog(TLOG_DEBUG, "name: %s, ttl: %d, cname: %s\n", name, ttl, cname);
if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 && if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) { strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
continue; continue;
@@ -3133,7 +3210,12 @@ static void _dns_server_query_end(struct dns_request *request)
/* Not need to wait check result if only has one ip address */ /* Not need to wait check result if only has one ip address */
if (ip_num == 1 && request_wait == 1) { if (ip_num == 1 && request_wait == 1) {
if (request->dualstack_selection_query == 1) { if (request->dualstack_selection_query == 1) {
_dns_server_request_complete(request); if ((dns_conf_ipset_no_speed.ipv4_enable || dns_conf_nftset_no_speed.ip6_enable ||
dns_conf_ipset_no_speed.ipv6_enable || dns_conf_nftset_no_speed.ip6_enable) &&
dns_conf_dns_dns64.prefix_len == 0) {
/* if speed check fail enabled, we need reply quickly, otherwise wait for ping result.*/
_dns_server_request_complete(request);
}
goto out; goto out;
} }
@@ -3681,7 +3763,7 @@ static int _dns_server_get_rules(unsigned char *key, uint32_t key_len, int is_su
return 0; return 0;
} }
static void _dns_server_get_domain_rule(struct dns_request *request) static void _dns_server_get_domain_rule_by_domain(struct dns_request *request, const char *domain, int out_log)
{ {
int domain_len = 0; int domain_len = 0;
char domain_key[DNS_MAX_CNAME_LEN]; char domain_key[DNS_MAX_CNAME_LEN];
@@ -3690,12 +3772,16 @@ static void _dns_server_get_domain_rule(struct dns_request *request)
struct rule_walk_args walk_args; struct rule_walk_args walk_args;
int i = 0; int i = 0;
if (request->skip_domain_rule != 0) {
return;
}
memset(&walk_args, 0, sizeof(walk_args)); memset(&walk_args, 0, sizeof(walk_args));
walk_args.args = request; walk_args.args = request;
/* reverse domain string */ /* reverse domain string */
domain_len = strlen(request->domain); domain_len = strlen(domain);
reverse_string(domain_key, request->domain, domain_len, 1); reverse_string(domain_key, domain, domain_len, 1);
domain_key[domain_len] = '.'; domain_key[domain_len] = '.';
domain_len++; domain_len++;
domain_key[domain_len] = 0; domain_key[domain_len] = 0;
@@ -3722,8 +3808,17 @@ static void _dns_server_get_domain_rule(struct dns_request *request)
matched_key_len--; matched_key_len--;
matched_key[matched_key_len] = 0; matched_key[matched_key_len] = 0;
_dns_server_log_rule(request->domain, i, matched_key, matched_key_len); if (out_log != 0) {
_dns_server_log_rule(request->domain, i, matched_key, matched_key_len);
}
} }
request->skip_domain_rule = 1;
}
static void _dns_server_get_domain_rule(struct dns_request *request)
{
_dns_server_get_domain_rule_by_domain(request, request->domain, 1);
} }
static int _dns_server_pre_process_rule_flags(struct dns_request *request) static int _dns_server_pre_process_rule_flags(struct dns_request *request)
@@ -3794,6 +3889,34 @@ soa:
return 0; return 0;
} }
static int _dns_server_get_local_ttl(struct dns_request *request)
{
struct dns_ttl_rule *ttl_rule;
/* get domain rule flag */
ttl_rule = _dns_server_get_dns_rule(request, DOMAIN_RULE_TTL);
if (ttl_rule != NULL) {
if (ttl_rule->ttl > 0) {
return ttl_rule->ttl;
}
}
if (dns_conf_local_ttl > 0) {
return dns_conf_local_ttl;
}
if (dns_conf_rr_ttl > 0) {
return dns_conf_rr_ttl;
}
if (dns_conf_rr_ttl_min > 0) {
return dns_conf_rr_ttl_min;
}
return DNS_SERVER_ADDR_TTL;
}
static int _dns_server_process_address(struct dns_request *request) static int _dns_server_process_address(struct dns_request *request)
{ {
struct dns_rule_address_IPV4 *address_ipv4 = NULL; struct dns_rule_address_IPV4 *address_ipv4 = NULL;
@@ -3825,7 +3948,7 @@ static int _dns_server_process_address(struct dns_request *request)
} }
request->rcode = DNS_RC_NOERROR; request->rcode = DNS_RC_NOERROR;
request->ip_ttl = dns_conf_local_ttl; request->ip_ttl = _dns_server_get_local_ttl(request);
request->has_ip = 1; request->has_ip = 1;
struct dns_server_post_context context; struct dns_server_post_context context;
@@ -3840,8 +3963,8 @@ errout:
return -1; return -1;
} }
static struct dns_request *_dns_server_new_child_request(struct dns_request *request, static struct dns_request *_dns_server_new_child_request(struct dns_request *request, const char *domain,
child_request_callback child_callback) dns_type_t qtype, child_request_callback child_callback)
{ {
struct dns_request *child_request = NULL; struct dns_request *child_request = NULL;
@@ -3853,10 +3976,14 @@ static struct dns_request *_dns_server_new_child_request(struct dns_request *req
child_request->server_flags = request->server_flags; child_request->server_flags = request->server_flags;
safe_strncpy(child_request->dns_group_name, request->dns_group_name, sizeof(request->dns_group_name)); safe_strncpy(child_request->dns_group_name, request->dns_group_name, sizeof(request->dns_group_name));
safe_strncpy(child_request->domain, domain, sizeof(child_request->domain));
child_request->prefetch = request->prefetch; child_request->prefetch = request->prefetch;
child_request->prefetch_expired_domain = request->prefetch_expired_domain; child_request->prefetch_expired_domain = request->prefetch_expired_domain;
child_request->child_callback = child_callback; child_request->child_callback = child_callback;
child_request->parent_request = request; child_request->parent_request = request;
child_request->qtype = qtype;
child_request->qclass = request->qclass;
if (request->has_ecs) { if (request->has_ecs) {
memcpy(&child_request->ecs, &request->ecs, sizeof(child_request->ecs)); memcpy(&child_request->ecs, &request->ecs, sizeof(child_request->ecs));
child_request->has_ecs = request->has_ecs; child_request->has_ecs = request->has_ecs;
@@ -3864,6 +3991,7 @@ static struct dns_request *_dns_server_new_child_request(struct dns_request *req
_dns_server_request_get(request); _dns_server_request_get(request);
/* reference count is 1 hold by parent request */ /* reference count is 1 hold by parent request */
request->child_request = child_request; request->child_request = child_request;
_dns_server_get_domain_rule(child_request);
return child_request; return child_request;
errout: errout:
if (child_request) { if (child_request) {
@@ -3885,7 +4013,7 @@ static int _dns_server_request_copy(struct dns_request *request, struct dns_requ
if (from->has_ip) { if (from->has_ip) {
request->has_ip = 1; request->has_ip = 1;
request->ip_ttl = from->ip_ttl; request->ip_ttl = _dns_server_get_conf_ttl(request, from->ip_ttl);
request->ping_time = from->ping_time; request->ping_time = from->ping_time;
memcpy(request->ip_addr, from->ip_addr, sizeof(request->ip_addr)); memcpy(request->ip_addr, from->ip_addr, sizeof(request->ip_addr));
} }
@@ -3946,14 +4074,57 @@ static DNS_CHILD_POST_RESULT _dns_server_process_cname_callback(struct dns_reque
struct dns_request *child_request, int is_first_resp) struct dns_request *child_request, int is_first_resp)
{ {
_dns_server_request_copy(request, child_request); _dns_server_request_copy(request, child_request);
safe_strncpy(request->cname, child_request->domain, sizeof(request->cname)); if (child_request->rcode == DNS_RC_NOERROR && dns_conf_force_no_cname == 0 && child_request->has_soa == 0) {
safe_strncpy(request->cname, child_request->domain, sizeof(request->cname));
request->has_cname = 1;
request->ttl_cname = _dns_server_get_conf_ttl(request, child_request->ip_ttl);
}
return DNS_CHILD_POST_SUCCESS; return DNS_CHILD_POST_SUCCESS;
} }
static int _dns_server_process_cname_pre(struct dns_request *request)
{
struct dns_cname_rule *cname = NULL;
struct dns_rule_flags *rule_flag = NULL;
struct dns_domain_rule domain_rule;
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_CNAME) == 0) {
return 0;
}
/* get domain rule flag */
rule_flag = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS);
if (rule_flag != NULL) {
if (rule_flag->flags & DOMAIN_FLAG_CNAME_IGN) {
return 0;
}
}
cname = _dns_server_get_dns_rule(request, DOMAIN_RULE_CNAME);
if (cname == NULL) {
return 0;
}
request->skip_domain_rule = 0;
/* copy child rules */
memcpy(&domain_rule, &request->domain_rule, sizeof(domain_rule));
memset(&request->domain_rule, 0, sizeof(request->domain_rule));
_dns_server_get_domain_rule_by_domain(request, cname->cname, 0);
request->domain_rule.rules[DOMAIN_RULE_CNAME] = domain_rule.rules[DOMAIN_RULE_CNAME];
request->domain_rule.is_sub_rule[DOMAIN_RULE_CNAME] = domain_rule.is_sub_rule[DOMAIN_RULE_CNAME];
request->no_select_possible_ip = 1;
request->no_cache_cname = 1;
safe_strncpy(request->cname, cname->cname, sizeof(request->cname));
return 0;
}
static int _dns_server_process_cname(struct dns_request *request) static int _dns_server_process_cname(struct dns_request *request)
{ {
struct dns_cname_rule *cname = NULL; struct dns_cname_rule *cname = NULL;
const char *child_group_name = NULL;
int ret = 0; int ret = 0;
struct dns_rule_flags *rule_flag = NULL; struct dns_rule_flags *rule_flag = NULL;
@@ -3969,11 +4140,6 @@ static int _dns_server_process_cname(struct dns_request *request)
} }
} }
/* cname /domain/ rule */
if (request->domain_rule.rules[DOMAIN_RULE_CNAME] == NULL) {
return 0;
}
cname = _dns_server_get_dns_rule(request, DOMAIN_RULE_CNAME); cname = _dns_server_get_dns_rule(request, DOMAIN_RULE_CNAME);
if (cname == NULL) { if (cname == NULL) {
return 0; return 0;
@@ -3981,15 +4147,18 @@ static int _dns_server_process_cname(struct dns_request *request)
tlog(TLOG_INFO, "query %s with cname %s", request->domain, cname->cname); tlog(TLOG_INFO, "query %s with cname %s", request->domain, cname->cname);
struct dns_request *child_request = _dns_server_new_child_request(request, _dns_server_process_cname_callback); struct dns_request *child_request =
_dns_server_new_child_request(request, cname->cname, request->qtype, _dns_server_process_cname_callback);
if (child_request == NULL) { if (child_request == NULL) {
tlog(TLOG_ERROR, "malloc failed.\n"); tlog(TLOG_ERROR, "malloc failed.\n");
return -1; return -1;
} }
child_request->qtype = request->qtype; child_group_name = _dns_server_get_request_groupname(child_request);
child_request->qclass = request->qclass; if (child_group_name) {
safe_strncpy(child_request->domain, cname->cname, sizeof(child_request->cname)); /* reset dns group and setup child request domain group again when do query.*/
child_request->dns_group_name[0] = '\0';
}
request->request_wait++; request->request_wait++;
ret = _dns_server_do_query(child_request, 0); ret = _dns_server_do_query(child_request, 0);
@@ -4031,6 +4200,12 @@ _dns_server_process_dns64_callback(struct dns_request *request, struct dns_reque
return DNS_CHILD_POST_FAIL; return DNS_CHILD_POST_FAIL;
} }
if (child_request->has_cname == 1) {
safe_strncpy(request->cname, child_request->cname, sizeof(request->cname));
request->has_cname = 1;
request->ttl_cname = child_request->ttl_cname;
}
if (child_request->has_ip == 0) { if (child_request->has_ip == 0) {
if (child_request->has_soa) { if (child_request->has_soa) {
memcpy(&request->soa, &child_request->soa, sizeof(struct dns_soa)); memcpy(&request->soa, &child_request->soa, sizeof(struct dns_soa));
@@ -4078,7 +4253,7 @@ _dns_server_process_dns64_callback(struct dns_request *request, struct dns_reque
return DNS_CHILD_POST_FAIL; return DNS_CHILD_POST_FAIL;
} }
memset(new_addr_map, 0, sizeof(struct dns_ip_address)); memset(new_addr_map, 0, sizeof(struct dns_ip_address));
new_addr_map->addr_type = DNS_T_AAAA; new_addr_map->addr_type = DNS_T_AAAA;
addr_len = DNS_RR_AAAA_LEN; addr_len = DNS_RR_AAAA_LEN;
memcpy(new_addr_map->ip_addr, dns_conf_dns_dns64.prefix, 16); memcpy(new_addr_map->ip_addr, dns_conf_dns_dns64.prefix, 16);
@@ -4102,27 +4277,19 @@ _dns_server_process_dns64_callback(struct dns_request *request, struct dns_reque
static int _dns_server_process_dns64(struct dns_request *request) static int _dns_server_process_dns64(struct dns_request *request)
{ {
if (request->qtype != DNS_T_AAAA) { if (_dns_server_is_dns64_request(request) == 0) {
return 0;
}
if (dns_conf_dns_dns64.prefix_len <= 0) {
/* no dns64 prefix, no need to do dns64 */
return 0; return 0;
} }
tlog(TLOG_DEBUG, "query %s with dns64", request->domain); tlog(TLOG_DEBUG, "query %s with dns64", request->domain);
struct dns_request *child_request = _dns_server_new_child_request(request, _dns_server_process_dns64_callback); struct dns_request *child_request =
_dns_server_new_child_request(request, request->domain, DNS_T_A, _dns_server_process_dns64_callback);
if (child_request == NULL) { if (child_request == NULL) {
tlog(TLOG_ERROR, "malloc failed.\n"); tlog(TLOG_ERROR, "malloc failed.\n");
return -1; return -1;
} }
child_request->qtype = DNS_T_A;
child_request->qclass = request->qclass;
safe_strncpy(child_request->domain, request->domain, sizeof(child_request->domain));
request->request_wait++; request->request_wait++;
int ret = _dns_server_do_query(child_request, 0); int ret = _dns_server_do_query(child_request, 0);
if (ret != 0) { if (ret != 0) {
@@ -4184,10 +4351,6 @@ static int _dns_server_get_expired_ttl_reply(struct dns_cache *dns_cache)
{ {
int ttl = dns_cache_get_ttl(dns_cache); int ttl = dns_cache_get_ttl(dns_cache);
if (ttl > 0) { if (ttl > 0) {
if (dns_conf_rr_ttl_reply_max > 0 && ttl > dns_conf_rr_ttl_reply_max) {
ttl = dns_conf_rr_ttl_reply_max;
}
return ttl; return ttl;
} }
@@ -4299,7 +4462,6 @@ static int _dns_server_process_cache_data(struct dns_request *request, struct dn
if (ret != 0) { if (ret != 0) {
goto out; goto out;
} }
break; break;
default: default:
goto out; goto out;
@@ -4352,9 +4514,13 @@ static int _dns_server_process_cache(struct dns_request *request)
cache_key.qtype = dualstack_qtype; cache_key.qtype = dualstack_qtype;
dualstack_dns_cache = dns_cache_lookup(&cache_key); dualstack_dns_cache = dns_cache_lookup(&cache_key);
if (dualstack_dns_cache == NULL && request->cname[0] != '\0') {
cache_key.domain = request->cname;
dualstack_dns_cache = dns_cache_lookup(&cache_key);
}
if (dualstack_dns_cache && dns_cache_is_soa(dualstack_dns_cache) == 0 && if (dualstack_dns_cache && dns_cache_is_soa(dualstack_dns_cache) == 0 &&
(dualstack_dns_cache->info.speed > 0)) { (dualstack_dns_cache->info.speed > 0)) {
if (dns_cache_is_soa(dns_cache)) { if (dns_cache_is_soa(dns_cache)) {
ret = _dns_server_process_cache_packet(request, dns_cache); ret = _dns_server_process_cache_packet(request, dns_cache);
goto out_update_cache; goto out_update_cache;
@@ -4366,6 +4532,7 @@ static int _dns_server_process_cache(struct dns_request *request)
tlog(TLOG_DEBUG, "cache result: %s, qtype: %d, force %s preferred, id: %d, time1: %d, time2: %d", tlog(TLOG_DEBUG, "cache result: %s, qtype: %d, force %s preferred, id: %d, time1: %d, time2: %d",
request->domain, request->qtype, request->qtype == DNS_T_AAAA ? "IPv4" : "IPv6", request->id, request->domain, request->qtype, request->qtype == DNS_T_AAAA ? "IPv4" : "IPv6", request->id,
dns_cache->info.speed, dualstack_dns_cache->info.speed); dns_cache->info.speed, dualstack_dns_cache->info.speed);
request->ip_ttl = _dns_server_get_expired_ttl_reply(dualstack_dns_cache);
ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request); ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request);
goto out_update_cache; goto out_update_cache;
} }
@@ -4699,7 +4866,7 @@ static int _dns_server_query_dualstack(struct dns_request *request)
{ {
int ret = -1; int ret = -1;
struct dns_request *request_dualstack = NULL; struct dns_request *request_dualstack = NULL;
int qtype = request->qtype; dns_type_t qtype = request->qtype;
if (request->dualstack_selection == 0) { if (request->dualstack_selection == 0) {
return 0; return 0;
@@ -4775,6 +4942,10 @@ static int _dns_server_do_query(struct dns_request *request, int skip_notify_eve
safe_strncpy(request->dns_group_name, group_name, DNS_GROUP_NAME_LEN); safe_strncpy(request->dns_group_name, group_name, DNS_GROUP_NAME_LEN);
} }
if (_dns_server_process_cname_pre(request) != 0) {
goto errout;
}
_dns_server_set_dualstack_selection(request); _dns_server_set_dualstack_selection(request);
if (_dns_server_process_special_query(request) == 0) { if (_dns_server_process_special_query(request) == 0) {

View File

@@ -336,7 +336,8 @@ static struct addrinfo *_fast_ping_getaddr(const char *host, const char *port, i
hints.ai_protocol = protocol; hints.ai_protocol = protocol;
errcode = getaddrinfo(host, port, &hints, &result); errcode = getaddrinfo(host, port, &hints, &result);
if (errcode != 0) { if (errcode != 0) {
tlog(TLOG_ERROR, "get addr info failed. host:%s, port: %s, error %s\n", host, port, gai_strerror(errcode)); tlog(TLOG_ERROR, "get addr info failed. host:%s, port: %s, error %s\n", host != NULL ? host : "",
port != NULL ? port : "", gai_strerror(errcode));
goto errout; goto errout;
} }

View File

@@ -110,6 +110,7 @@ struct tlog {
tlog_log_output_func output_func; tlog_log_output_func output_func;
struct tlog_log *wait_on_log; struct tlog_log *wait_on_log;
int is_wait; int is_wait;
char gzip_cmd[PATH_MAX];
}; };
struct tlog_segment_log_head { struct tlog_segment_log_head {
@@ -520,7 +521,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
return -1; return -1;
} }
if (unlikely(log->logcount <= 0 && log->logscreen == 0) ) { if (unlikely(log->logcount <= 0 && log->logscreen == 0)) {
return 0; return 0;
} }
@@ -1018,7 +1019,6 @@ errout:
static int _tlog_archive_log_compressed(struct tlog_log *log) static int _tlog_archive_log_compressed(struct tlog_log *log)
{ {
char gzip_file[TLOG_BUFF_LEN]; char gzip_file[TLOG_BUFF_LEN];
char gzip_cmd[PATH_MAX * 2];
char log_file[TLOG_BUFF_LEN]; char log_file[TLOG_BUFF_LEN];
char pending_file[TLOG_BUFF_LEN]; char pending_file[TLOG_BUFF_LEN];
@@ -1046,12 +1046,11 @@ static int _tlog_archive_log_compressed(struct tlog_log *log)
} }
/* start gzip process to compress log file */ /* start gzip process to compress log file */
snprintf(gzip_cmd, sizeof(gzip_cmd), "gzip -1 %s", pending_file);
if (log->zip_pid <= 0) { if (log->zip_pid <= 0) {
int pid = vfork(); int pid = vfork();
if (pid == 0) { if (pid == 0) {
_tlog_close_all_fd(); _tlog_close_all_fd();
execl("/bin/sh", "sh", "-c", gzip_cmd, NULL); execl(tlog.gzip_cmd, tlog.gzip_cmd, "-1", pending_file, NULL);
_exit(1); _exit(1);
} else if (pid < 0) { } else if (pid < 0) {
goto errout; goto errout;
@@ -1363,12 +1362,26 @@ static struct tlog_log *_tlog_wait_log_locked(struct tlog_log *last_log)
int ret = 0; int ret = 0;
struct timespec tm; struct timespec tm;
struct tlog_log *log = NULL; struct tlog_log *log = NULL;
struct tlog_log *next = NULL;
int need_wait_pid = 0;
for (next = tlog.log; next != NULL; next = next->next) {
if (next->zip_pid > 0) {
need_wait_pid = 1;
break;
}
}
clock_gettime(CLOCK_REALTIME, &tm); clock_gettime(CLOCK_REALTIME, &tm);
tm.tv_sec += 2; tm.tv_sec += 2;
tlog.is_wait = 1; tlog.is_wait = 1;
tlog.wait_on_log = last_log; tlog.wait_on_log = last_log;
ret = pthread_cond_timedwait(&tlog.cond, &tlog.lock, &tm); if (need_wait_pid != 0) {
ret = pthread_cond_timedwait(&tlog.cond, &tlog.lock, &tm);
} else {
ret = pthread_cond_wait(&tlog.cond, &tlog.lock);
}
tlog.is_wait = 0; tlog.is_wait = 0;
tlog.wait_on_log = NULL; tlog.wait_on_log = NULL;
errno = ret; errno = ret;
@@ -1676,6 +1689,15 @@ int tlog_setlevel(tlog_level level)
return 0; return 0;
} }
int tlog_log_enabled(tlog_level level)
{
if (level >= TLOG_END) {
return 0;
}
return (tlog_set_level >= level) ? 1 : 0;
}
tlog_level tlog_getlevel(void) tlog_level tlog_getlevel(void)
{ {
return tlog_set_level; return tlog_set_level;
@@ -1686,6 +1708,35 @@ void tlog_set_logfile(const char *logfile)
tlog_rename_logfile(tlog.root, logfile); tlog_rename_logfile(tlog.root, logfile);
} }
static void _tlog_get_gzip_cmd_path(void)
{
char *copy_path = NULL;
char gzip_cmd_path[PATH_MAX];
const char *env_path = getenv("PATH");
char *save_ptr = NULL;
if (env_path == NULL) {
env_path = "/bin:/usr/bin:/usr/local/bin";
}
copy_path = strdup(env_path);
if (copy_path == NULL) {
return;
}
for (char *tok = strtok_r(copy_path, ":", &save_ptr); tok; tok = strtok_r(NULL, ":", &save_ptr)) {
snprintf(gzip_cmd_path, sizeof(gzip_cmd_path), "%s/gzip", tok);
if (access(gzip_cmd_path, X_OK) != 0) {
continue;
}
snprintf(tlog.gzip_cmd, sizeof(tlog.gzip_cmd), "%s", gzip_cmd_path);
break;
}
free(copy_path);
}
tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag) tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag)
{ {
struct tlog_log *log = NULL; struct tlog_log *log = NULL;
@@ -1726,6 +1777,10 @@ tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int bu
log->file_perm = S_IRUSR | S_IWUSR | S_IRGRP; log->file_perm = S_IRUSR | S_IWUSR | S_IRGRP;
log->archive_perm = S_IRUSR | S_IRGRP; log->archive_perm = S_IRUSR | S_IRGRP;
if (log->nocompress == 0 && tlog.gzip_cmd[0] == '\0') {
log->nocompress = 1;
}
tlog_rename_logfile(log, logfile); tlog_rename_logfile(log, logfile);
if (log->nocompress) { if (log->nocompress) {
strncpy(log->suffix, TLOG_SUFFIX_LOG, sizeof(log->suffix)); strncpy(log->suffix, TLOG_SUFFIX_LOG, sizeof(log->suffix));
@@ -1859,6 +1914,7 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
memset(&tlog, 0, sizeof(tlog)); memset(&tlog, 0, sizeof(tlog));
tlog.is_wait = 0; tlog.is_wait = 0;
_tlog_get_gzip_cmd_path();
pthread_attr_init(&attr); pthread_attr_init(&attr);
pthread_cond_init(&tlog.cond, NULL); pthread_cond_init(&tlog.cond, NULL);
pthread_mutex_init(&tlog.lock, NULL); pthread_mutex_init(&tlog.lock, NULL);
@@ -1871,6 +1927,10 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
} }
tlog_reg_output_func(log, _tlog_root_write_log); tlog_reg_output_func(log, _tlog_root_write_log);
if ((flag & TLOG_NOCOMPRESS) == 0 && tlog.gzip_cmd[0] == '\0') {
fprintf(stderr, "can not find gzip command, disable compress.\n");
}
tlog.root = log; tlog.root = log;
ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL); ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL);
if (ret != 0) { if (ret != 0) {

View File

@@ -79,9 +79,9 @@ level: Current log Levels
format: Log formats format: Log formats
*/ */
#ifndef BASE_FILE_NAME #ifndef BASE_FILE_NAME
#define BASE_FILE_NAME \ #define BASE_FILE_NAME \
(__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \ (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \
: __FILE__) : __FILE__)
#endif #endif
#define tlog(level, format, ...) tlog_ext(level, BASE_FILE_NAME, __LINE__, __func__, NULL, format, ##__VA_ARGS__) #define tlog(level, format, ...) tlog_ext(level, BASE_FILE_NAME, __LINE__, __func__, NULL, format, ##__VA_ARGS__)
@@ -95,6 +95,9 @@ extern int tlog_write_log(char *buff, int bufflen);
/* set log level */ /* set log level */
extern int tlog_setlevel(tlog_level level); extern int tlog_setlevel(tlog_level level);
/* is log level enabled*/
extern int tlog_log_enabled(tlog_level level);
/* get log level */ /* get log level */
extern tlog_level tlog_getlevel(void); extern tlog_level tlog_getlevel(void);
@@ -137,7 +140,7 @@ read _tlog_format for example.
typedef int (*tlog_format_func)(char *buff, int maxlen, struct tlog_loginfo *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); extern int tlog_reg_format_func(tlog_format_func func);
/* register log output callback /* register log output callback
Note: info is invalid when flag TLOG_SEGMENT is not set. Note: info is invalid when flag TLOG_SEGMENT is not set.
*/ */
typedef int (*tlog_log_output_func)(struct tlog_loginfo *info, const 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);
@@ -213,7 +216,7 @@ file: log file permission, default is 640
archive: archive file permission, default is 440 archive: archive file permission, default is 440
*/ */
extern void tlog_set_permission(struct tlog_log *log, mode_t file, mode_t archive); extern void tlog_set_permission(struct tlog_log *log, mode_t file, mode_t archive);
#ifdef __cplusplus #ifdef __cplusplus
class Tlog { class Tlog {