Compare commits

..

23 Commits

Author SHA1 Message Date
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
Nick Peng
d2d7dac7e9 dns_server: fix ttl issue. 2023-02-17 22:39:23 +08:00
Nick Peng
a62d716b10 smartdns: fix valgrind warnings. 2023-02-17 22:09:38 +08:00
Nick Peng
694d093fc4 smartdns: fix compile warnings for gcc 11. 2023-02-17 21:51:17 +08:00
Nick Peng
464bf28601 ReadMe: update rust version smartdns link 2023-02-17 21:06:40 +08:00
Nick Peng
24e1dac854 feature: Simple add dns64 support. 2023-02-17 20:51:48 +08:00
Nick Peng
e51580ea57 luci: move auto set dnsmasq option to basic settings 2023-02-16 23:09:37 +08:00
Nick Peng
499ab1b64f feature: support set ttl, ttl-min, ttl-max to domain. 2023-02-14 22:46:15 +08:00
Nick Peng
db56472b84 luci: add ipset-no-speed and nftset-no-speed options. 2023-02-12 23:02:13 +08:00
Nick Peng
60e3a109e4 dns_client: fix bootstrap DNS soa host issue. 2023-02-12 16:00:19 +08:00
Nick Peng
7256f5af32 cname: fix cname recursive query issue 2023-02-12 12:29:21 +08:00
Nick Peng
1e6a5f3809 luci: simple fix server option URI parse issue 2023-02-11 23:26:48 +08:00
Nick Peng
4941594182 dns_client: bootstrap dns: fail when domain not found. 2023-02-11 15:15:06 +08:00
Nick Peng
a6d6781a2a feature: add cname option 2023-02-11 14:34:23 +08:00
Nick Peng
be71e085ad dns_conf: fix relative path issue 2023-02-09 21:37:35 +08:00
Nick Peng
69a2f3bb7f feature: add new option: ipset-no-speed and nftset-no-speed 2023-02-09 21:31:02 +08:00
Nick Peng
d6f9b07f1c dns_client: use RAND_bytes instead getrandom for compatibility 2023-02-03 22:34:57 +08:00
Nick Peng
03ba24480b smartdns: support multiline config option and fix timer issue. 2023-02-02 20:23:53 +08:00
23 changed files with 1394 additions and 234 deletions

View File

@@ -112,7 +112,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
支持域名后缀匹配模式,简化过滤配置,过滤 20 万条记录时间 < 1ms。 支持域名后缀匹配模式,简化过滤配置,过滤 20 万条记录时间 < 1ms。
1. **域名分流** 1. **域名分流**
支持域名分流,不同类型的域名向不同的 DNS 服务器查询支持iptable和nftable更好的分流。 支持域名分流,不同类型的域名向不同的 DNS 服务器查询支持iptable和nftable更好的分流支持测速失败的情况下设置域名结果到对应ipset和nftset集合
1. **Windows / Linux 多平台支持** 1. **Windows / Linux 多平台支持**
支持标准 Linux 系统树莓派、OpenWrt 系统各种固件和华硕路由器原生固件。同时还支持 WSLWindows Subsystem for Linux适用于 Linux 的 Windows 子系统)。 支持标准 Linux 系统树莓派、OpenWrt 系统各种固件和华硕路由器原生固件。同时还支持 WSLWindows Subsystem for Linux适用于 Linux 的 Windows 子系统)。
@@ -120,10 +120,13 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
1. **支持 IPv4、IPv6 双栈** 1. **支持 IPv4、IPv6 双栈**
支持 IPv4 和 IPV 6网络支持查询 A 和 AAAA 记录,支持双栈 IP 速度优化,并支持完全禁用 IPv6 AAAA 解析。 支持 IPv4 和 IPV 6网络支持查询 A 和 AAAA 记录,支持双栈 IP 速度优化,并支持完全禁用 IPv6 AAAA 解析。
1. **支持DNS64**
支持DNS64转换。
1. **高性能、占用资源少** 1. **高性能、占用资源少**
多线程异步 IO 模式cache 缓存查询结果。 多线程异步 IO 模式cache 缓存查询结果。
1. **主流系统官方支持** 1. **主流系统官方支持**
主流路由系统官方软件源安装smartdns。 主流路由系统官方软件源安装smartdns。
## 架构 ## 架构
@@ -170,7 +173,7 @@ entware|ipkg update<br />ipkg install smartdns|软件源路径:<https://bin.en
| 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 及之前版本 |
**[前往 Release 页面下载](https://github.com/pymumu/smartdns/releases)。** **[前往 Release 页面下载](https://github.com/pymumu/smartdns/releases)。**
**请注意:** **请注意:**
@@ -178,6 +181,8 @@ 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 系统 / 树莓派
@@ -602,13 +607,17 @@ entware|ipkg update<br />ipkg install smartdns|软件源路径:<https://bin.en
| speed-check-mode | 测速模式选择 | 无 | [ping\|tcp:[80]\|none] | speed-check-mode ping,tcp:80,tcp:443 | | speed-check-mode | 测速模式选择 | 无 | [ping\|tcp:[80]\|none] | speed-check-mode ping,tcp:80,tcp:443 |
| response-mode | 首次查询响应模式 | first-ping |模式:[first-ping\|fastest-ip\|fastest-response]<br /> [first-ping]: 最快ping响应地址模式DNS上游最快查询时延+ping时延最短查询等待与链接体验最佳;<br />[fastest-ip]: 最快IP地址模式查询到的所有IP地址中ping最短的IP。需等待IP测速; <br />[fastest-response]: 最快响应的DNS结果DNS查询等待时间最短返回的IP地址可能不是最快。| response-mode first-ping | | response-mode | 首次查询响应模式 | first-ping |模式:[first-ping\|fastest-ip\|fastest-response]<br /> [first-ping]: 最快ping响应地址模式DNS上游最快查询时延+ping时延最短查询等待与链接体验最佳;<br />[fastest-ip]: 最快IP地址模式查询到的所有IP地址中ping最短的IP。需等待IP测速; <br />[fastest-response]: 最快响应的DNS结果DNS查询等待时间最短返回的IP地址可能不是最快。| response-mode first-ping |
| address | 指定域名 IP 地址 | 无 | address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6] <br />- 表示忽略 <br /># 表示返回 SOA <br />4 表示 IPv4 <br />6 表示 IPv6 | address /www.example.com/1.2.3.4 | | address | 指定域名 IP 地址 | 无 | address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6] <br />- 表示忽略 <br /># 表示返回 SOA <br />4 表示 IPv4 <br />6 表示 IPv6 | address /www.example.com/1.2.3.4 |
| cname | 指定域名别名 | 无 | cname /domain/target <br />- 表示忽略 <br />指定对应域名的cname | cname /www.example.com/cdn.example.com |
| dns64 | DNS64转换 | 无 | dns64 ip-prefix/mask <br /> ipv6前缀和掩码 | dns64 64:ff9b::/96 |
| 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:- | | 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 |
| nftset | 域名 nftset | 无 | nftset /domain/[#4\|#6\|-]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]]-表示忽略ipv4 地址的 family 只支持 inet 和 ipipv6 地址的 family 只支持 inet 和 ip6由于 nft 限制,两种地址只能分开存放于两个 set 中。| nftset /www.example.com/#4:inet#tab#dns4,#6:- | | ipset-no-speed | 当测速失败时将域名结果设置到ipset集合中 | 无 | ipset \| #[4\|6]:ipset | ipset-no-speed #4:ipset4,#6:ipse6 <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-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-debug | 设置 nftset 调试功能启用 | no | [yes\|no] | nftset-debug yes | | nftset-debug | 设置 nftset 调试功能启用 | no | [yes\|no] | nftset-debug yes |
| domain-rules | 设置域名规则 | 无 | domain-rules /domain/ [-rules...]<br />[-c\|-speed-check-mode]:测速模式,参考 speed-check-mode 配置<br />[-a\|-address]:参考 address 配置<br />[-n\|-nameserver]:参考 nameserver 配置<br />[-p\|-ipset]参考ipset配置<br />[-t\|-nftset]参考nftset配置<br />[-d\|-dualstack-ip-selection]:参考 dualstack-ip-selection<br /> [-no-serve-expired]:禁用过期缓存<br />[-delete]:删除对应的规则 | domain-rules /www.example.com/ -speed-check-mode none | | domain-rules | 设置域名规则 | 无 | domain-rules /domain/ [-rules...]<br />[-c\|-speed-check-mode]:测速模式,参考 speed-check-mode 配置<br />[-a\|-address]:参考 address 配置<br />[-n\|-nameserver]:参考 nameserver 配置<br />[-p\|-ipset]参考ipset配置<br />[-t\|-nftset]参考nftset配置<br />[-d\|-dualstack-ip-selection]:参考 dualstack-ip-selection<br /> [-no-serve-expired]:禁用过期缓存<br />[-rr-ttl\|-rr-ttl-min\|-rr-ttl-max]: 参考配置rr-ttl, rr-ttl-min, rr-ttl-max<br />[-delete]:删除对应的规则 | domain-rules /www.example.com/ -speed-check-mode none |
| domain-set | 设置域名集合 | 无 | domain-set [options...]<br />[-n\|-name]:域名集合名称 <br />[-t\|-type]域名集合类型当前仅支持list格式为域名列表一行一个域名。<br />[-f\|-file]:域名集合文件路径。<br /> 选项需要配合address, nameserver, ipset, nftset等需要指定域名的地方使用使用方式为 /domain-set:[name]/| domain-set -name set -type list -file /path/to/list <br /> address /domain-set:set/1.2.4.8 | | domain-set | 设置域名集合 | 无 | domain-set [options...]<br />[-n\|-name]:域名集合名称 <br />[-t\|-type]域名集合类型当前仅支持list格式为域名列表一行一个域名。<br />[-f\|-file]:域名集合文件路径。<br /> 选项需要配合address, nameserver, ipset, nftset等需要指定域名的地方使用使用方式为 /domain-set:[name]/| domain-set -name set -type list -file /path/to/list <br /> address /domain-set:set/1.2.4.8 |
| bogus-nxdomain | 假冒 IP 地址过滤 | 无 | [ip/subnet],可重复 | bogus-nxdomain 1.2.3.4/16 | | bogus-nxdomain | 假冒 IP 地址过滤 | 无 | [ip/subnet],可重复 | bogus-nxdomain 1.2.3.4/16 |
| ignore-ip | 忽略 IP 地址 | 无 | [ip/subnet],可重复 | ignore-ip 1.2.3.4/16 | | ignore-ip | 忽略 IP 地址 | 无 | [ip/subnet],可重复 | ignore-ip 1.2.3.4/16 |
@@ -868,7 +877,8 @@ entware|ipkg update<br />ipkg install smartdns|软件源路径:<https://bin.en
1. 额外说明 1. 额外说明
为保证DNS查询结果的位置亲和性可以使用smartdns的`server`代理参数,将对应域名的查询请求,通过代理查询,使结果位置更好。如:
- 为保证DNS查询结果的位置亲和性可以使用smartdns的`server`代理参数,将对应域名的查询请求,通过代理查询,使结果位置更好。如:
```shell ```shell
# 增加DNS上游并设置通过名称为proxy的代理查询查询组为pass # 增加DNS上游并设置通过名称为proxy的代理查询查询组为pass
@@ -879,6 +889,12 @@ entware|ipkg update<br />ipkg install smartdns|软件源路径:<https://bin.en
domain-rules /example.com/ -ipset proxy -c none -address #6 -nameserver pass domain-rules /example.com/ -ipset proxy -c none -address #6 -nameserver pass
``` ```
- 如需要配合测速自动完成ipset的设置可增加如下配置参数
```shell
ipset-no-speed proxy
```
如果使用openwrt的luci界面可以直接在界面配置相关的域名分流规则。 如果使用openwrt的luci界面可以直接在界面配置相关的域名分流规则。
1. 更多问题 1. 更多问题

View File

@@ -115,11 +115,14 @@ From the comparison, smartdns found the fastest IP address to visit www.baidu.co
1. **Support IPV4, IPV6 dual stack** 1. **Support IPV4, IPV6 dual stack**
Support IPV4, IPV6 network, support query A, AAAA record, dual-stack IP selection, and filter IPV6 AAAA record. Support IPV4, IPV6 network, support query A, AAAA record, dual-stack IP selection, and filter IPV6 AAAA record.
1. **DNS64**
Support DNS64 translation.
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 DNS forwarding, ipset and nftables. Support setting the domain result to ipset and nftset set when speed check fails.
## Architecture ## Architecture
@@ -167,11 +170,13 @@ Download the matching version of the SmartDNS installation package. The correspo
- 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.
- **Please download from the Release page: [Download here](https://github.com/pymumu/smartdns/releases)** - **Please download from the Release page: [Download here](https://github.com/pymumu/smartdns/releases)**
```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.
@@ -565,13 +570,17 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp: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 |
|address|Domain IP address|None|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-` for ignore, `#` for return SOA, `4` for IPV4, `6` for IPV6| address /www.example.com/1.2.3.4 |address|Domain IP address|None|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-` for ignore, `#` for return SOA, `4` for IPV4, `6` for IPV6| address /www.example.com/1.2.3.4
|cname|set cname to domain| None | cname /domain/target <br />- for ignore <br />set cname to domain. | cname /www.example.com/cdn.example.com |
|dns64|dns64 translation | None | dns64 ip-prefix/mask <br /> ipv6 prefix and mask. | dns64 64:ff9b::/96 |
|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
|nftset|Domain nftset|None|nftset /domain/[#4\|#6\|-]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]], `-` to ignore; the valid families are inet and ip for ipv4 addresses while the valid ones are inet and ip6 for ipv6 addresses; due to the limitation of nft, two types of addresses have to be stored in two sets|nftset /www.example.com/#4:inet#tab#dns4,#6:- |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|
|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-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 />[-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 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-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

View File

@@ -105,7 +105,7 @@ force-qtype-SOA 65
# dualstack-ip-selection-threshold [num] (0~1000) # dualstack-ip-selection-threshold [num] (0~1000)
# dualstack-ip-allow-force-AAAA [yes|no] # dualstack-ip-allow-force-AAAA [yes|no]
# dualstack-ip-selection [yes|no] # dualstack-ip-selection [yes|no]
# dualstack-ip-selection yes # dualstack-ip-selection no
# edns client subnet # edns client subnet
# edns-client-subnet [ip/subnet] # edns-client-subnet [ip/subnet]
@@ -226,6 +226,13 @@ log-level info
# address /www.example.com/-, ignore address, query from upstream, suffix 4, for ipv4, 6 for ipv6, none for all # address /www.example.com/-, ignore address, query from upstream, suffix 4, for ipv4, 6 for ipv6, none for all
# address /www.example.com/#, return SOA to client, suffix 4, for ipv4, 6 for ipv6, none for all # address /www.example.com/#, return SOA to client, suffix 4, for ipv4, 6 for ipv6, none for all
# specific cname to domain
# cname /domain/target
# enalbe DNS64 feature
# dns64 [ip/subnet]
# dns64 64:ff9b::/96
# enable ipset timeout by ttl feature # enable ipset timeout by ttl feature
# ipset-timeout [yes] # ipset-timeout [yes]
@@ -234,10 +241,18 @@ log-level info
# ipset /www.example.com/block, set ipset with ipset name of block # ipset /www.example.com/block, set ipset with ipset name of block
# ipset /www.example.com/-, ignore this domain # ipset /www.example.com/-, ignore this domain
# add to ipset when ping is unreachable
# ipset-no-speed ipsetname
# ipset-no-speed pass
# enable nftset timeout by ttl feature # enable nftset timeout by ttl feature
# nftset-timeout [yes|no] # nftset-timeout [yes|no]
# nftset-timeout yes # nftset-timeout yes
# add to nftset when ping is unreachable
# nftset-no-speed [#4:ip#table#set,#6:ipv6#table#setv6]
# nftset-no-speed #4:ip#table#set
# enable nftset debug, check nftset setting result, output log when error. # enable nftset debug, check nftset setting result, output log when error.
# nftset-debug [yes|no] # nftset-debug [yes|no]
# nftset-debug yes # nftset-debug yes

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 "描述"
@@ -231,6 +234,12 @@ msgstr "IPSet名称"
msgid "IPset name." msgid "IPset name."
msgstr "IPSet名称。" msgstr "IPSet名称。"
msgid "Ipset name, Add domain result to ipset when speed check fails."
msgstr "IPset名称当测速失败时将查询到的结果添加到对应的IPSet集合中。"
msgid "ipset name format error, format: [#[4|6]:]ipsetname"
msgstr "IPset名称格式错误格式[#[4|6]:]ipsetname"
msgid "If you like this software, please buy me a cup of coffee." msgid "If you like this software, please buy me a cup of coffee."
msgstr "如果本软件对你有帮助,请给作者加个蛋。" msgstr "如果本软件对你有帮助,请给作者加个蛋。"
@@ -240,7 +249,7 @@ msgstr "包含配置文件"
msgid "" msgid ""
"Include other config files from /etc/smartdns/conf.d or custom path, can be " "Include other config files from /etc/smartdns/conf.d or custom path, can be "
"downloaded from the download page." "downloaded from the download page."
msgstr "包含配置文件,路径为/etc/smartdns/conf.d或自定义配置文件路径可以从下载页" msgstr "包含配置文件,路径为/etc/smartdns/conf.d或自定义配置文件路径可以从下载页配置自动下载。"
msgid "List of files to download." msgid "List of files to download."
msgstr "下载的文件列表。" msgstr "下载的文件列表。"
@@ -275,6 +284,15 @@ msgstr "NFTSet名称格式错误格式[#[4|6]:[family#table#set]]"
msgid "NFTset name, format: [#[4|6]:[family#table#set]]" msgid "NFTset name, format: [#[4|6]:[family#table#set]]"
msgstr "NFTSet名称格式[#[4|6]:[family#table#set]]" msgstr "NFTSet名称格式[#[4|6]:[family#table#set]]"
msgid "Nftset name, Add domain result to nftset when speed check fails, format: [#[4|6]:[family#table#set]]"
msgstr "NFTset名称当测速失败时将查询到的结果添加到对应的NFTSet集合中。"
msgid "No Speed IPset Name"
msgstr "无速度时IPSet名称"
msgid "No Speed NFTset Name"
msgstr "无速度时NFTSet名称"
msgid "NOT RUNNING" msgid "NOT RUNNING"
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"))
@@ -56,6 +57,14 @@ o.default = 53
o.datatype = "port" o.datatype = "port"
o.rempty = false o.rempty = false
-- Automatically Set Dnsmasq
o = s:taboption("settings", Flag, "auto_set_dnsmasq", translate("Automatically Set Dnsmasq"), translate("Automatically set as upstream of dnsmasq when port changes."))
o.rmempty = false
o.default = o.enabled
o.cfgvalue = function(...)
return Flag.cfgvalue(...) or "0"
end
---- Speed check mode; ---- Speed check mode;
o = s:taboption("advanced", Value, "speed_check_mode", translate("Speed Check Mode"), translate("Smartdns speed check mode.")); o = s:taboption("advanced", Value, "speed_check_mode", translate("Speed Check Mode"), translate("Smartdns speed check mode."));
o.rmempty = true; o.rmempty = true;
@@ -187,14 +196,6 @@ o.cfgvalue = function(...)
return Flag.cfgvalue(...) or "1" return Flag.cfgvalue(...) or "1"
end end
-- Automatically Set Dnsmasq
o = s:taboption("advanced", Flag, "auto_set_dnsmasq", translate("Automatically Set Dnsmasq"), translate("Automatically set as upstream of dnsmasq when port changes."))
o.rmempty = false
o.default = o.enabled
o.cfgvalue = function(...)
return Flag.cfgvalue(...) or "0"
end
-- Force AAAA SOA -- Force AAAA SOA
o = s:taboption("advanced", Flag, "force_aaaa_soa", translate("Force AAAA SOA"), translate("Force AAAA SOA.")) o = s:taboption("advanced", Flag, "force_aaaa_soa", translate("Force AAAA SOA"), translate("Force AAAA SOA."))
o.rmempty = false o.rmempty = false
@@ -211,6 +212,31 @@ o.cfgvalue = function(...)
return Flag.cfgvalue(...) or "1" return Flag.cfgvalue(...) or "1"
end end
---- Ipset no speed.
o = s:taboption("advanced", Value, "ipset_no_speed", translate("No Speed IPset Name"),
translate("Ipset name, Add domain result to ipset when speed check fails."));
o.rmempty = true;
o.datatype = "hostname";
o.rempty = true;
---- NFTset no speed.
o = s:taboption("advanced", Value, "nftset_no_speed", translate("No Speed NFTset Name"),
translate("Nftset name, Add domain result to nftset when speed check fails, format: [#[4|6]:[family#table#set]]"));
o.rmempty = true;
o.datatype = "string";
o.rempty = true;
function o.validate(self, value)
if (value == "") then
return value
end
if (value:match("#[4|6]:[a-zA-Z0-9%-_]+#[a-zA-Z0-9%-_]+#[a-zA-Z0-9%-_]+$")) then
return value
end
return nil, translate("NFTset name format error, format: [#[4|6]:[family#table#set]]")
end
---- rr-ttl ---- rr-ttl
o = s:taboption("advanced", Value, "rr_ttl", translate("Domain TTL"), translate("TTL for all domain result.")) o = s:taboption("advanced", Value, "rr_ttl", translate("Domain TTL"), translate("TTL for all domain result."))
o.rempty = true o.rempty = true
@@ -346,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 "默认"
@@ -255,6 +258,12 @@ msgstr "IPset名称"
msgid "IPset name." msgid "IPset name."
msgstr "IPSet名称。" msgstr "IPSet名称。"
msgid "Ipset name, Add domain result to ipset when speed check fails."
msgstr "IPset名称当测速失败时将查询到的结果添加到对应的IPSet集合中。"
msgid "ipset name format error, format: [#[4|6]:]ipsetname"
msgstr "IPset名称格式错误格式[#[4|6]:]ipsetname"
msgid "If you like this software, please buy me a cup of coffee." msgid "If you like this software, please buy me a cup of coffee."
msgstr "如果本软件对你有帮助,请给作者加个蛋。" msgstr "如果本软件对你有帮助,请给作者加个蛋。"
@@ -265,7 +274,7 @@ msgid ""
"Include other config files from /etc/smartdns/conf.d or custom path, can be " "Include other config files from /etc/smartdns/conf.d or custom path, can be "
"downloaded from the download page." "downloaded from the download page."
msgstr "" msgstr ""
"包含配置文件,路径为/etc/smartdns/conf.d或自定义配置文件路径可以从下载页" "包含配置文件,路径为/etc/smartdns/conf.d或自定义配置文件路径可以从下载页配置自动下载。"
"面配置自动下载。" "面配置自动下载。"
msgid "List of files to download." msgid "List of files to download."
@@ -301,6 +310,15 @@ msgstr "NFTSet名称格式错误格式[#[4|6]:[family#table#set]]"
msgid "NFTset name, format: [#[4|6]:[family#table#set]]" msgid "NFTset name, format: [#[4|6]:[family#table#set]]"
msgstr "NFTSet名称格式[#[4|6]:[family#table#set]]" msgstr "NFTSet名称格式[#[4|6]:[family#table#set]]"
msgid "Nftset name, Add domain result to nftset when speed check fails, format: [#[4|6]:[family#table#set]]"
msgstr "NFTset名称当测速失败时将查询到的结果添加到对应的NFTSet集合中。"
msgid "No Speed IPset Name"
msgstr "无速度时IPSet名称"
msgid "No Speed NFTset Name"
msgstr "无速度时NFTSet名称"
msgid "NOT RUNNING" msgid "NOT RUNNING"
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"));
@@ -155,6 +156,11 @@ return view.extend({
o.default = 53; o.default = 53;
o.datatype = "port"; o.datatype = "port";
o.rempty = false; o.rempty = false;
// auto-conf-dnsmasq;
o = s.taboption("settings", form.Flag, "auto_set_dnsmasq", _("Automatically Set Dnsmasq"), _("Automatically set as upstream of dnsmasq when port changes."));
o.rmempty = false;
o.default = o.enabled;
/////////////////////////////////////// ///////////////////////////////////////
// advanced settings; // advanced settings;
@@ -262,11 +268,6 @@ return view.extend({
o.rmempty = false; o.rmempty = false;
o.default = o.enabled; o.default = o.enabled;
// auto-conf-dnsmasq;
o = s.taboption("advanced", form.Flag, "auto_set_dnsmasq", _("Automatically Set Dnsmasq"), _("Automatically set as upstream of dnsmasq when port changes."));
o.rmempty = false;
o.default = o.enabled;
// Force AAAA SOA // Force AAAA SOA
o = s.taboption("advanced", form.Flag, "force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA.")); o = s.taboption("advanced", form.Flag, "force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
o.rmempty = false; o.rmempty = false;
@@ -277,6 +278,48 @@ return view.extend({
o.rmempty = false; o.rmempty = false;
o.default = o.enabled; o.default = o.enabled;
// Ipset no speed.
o = s.taboption("advanced", form.Value, "ipset_no_speed", _("No Speed IPset Name"),
_("Ipset name, Add domain result to ipset when speed check fails."));
o.rmempty = true;
o.datatype = "string";
o.rempty = true;
o.validate = function (section_id, value) {
if (value == "") {
return true;
}
var ipset = value.split(",")
for (var i = 0; i < ipset.length; i++) {
if (!ipset[i].match(/^(#[4|6]:)?[a-zA-Z0-9\-_]+$/)) {
return _("ipset name format error, format: [#[4|6]:]ipsetname");
}
}
return true;
}
// NFTset no speed.
o = s.taboption("advanced", form.Value, "nftset_no_speed", _("No Speed NFTset Name"),
_("Nftset name, Add domain result to nftset when speed check fails, format: [#[4|6]:[family#table#set]]"));
o.rmempty = true;
o.datatype = "string";
o.rempty = true;
o.validate = function (section_id, value) {
if (value == "") {
return true;
}
var nftset = value.split(",")
for (var i = 0; i < nftset.length; i++) {
if (!nftset[i].match(/^#[4|6]:[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+$/)) {
return _("NFTset name format error, format: [#[4|6]:[family#table#set]]");
}
}
return true;
}
// rr-ttl; // rr-ttl;
o = s.taboption("advanced", form.Value, "rr_ttl", _("Domain TTL"), _("TTL for all domain result.")); o = s.taboption("advanced", form.Value, "rr_ttl", _("Domain TTL"), _("TTL for all domain result."));
o.rempty = true; o.rempty = true;
@@ -388,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
/////////////////////////////////////// ///////////////////////////////////////
@@ -720,8 +771,22 @@ return view.extend({
o = s.taboption("forwarding", form.Value, "ipset_name", _("IPset Name"), _("IPset name.")); o = s.taboption("forwarding", form.Value, "ipset_name", _("IPset Name"), _("IPset name."));
o.rmempty = true; o.rmempty = true;
o.datatype = "hostname"; o.datatype = "string";
o.rempty = true; o.rempty = true;
o.validate = function (section_id, value) {
if (value == "") {
return true;
}
var ipset = value.split(",")
for (var i = 0; i < ipset.length; i++) {
if (!ipset[i].match(/^(#[4|6]:)?[a-zA-Z0-9\-_]+$/)) {
return _("ipset name format error, format: [#[4|6]:]ipsetname");
}
}
return true;
}
o = s.taboption("forwarding", form.Value, "nftset_name", _("NFTset Name"), _("NFTset name, format: [#[4|6]:[family#table#set]]")); o = s.taboption("forwarding", form.Value, "nftset_name", _("NFTset Name"), _("NFTset name, format: [#[4|6]:[family#table#set]]"));
o.rmempty = true; o.rmempty = true;
@@ -734,7 +799,7 @@ return view.extend({
var nftset = value.split(",") var nftset = value.split(",")
for (var i = 0; i < nftset.length; i++) { for (var i = 0; i < nftset.length; i++) {
if (!nftset[i].match(/#[4|6]:[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+$/)) { if (!nftset[i].match(/^#[4|6]:[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+#[a-zA-Z0-9\-_]+$/)) {
return _("NFTset name format error, format: [#[4|6]:[family#table#set]]"); return _("NFTset name format error, format: [#[4|6]:[family#table#set]]");
} }
} }

View File

@@ -169,6 +169,7 @@ load_server()
local section="$1" local section="$1"
local ADDITIONAL_ARGS="" local ADDITIONAL_ARGS=""
local DNS_ADDRESS="" local DNS_ADDRESS=""
local IS_URI="0"
config_get_bool enabled "$section" "enabled" "1" config_get_bool enabled "$section" "enabled" "1"
config_get port "$section" "port" "" config_get port "$section" "port" ""
@@ -202,7 +203,9 @@ load_server()
SERVER="server-https" SERVER="server-https"
fi fi
if echo "$ip" | grep ":" | grep -q -v "https://" >/dev/null 2>&1; then if echo "$ip" | grep "://" >/dev/null 2>&1; then
IS_URI="1"
elif echo "$ip" | grep ":"; then
if ! echo "$ip" | grep -q "\\[" >/dev/null 2>&1; then if ! echo "$ip" | grep -q "\\[" >/dev/null 2>&1; then
ip="[$ip]" ip="[$ip]"
fi fi
@@ -220,14 +223,12 @@ load_server()
[ -z "$set_mark" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -set-mark $set_mark" [ -z "$set_mark" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -set-mark $set_mark"
[ "$use_proxy" = "0" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -proxy default-proxy" [ "$use_proxy" = "0" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -proxy default-proxy"
if [ -z "$port" ]; then if [ -z "$port" ] || [ "$IS_URI" = "1" ]; then
DNS_ADDRESS="$ip" DNS_ADDRESS="$ip"
else else
DNS_ADDRESS="$ip:$port" DNS_ADDRESS="$ip:$port"
fi fi
[ "$type" = "https" ] && DNS_ADDRESS="$ip"
conf_append "$SERVER" "$DNS_ADDRESS $ADDITIONAL_ARGS $addition_arg" conf_append "$SERVER" "$DNS_ADDRESS $ADDITIONAL_ARGS $addition_arg"
} }
@@ -479,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"
@@ -506,6 +508,12 @@ load_service()
config_get auto_set_dnsmasq "$section" "auto_set_dnsmasq" "1" config_get auto_set_dnsmasq "$section" "auto_set_dnsmasq" "1"
config_get ipset_no_speed "$section" "ipset_no_speed" ""
[ -z "$ipset_no_speed" ] || conf_append "ipset-no-speed" "$ipset_no_speed"
config_get nftset_no_speed "$section" "nftset_no_speed" ""
[ -z "$nftset_no_speed" ] || conf_append "nftset-no-speed" "$nftset_no_speed"
config_get rr_ttl "$section" "rr_ttl" "" config_get rr_ttl "$section" "rr_ttl" ""
[ -z "$rr_ttl" ] || conf_append "rr-ttl" "$rr_ttl" [ -z "$rr_ttl" ] || conf_append "rr-ttl" "$rr_ttl"
@@ -556,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"
@@ -622,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

@@ -20,7 +20,12 @@ OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_co
# cflags # cflags
ifndef CFLAGS ifndef CFLAGS
CFLAGS =-O2 -g -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing -funwind-tables -Wmissing-prototypes -Wshadow -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough ifdef DEBUG
CFLAGS = -g
else
CFLAGS = -O2 -g
endif
CFLAGS +=-Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing -funwind-tables -Wmissing-prototypes -Wshadow -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough
endif endif
override CFLAGS +=-Iinclude override CFLAGS +=-Iinclude
override CFLAGS += -DBASE_FILE_NAME='"$(notdir $<)"' override CFLAGS += -DBASE_FILE_NAME='"$(notdir $<)"'
@@ -34,9 +39,9 @@ override CXXFLAGS +=-Iinclude
# ldflags # ldflags
ifeq ($(STATIC), yes) ifeq ($(STATIC), yes)
override LDFLAGS += -lssl -lcrypto -Wl,--whole-archive -lpthread -Wl,--no-whole-archive -ldl -static override LDFLAGS += -lssl -lcrypto -Wl,--whole-archive -lpthread -Wl,--no-whole-archive -ldl -static
else else
override LDFLAGS += -lssl -lcrypto -lpthread -ldl override LDFLAGS += -lssl -lcrypto -lpthread -ldl
endif endif
.PHONY: all clean .PHONY: all clean

View File

@@ -42,6 +42,8 @@
(void)(expr); \ (void)(expr); \
} while (0) } while (0)
#define member_size(type, member) sizeof(((type *)0)->member)
/* read short and move pointer */ /* read short and move pointer */
static unsigned short _dns_read_short(unsigned char **buffer) static unsigned short _dns_read_short(unsigned char **buffer)
{ {
@@ -111,7 +113,7 @@ static int _dns_get_domain_from_packet(unsigned char *packet, int packet_size, u
/*[len]string[len]string...[0]0 */ /*[len]string[len]string...[0]0 */
while (1) { while (1) {
if (ptr >= packet + packet_size || ptr < packet || output_len >= size - 1 || ptr_jump > 4) { if (ptr >= packet + packet_size || ptr < packet || output_len >= size - 1 || ptr_jump > 32) {
return -1; return -1;
} }
@@ -1639,12 +1641,12 @@ static int _dns_encode_SOA(struct dns_context *context, struct dns_rrs *rrs)
return 0; return 0;
} }
static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *ecs) static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *ecs, int opt_len)
{ {
// TODO // TODO
int len = 0; int len = 0;
if (_dns_left_len(context) < 4) { if (opt_len < 4) {
return -1; return -1;
} }
@@ -1668,25 +1670,24 @@ static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *
return 0; return 0;
} }
static int _dns_decode_opt_cookie(struct dns_context *context, struct dns_opt_cookie *cookie) static int _dns_decode_opt_cookie(struct dns_context *context, struct dns_opt_cookie *cookie, int opt_len)
{ {
// TODO // TODO
int len = _dns_left_len(context); if (opt_len < (int)member_size(struct dns_opt_cookie, client_cookie)) {
if (len < 8) {
return -1; return -1;
} }
len = 8; int len = 8;
memcpy(cookie->client_cookie, context->ptr, len); memcpy(cookie->client_cookie, context->ptr, len);
context->ptr += len; context->ptr += len;
len = _dns_left_len(context); opt_len -= len;
if (len == 0) { if (opt_len <= 0) {
cookie->server_cookie_len = 0; cookie->server_cookie_len = 0;
return 0; return 0;
} }
if (len < 8) { if (opt_len < (int)member_size(struct dns_opt_cookie, server_cookie)) {
return -1; return -1;
} }
@@ -1881,7 +1882,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
switch (opt_code) { switch (opt_code) {
case DNS_OPT_T_ECS: { case DNS_OPT_T_ECS: {
struct dns_opt_ecs ecs; struct dns_opt_ecs ecs;
ret = _dns_decode_opt_ecs(context, &ecs); ret = _dns_decode_opt_ecs(context, &ecs, opt_len);
if (ret != 0) { if (ret != 0) {
tlog(TLOG_ERROR, "decode ecs failed."); tlog(TLOG_ERROR, "decode ecs failed.");
return -1; return -1;
@@ -1895,7 +1896,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
} break; } break;
case DNS_OPT_T_COOKIE: { case DNS_OPT_T_COOKIE: {
struct dns_opt_cookie cookie; struct dns_opt_cookie cookie;
ret = _dns_decode_opt_cookie(context, &cookie); ret = _dns_decode_opt_cookie(context, &cookie, opt_len);
if (ret != 0) { if (ret != 0) {
tlog(TLOG_ERROR, "decode cookie failed."); tlog(TLOG_ERROR, "decode cookie failed.");
return -1; return -1;
@@ -2254,6 +2255,16 @@ static int _dns_encode_qd(struct dns_context *context, struct dns_rrs *rrs)
return -1; return -1;
} }
if (domain[0] == '-') {
/* for google and cloudflare */
unsigned char *ptr = context->ptr - 7;
memcpy(ptr, "\xC0\x12", 2);
ptr += 2;
_dns_write_short(&ptr, qtype);
_dns_write_short(&ptr, qclass);
context->ptr = ptr;
}
return 0; return 0;
} }

View File

@@ -329,7 +329,7 @@ static void _dns_cache_remove_by_domain(struct dns_cache_key *cache_key)
continue; continue;
} }
if (strncmp(dns_cache->info.dns_group_name, cache_key->dns_group_name, DNS_MAX_CNAME_LEN) != 0) { if (strncmp(dns_cache->info.dns_group_name, cache_key->dns_group_name, DNS_GROUP_NAME_LEN) != 0) {
continue; continue;
} }
@@ -408,6 +408,7 @@ int dns_cache_insert(struct dns_cache_key *cache_key, int ttl, int speed, int no
ttl = DNS_CACHE_TTL_MIN; ttl = DNS_CACHE_TTL_MIN;
} }
memset(&info, 0, sizeof(info));
info.hitnum = 3; info.hitnum = 3;
safe_strncpy(info.domain, cache_key->domain, DNS_MAX_CNAME_LEN); safe_strncpy(info.domain, cache_key->domain, DNS_MAX_CNAME_LEN);
info.qtype = cache_key->qtype; info.qtype = cache_key->qtype;

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/rand.h>
#include <openssl/ssl.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/random.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>
@@ -97,6 +98,7 @@ struct dns_server_info {
/* server type */ /* server type */
dns_server_type_t type; dns_server_type_t type;
long long so_mark; long long so_mark;
int drop_packet_latency_ms;
/* client socket */ /* client socket */
int fd; int fd;
@@ -118,6 +120,7 @@ struct dns_server_info {
time_t last_send; time_t last_send;
time_t last_recv; time_t last_recv;
unsigned long send_tick;
int prohibit; int prohibit;
/* server addr info */ /* server addr info */
@@ -152,6 +155,8 @@ struct dns_server_pending {
unsigned int has_v6; unsigned int has_v6;
unsigned int query_v4; unsigned int query_v4;
unsigned int query_v6; unsigned int query_v6;
unsigned int has_soa;
/* server type */ /* server type */
dns_server_type_t type; dns_server_type_t type;
int retry_cnt; int retry_cnt;
@@ -192,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;
@@ -204,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 */
@@ -260,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)
{ {
@@ -439,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;
@@ -450,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;
} }
@@ -1021,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;
} }
@@ -1054,6 +1066,7 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
server_info->skip_check_cert = skip_check_cert; server_info->skip_check_cert = skip_check_cert;
server_info->prohibit = 0; server_info->prohibit = 0;
server_info->so_mark = flags->set_mark; server_info->so_mark = flags->set_mark;
server_info->drop_packet_latency_ms = flags->drop_packet_latency_ms;
safe_strncpy(server_info->proxy_name, flags->proxyname, sizeof(server_info->proxy_name)); safe_strncpy(server_info->proxy_name, flags->proxyname, sizeof(server_info->proxy_name));
pthread_mutex_init(&server_info->lock, NULL); pthread_mutex_init(&server_info->lock, NULL);
memcpy(&server_info->flags, flags, sizeof(server_info->flags)); memcpy(&server_info->flags, flags, sizeof(server_info->flags));
@@ -1332,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) {
@@ -1509,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);
} }
@@ -2259,6 +2271,11 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e
/* update recv time */ /* update recv time */
time(&server_info->last_recv); time(&server_info->last_recv);
int latency = get_tick_count() - server_info->send_tick;
if (latency < server_info->drop_packet_latency_ms) {
return 0;
}
/* processing dns packet */ /* processing dns packet */
if (_dns_client_recv(server_info, inpacket, len, (struct sockaddr *)&from, from_len) != 0) { if (_dns_client_recv(server_info, inpacket, len, (struct sockaddr *)&from, from_len) != 0) {
return -1; return -1;
@@ -3324,6 +3341,7 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
continue; continue;
} }
time(&server_info->last_send); time(&server_info->last_send);
server_info->send_tick = get_tick_count();
} }
pthread_mutex_unlock(&client.server_list_lock); pthread_mutex_unlock(&client.server_list_lock);
@@ -3524,7 +3542,7 @@ int dns_client_query(const char *domain, int qtype, dns_client_callback callback
query->qtype = qtype; query->qtype = qtype;
query->send_tick = 0; query->send_tick = 0;
query->has_result = 0; query->has_result = 0;
if (getrandom(&query->sid, sizeof(query->sid), GRND_NONBLOCK) != sizeof(query->sid)) { if (RAND_bytes((unsigned char *)&query->sid, sizeof(query->sid)) != 1) {
query->sid = random(); query->sid = random();
} }
query->server_group = _dns_client_get_dnsserver_group(group_name); query->server_group = _dns_client_get_dnsserver_group(group_name);
@@ -3558,7 +3576,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);
@@ -3614,11 +3632,16 @@ static int _dns_client_pending_server_resolve(const char *domain, dns_rtcode_t r
struct dns_server_pending *pending = user_ptr; struct dns_server_pending *pending = user_ptr;
int ret = 0; int ret = 0;
if (rtcode == DNS_RC_NXDOMAIN) {
pending->has_soa = 1;
}
if (addr_type == DNS_T_A) { if (addr_type == DNS_T_A) {
pending->ping_time_v4 = -1; pending->ping_time_v4 = -1;
if (rtcode == DNS_RC_NOERROR) { if (rtcode == DNS_RC_NOERROR) {
pending->has_v4 = 1; pending->has_v4 = 1;
pending->ping_time_v4 = ping_time; pending->ping_time_v4 = ping_time;
pending->has_soa = 0;
safe_strncpy(pending->ipv4, ip, DNS_HOSTNAME_LEN); safe_strncpy(pending->ipv4, ip, DNS_HOSTNAME_LEN);
} }
} else if (addr_type == DNS_T_AAAA) { } else if (addr_type == DNS_T_AAAA) {
@@ -3626,6 +3649,7 @@ static int _dns_client_pending_server_resolve(const char *domain, dns_rtcode_t r
if (rtcode == DNS_RC_NOERROR) { if (rtcode == DNS_RC_NOERROR) {
pending->has_v6 = 1; pending->has_v6 = 1;
pending->ping_time_v6 = ping_time; pending->ping_time_v6 = ping_time;
pending->has_soa = 0;
safe_strncpy(pending->ipv6, ip, DNS_HOSTNAME_LEN); safe_strncpy(pending->ipv6, ip, DNS_HOSTNAME_LEN);
} }
} else { } else {
@@ -3759,6 +3783,12 @@ static void _dns_client_add_pending_servers(void)
continue; continue;
} }
if (pending->has_soa && dnsserver_ip == NULL) {
tlog(TLOG_WARN, "add pending DNS server %s failed, no such host.", pending->host);
_dns_client_server_pending_remove(pending);
continue;
}
if (pending->retry_cnt - 1 > DNS_PENDING_SERVER_RETRY || add_success) { if (pending->retry_cnt - 1 > DNS_PENDING_SERVER_RETRY || add_success) {
if (add_success == 0) { if (add_success == 0) {
tlog(TLOG_WARN, "add pending DNS server %s failed.", pending->host); tlog(TLOG_WARN, "add pending DNS server %s failed.", pending->host);
@@ -3795,15 +3825,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 */
@@ -3846,9 +3873,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;
@@ -3861,11 +3890,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);
@@ -3873,19 +3908,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);
@@ -3895,6 +3932,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;
@@ -3948,10 +3990,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) {
@@ -3979,8 +4082,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;
@@ -3997,6 +4098,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) {
@@ -4006,13 +4115,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;
} }
@@ -4022,14 +4134,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();
@@ -4037,7 +4148,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

@@ -113,6 +113,7 @@ struct client_dns_server_flags {
unsigned int server_flag; unsigned int server_flag;
unsigned int result_flag; unsigned int result_flag;
long long set_mark; long long set_mark;
int drop_packet_latency_ms;
char proxyname[DNS_MAX_CNAME_LEN]; char proxyname[DNS_MAX_CNAME_LEN];
union { union {
struct client_dns_server_flag_udp udp; struct client_dns_server_flag_udp udp;

View File

@@ -61,6 +61,9 @@ static time_t dns_conf_dnsmasq_lease_file_time;
struct dns_hosts_table dns_hosts_table; struct dns_hosts_table dns_hosts_table;
int dns_hosts_record_num; int dns_hosts_record_num;
/* DNS64 */
struct dns_dns64 dns_conf_dns_dns64;
/* server ip/port */ /* server ip/port */
struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP]; struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP];
int dns_conf_bind_ip_num = 0; int dns_conf_bind_ip_num = 0;
@@ -140,7 +143,9 @@ int dns_conf_local_ttl;
int dns_conf_force_AAAA_SOA; int dns_conf_force_AAAA_SOA;
int dns_conf_force_no_cname; int dns_conf_force_no_cname;
int dns_conf_ipset_timeout_enable; int dns_conf_ipset_timeout_enable;
struct dns_ipset_names dns_conf_ipset_no_speed;
int dns_conf_nftset_timeout_enable; int dns_conf_nftset_timeout_enable;
struct dns_nftset_names dns_conf_nftset_no_speed;
int dns_conf_nftset_debug_enable; int dns_conf_nftset_debug_enable;
char dns_conf_user[DNS_CONF_USERNAME_LEN]; char dns_conf_user[DNS_CONF_USERNAME_LEN];
@@ -189,6 +194,12 @@ static void *_new_dns_rule(enum domain_rule domain_rule)
case DOMAIN_RULE_CHECKSPEED: case DOMAIN_RULE_CHECKSPEED:
size = sizeof(struct dns_domain_check_orders); size = sizeof(struct dns_domain_check_orders);
break; break;
case DOMAIN_RULE_CNAME:
size = sizeof(struct dns_cname_rule);
break;
case DOMAIN_RULE_TTL:
size = sizeof(struct dns_ttl_rule);
break;
default: default:
return NULL; return NULL;
} }
@@ -451,6 +462,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
unsigned int result_flag = 0; unsigned int result_flag = 0;
unsigned int server_flag = 0; unsigned int server_flag = 0;
unsigned char *spki = NULL; unsigned char *spki = NULL;
int drop_packet_latency_ms = 0;
int ttl = 0; int ttl = 0;
/* clang-format off */ /* clang-format off */
@@ -461,6 +473,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
/* experimental feature */ /* experimental feature */
{"check-edns", no_argument, NULL, 'e'}, /* check edns */ {"check-edns", no_argument, NULL, 'e'}, /* check edns */
#endif #endif
{"drop-packet-latency", required_argument, NULL, 'D'},
{"spki-pin", required_argument, NULL, 'p'}, /* check SPKI pin */ {"spki-pin", required_argument, NULL, 'p'}, /* check SPKI pin */
{"host-name", required_argument, NULL, 'h'}, /* host name */ {"host-name", required_argument, NULL, 'h'}, /* host name */
{"http-host", required_argument, NULL, 'H'}, /* http host */ {"http-host", required_argument, NULL, 'H'}, /* http host */
@@ -492,6 +505,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
server->tls_host_verify[0] = '\0'; server->tls_host_verify[0] = '\0';
server->proxyname[0] = '\0'; server->proxyname[0] = '\0';
server->set_mark = -1; server->set_mark = -1;
server->drop_packet_latency_ms = drop_packet_latency_ms;
if (parse_uri(ip, scheme, server->server, &port, server->path) != 0) { if (parse_uri(ip, scheme, server->server, &port, server->path) != 0) {
return -1; return -1;
@@ -561,6 +575,10 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
safe_strncpy(server->httphost, optarg, DNS_MAX_CNAME_LEN); safe_strncpy(server->httphost, optarg, DNS_MAX_CNAME_LEN);
break; break;
} }
case 'D': {
drop_packet_latency_ms = atoi(optarg);
break;
}
case 'E': { case 'E': {
server_flag |= SERVER_FLAG_EXCLUDE_DEFAULT; server_flag |= SERVER_FLAG_EXCLUDE_DEFAULT;
break; break;
@@ -607,6 +625,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
server->result_flag = result_flag; server->result_flag = result_flag;
server->server_flag = server_flag; server->server_flag = server_flag;
server->ttl = ttl; server->ttl = ttl;
server->drop_packet_latency_ms = drop_packet_latency_ms;
dns_conf_server_num++; dns_conf_server_num++;
tlog(TLOG_DEBUG, "add server %s, flag: %X, ttl: %d", ip, result_flag, ttl); tlog(TLOG_DEBUG, "add server %s, flag: %X, ttl: %d", ip, result_flag, ttl);
@@ -1076,6 +1095,78 @@ errout:
return 0; return 0;
} }
static int _config_ipset_no_speed(void *data, int argc, char *argv[])
{
char *ipsetname = argv[1];
char *copied_name = NULL;
const char *ipset = NULL;
struct dns_ipset_rule *ipset_rule_array[2] = {NULL, NULL};
char *ipset_rule_enable_array[2] = {NULL, NULL};
int ipset_num = 0;
if (argc <= 1) {
goto errout;
}
copied_name = strdup(ipsetname);
if (copied_name == NULL) {
goto errout;
}
for (char *tok = strtok(copied_name, ","); tok && ipset_num <= 2; tok = strtok(NULL, ",")) {
if (tok[0] == '#') {
if (strncmp(tok, "#6:", 3U) == 0) {
ipset_rule_array[ipset_num] = &dns_conf_ipset_no_speed.ipv6;
ipset_rule_enable_array[ipset_num] = &dns_conf_ipset_no_speed.ipv6_enable;
ipset_num++;
} else if (strncmp(tok, "#4:", 3U) == 0) {
ipset_rule_array[ipset_num] = &dns_conf_ipset_no_speed.ipv4;
ipset_rule_enable_array[ipset_num] = &dns_conf_ipset_no_speed.ipv4_enable;
ipset_num++;
} else {
goto errout;
}
tok += 3;
}
if (ipset_num == 0) {
ipset_rule_array[1] = &dns_conf_ipset_no_speed.ipv6;
ipset_rule_enable_array[1] = &dns_conf_ipset_no_speed.ipv6_enable;
ipset_rule_array[0] = &dns_conf_ipset_no_speed.ipv4;
ipset_rule_enable_array[0] = &dns_conf_ipset_no_speed.ipv4_enable;
ipset_num = 2;
}
if (strncmp(tok, "-", 1) == 0) {
continue;
}
/* new ipset domain */
ipset = _dns_conf_get_ipset(tok);
if (ipset == NULL) {
goto errout;
}
for (int i = 0; i < ipset_num; i++) {
ipset_rule_array[i]->ipsetname = ipset;
*ipset_rule_enable_array[i] = 1;
}
ipset_num = 0;
}
free(copied_name);
return 0;
errout:
if (copied_name) {
free(copied_name);
}
tlog(TLOG_ERROR, "add ipset-no-speed %s failed", ipsetname);
return 0;
}
static void _config_nftset_table_destroy(void) static void _config_nftset_table_destroy(void)
{ {
struct dns_nftset_name *nftset = NULL; struct dns_nftset_name *nftset = NULL;
@@ -1187,7 +1278,7 @@ static int _conf_domain_rule_nftset(char *domain, const char *nftsetname)
goto errout; goto errout;
} }
/* new ipset domain */ /* new nftset domain */
nftset = _dns_conf_get_nftable(family, tablename, setname); nftset = _dns_conf_get_nftable(family, tablename, setname);
if (nftset == NULL) { if (nftset == NULL) {
goto errout; goto errout;
@@ -1244,6 +1335,105 @@ errout:
return 0; return 0;
} }
static int _config_nftset_no_speed(void *data, int argc, char *argv[])
{
const struct dns_nftset_name *nftset = NULL;
char *copied_name = NULL;
char *nftsetname = argv[1];
int nftset_num = 0;
char *setname = NULL;
char *tablename = NULL;
char *family = NULL;
struct dns_nftset_rule *nftset_rule_array[2] = {NULL, NULL};
char *nftset_rule_enable_array[2] = {NULL, NULL};
if (argc <= 1) {
goto errout;
}
copied_name = strdup(nftsetname);
if (copied_name == NULL) {
goto errout;
}
for (char *tok = strtok(copied_name, ","); tok && nftset_num <=2 ; tok = strtok(NULL, ",")) {
char *saveptr = NULL;
char *tok_set = NULL;
if (strncmp(tok, "#4:", 3U) == 0) {
dns_conf_nftset_no_speed.ip_enable = 1;
nftset_rule_array[nftset_num] = &dns_conf_nftset_no_speed.ip;
nftset_rule_enable_array[nftset_num] = &dns_conf_nftset_no_speed.ip_enable;
nftset_num++;
} else if (strncmp(tok, "#6:", 3U) == 0) {
nftset_rule_enable_array[nftset_num] = &dns_conf_nftset_no_speed.ip6_enable;
nftset_rule_array[nftset_num] = &dns_conf_nftset_no_speed.ip6;
nftset_num++;
} else if (strncmp(tok, "-", 2U) == 0) {
continue;
continue;
} else {
goto errout;
}
tok_set = tok + 3;
if (nftset_num == 0) {
nftset_rule_array[0] = &dns_conf_nftset_no_speed.ip;
nftset_rule_enable_array[0] = &dns_conf_nftset_no_speed.ip_enable;
nftset_rule_array[1] = &dns_conf_nftset_no_speed.ip6;
nftset_rule_enable_array[1] = &dns_conf_nftset_no_speed.ip6_enable;
nftset_num = 2;
}
if (strncmp(tok_set, "-", 2U) == 0) {
continue;
}
family = strtok_r(tok_set, "#", &saveptr);
if (family == NULL) {
goto errout;
}
tablename = strtok_r(NULL, "#", &saveptr);
if (tablename == NULL) {
goto errout;
}
setname = strtok_r(NULL, "#", &saveptr);
if (setname == NULL) {
goto errout;
}
/* new nftset domain */
nftset = _dns_conf_get_nftable(family, tablename, setname);
if (nftset == NULL) {
goto errout;
}
for (int i = 0; i < nftset_num; i++) {
nftset_rule_array[i]->familyname = nftset->nftfamilyname;
nftset_rule_array[i]->nfttablename = nftset->nfttablename;
nftset_rule_array[i]->nftsetname = nftset->nftsetname;
*nftset_rule_enable_array[i] = 1;
}
nftset_num = 0;
}
goto clear;
errout:
tlog(TLOG_ERROR, "add nftset %s failed", nftsetname);
clear:
if (copied_name) {
free(copied_name);
}
return 0;
}
static int _conf_domain_rule_address(char *domain, const char *domain_address) static int _conf_domain_rule_address(char *domain, const char *domain_address)
{ {
struct dns_rule_address_IPV4 *address_ipv4 = NULL; struct dns_rule_address_IPV4 *address_ipv4 = NULL;
@@ -1374,6 +1564,64 @@ errout:
return 0; return 0;
} }
static int _conf_domain_rule_cname(const char *domain, const char *cname)
{
struct dns_cname_rule *cname_rule = NULL;
enum domain_rule type = DOMAIN_RULE_CNAME;
cname_rule = _new_dns_rule(type);
if (cname_rule == NULL) {
goto errout;
}
/* ignore this domain */
if (*cname == '-') {
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_CNAME_IGN, 0) != 0) {
goto errout;
}
return 0;
}
safe_strncpy(cname_rule->cname, cname, DNS_MAX_CONF_CNAME_LEN);
if (_config_domain_rule_add(domain, type, cname_rule) != 0) {
goto errout;
}
_dns_rule_put(&cname_rule->head);
cname_rule = NULL;
return 0;
errout:
tlog(TLOG_ERROR, "add cname %s:%s failed", domain, cname);
if (cname_rule) {
_dns_rule_put(&cname_rule->head);
}
return 0;
}
static int _config_cname(void *data, int argc, char *argv[])
{
char *value = argv[1];
char domain[DNS_MAX_CONF_CNAME_LEN];
if (argc <= 1) {
goto errout;
}
if (_get_domain(value, domain, DNS_MAX_CONF_CNAME_LEN, &value) != 0) {
goto errout;
}
return _conf_domain_rule_cname(domain, value);
errout:
tlog(TLOG_ERROR, "add cname %s:%s failed", domain, value);
return 0;
}
static void _config_speed_check_mode_clear(struct dns_domain_check_orders *check_orders) static void _config_speed_check_mode_clear(struct dns_domain_check_orders *check_orders)
{ {
memset(check_orders->orders, 0, sizeof(check_orders->orders)); memset(check_orders->orders, 0, sizeof(check_orders->orders));
@@ -1453,6 +1701,43 @@ static int _config_speed_check_mode(void *data, int argc, char *argv[])
return _config_speed_check_mode_parser(&dns_conf_check_orders, mode); return _config_speed_check_mode_parser(&dns_conf_check_orders, mode);
} }
static int _config_dns64(void *data, int argc, char *argv[])
{
prefix_t prefix;
char *subnet = NULL;
const char *errmsg = NULL;
void *p = NULL;
if (argc <= 1) {
return -1;
}
subnet = argv[1];
p = prefix_pton(subnet, -1, &prefix, &errmsg);
if (p == NULL) {
goto errout;
}
if (prefix.family != AF_INET6) {
tlog(TLOG_ERROR, "dns64 subnet %s is not ipv6", subnet);
goto errout;
}
if (prefix.bitlen <= 0 || prefix.bitlen > 96) {
tlog(TLOG_ERROR, "dns64 subnet %s is not valid", subnet);
goto errout;
}
memcpy(&dns_conf_dns_dns64.prefix, &prefix.add.sin6.s6_addr, sizeof(dns_conf_dns_dns64.prefix));
dns_conf_dns_dns64.prefix_len = prefix.bitlen;
return 0;
errout:
return -1;
}
static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type) static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
{ {
int index = dns_conf_bind_ip_num; int index = dns_conf_bind_ip_num;
@@ -2129,6 +2414,39 @@ errout:
return -1; return -1;
} }
static int _conf_domain_rule_rr_ttl(const char *domain, int ttl, int ttl_min, int ttl_max)
{
struct dns_ttl_rule *rr_ttl = NULL;
if (ttl < 0 || ttl_min < 0 || ttl_max < 0) {
tlog(TLOG_ERROR, "invalid ttl value.");
goto errout;
}
rr_ttl = _new_dns_rule(DOMAIN_RULE_TTL);
if (rr_ttl == NULL) {
goto errout;
}
rr_ttl->ttl = ttl;
rr_ttl->ttl_min = ttl_min;
rr_ttl->ttl_max = ttl_max;
if (_config_domain_rule_add(domain, DOMAIN_RULE_TTL, rr_ttl) != 0) {
goto errout;
}
_dns_rule_put(&rr_ttl->head);
return 0;
errout:
if (rr_ttl != NULL) {
_dns_rule_put(&rr_ttl->head);
}
return -1;
}
static int _conf_domain_rule_no_serve_expired(const char *domain) static int _conf_domain_rule_no_serve_expired(const char *domain)
{ {
return _config_domain_rule_flag_set(domain, DOMAIN_FLAG_NO_SERVE_EXPIRED, 0); return _config_domain_rule_flag_set(domain, DOMAIN_FLAG_NO_SERVE_EXPIRED, 0);
@@ -2144,6 +2462,9 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
int opt = 0; int opt = 0;
char domain[DNS_MAX_CONF_CNAME_LEN]; char domain[DNS_MAX_CONF_CNAME_LEN];
char *value = argv[1]; char *value = argv[1];
int rr_ttl = 0;
int rr_ttl_min = 0;
int rr_ttl_max = 0;
/* clang-format off */ /* clang-format off */
static struct option long_options[] = { static struct option long_options[] = {
@@ -2153,6 +2474,10 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
{"nftset", required_argument, NULL, 't'}, {"nftset", required_argument, NULL, 't'},
{"nameserver", required_argument, NULL, 'n'}, {"nameserver", required_argument, NULL, 'n'},
{"dualstack-ip-selection", required_argument, NULL, 'd'}, {"dualstack-ip-selection", required_argument, NULL, 'd'},
{"cname", required_argument, NULL, 'A'},
{"rr-ttl", required_argument, NULL, 251},
{"rr-ttl-min", required_argument, NULL, 252},
{"rr-ttl-max", required_argument, NULL, 253},
{"no-serve-expired", no_argument, NULL, 254}, {"no-serve-expired", no_argument, NULL, 254},
{"delete", no_argument, NULL, 255}, {"delete", no_argument, NULL, 255},
{NULL, no_argument, NULL, 0} {NULL, no_argument, NULL, 0}
@@ -2171,7 +2496,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
/* process extra options */ /* process extra options */
optind = 1; optind = 1;
while (1) { while (1) {
opt = getopt_long_only(argc, argv, "c:a:p:t:n:d:", long_options, NULL); opt = getopt_long_only(argc, argv, "c:a:p:t:n:d:A:", long_options, NULL);
if (opt == -1) { if (opt == -1) {
break; break;
} }
@@ -2229,6 +2554,16 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
break; break;
} }
case 'A': {
const char *cname = optarg;
if (_conf_domain_rule_cname(domain, cname) != 0) {
tlog(TLOG_ERROR, "add cname rule failed.");
goto errout;
}
break;
}
case 'd': { case 'd': {
const char *yesno = optarg; const char *yesno = optarg;
if (_conf_domain_rule_dualstack_selection(domain, yesno) != 0) { if (_conf_domain_rule_dualstack_selection(domain, yesno) != 0) {
@@ -2251,6 +2586,18 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
break; break;
} }
case 251: {
rr_ttl = atoi(optarg);
break;
}
case 252: {
rr_ttl_min = atoi(optarg);
break;
}
case 253: {
rr_ttl_max = atoi(optarg);
break;
}
case 254: { case 254: {
if (_conf_domain_rule_no_serve_expired(domain) != 0) { if (_conf_domain_rule_no_serve_expired(domain) != 0) {
tlog(TLOG_ERROR, "set no-serve-expired rule failed."); tlog(TLOG_ERROR, "set no-serve-expired rule failed.");
@@ -2272,6 +2619,13 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
} }
} }
if (rr_ttl > 0 || rr_ttl_min > 0 || rr_ttl_max > 0) {
if (_conf_domain_rule_rr_ttl(domain, rr_ttl, rr_ttl_min, rr_ttl_max) != 0) {
tlog(TLOG_ERROR, "set rr-ttl rule failed.");
goto errout;
}
}
return 0; return 0;
errout: errout:
return -1; return -1;
@@ -2693,12 +3047,15 @@ static struct config_item _config_item[] = {
CONF_CUSTOM("server-https", _config_server_https, NULL), CONF_CUSTOM("server-https", _config_server_https, NULL),
CONF_CUSTOM("nameserver", _config_nameserver, NULL), CONF_CUSTOM("nameserver", _config_nameserver, NULL),
CONF_CUSTOM("address", _config_address, NULL), CONF_CUSTOM("address", _config_address, NULL),
CONF_CUSTOM("cname", _config_cname, NULL),
CONF_CUSTOM("proxy-server", _config_proxy_server, NULL), CONF_CUSTOM("proxy-server", _config_proxy_server, NULL),
CONF_YESNO("ipset-timeout", &dns_conf_ipset_timeout_enable), CONF_YESNO("ipset-timeout", &dns_conf_ipset_timeout_enable),
CONF_CUSTOM("ipset", _config_ipset, NULL), CONF_CUSTOM("ipset", _config_ipset, NULL),
CONF_CUSTOM("ipset-no-speed", _config_ipset_no_speed, NULL),
CONF_YESNO("nftset-timeout", &dns_conf_nftset_timeout_enable), CONF_YESNO("nftset-timeout", &dns_conf_nftset_timeout_enable),
CONF_YESNO("nftset-debug", &dns_conf_nftset_debug_enable), CONF_YESNO("nftset-debug", &dns_conf_nftset_debug_enable),
CONF_CUSTOM("nftset", _config_nftset, NULL), CONF_CUSTOM("nftset", _config_nftset, NULL),
CONF_CUSTOM("nftset-no-speed", _config_nftset_no_speed, NULL),
CONF_CUSTOM("speed-check-mode", _config_speed_check_mode, NULL), CONF_CUSTOM("speed-check-mode", _config_speed_check_mode, NULL),
CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600), CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),
CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX), CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX),
@@ -2712,6 +3069,7 @@ static struct config_item _config_item[] = {
CONF_YESNO("dualstack-ip-selection", &dns_conf_dualstack_ip_selection), CONF_YESNO("dualstack-ip-selection", &dns_conf_dualstack_ip_selection),
CONF_YESNO("dualstack-ip-allow-force-AAAA", &dns_conf_dualstack_ip_allow_force_AAAA), CONF_YESNO("dualstack-ip-allow-force-AAAA", &dns_conf_dualstack_ip_allow_force_AAAA),
CONF_INT("dualstack-ip-selection-threshold", &dns_conf_dualstack_ip_selection_threshold, 0, 1000), CONF_INT("dualstack-ip-selection-threshold", &dns_conf_dualstack_ip_selection_threshold, 0, 1000),
CONF_CUSTOM("dns64", _config_dns64, NULL),
CONF_CUSTOM("log-level", _config_log_level, NULL), CONF_CUSTOM("log-level", _config_log_level, NULL),
CONF_STRING("log-file", (char *)dns_conf_log_file, DNS_MAX_PATH), CONF_STRING("log-file", (char *)dns_conf_log_file, DNS_MAX_PATH),
CONF_SIZE("log-size", &dns_conf_log_size, 0, 1024 * 1024 * 1024), CONF_SIZE("log-size", &dns_conf_log_size, 0, 1024 * 1024 * 1024),
@@ -2782,7 +3140,7 @@ int config_additional_file(void *data, int argc, char *argv[])
conf_file = argv[1]; conf_file = argv[1];
if (conf_file[0] != '/') { if (conf_file[0] != '/') {
safe_strncpy(file_path_dir, conf_get_conf_file(), DNS_MAX_PATH); safe_strncpy(file_path_dir, conf_get_conf_file(), DNS_MAX_PATH);
dirname(file_path_dir); dir_name(file_path_dir);
if (strncmp(file_path_dir, conf_get_conf_file(), sizeof(file_path_dir)) == 0) { if (strncmp(file_path_dir, conf_get_conf_file(), sizeof(file_path_dir)) == 0) {
if (snprintf(file_path, DNS_MAX_PATH, "%s", conf_file) < 0) { if (snprintf(file_path, DNS_MAX_PATH, "%s", conf_file) < 0) {
return -1; return -1;

View File

@@ -74,6 +74,8 @@ enum domain_rule {
DOMAIN_RULE_NFTSET_IP6, DOMAIN_RULE_NFTSET_IP6,
DOMAIN_RULE_NAMESERVER, DOMAIN_RULE_NAMESERVER,
DOMAIN_RULE_CHECKSPEED, DOMAIN_RULE_CHECKSPEED,
DOMAIN_RULE_CNAME,
DOMAIN_RULE_TTL,
DOMAIN_RULE_MAX, DOMAIN_RULE_MAX,
}; };
@@ -104,6 +106,7 @@ typedef enum {
#define DOMAIN_FLAG_NFTSET_IP_IGN (1 << 13) #define DOMAIN_FLAG_NFTSET_IP_IGN (1 << 13)
#define DOMAIN_FLAG_NFTSET_IP6_IGN (1 << 14) #define DOMAIN_FLAG_NFTSET_IP6_IGN (1 << 14)
#define DOMAIN_FLAG_NO_SERVE_EXPIRED (1 << 15) #define DOMAIN_FLAG_NO_SERVE_EXPIRED (1 << 15)
#define DOMAIN_FLAG_CNAME_IGN (1 << 16)
#define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0) #define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0)
@@ -116,6 +119,7 @@ typedef enum {
#define BIND_FLAG_NO_CACHE (1 << 6) #define BIND_FLAG_NO_CACHE (1 << 6)
#define BIND_FLAG_NO_DUALSTACK_SELECTION (1 << 7) #define BIND_FLAG_NO_DUALSTACK_SELECTION (1 << 7)
#define BIND_FLAG_FORCE_AAAA_SOA (1 << 8) #define BIND_FLAG_FORCE_AAAA_SOA (1 << 8)
#define BIND_FLAG_NO_RULE_CNAME (1 << 9)
struct dns_rule { struct dns_rule {
atomic_t refcnt; atomic_t refcnt;
@@ -148,6 +152,26 @@ struct dns_ipset_rule {
const char *ipsetname; const char *ipsetname;
}; };
struct dns_ipset_names {
char ipv4_enable;
char ipv6_enable;
struct dns_ipset_rule ipv4;
struct dns_ipset_rule ipv6;
};
extern struct dns_ipset_names dns_conf_ipset_no_speed;
struct dns_cname_rule {
struct dns_rule head;
char cname[DNS_MAX_CNAME_LEN];
};
struct dns_ttl_rule {
struct dns_rule head;
int ttl;
int ttl_max;
int ttl_min;
};
struct dns_nftset_name { struct dns_nftset_name {
struct hlist_node node; struct hlist_node node;
char nftfamilyname[DNS_MAX_NFTSET_FAMILYLEN]; char nftfamilyname[DNS_MAX_NFTSET_FAMILYLEN];
@@ -162,6 +186,16 @@ struct dns_nftset_rule {
const char *nftsetname; const char *nftsetname;
}; };
struct dns_nftset_names {
char inet_enable;
char ip_enable;
char ip6_enable;
struct dns_nftset_rule inet;
struct dns_nftset_rule ip;
struct dns_nftset_rule ip6;
};
extern struct dns_nftset_names dns_conf_nftset_no_speed;
struct dns_domain_rule { struct dns_domain_rule {
struct dns_rule head; struct dns_rule head;
struct dns_rule *rules[DOMAIN_RULE_MAX]; struct dns_rule *rules[DOMAIN_RULE_MAX];
@@ -248,6 +282,7 @@ struct dns_servers {
int ttl; int ttl;
dns_server_type_t type; dns_server_type_t type;
long long set_mark; long long set_mark;
unsigned int drop_packet_latency_ms;
char skip_check_cert; char skip_check_cert;
char spki[DNS_MAX_SPKI_LEN]; char spki[DNS_MAX_SPKI_LEN];
char hostname[DNS_MAX_CNAME_LEN]; char hostname[DNS_MAX_CNAME_LEN];
@@ -359,6 +394,13 @@ struct dns_set_rule_flags_callback_args {
int is_clear_flag; int is_clear_flag;
}; };
struct dns_dns64 {
unsigned char prefix[DNS_RR_AAAA_LEN];
uint32_t prefix_len;
};
extern struct dns_dns64 dns_conf_dns_dns64;
extern struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP]; extern struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP];
extern int dns_conf_bind_ip_num; extern int dns_conf_bind_ip_num;

View File

@@ -62,7 +62,6 @@
#define CACHE_AUTO_ENABLE_SIZE (1024 * 1024 * 128) #define CACHE_AUTO_ENABLE_SIZE (1024 * 1024 * 128)
#define EXPIRED_DOMAIN_PREFETCH_TIME (3600 * 8) #define EXPIRED_DOMAIN_PREFETCH_TIME (3600 * 8)
#define DNS_MAX_DOMAIN_REFETCH_NUM 16 #define DNS_MAX_DOMAIN_REFETCH_NUM 16
#define DNS_WORKER_NUM 4
#define RECV_ERROR_AGAIN 1 #define RECV_ERROR_AGAIN 1
#define RECV_ERROR_OK 0 #define RECV_ERROR_OK 0
@@ -78,6 +77,13 @@ typedef enum {
DNS_CONN_TYPE_TLS_CLIENT, DNS_CONN_TYPE_TLS_CLIENT,
} DNS_CONN_TYPE; } DNS_CONN_TYPE;
typedef enum DNS_CHILD_POST_RESULT {
DNS_CHILD_POST_SUCCESS = 0,
DNS_CHILD_POST_FAIL,
DNS_CHILD_POST_SKIP,
DNS_CHILD_POST_NO_RESPONSE,
} DNS_CHILD_POST_RESULT;
struct rule_walk_args { struct rule_walk_args {
void *args; void *args;
unsigned char *key[DOMAIN_RULE_MAX]; unsigned char *key[DOMAIN_RULE_MAX];
@@ -122,6 +128,7 @@ struct dns_server_post_context {
int do_force_soa; int do_force_soa;
int skip_notify_count; int skip_notify_count;
int select_all_best_ip; int select_all_best_ip;
int no_release_parent;
}; };
struct dns_server_conn_udp { struct dns_server_conn_udp {
@@ -166,6 +173,9 @@ struct dns_request_pending_list {
struct hlist_node node; struct hlist_node node;
}; };
typedef DNS_CHILD_POST_RESULT (*child_request_callback)(struct dns_request *request, struct dns_request *child_request,
int is_first_resp);
struct dns_request { struct dns_request {
atomic_t refcnt; atomic_t refcnt;
@@ -217,7 +227,6 @@ struct dns_request {
int ping_time; int ping_time;
int ip_ttl; int ip_ttl;
unsigned char ip_addr[DNS_RR_AAAA_LEN]; unsigned char ip_addr[DNS_RR_AAAA_LEN];
int ip_addr_len;
struct dns_soa soa; struct dns_soa soa;
int has_soa; int has_soa;
@@ -243,6 +252,10 @@ struct dns_request {
pthread_mutex_t ip_map_lock; pthread_mutex_t ip_map_lock;
struct dns_request *child_request;
struct dns_request *parent_request;
child_request_callback child_callback;
atomic_t ip_map_num; atomic_t ip_map_num;
DECLARE_HASHTABLE(ip_map, 4); DECLARE_HASHTABLE(ip_map, 4);
@@ -253,26 +266,9 @@ struct dns_request {
struct dns_request_pending_list *request_pending_list; struct dns_request_pending_list *request_pending_list;
}; };
struct dns_server_work_event {
struct list_head list;
struct dns_server_conn_head *conn;
unsigned char inpacket[DNS_IN_PACKSIZE];
int inpacket_len;
struct sockaddr_storage local;
socklen_t local_len;
struct sockaddr_storage from;
socklen_t from_len;
};
/* dns server data */ /* dns server data */
struct dns_server { struct dns_server {
atomic_t run; atomic_t run;
pthread_t worker[DNS_WORKER_NUM];
pthread_mutex_t worker_notify_lock;
pthread_cond_t worker_notify_cond;
struct list_head work_list;
int epoll_fd; int epoll_fd;
int event_fd; int event_fd;
struct list_head conn_list; struct list_head conn_list;
@@ -299,6 +295,9 @@ 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_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_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_wakeup_thread(void) static void _dns_server_wakeup_thread(void)
{ {
@@ -322,17 +321,37 @@ static int _dns_server_has_bind_flag(struct dns_request *request, uint32_t flag)
return -1; return -1;
} }
static int _dns_server_get_conf_ttl(int ttl) static int _dns_server_get_conf_ttl(struct dns_request *request, int ttl)
{ {
if (dns_conf_rr_ttl > 0) { int rr_ttl = dns_conf_rr_ttl;
return dns_conf_rr_ttl; int rr_ttl_min = dns_conf_rr_ttl_min;
int rr_ttl_max = dns_conf_rr_ttl_max;
struct dns_ttl_rule *ttl_rule = _dns_server_get_dns_rule(request, DOMAIN_RULE_TTL);
if (ttl_rule != NULL) {
if (ttl_rule->ttl > 0) {
rr_ttl = ttl_rule->ttl;
}
if (ttl_rule->ttl_min > 0) {
rr_ttl_min = ttl_rule->ttl_min;
}
if (ttl_rule->ttl_max > 0) {
rr_ttl_max = ttl_rule->ttl_max;
}
} }
if (dns_conf_rr_ttl_max > 0 && ttl > dns_conf_rr_ttl_max) { if (rr_ttl > 0) {
ttl = dns_conf_rr_ttl_max; return rr_ttl;
} else if (dns_conf_rr_ttl_min > 0 && ttl < dns_conf_rr_ttl_min) {
ttl = dns_conf_rr_ttl_min;
} }
if (rr_ttl_max > 0 && ttl >= rr_ttl_max) {
ttl = rr_ttl_max;
} else if (rr_ttl_min > 0 && ttl <= rr_ttl_min) {
ttl = rr_ttl_min;
}
return ttl; return ttl;
} }
@@ -405,6 +424,11 @@ static int _dns_server_is_return_soa(struct dns_request *request)
unsigned int flags = 0; unsigned int flags = 0;
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_SOA) == 0) { if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_SOA) == 0) {
/* when both has no rule SOA and force AAAA soa, foce AAAA soa has high priority */
if (request->qtype == DNS_T_AAAA && _dns_server_has_bind_flag(request, BIND_FLAG_FORCE_AAAA_SOA) == 0) {
return 1;
}
return 0; return 0;
} }
@@ -1062,13 +1086,13 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
if (cache_ttl > 0) { if (cache_ttl > 0) {
ttl = cache_ttl; ttl = cache_ttl;
} else { } else {
ttl = _dns_server_get_conf_ttl(request->ip_ttl); ttl = _dns_server_get_conf_ttl(request, request->ip_ttl);
} }
speed = request->ping_time; speed = request->ping_time;
if (has_soa) { if (has_soa) {
if (request->dualstack_selection && request->has_ip && request->qtype == DNS_T_AAAA) { if (request->dualstack_selection && request->has_ip && request->qtype == DNS_T_AAAA) {
ttl = _dns_server_get_conf_ttl(request->ip_ttl); ttl = _dns_server_get_conf_ttl(request, request->ip_ttl);
} else { } else {
ttl = dns_conf_rr_ttl; ttl = dns_conf_rr_ttl;
if (ttl == 0) { if (ttl == 0) {
@@ -1224,7 +1248,7 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
return -1; return -1;
} }
ttl = _dns_server_get_conf_ttl(request->ip_ttl); ttl = _dns_server_get_conf_ttl(request, request->ip_ttl);
speed = request->ping_time; speed = request->ping_time;
tlog(TLOG_DEBUG, "Cache CNAME: %s, qtype: %d, speed: %d", request->cname, request->qtype, speed); tlog(TLOG_DEBUG, "Cache CNAME: %s, qtype: %d, speed: %d", request->cname, request->qtype, speed);
@@ -1309,7 +1333,7 @@ static int _dns_result_callback_nxdomain(struct dns_request *request)
return 0; return 0;
} }
return request->result_callback(request->domain, DNS_RC_NXDOMAIN, request->qtype, ip, ping_time, request->user_ptr); return request->result_callback(request->domain, request->rcode, request->qtype, ip, ping_time, request->user_ptr);
} }
static int _dns_result_callback(struct dns_server_post_context *context) static int _dns_result_callback(struct dns_server_post_context *context)
@@ -1441,6 +1465,7 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
struct dns_nftset_rule *nftset_ip = NULL; struct dns_nftset_rule *nftset_ip = NULL;
struct dns_nftset_rule *nftset_ip6 = NULL; struct dns_nftset_rule *nftset_ip6 = NULL;
struct dns_rule_flags *rule_flags = NULL; struct dns_rule_flags *rule_flags = NULL;
int check_no_speed_rule = 0;
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_IPSET) == 0) { if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_IPSET) == 0) {
return 0; return 0;
@@ -1454,6 +1479,10 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
return 0; return 0;
} }
if (request->ping_time < 0 && request->has_ip > 0 && request->passthrough == 0) {
check_no_speed_rule = 1;
}
/* check ipset rule */ /* check ipset rule */
rule_flags = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS); rule_flags = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS);
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) { if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
@@ -1462,18 +1491,30 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) { if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
ipset_rule_v4 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV4); ipset_rule_v4 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV4);
if (ipset_rule == NULL && check_no_speed_rule && dns_conf_ipset_no_speed.ipv4_enable) {
ipset_rule_v4 = &dns_conf_ipset_no_speed.ipv4;
}
} }
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV6_IGN) == 0) { if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV6_IGN) == 0) {
ipset_rule_v6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV6); ipset_rule_v6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET_IPV6);
if (ipset_rule_v6 == NULL && check_no_speed_rule && dns_conf_ipset_no_speed.ipv6_enable) {
ipset_rule_v6 = &dns_conf_ipset_no_speed.ipv6;
}
} }
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP_IGN) == 0) { if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP_IGN) == 0) {
nftset_ip = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP); nftset_ip = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP);
if (nftset_ip == NULL && check_no_speed_rule && dns_conf_nftset_no_speed.ip_enable) {
nftset_ip = &dns_conf_nftset_no_speed.ip;
}
} }
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP6_IGN) == 0) { if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP6_IGN) == 0) {
nftset_ip6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP6); nftset_ip6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP6);
if (nftset_ip6 == NULL && check_no_speed_rule && dns_conf_nftset_no_speed.ip6_enable) {
nftset_ip6 = &dns_conf_nftset_no_speed.ip6;
}
} }
if (!(ipset_rule || ipset_rule_v4 || ipset_rule_v6 || nftset_ip || nftset_ip6)) { if (!(ipset_rule || ipset_rule_v4 || ipset_rule_v6 || nftset_ip || nftset_ip6)) {
@@ -1549,6 +1590,53 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
return 0; return 0;
} }
static int _dns_result_child_post(struct dns_server_post_context *context)
{
struct dns_request *request = context->request;
struct dns_request *parent_request = request->parent_request;
DNS_CHILD_POST_RESULT child_ret = DNS_CHILD_POST_FAIL;
/* not a child request */
if (parent_request == NULL) {
return 0;
}
if (request->child_callback) {
int is_first_resp = context->no_release_parent;
child_ret = request->child_callback(parent_request, request, is_first_resp);
}
if (context->do_reply == 1 && child_ret == DNS_CHILD_POST_SUCCESS) {
struct dns_server_post_context parent_context;
_dns_server_post_context_init(&parent_context, parent_request);
parent_context.do_cache = context->do_cache;
parent_context.do_ipset = context->do_ipset;
parent_context.do_force_soa = context->do_force_soa;
parent_context.do_audit = context->do_audit;
parent_context.do_reply = context->do_reply;
parent_context.reply_ttl = context->reply_ttl;
parent_context.skip_notify_count = context->skip_notify_count;
parent_context.select_all_best_ip = 1;
parent_context.no_release_parent = context->no_release_parent;
_dns_request_post(&parent_context);
_dns_server_reply_all_pending_list(parent_request, &parent_context);
}
if (context->no_release_parent == 0) {
tlog(TLOG_INFO, "query %s with child %s done", parent_request->domain, request->domain);
request->parent_request = NULL;
parent_request->request_wait--;
_dns_server_request_release(parent_request);
}
if (child_ret == DNS_CHILD_POST_FAIL) {
return -1;
}
return 0;
}
static int _dns_request_post(struct dns_server_post_context *context) static int _dns_request_post(struct dns_server_post_context *context)
{ {
struct dns_request *request = context->request; struct dns_request *request = context->request;
@@ -1579,6 +1667,9 @@ static int _dns_request_post(struct dns_server_post_context *context)
/* setup ipset */ /* setup ipset */
_dns_server_setup_ipset_nftset_packet(context); _dns_server_setup_ipset_nftset_packet(context);
/* reply child request */
_dns_result_child_post(context);
if (context->do_reply == 0) { if (context->do_reply == 0) {
return 0; return 0;
} }
@@ -1664,13 +1755,13 @@ static int _dns_server_reply_all_pending_list(struct dns_request *request, struc
struct dns_server_post_context context_pending; struct dns_server_post_context context_pending;
_dns_server_post_context_init_from(&context_pending, req, context->packet, context->inpacket, _dns_server_post_context_init_from(&context_pending, req, context->packet, context->inpacket,
context->inpacket_len); context->inpacket_len);
_dns_server_get_answer(&context_pending);
req->dualstack_selection = request->dualstack_selection; req->dualstack_selection = request->dualstack_selection;
req->dualstack_selection_query = request->dualstack_selection_query; req->dualstack_selection_query = request->dualstack_selection_query;
req->dualstack_selection_force_soa = request->dualstack_selection_force_soa; req->dualstack_selection_force_soa = request->dualstack_selection_force_soa;
req->dualstack_selection_has_ip = request->dualstack_selection_has_ip; req->dualstack_selection_has_ip = request->dualstack_selection_has_ip;
req->dualstack_selection_ping_time = request->dualstack_selection_ping_time; req->dualstack_selection_ping_time = request->dualstack_selection_ping_time;
req->ping_time = request->ping_time; req->ping_time = request->ping_time;
_dns_server_get_answer(&context_pending);
context_pending.do_cache = 0; context_pending.do_cache = 0;
context_pending.do_audit = context->do_audit; context_pending.do_audit = context->do_audit;
@@ -1678,6 +1769,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;
_dns_server_reply_passthrough(&context_pending); _dns_server_reply_passthrough(&context_pending);
req->request_pending_list = NULL; req->request_pending_list = NULL;
@@ -1807,6 +1899,7 @@ out:
context.reply_ttl = reply_ttl; context.reply_ttl = reply_ttl;
context.skip_notify_count = 1; context.skip_notify_count = 1;
context.select_all_best_ip = with_all_ips; context.select_all_best_ip = with_all_ips;
context.no_release_parent = 1;
_dns_request_post(&context); _dns_request_post(&context);
return _dns_server_reply_all_pending_list(request, &context); return _dns_server_reply_all_pending_list(request, &context);
@@ -1818,12 +1911,16 @@ static int _dns_server_request_complete(struct dns_request *request)
} }
static int _dns_ip_address_check_add(struct dns_request *request, char *cname, unsigned char *addr, static int _dns_ip_address_check_add(struct dns_request *request, char *cname, unsigned char *addr,
dns_type_t addr_type) dns_type_t addr_type, int ping_time)
{ {
uint32_t key = 0; uint32_t key = 0;
struct dns_ip_address *addr_map = NULL; struct dns_ip_address *addr_map = NULL;
int addr_len = 0; int addr_len = 0;
if (ping_time == 0) {
ping_time = -1;
}
if (addr_type == DNS_T_A) { if (addr_type == DNS_T_A) {
addr_len = DNS_RR_A_LEN; addr_len = DNS_RR_A_LEN;
} else if (addr_type == DNS_T_AAAA) { } else if (addr_type == DNS_T_AAAA) {
@@ -1864,7 +1961,7 @@ static int _dns_ip_address_check_add(struct dns_request *request, char *cname, u
addr_map->addr_type = addr_type; addr_map->addr_type = addr_type;
addr_map->hitnum = 1; addr_map->hitnum = 1;
addr_map->recv_tick = get_tick_count(); addr_map->recv_tick = get_tick_count();
addr_map->ping_time = -1; addr_map->ping_time = ping_time;
memcpy(addr_map->ip_addr, addr, addr_len); memcpy(addr_map->ip_addr, addr, addr_len);
if (dns_conf_force_no_cname == 0) { if (dns_conf_force_no_cname == 0) {
safe_strncpy(addr_map->cname, cname, DNS_MAX_CNAME_LEN); safe_strncpy(addr_map->cname, cname, DNS_MAX_CNAME_LEN);
@@ -2046,6 +2143,11 @@ static void _dns_server_request_release_complete(struct dns_request *request, in
_dns_server_complete_with_multi_ipaddress(request); _dns_server_complete_with_multi_ipaddress(request);
} }
if (request->parent_request != NULL) {
_dns_server_request_release(request->parent_request);
request->parent_request = NULL;
}
pthread_mutex_lock(&request->ip_map_lock); pthread_mutex_lock(&request->ip_map_lock);
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node) hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
{ {
@@ -2504,14 +2606,14 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
if (request->has_ip == 0) { if (request->has_ip == 0) {
request->has_ip = 1; request->has_ip = 1;
memcpy(request->ip_addr, addr, DNS_RR_A_LEN); memcpy(request->ip_addr, addr, DNS_RR_A_LEN);
request->ip_ttl = _dns_server_get_conf_ttl(ttl); request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
if (cname[0] != 0 && request->has_cname == 0 && dns_conf_force_no_cname == 0) { if (cname[0] != 0 && request->has_cname == 0 && dns_conf_force_no_cname == 0) {
request->has_cname = 1; request->has_cname = 1;
safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN); safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
} }
} else { } else {
if (ttl < request->ip_ttl) { if (ttl < request->ip_ttl) {
request->ip_ttl = _dns_server_get_conf_ttl(ttl); request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
} }
} }
@@ -2526,7 +2628,7 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
} }
/* add this ip to request */ /* add this ip to request */
if (_dns_ip_address_check_add(request, cname, addr, DNS_T_A) != 0) { if (_dns_ip_address_check_add(request, cname, addr, DNS_T_A, 0) != 0) {
_dns_server_request_release(request); _dns_server_request_release(request);
return -1; return -1;
} }
@@ -2581,14 +2683,14 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
if (request->has_ip == 0) { if (request->has_ip == 0) {
request->has_ip = 1; request->has_ip = 1;
memcpy(request->ip_addr, addr, DNS_RR_AAAA_LEN); memcpy(request->ip_addr, addr, DNS_RR_AAAA_LEN);
request->ip_ttl = _dns_server_get_conf_ttl(ttl); request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
if (cname[0] != 0 && request->has_cname == 0 && dns_conf_force_no_cname == 0) { if (cname[0] != 0 && request->has_cname == 0 && dns_conf_force_no_cname == 0) {
request->has_cname = 1; request->has_cname = 1;
safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN); safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
} }
} else { } else {
if (ttl < request->ip_ttl) { if (ttl < request->ip_ttl) {
request->ip_ttl = _dns_server_get_conf_ttl(ttl); request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
} }
} }
@@ -2603,7 +2705,7 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
} }
/* add this ip to request */ /* add this ip to request */
if (_dns_ip_address_check_add(request, cname, addr, DNS_T_AAAA) != 0) { if (_dns_ip_address_check_add(request, cname, addr, DNS_T_AAAA, 0) != 0) {
_dns_server_request_release(request); _dns_server_request_release(request);
return -1; return -1;
} }
@@ -2683,7 +2785,7 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
continue; continue;
} }
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(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", name, ttl, cname);
} break; } break;
case DNS_T_SOA: { case DNS_T_SOA: {
@@ -2697,6 +2799,12 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
"%d, minimum: %d", "%d, minimum: %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;
@@ -2840,6 +2948,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;
} }
} }
@@ -2879,7 +2993,8 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
continue; continue;
} }
if (context->no_check_add_ip == 0 && _dns_ip_address_check_add(request, name, addr, DNS_T_A) != 0) { if (context->no_check_add_ip == 0 &&
_dns_ip_address_check_add(request, name, addr, DNS_T_A, request->ping_time) != 0) {
continue; continue;
} }
@@ -2890,7 +3005,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
memcpy(request->ip_addr, addr, DNS_RR_A_LEN); memcpy(request->ip_addr, addr, DNS_RR_A_LEN);
/* add this ip to request */ /* add this ip to request */
request->ip_ttl = _dns_server_get_conf_ttl(ttl); request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
request->has_ip = 1; request->has_ip = 1;
request->rcode = packet->head.rcode; request->rcode = packet->head.rcode;
} break; } break;
@@ -2909,7 +3024,8 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
continue; continue;
} }
if (context->no_check_add_ip == 0 && _dns_ip_address_check_add(request, name, addr, DNS_T_AAAA) != 0) { if (context->no_check_add_ip == 0 &&
_dns_ip_address_check_add(request, name, addr, DNS_T_AAAA, request->ping_time) != 0) {
continue; continue;
} }
@@ -2919,7 +3035,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
} }
memcpy(request->ip_addr, addr, DNS_RR_AAAA_LEN); memcpy(request->ip_addr, addr, DNS_RR_AAAA_LEN);
request->ip_ttl = _dns_server_get_conf_ttl(ttl); request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
request->has_ip = 1; request->has_ip = 1;
request->rcode = packet->head.rcode; request->rcode = packet->head.rcode;
} break; } break;
@@ -2944,7 +3060,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
} }
safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN); safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
request->ttl_cname = _dns_server_get_conf_ttl(ttl); request->ttl_cname = _dns_server_get_conf_ttl(request, ttl);
request->has_cname = 1; request->has_cname = 1;
} break; } break;
case DNS_T_SOA: { case DNS_T_SOA: {
@@ -2979,16 +3095,19 @@ static int _dns_server_reply_passthrough(struct dns_server_post_context *context
_dns_server_get_answer(context); _dns_server_get_answer(context);
_dns_result_callback(context);
_dns_cache_reply_packet(context); _dns_cache_reply_packet(context);
if (_dns_server_setup_ipset_nftset_packet(context) != 0) { if (_dns_server_setup_ipset_nftset_packet(context) != 0) {
tlog(TLOG_DEBUG, "setup ipset failed."); tlog(TLOG_DEBUG, "setup ipset failed.");
} }
_dns_result_callback(context);
_dns_server_audit_log(context); _dns_server_audit_log(context);
/* reply child request */
_dns_result_child_post(context);
if (request->conn && context->do_reply == 1) { if (request->conn && context->do_reply == 1) {
/* When passthrough, modify the id to be the id of the client request. */ /* When passthrough, modify the id to be the id of the client request. */
struct dns_update_param param; struct dns_update_param param;
@@ -3008,6 +3127,7 @@ static void _dns_server_query_end(struct dns_request *request)
{ {
int ip_num = 0; int ip_num = 0;
int request_wait = 0; int request_wait = 0;
pthread_mutex_lock(&request->ip_map_lock); pthread_mutex_lock(&request->ip_map_lock);
ip_num = atomic_read(&request->ip_map_num); ip_num = atomic_read(&request->ip_map_num);
/* if adblock ip address exist */ /* if adblock ip address exist */
@@ -3019,6 +3139,7 @@ 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);
goto out; goto out;
} }
@@ -3113,7 +3234,7 @@ static int dns_server_resolve_callback(const char *domain, dns_result_type rtype
return 0; return 0;
} }
ttl = _dns_server_get_conf_ttl(ttl); ttl = _dns_server_get_conf_ttl(request, ttl);
if (ttl > dns_conf_rr_ttl_reply_max && dns_conf_rr_ttl_reply_max > 0) { if (ttl > dns_conf_rr_ttl_reply_max && dns_conf_rr_ttl_reply_max > 0) {
ttl = dns_conf_rr_ttl_reply_max; ttl = dns_conf_rr_ttl_reply_max;
} }
@@ -3725,6 +3846,310 @@ errout:
return -1; return -1;
} }
static struct dns_request *_dns_server_new_child_request(struct dns_request *request,
child_request_callback child_callback)
{
struct dns_request *child_request = NULL;
child_request = _dns_server_new_request();
if (child_request == NULL) {
tlog(TLOG_ERROR, "malloc failed.\n");
goto errout;
}
child_request->server_flags = request->server_flags;
safe_strncpy(child_request->dns_group_name, request->dns_group_name, sizeof(request->dns_group_name));
child_request->prefetch = request->prefetch;
child_request->prefetch_expired_domain = request->prefetch_expired_domain;
child_request->child_callback = child_callback;
child_request->parent_request = request;
if (request->has_ecs) {
memcpy(&child_request->ecs, &request->ecs, sizeof(child_request->ecs));
child_request->has_ecs = request->has_ecs;
}
_dns_server_request_get(request);
/* reference count is 1 hold by parent request */
request->child_request = child_request;
return child_request;
errout:
if (child_request) {
_dns_server_request_release(child_request);
}
return NULL;
}
static int _dns_server_request_copy(struct dns_request *request, struct dns_request *from)
{
unsigned long bucket = 0;
struct dns_ip_address *addr_map = NULL;
struct hlist_node *tmp = NULL;
uint32_t key = 0;
int addr_len = 0;
request->rcode = from->rcode;
if (from->has_ip) {
request->has_ip = 1;
request->ip_ttl = from->ip_ttl;
request->ping_time = from->ping_time;
memcpy(request->ip_addr, from->ip_addr, sizeof(request->ip_addr));
}
if (from->has_cname) {
request->has_cname = 1;
request->ttl_cname = from->ttl_cname;
safe_strncpy(request->cname, from->cname, sizeof(request->cname));
}
if (from->has_soa) {
request->has_soa = 1;
memcpy(&request->soa, &from->soa, sizeof(request->soa));
}
pthread_mutex_lock(&request->ip_map_lock);
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
{
hash_del(&addr_map->node);
free(addr_map);
}
pthread_mutex_unlock(&request->ip_map_lock);
pthread_mutex_lock(&from->ip_map_lock);
hash_for_each_safe(from->ip_map, bucket, tmp, addr_map, node)
{
struct dns_ip_address *new_addr_map = NULL;
if (addr_map->addr_type == DNS_T_A) {
addr_len = DNS_RR_A_LEN;
} else if (addr_map->addr_type == DNS_T_AAAA) {
addr_len = DNS_RR_AAAA_LEN;
} else {
continue;
}
new_addr_map = malloc(sizeof(struct dns_ip_address));
if (new_addr_map == NULL) {
tlog(TLOG_ERROR, "malloc failed.\n");
pthread_mutex_unlock(&from->ip_map_lock);
return -1;
}
memcpy(new_addr_map, addr_map, sizeof(struct dns_ip_address));
new_addr_map->ping_time = addr_map->ping_time;
key = jhash(new_addr_map->ip_addr, addr_len, 0);
key = jhash(&addr_map->addr_type, sizeof(addr_map->addr_type), key);
pthread_mutex_lock(&request->ip_map_lock);
hash_add(request->ip_map, &new_addr_map->node, key);
pthread_mutex_unlock(&request->ip_map_lock);
}
pthread_mutex_unlock(&from->ip_map_lock);
return 0;
}
static DNS_CHILD_POST_RESULT _dns_server_process_cname_callback(struct dns_request *request,
struct dns_request *child_request, int is_first_resp)
{
_dns_server_request_copy(request, child_request);
safe_strncpy(request->cname, child_request->domain, sizeof(request->cname));
return DNS_CHILD_POST_SUCCESS;
}
static int _dns_server_process_cname(struct dns_request *request)
{
struct dns_cname_rule *cname = NULL;
int ret = 0;
struct dns_rule_flags *rule_flag = NULL;
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 /domain/ rule */
if (request->domain_rule.rules[DOMAIN_RULE_CNAME] == NULL) {
return 0;
}
cname = _dns_server_get_dns_rule(request, DOMAIN_RULE_CNAME);
if (cname == NULL) {
return 0;
}
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);
if (child_request == NULL) {
tlog(TLOG_ERROR, "malloc failed.\n");
return -1;
}
child_request->qtype = request->qtype;
child_request->qclass = request->qclass;
safe_strncpy(child_request->domain, cname->cname, sizeof(child_request->cname));
request->request_wait++;
ret = _dns_server_do_query(child_request, 0);
if (ret != 0) {
request->request_wait--;
tlog(TLOG_ERROR, "do query %s type %d failed.\n", request->domain, request->qtype);
goto errout;
}
_dns_server_request_release_complete(child_request, 0);
return 1;
errout:
if (child_request) {
request->child_request = NULL;
_dns_server_request_release(child_request);
}
return -1;
}
static enum DNS_CHILD_POST_RESULT
_dns_server_process_dns64_callback(struct dns_request *request, struct dns_request *child_request, int is_first_resp)
{
unsigned long bucket = 0;
struct dns_ip_address *addr_map = NULL;
struct hlist_node *tmp = NULL;
uint32_t key = 0;
int addr_len = 0;
if (request->has_ip == 1) {
if (memcmp(request->ip_addr, dns_conf_dns_dns64.prefix, 12) != 0) {
return DNS_CHILD_POST_SKIP;
}
}
if (child_request->qtype != DNS_T_A) {
return DNS_CHILD_POST_FAIL;
}
if (child_request->has_ip == 0) {
if (child_request->has_soa) {
memcpy(&request->soa, &child_request->soa, sizeof(struct dns_soa));
request->has_soa = 1;
return DNS_CHILD_POST_SUCCESS;
}
if (request->has_soa == 0) {
_dns_server_setup_soa(request);
request->has_soa = 1;
}
return DNS_CHILD_POST_FAIL;
}
memcpy(request->ip_addr, dns_conf_dns_dns64.prefix, 16);
memcpy(request->ip_addr + 12, child_request->ip_addr, 4);
request->ip_ttl = child_request->ip_ttl;
request->has_ip = 1;
request->has_soa = 0;
request->rcode = child_request->rcode;
pthread_mutex_lock(&request->ip_map_lock);
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
{
hash_del(&addr_map->node);
free(addr_map);
}
pthread_mutex_unlock(&request->ip_map_lock);
pthread_mutex_lock(&child_request->ip_map_lock);
hash_for_each_safe(child_request->ip_map, bucket, tmp, addr_map, node)
{
struct dns_ip_address *new_addr_map = NULL;
if (addr_map->addr_type == DNS_T_A) {
addr_len = DNS_RR_A_LEN;
} else {
continue;
}
new_addr_map = malloc(sizeof(struct dns_ip_address));
if (new_addr_map == NULL) {
tlog(TLOG_ERROR, "malloc failed.\n");
pthread_mutex_unlock(&child_request->ip_map_lock);
return DNS_CHILD_POST_FAIL;
}
memset(new_addr_map, 0, sizeof(struct dns_ip_address));
new_addr_map->addr_type = DNS_T_AAAA;
addr_len = DNS_RR_AAAA_LEN;
memcpy(new_addr_map->ip_addr, dns_conf_dns_dns64.prefix, 16);
memcpy(new_addr_map->ip_addr + 12, addr_map->ip_addr, 4);
new_addr_map->ping_time = addr_map->ping_time;
key = jhash(new_addr_map->ip_addr, addr_len, 0);
key = jhash(&new_addr_map->addr_type, sizeof(new_addr_map->addr_type), key);
pthread_mutex_lock(&request->ip_map_lock);
hash_add(request->ip_map, &new_addr_map->node, key);
pthread_mutex_unlock(&request->ip_map_lock);
}
pthread_mutex_unlock(&child_request->ip_map_lock);
if (request->dualstack_selection == 1) {
return DNS_CHILD_POST_NO_RESPONSE;
}
return DNS_CHILD_POST_SUCCESS;
}
static int _dns_server_process_dns64(struct dns_request *request)
{
if (request->qtype != DNS_T_AAAA) {
return 0;
}
if (dns_conf_dns_dns64.prefix_len <= 0) {
/* no dns64 prefix, no need to do dns64 */
return 0;
}
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);
if (child_request == NULL) {
tlog(TLOG_ERROR, "malloc failed.\n");
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++;
int ret = _dns_server_do_query(child_request, 0);
if (ret != 0) {
request->request_wait--;
tlog(TLOG_ERROR, "do query %s type %d failed.\n", request->domain, request->qtype);
goto errout;
}
_dns_server_request_release_complete(child_request, 0);
return 1;
errout:
if (child_request) {
request->child_request = NULL;
_dns_server_request_release(child_request);
}
return -1;
}
static int _dns_server_qtype_soa(struct dns_request *request) static int _dns_server_qtype_soa(struct dns_request *request)
{ {
struct dns_qtype_soa_list *soa_list = NULL; struct dns_qtype_soa_list *soa_list = NULL;
@@ -4403,6 +4828,10 @@ static int _dns_server_do_query(struct dns_request *request, int skip_notify_eve
goto clean_exit; goto clean_exit;
} }
if (_dns_server_process_cname(request) != 0) {
goto clean_exit;
}
// setup options // setup options
_dns_server_setup_query_option(request, &options); _dns_server_setup_query_option(request, &options);
@@ -4427,6 +4856,10 @@ static int _dns_server_do_query(struct dns_request *request, int skip_notify_eve
/* When the dual stack ip preference is enabled, both A and AAAA records are requested. */ /* When the dual stack ip preference is enabled, both A and AAAA records are requested. */
_dns_server_query_dualstack(request); _dns_server_query_dualstack(request);
if (_dns_server_process_dns64(request) != 0) {
goto clean_exit;
}
clean_exit: clean_exit:
return 0; return 0;
errout: errout:
@@ -4506,9 +4939,9 @@ errout:
return -1; return -1;
} }
static int _dns_server_process_work(struct dns_server_conn_head *conn, unsigned char *inpacket, int inpacket_len, static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *inpacket, int inpacket_len,
struct sockaddr_storage *local, socklen_t local_len, struct sockaddr_storage *from, struct sockaddr_storage *local, socklen_t local_len, struct sockaddr_storage *from,
socklen_t from_len) socklen_t from_len)
{ {
int decode_len = 0; int decode_len = 0;
int ret = -1; int ret = -1;
@@ -4571,34 +5004,6 @@ errout:
return ret; return ret;
} }
static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *inpacket, int inpacket_len,
struct sockaddr_storage *local, socklen_t local_len, struct sockaddr_storage *from,
socklen_t from_len)
{
struct dns_server_work_event *event = NULL;
event = (struct dns_server_work_event *)malloc(sizeof(struct dns_server_work_event));
if (event == NULL) {
tlog(TLOG_ERROR, "malloc failed.\n");
return -1;
}
memset(event, 0, sizeof(struct dns_server_work_event));
event->conn = conn;
memcpy(event->inpacket, inpacket, inpacket_len);
event->inpacket_len = inpacket_len;
memcpy(&event->local, local, local_len);
event->local_len = local_len;
memcpy(&event->from, from, from_len);
event->from_len = from_len;
INIT_LIST_HEAD(&event->list);
pthread_mutex_lock(&server.worker_notify_lock);
list_add_tail(&event->list, &server.work_list);
pthread_mutex_unlock(&server.worker_notify_lock);
pthread_cond_signal(&server.worker_notify_cond);
return 0;
}
static int _dns_server_setup_server_query_options(struct dns_request *request, static int _dns_server_setup_server_query_options(struct dns_request *request,
struct dns_server_query_option *server_query_option) struct dns_server_query_option *server_query_option)
{ {
@@ -5244,34 +5649,6 @@ static void _dns_server_close_socket_server(void)
} }
} }
static void *_dns_server_worker(void *args)
{
struct dns_server_work_event *work_event = NULL;
while (atomic_read(&server.run)) {
pthread_mutex_lock(&server.worker_notify_lock);
if (list_empty(&server.work_list)) {
pthread_cond_wait(&server.worker_notify_cond, &server.worker_notify_lock);
}
work_event = list_first_entry_or_null(&server.work_list, struct dns_server_work_event, list);
if (work_event) {
list_del_init(&work_event->list);
}
pthread_mutex_unlock(&server.worker_notify_lock);
if (work_event == NULL) {
continue;
}
_dns_server_process_work(work_event->conn, work_event->inpacket, work_event->inpacket_len, &work_event->local,
work_event->local_len, &work_event->from, work_event->from_len);
free(work_event);
}
return NULL;
}
int dns_server_run(void) int dns_server_run(void)
{ {
struct epoll_event events[DNS_MAX_EVENTS + 1]; struct epoll_event events[DNS_MAX_EVENTS + 1];
@@ -5756,10 +6133,7 @@ int dns_server_init(void)
} }
pthread_mutex_init(&server.request_list_lock, NULL); pthread_mutex_init(&server.request_list_lock, NULL);
pthread_mutex_init(&server.worker_notify_lock, NULL);
pthread_cond_init(&server.worker_notify_cond, NULL);
INIT_LIST_HEAD(&server.request_list); INIT_LIST_HEAD(&server.request_list);
INIT_LIST_HEAD(&server.work_list);
server.epoll_fd = epollfd; server.epoll_fd = epollfd;
atomic_set(&server.run, 1); atomic_set(&server.run, 1);
@@ -5777,14 +6151,6 @@ int dns_server_init(void)
goto errout; goto errout;
} }
for (int i = 0; i < DNS_WORKER_NUM; i++) {
ret = pthread_create(&server.worker[i], &attr, _dns_server_worker, NULL);
if (ret != 0) {
tlog(TLOG_ERROR, "create server work thread failed, %s\n", strerror(ret));
goto errout;
}
}
return 0; return 0;
errout: errout:
atomic_set(&server.run, 0); atomic_set(&server.run, 0);
@@ -5813,15 +6179,6 @@ void dns_server_exit(void)
close(server.event_fd); close(server.event_fd);
server.event_fd = -1; server.event_fd = -1;
} }
for (int i = 0; i < DNS_WORKER_NUM; i++) {
if (server.worker[i]) {
pthread_cond_broadcast(&server.worker_notify_cond);
pthread_join(server.worker[i], NULL);
server.worker[i] = 0;
}
}
_dns_server_close_socket(); _dns_server_close_socket();
_dns_server_cache_save(); _dns_server_cache_save();
_dns_server_request_remove_all(); _dns_server_request_remove_all();

View File

@@ -32,6 +32,16 @@ const char *conf_get_conf_file(void)
return current_conf_file; return current_conf_file;
} }
static char *get_dir_name(char *path)
{
if (strstr(path, "/") == NULL) {
strncpy(path, "./", PATH_MAX);
return path;
}
return dirname(path);
}
const char *conf_get_conf_fullpath(const char *path, char *fullpath, size_t path_len) const char *conf_get_conf_fullpath(const char *path, char *fullpath, size_t path_len)
{ {
char file_path_dir[PATH_MAX]; char file_path_dir[PATH_MAX];
@@ -47,7 +57,7 @@ const char *conf_get_conf_fullpath(const char *path, char *fullpath, size_t path
strncpy(file_path_dir, conf_get_conf_file(), PATH_MAX - 1); strncpy(file_path_dir, conf_get_conf_file(), PATH_MAX - 1);
file_path_dir[PATH_MAX - 1] = 0; file_path_dir[PATH_MAX - 1] = 0;
dirname(file_path_dir); get_dir_name(file_path_dir);
if (file_path_dir[0] == '\0') { if (file_path_dir[0] == '\0') {
strncpy(fullpath, path, path_len); strncpy(fullpath, path, path_len);
return fullpath; return fullpath;

View File

@@ -269,6 +269,7 @@ static int _smartdns_add_servers(void)
flags.server_flag = dns_conf_servers[i].server_flag; flags.server_flag = dns_conf_servers[i].server_flag;
flags.result_flag = dns_conf_servers[i].result_flag; flags.result_flag = dns_conf_servers[i].result_flag;
flags.set_mark = dns_conf_servers[i].set_mark; flags.set_mark = dns_conf_servers[i].set_mark;
flags.drop_packet_latency_ms = dns_conf_servers[i].drop_packet_latency_ms;
safe_strncpy(flags.proxyname, dns_conf_servers[i].proxyname, sizeof(flags.proxyname)); safe_strncpy(flags.proxyname, dns_conf_servers[i].proxyname, sizeof(flags.proxyname));
ret = dns_client_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type, ret = dns_client_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type,
&flags); &flags);
@@ -542,7 +543,7 @@ static int _smartdns_create_logdir(void)
int gid = 0; int gid = 0;
char logdir[PATH_MAX] = {0}; char logdir[PATH_MAX] = {0};
safe_strncpy(logdir, _smartdns_log_path(), PATH_MAX); safe_strncpy(logdir, _smartdns_log_path(), PATH_MAX);
dirname(logdir); dir_name(logdir);
if (access(logdir, F_OK) == 0) { if (access(logdir, F_OK) == 0) {
return 0; return 0;

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 {

View File

@@ -29,6 +29,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <libgen.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/netlink.h> #include <linux/netlink.h>
@@ -109,6 +110,16 @@ unsigned long get_tick_count(void)
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
} }
char *dir_name(char *path)
{
if (strstr(path, "/") == NULL) {
safe_strncpy(path, "./", PATH_MAX);
return path;
}
return dirname(path);
}
char *get_host_by_addr(char *host, int maxsize, struct sockaddr *addr) char *get_host_by_addr(char *host, int maxsize, struct sockaddr *addr)
{ {
struct sockaddr_storage *addr_store = (struct sockaddr_storage *)addr; struct sockaddr_storage *addr_store = (struct sockaddr_storage *)addr;

View File

@@ -55,6 +55,8 @@ void bug_ext(const char *file, int line, const char *func, const char *errfmt, .
unsigned long get_tick_count(void); unsigned long get_tick_count(void);
char *dir_name(char *path);
char *get_host_by_addr(char *host, int maxsize, struct sockaddr *addr); char *get_host_by_addr(char *host, int maxsize, struct sockaddr *addr);
int getaddr_by_host(const char *host, struct sockaddr *addr, socklen_t *addr_len); int getaddr_by_host(const char *host, struct sockaddr *addr, socklen_t *addr_len);