Compare commits
17 Commits
multi-thre
...
Release41-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2d7dac7e9 | ||
|
|
a62d716b10 | ||
|
|
694d093fc4 | ||
|
|
464bf28601 | ||
|
|
24e1dac854 | ||
|
|
e51580ea57 | ||
|
|
499ab1b64f | ||
|
|
db56472b84 | ||
|
|
60e3a109e4 | ||
|
|
7256f5af32 | ||
|
|
1e6a5f3809 | ||
|
|
4941594182 | ||
|
|
a6d6781a2a | ||
|
|
be71e085ad | ||
|
|
69a2f3bb7f | ||
|
|
d6f9b07f1c | ||
|
|
03ba24480b |
28
ReadMe.md
28
ReadMe.md
@@ -112,7 +112,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
支持域名后缀匹配模式,简化过滤配置,过滤 20 万条记录时间 < 1ms。
|
||||
|
||||
1. **域名分流**
|
||||
支持域名分流,不同类型的域名向不同的 DNS 服务器查询,支持iptable和nftable更好的分流。
|
||||
支持域名分流,不同类型的域名向不同的 DNS 服务器查询,支持iptable和nftable更好的分流;支持测速失败的情况下设置域名结果到对应ipset和nftset集合。
|
||||
|
||||
1. **Windows / Linux 多平台支持**
|
||||
支持标准 Linux 系统(树莓派)、OpenWrt 系统各种固件和华硕路由器原生固件。同时还支持 WSL(Windows Subsystem for Linux,适用于 Linux 的 Windows 子系统)。
|
||||
@@ -120,6 +120,9 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
1. **支持 IPv4、IPv6 双栈**
|
||||
支持 IPv4 和 IPV 6网络,支持查询 A 和 AAAA 记录,支持双栈 IP 速度优化,并支持完全禁用 IPv6 AAAA 解析。
|
||||
|
||||
1. **支持DNS64**
|
||||
支持DNS64转换。
|
||||
|
||||
1. **高性能、占用资源少**
|
||||
多线程异步 IO 模式,cache 缓存查询结果。
|
||||
|
||||
@@ -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-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 架构,安装不正确的软件包将会导致服务无法启动,请确保正确安装对应的版本。
|
||||
|
||||
- MacOS,Windows可获取Rust语言实现的Smartdns: [SmartDNS-rs](https://github.com/mokeyish/smartdns-rs)。
|
||||
|
||||
## 安装和使用
|
||||
|
||||
### 标准 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| nftset | 域名 nftset | 无 | nftset /domain/[#4\|#6\|-]:[family#nftable#nftset\|-][,#[4\|6]:[family#nftable#nftset\|-]]],-表示忽略;ipv4 地址的 family 只支持 inet 和 ip;ipv6 地址的 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-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 |
|
||||
| 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 |
|
||||
| bogus-nxdomain | 假冒 IP 地址过滤 | 无 | [ip/subnet],可重复 | bogus-nxdomain 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. 额外说明
|
||||
为保证DNS查询结果的位置亲和性,可以使用smartdns的`server`代理参数,将对应域名的查询请求,通过代理查询,使结果位置更好。如:
|
||||
|
||||
- 为保证DNS查询结果的位置亲和性,可以使用smartdns的`server`代理参数,将对应域名的查询请求,通过代理查询,使结果位置更好。如:
|
||||
|
||||
```shell
|
||||
# 增加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
|
||||
```
|
||||
|
||||
- 如需要配合测速自动完成ipset的设置,可增加如下配置参数
|
||||
|
||||
```shell
|
||||
ipset-no-speed proxy
|
||||
```
|
||||
|
||||
如果使用openwrt的luci界面,可以直接在界面配置相关的域名分流规则。
|
||||
|
||||
1. 更多问题
|
||||
|
||||
17
ReadMe_en.md
17
ReadMe_en.md
@@ -115,11 +115,14 @@ From the comparison, smartdns found the fastest IP address to visit www.baidu.co
|
||||
1. **Support IPV4, IPV6 dual stack**
|
||||
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**
|
||||
Multi-threaded asynchronous IO mode, cache cache query results.
|
||||
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
|
||||
- **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
|
||||
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.
|
||||
|
||||
@@ -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
|
||||
|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
|
||||
|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
|
||||
|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
|
||||
|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-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
|
||||
|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br />[-c\|-speed-check-mode]: set speed check mode,same as parameter speed-check-mode<br />[-a\|-address]: same as parameter `address` <br />[-n\|-nameserver]: same as parameter `nameserver`<br />[-p\|-ipset]: same as parameter `nftset`<br />[-t\|-nftset]: same as parameter `nftset`<br />[-d\|-dualstack-ip-selection]: same as parameter `dualstack-ip-selection`<br /> [-no-serve-expired]:disable serve expired<br />[-delete]:delete rule|domain-rules /www.example.com/ -speed-check-mode none
|
||||
|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br />[-c\|-speed-check-mode]: set speed check mode,same as parameter speed-check-mode<br />[-a\|-address]: same as parameter `address` <br />[-n\|-nameserver]: same as parameter `nameserver`<br />[-p\|-ipset]: same as parameter `nftset`<br />[-t\|-nftset]: same as parameter `nftset`<br />[-d\|-dualstack-ip-selection]: same as parameter `dualstack-ip-selection`<br /> [-no-serve-expired]:disable serve expired<br />[-rr-ttl\|-rr-ttl-min\|-rr-ttl-max]: same as parameter: rr-ttl, rr-ttl-min, rr-ttl-max<br />[-delete]:delete rule|domain-rules /www.example.com/ -speed-check-mode none
|
||||
| domain-set | collection of domains|None| domain-set [options...]<br />[-n\|-name]:name of set <br />[-t\|-type] [list]: set type, only support list, one domain per line <br />[-f\|-file]:file path of domain set<br /> used with address, nameserver, ipset, nftset, example: /domain-set:[name]/ | domain-set -name set -type list -file /path/to/list <br /> address /domain-set:set/1.2.4.8 |
|
||||
|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
|
||||
|
||||
@@ -105,7 +105,7 @@ force-qtype-SOA 65
|
||||
# dualstack-ip-selection-threshold [num] (0~1000)
|
||||
# dualstack-ip-allow-force-AAAA [yes|no]
|
||||
# dualstack-ip-selection [yes|no]
|
||||
# dualstack-ip-selection yes
|
||||
# dualstack-ip-selection no
|
||||
|
||||
# edns client 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/#, 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
|
||||
# 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/-, ignore this domain
|
||||
|
||||
# add to ipset when ping is unreachable
|
||||
# ipset-no-speed ipsetname
|
||||
# ipset-no-speed pass
|
||||
|
||||
# enable nftset timeout by ttl feature
|
||||
# nftset-timeout [yes|no]
|
||||
# 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.
|
||||
# nftset-debug [yes|no]
|
||||
# nftset-debug yes
|
||||
|
||||
@@ -231,6 +231,12 @@ msgstr "IPSet名称"
|
||||
msgid "IPset name."
|
||||
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."
|
||||
msgstr "如果本软件对你有帮助,请给作者加个蛋。"
|
||||
|
||||
@@ -240,7 +246,7 @@ msgstr "包含配置文件"
|
||||
msgid ""
|
||||
"Include other config files from /etc/smartdns/conf.d or custom path, can be "
|
||||
"downloaded from the download page."
|
||||
msgstr "包含配置文件,路径为/etc/smartdns/conf.d,或自定义配置文件路径,可以从下载页"
|
||||
msgstr "包含配置文件,路径为/etc/smartdns/conf.d,或自定义配置文件路径,可以从下载页配置自动下载。"
|
||||
|
||||
msgid "List of files to download."
|
||||
msgstr "下载的文件列表。"
|
||||
@@ -275,6 +281,15 @@ msgstr "NFTSet名称格式错误,格式:[#[4|6]:[family#table#set]]"
|
||||
msgid "NFTset name, format: [#[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"
|
||||
msgstr "未运行"
|
||||
|
||||
|
||||
@@ -56,6 +56,14 @@ o.default = 53
|
||||
o.datatype = "port"
|
||||
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;
|
||||
o = s:taboption("advanced", Value, "speed_check_mode", translate("Speed Check Mode"), translate("Smartdns speed check mode."));
|
||||
o.rmempty = true;
|
||||
@@ -187,14 +195,6 @@ o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "1"
|
||||
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
|
||||
o = s:taboption("advanced", Flag, "force_aaaa_soa", translate("Force AAAA SOA"), translate("Force AAAA SOA."))
|
||||
o.rmempty = false
|
||||
@@ -211,6 +211,31 @@ o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "1"
|
||||
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
|
||||
o = s:taboption("advanced", Value, "rr_ttl", translate("Domain TTL"), translate("TTL for all domain result."))
|
||||
o.rempty = true
|
||||
|
||||
@@ -255,6 +255,12 @@ msgstr "IPset名称"
|
||||
msgid "IPset name."
|
||||
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."
|
||||
msgstr "如果本软件对你有帮助,请给作者加个蛋。"
|
||||
|
||||
@@ -265,7 +271,7 @@ msgid ""
|
||||
"Include other config files from /etc/smartdns/conf.d or custom path, can be "
|
||||
"downloaded from the download page."
|
||||
msgstr ""
|
||||
"包含配置文件,路径为/etc/smartdns/conf.d,或自定义配置文件路径,可以从下载页"
|
||||
"包含配置文件,路径为/etc/smartdns/conf.d,或自定义配置文件路径,可以从下载页配置自动下载。"
|
||||
"面配置自动下载。"
|
||||
|
||||
msgid "List of files to download."
|
||||
@@ -301,6 +307,15 @@ msgstr "NFTSet名称格式错误,格式:[#[4|6]:[family#table#set]]"
|
||||
msgid "NFTset name, format: [#[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"
|
||||
msgstr "未运行"
|
||||
|
||||
|
||||
@@ -155,6 +155,11 @@ return view.extend({
|
||||
o.default = 53;
|
||||
o.datatype = "port";
|
||||
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;
|
||||
@@ -262,11 +267,6 @@ return view.extend({
|
||||
o.rmempty = false;
|
||||
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
|
||||
o = s.taboption("advanced", form.Flag, "force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
|
||||
o.rmempty = false;
|
||||
@@ -277,6 +277,48 @@ return view.extend({
|
||||
o.rmempty = false;
|
||||
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;
|
||||
o = s.taboption("advanced", form.Value, "rr_ttl", _("Domain TTL"), _("TTL for all domain result."));
|
||||
o.rempty = true;
|
||||
@@ -720,8 +762,22 @@ return view.extend({
|
||||
|
||||
o = s.taboption("forwarding", form.Value, "ipset_name", _("IPset Name"), _("IPset name."));
|
||||
o.rmempty = true;
|
||||
o.datatype = "hostname";
|
||||
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;
|
||||
}
|
||||
|
||||
o = s.taboption("forwarding", form.Value, "nftset_name", _("NFTset Name"), _("NFTset name, format: [#[4|6]:[family#table#set]]"));
|
||||
o.rmempty = true;
|
||||
@@ -734,7 +790,7 @@ return view.extend({
|
||||
|
||||
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\-_]+$/)) {
|
||||
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]]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +169,7 @@ load_server()
|
||||
local section="$1"
|
||||
local ADDITIONAL_ARGS=""
|
||||
local DNS_ADDRESS=""
|
||||
local IS_URI="0"
|
||||
|
||||
config_get_bool enabled "$section" "enabled" "1"
|
||||
config_get port "$section" "port" ""
|
||||
@@ -202,7 +203,9 @@ load_server()
|
||||
SERVER="server-https"
|
||||
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
|
||||
ip="[$ip]"
|
||||
fi
|
||||
@@ -220,14 +223,12 @@ load_server()
|
||||
[ -z "$set_mark" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -set-mark $set_mark"
|
||||
[ "$use_proxy" = "0" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -proxy default-proxy"
|
||||
|
||||
if [ -z "$port" ]; then
|
||||
if [ -z "$port" ] || [ "$IS_URI" = "1" ]; then
|
||||
DNS_ADDRESS="$ip"
|
||||
else
|
||||
DNS_ADDRESS="$ip:$port"
|
||||
fi
|
||||
|
||||
[ "$type" = "https" ] && DNS_ADDRESS="$ip"
|
||||
|
||||
conf_append "$SERVER" "$DNS_ADDRESS $ADDITIONAL_ARGS $addition_arg"
|
||||
}
|
||||
|
||||
@@ -506,6 +507,12 @@ load_service()
|
||||
|
||||
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" ""
|
||||
[ -z "$rr_ttl" ] || conf_append "rr-ttl" "$rr_ttl"
|
||||
|
||||
|
||||
11
src/Makefile
11
src/Makefile
@@ -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
|
||||
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
|
||||
override CFLAGS +=-Iinclude
|
||||
override CFLAGS += -DBASE_FILE_NAME='"$(notdir $<)"'
|
||||
@@ -34,9 +39,9 @@ override CXXFLAGS +=-Iinclude
|
||||
|
||||
# ldflags
|
||||
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
|
||||
override LDFLAGS += -lssl -lcrypto -lpthread -ldl
|
||||
override LDFLAGS += -lssl -lcrypto -lpthread -ldl
|
||||
endif
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
35
src/dns.c
35
src/dns.c
@@ -42,6 +42,8 @@
|
||||
(void)(expr); \
|
||||
} while (0)
|
||||
|
||||
#define member_size(type, member) sizeof(((type *)0)->member)
|
||||
|
||||
/* read short and move pointer */
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1639,12 +1641,12 @@ static int _dns_encode_SOA(struct dns_context *context, struct dns_rrs *rrs)
|
||||
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
|
||||
|
||||
int len = 0;
|
||||
if (_dns_left_len(context) < 4) {
|
||||
if (opt_len < 4) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1668,25 +1670,24 @@ static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *
|
||||
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
|
||||
int len = _dns_left_len(context);
|
||||
if (len < 8) {
|
||||
if (opt_len < (int)member_size(struct dns_opt_cookie, client_cookie)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = 8;
|
||||
int len = 8;
|
||||
memcpy(cookie->client_cookie, context->ptr, len);
|
||||
context->ptr += len;
|
||||
|
||||
len = _dns_left_len(context);
|
||||
if (len == 0) {
|
||||
opt_len -= len;
|
||||
if (opt_len <= 0) {
|
||||
cookie->server_cookie_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len < 8) {
|
||||
if (opt_len < (int)member_size(struct dns_opt_cookie, server_cookie)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1881,7 +1882,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
switch (opt_code) {
|
||||
case DNS_OPT_T_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) {
|
||||
tlog(TLOG_ERROR, "decode ecs failed.");
|
||||
return -1;
|
||||
@@ -1895,7 +1896,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
} break;
|
||||
case DNS_OPT_T_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) {
|
||||
tlog(TLOG_ERROR, "decode cookie failed.");
|
||||
return -1;
|
||||
@@ -2254,6 +2255,16 @@ static int _dns_encode_qd(struct dns_context *context, struct dns_rrs *rrs)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -329,7 +329,7 @@ static void _dns_cache_remove_by_domain(struct dns_cache_key *cache_key)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.hitnum = 3;
|
||||
safe_strncpy(info.domain, cache_key->domain, DNS_MAX_CNAME_LEN);
|
||||
info.qtype = cache_key->qtype;
|
||||
|
||||
@@ -42,12 +42,12 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/random.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
@@ -97,6 +97,7 @@ struct dns_server_info {
|
||||
/* server type */
|
||||
dns_server_type_t type;
|
||||
long long so_mark;
|
||||
int drop_packet_latency_ms;
|
||||
|
||||
/* client socket */
|
||||
int fd;
|
||||
@@ -118,6 +119,7 @@ struct dns_server_info {
|
||||
|
||||
time_t last_send;
|
||||
time_t last_recv;
|
||||
unsigned long send_tick;
|
||||
int prohibit;
|
||||
|
||||
/* server addr info */
|
||||
@@ -152,6 +154,8 @@ struct dns_server_pending {
|
||||
unsigned int has_v6;
|
||||
unsigned int query_v4;
|
||||
unsigned int query_v6;
|
||||
unsigned int has_soa;
|
||||
|
||||
/* server type */
|
||||
dns_server_type_t type;
|
||||
int retry_cnt;
|
||||
@@ -1054,6 +1058,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->prohibit = 0;
|
||||
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));
|
||||
pthread_mutex_init(&server_info->lock, NULL);
|
||||
memcpy(&server_info->flags, flags, sizeof(server_info->flags));
|
||||
@@ -2259,6 +2264,11 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e
|
||||
/* update recv time */
|
||||
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 */
|
||||
if (_dns_client_recv(server_info, inpacket, len, (struct sockaddr *)&from, from_len) != 0) {
|
||||
return -1;
|
||||
@@ -3324,6 +3334,7 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
continue;
|
||||
}
|
||||
time(&server_info->last_send);
|
||||
server_info->send_tick = get_tick_count();
|
||||
}
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
|
||||
@@ -3524,7 +3535,7 @@ int dns_client_query(const char *domain, int qtype, dns_client_callback callback
|
||||
query->qtype = qtype;
|
||||
query->send_tick = 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->server_group = _dns_client_get_dnsserver_group(group_name);
|
||||
@@ -3614,11 +3625,16 @@ static int _dns_client_pending_server_resolve(const char *domain, dns_rtcode_t r
|
||||
struct dns_server_pending *pending = user_ptr;
|
||||
int ret = 0;
|
||||
|
||||
if (rtcode == DNS_RC_NXDOMAIN) {
|
||||
pending->has_soa = 1;
|
||||
}
|
||||
|
||||
if (addr_type == DNS_T_A) {
|
||||
pending->ping_time_v4 = -1;
|
||||
if (rtcode == DNS_RC_NOERROR) {
|
||||
pending->has_v4 = 1;
|
||||
pending->ping_time_v4 = ping_time;
|
||||
pending->has_soa = 0;
|
||||
safe_strncpy(pending->ipv4, ip, DNS_HOSTNAME_LEN);
|
||||
}
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
@@ -3626,6 +3642,7 @@ static int _dns_client_pending_server_resolve(const char *domain, dns_rtcode_t r
|
||||
if (rtcode == DNS_RC_NOERROR) {
|
||||
pending->has_v6 = 1;
|
||||
pending->ping_time_v6 = ping_time;
|
||||
pending->has_soa = 0;
|
||||
safe_strncpy(pending->ipv6, ip, DNS_HOSTNAME_LEN);
|
||||
}
|
||||
} else {
|
||||
@@ -3759,6 +3776,12 @@ static void _dns_client_add_pending_servers(void)
|
||||
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 (add_success == 0) {
|
||||
tlog(TLOG_WARN, "add pending DNS server %s failed.", pending->host);
|
||||
@@ -3862,10 +3885,12 @@ static void *_dns_client_work(void *arg)
|
||||
sleep_time = 0;
|
||||
}
|
||||
}
|
||||
last = now;
|
||||
|
||||
if (now >= expect_time) {
|
||||
_dns_client_period_run();
|
||||
if (last != now) {
|
||||
_dns_client_period_run();
|
||||
}
|
||||
|
||||
sleep_time = sleep - (now - expect_time);
|
||||
if (sleep_time < 0) {
|
||||
sleep_time = 0;
|
||||
@@ -3873,6 +3898,7 @@ static void *_dns_client_work(void *arg)
|
||||
}
|
||||
expect_time += sleep;
|
||||
}
|
||||
last = now;
|
||||
|
||||
pthread_mutex_lock(&client.domain_map_lock);
|
||||
if (list_empty(&client.dns_request_list) && atomic_read(&client.run_period) == 0) {
|
||||
|
||||
@@ -113,6 +113,7 @@ struct client_dns_server_flags {
|
||||
unsigned int server_flag;
|
||||
unsigned int result_flag;
|
||||
long long set_mark;
|
||||
int drop_packet_latency_ms;
|
||||
char proxyname[DNS_MAX_CNAME_LEN];
|
||||
union {
|
||||
struct client_dns_server_flag_udp udp;
|
||||
|
||||
364
src/dns_conf.c
364
src/dns_conf.c
@@ -61,6 +61,9 @@ static time_t dns_conf_dnsmasq_lease_file_time;
|
||||
struct dns_hosts_table dns_hosts_table;
|
||||
int dns_hosts_record_num;
|
||||
|
||||
/* DNS64 */
|
||||
struct dns_dns64 dns_conf_dns_dns64;
|
||||
|
||||
/* server ip/port */
|
||||
struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP];
|
||||
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_no_cname;
|
||||
int dns_conf_ipset_timeout_enable;
|
||||
struct dns_ipset_names dns_conf_ipset_no_speed;
|
||||
int dns_conf_nftset_timeout_enable;
|
||||
struct dns_nftset_names dns_conf_nftset_no_speed;
|
||||
int dns_conf_nftset_debug_enable;
|
||||
|
||||
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:
|
||||
size = sizeof(struct dns_domain_check_orders);
|
||||
break;
|
||||
case DOMAIN_RULE_CNAME:
|
||||
size = sizeof(struct dns_cname_rule);
|
||||
break;
|
||||
case DOMAIN_RULE_TTL:
|
||||
size = sizeof(struct dns_ttl_rule);
|
||||
break;
|
||||
default:
|
||||
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 server_flag = 0;
|
||||
unsigned char *spki = NULL;
|
||||
int drop_packet_latency_ms = 0;
|
||||
|
||||
int ttl = 0;
|
||||
/* clang-format off */
|
||||
@@ -461,6 +473,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
/* experimental feature */
|
||||
{"check-edns", no_argument, NULL, 'e'}, /* check edns */
|
||||
#endif
|
||||
{"drop-packet-latency", required_argument, NULL, 'D'},
|
||||
{"spki-pin", required_argument, NULL, 'p'}, /* check SPKI pin */
|
||||
{"host-name", required_argument, NULL, 'h'}, /* host name */
|
||||
{"http-host", required_argument, NULL, 'H'}, /* http host */
|
||||
@@ -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->proxyname[0] = '\0';
|
||||
server->set_mark = -1;
|
||||
server->drop_packet_latency_ms = drop_packet_latency_ms;
|
||||
|
||||
if (parse_uri(ip, scheme, server->server, &port, server->path) != 0) {
|
||||
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);
|
||||
break;
|
||||
}
|
||||
case 'D': {
|
||||
drop_packet_latency_ms = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
case 'E': {
|
||||
server_flag |= SERVER_FLAG_EXCLUDE_DEFAULT;
|
||||
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->server_flag = server_flag;
|
||||
server->ttl = ttl;
|
||||
server->drop_packet_latency_ms = drop_packet_latency_ms;
|
||||
dns_conf_server_num++;
|
||||
tlog(TLOG_DEBUG, "add server %s, flag: %X, ttl: %d", ip, result_flag, ttl);
|
||||
|
||||
@@ -1076,6 +1095,78 @@ errout:
|
||||
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)
|
||||
{
|
||||
struct dns_nftset_name *nftset = NULL;
|
||||
@@ -1187,7 +1278,7 @@ static int _conf_domain_rule_nftset(char *domain, const char *nftsetname)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* new ipset domain */
|
||||
/* new nftset domain */
|
||||
nftset = _dns_conf_get_nftable(family, tablename, setname);
|
||||
if (nftset == NULL) {
|
||||
goto errout;
|
||||
@@ -1244,6 +1335,105 @@ errout:
|
||||
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)
|
||||
{
|
||||
struct dns_rule_address_IPV4 *address_ipv4 = NULL;
|
||||
@@ -1374,6 +1564,64 @@ errout:
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int index = dns_conf_bind_ip_num;
|
||||
@@ -2129,6 +2414,39 @@ errout:
|
||||
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)
|
||||
{
|
||||
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;
|
||||
char domain[DNS_MAX_CONF_CNAME_LEN];
|
||||
char *value = argv[1];
|
||||
int rr_ttl = 0;
|
||||
int rr_ttl_min = 0;
|
||||
int rr_ttl_max = 0;
|
||||
|
||||
/* clang-format off */
|
||||
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'},
|
||||
{"nameserver", required_argument, NULL, 'n'},
|
||||
{"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},
|
||||
{"delete", no_argument, NULL, 255},
|
||||
{NULL, no_argument, NULL, 0}
|
||||
@@ -2171,7 +2496,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
/* process extra options */
|
||||
optind = 1;
|
||||
while (1) {
|
||||
opt = getopt_long_only(argc, argv, "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) {
|
||||
break;
|
||||
}
|
||||
@@ -2229,6 +2554,16 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
|
||||
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': {
|
||||
const char *yesno = optarg;
|
||||
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;
|
||||
}
|
||||
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: {
|
||||
if (_conf_domain_rule_no_serve_expired(domain) != 0) {
|
||||
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;
|
||||
errout:
|
||||
return -1;
|
||||
@@ -2693,12 +3047,15 @@ static struct config_item _config_item[] = {
|
||||
CONF_CUSTOM("server-https", _config_server_https, NULL),
|
||||
CONF_CUSTOM("nameserver", _config_nameserver, NULL),
|
||||
CONF_CUSTOM("address", _config_address, NULL),
|
||||
CONF_CUSTOM("cname", _config_cname, NULL),
|
||||
CONF_CUSTOM("proxy-server", _config_proxy_server, NULL),
|
||||
CONF_YESNO("ipset-timeout", &dns_conf_ipset_timeout_enable),
|
||||
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-debug", &dns_conf_nftset_debug_enable),
|
||||
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_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),
|
||||
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-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_CUSTOM("dns64", _config_dns64, NULL),
|
||||
CONF_CUSTOM("log-level", _config_log_level, NULL),
|
||||
CONF_STRING("log-file", (char *)dns_conf_log_file, DNS_MAX_PATH),
|
||||
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];
|
||||
if (conf_file[0] != '/') {
|
||||
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 (snprintf(file_path, DNS_MAX_PATH, "%s", conf_file) < 0) {
|
||||
return -1;
|
||||
|
||||
@@ -74,6 +74,8 @@ enum domain_rule {
|
||||
DOMAIN_RULE_NFTSET_IP6,
|
||||
DOMAIN_RULE_NAMESERVER,
|
||||
DOMAIN_RULE_CHECKSPEED,
|
||||
DOMAIN_RULE_CNAME,
|
||||
DOMAIN_RULE_TTL,
|
||||
DOMAIN_RULE_MAX,
|
||||
};
|
||||
|
||||
@@ -104,6 +106,7 @@ typedef enum {
|
||||
#define DOMAIN_FLAG_NFTSET_IP_IGN (1 << 13)
|
||||
#define DOMAIN_FLAG_NFTSET_IP6_IGN (1 << 14)
|
||||
#define DOMAIN_FLAG_NO_SERVE_EXPIRED (1 << 15)
|
||||
#define DOMAIN_FLAG_CNAME_IGN (1 << 16)
|
||||
|
||||
#define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0)
|
||||
|
||||
@@ -116,6 +119,7 @@ typedef enum {
|
||||
#define BIND_FLAG_NO_CACHE (1 << 6)
|
||||
#define BIND_FLAG_NO_DUALSTACK_SELECTION (1 << 7)
|
||||
#define BIND_FLAG_FORCE_AAAA_SOA (1 << 8)
|
||||
#define BIND_FLAG_NO_RULE_CNAME (1 << 9)
|
||||
|
||||
struct dns_rule {
|
||||
atomic_t refcnt;
|
||||
@@ -148,6 +152,26 @@ struct dns_ipset_rule {
|
||||
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 hlist_node node;
|
||||
char nftfamilyname[DNS_MAX_NFTSET_FAMILYLEN];
|
||||
@@ -162,6 +186,16 @@ struct dns_nftset_rule {
|
||||
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_rule head;
|
||||
struct dns_rule *rules[DOMAIN_RULE_MAX];
|
||||
@@ -248,6 +282,7 @@ struct dns_servers {
|
||||
int ttl;
|
||||
dns_server_type_t type;
|
||||
long long set_mark;
|
||||
unsigned int drop_packet_latency_ms;
|
||||
char skip_check_cert;
|
||||
char spki[DNS_MAX_SPKI_LEN];
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
@@ -359,6 +394,13 @@ struct dns_set_rule_flags_callback_args {
|
||||
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 int dns_conf_bind_ip_num;
|
||||
|
||||
|
||||
515
src/dns_server.c
515
src/dns_server.c
@@ -77,6 +77,13 @@ typedef enum {
|
||||
DNS_CONN_TYPE_TLS_CLIENT,
|
||||
} 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 {
|
||||
void *args;
|
||||
unsigned char *key[DOMAIN_RULE_MAX];
|
||||
@@ -121,6 +128,7 @@ struct dns_server_post_context {
|
||||
int do_force_soa;
|
||||
int skip_notify_count;
|
||||
int select_all_best_ip;
|
||||
int no_release_parent;
|
||||
};
|
||||
|
||||
struct dns_server_conn_udp {
|
||||
@@ -165,6 +173,9 @@ struct dns_request_pending_list {
|
||||
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 {
|
||||
atomic_t refcnt;
|
||||
|
||||
@@ -216,7 +227,6 @@ struct dns_request {
|
||||
int ping_time;
|
||||
int ip_ttl;
|
||||
unsigned char ip_addr[DNS_RR_AAAA_LEN];
|
||||
int ip_addr_len;
|
||||
|
||||
struct dns_soa soa;
|
||||
int has_soa;
|
||||
@@ -242,6 +252,10 @@ struct dns_request {
|
||||
|
||||
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;
|
||||
DECLARE_HASHTABLE(ip_map, 4);
|
||||
|
||||
@@ -281,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 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_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)
|
||||
{
|
||||
@@ -304,17 +321,37 @@ static int _dns_server_has_bind_flag(struct dns_request *request, uint32_t flag)
|
||||
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) {
|
||||
return dns_conf_rr_ttl;
|
||||
int rr_ttl = 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) {
|
||||
ttl = dns_conf_rr_ttl_max;
|
||||
} else if (dns_conf_rr_ttl_min > 0 && ttl < dns_conf_rr_ttl_min) {
|
||||
ttl = dns_conf_rr_ttl_min;
|
||||
if (rr_ttl > 0) {
|
||||
return rr_ttl;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -387,6 +424,11 @@ static int _dns_server_is_return_soa(struct dns_request *request)
|
||||
unsigned int flags = 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;
|
||||
}
|
||||
|
||||
@@ -1044,13 +1086,13 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
|
||||
if (cache_ttl > 0) {
|
||||
ttl = cache_ttl;
|
||||
} else {
|
||||
ttl = _dns_server_get_conf_ttl(request->ip_ttl);
|
||||
ttl = _dns_server_get_conf_ttl(request, request->ip_ttl);
|
||||
}
|
||||
speed = request->ping_time;
|
||||
|
||||
if (has_soa) {
|
||||
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 {
|
||||
ttl = dns_conf_rr_ttl;
|
||||
if (ttl == 0) {
|
||||
@@ -1206,7 +1248,7 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
||||
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;
|
||||
|
||||
tlog(TLOG_DEBUG, "Cache CNAME: %s, qtype: %d, speed: %d", request->cname, request->qtype, speed);
|
||||
@@ -1291,7 +1333,7 @@ static int _dns_result_callback_nxdomain(struct dns_request *request)
|
||||
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)
|
||||
@@ -1423,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_ip6 = 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) {
|
||||
return 0;
|
||||
@@ -1436,6 +1479,10 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (request->ping_time < 0 && request->has_ip > 0 && request->passthrough == 0) {
|
||||
check_no_speed_rule = 1;
|
||||
}
|
||||
|
||||
/* check ipset rule */
|
||||
rule_flags = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS);
|
||||
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
|
||||
@@ -1444,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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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)) {
|
||||
@@ -1531,6 +1590,53 @@ static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context
|
||||
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)
|
||||
{
|
||||
struct dns_request *request = context->request;
|
||||
@@ -1561,6 +1667,9 @@ static int _dns_request_post(struct dns_server_post_context *context)
|
||||
/* setup ipset */
|
||||
_dns_server_setup_ipset_nftset_packet(context);
|
||||
|
||||
/* reply child request */
|
||||
_dns_result_child_post(context);
|
||||
|
||||
if (context->do_reply == 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -1646,13 +1755,13 @@ static int _dns_server_reply_all_pending_list(struct dns_request *request, struc
|
||||
struct dns_server_post_context context_pending;
|
||||
_dns_server_post_context_init_from(&context_pending, req, context->packet, context->inpacket,
|
||||
context->inpacket_len);
|
||||
_dns_server_get_answer(&context_pending);
|
||||
req->dualstack_selection = request->dualstack_selection;
|
||||
req->dualstack_selection_query = request->dualstack_selection_query;
|
||||
req->dualstack_selection_force_soa = request->dualstack_selection_force_soa;
|
||||
req->dualstack_selection_has_ip = request->dualstack_selection_has_ip;
|
||||
req->dualstack_selection_ping_time = request->dualstack_selection_ping_time;
|
||||
req->ping_time = request->ping_time;
|
||||
_dns_server_get_answer(&context_pending);
|
||||
|
||||
context_pending.do_cache = 0;
|
||||
context_pending.do_audit = context->do_audit;
|
||||
@@ -1660,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_ipset = 0;
|
||||
context_pending.reply_ttl = request->ip_ttl;
|
||||
context_pending.no_release_parent = context->no_release_parent;
|
||||
_dns_server_reply_passthrough(&context_pending);
|
||||
|
||||
req->request_pending_list = NULL;
|
||||
@@ -1789,6 +1899,7 @@ out:
|
||||
context.reply_ttl = reply_ttl;
|
||||
context.skip_notify_count = 1;
|
||||
context.select_all_best_ip = with_all_ips;
|
||||
context.no_release_parent = 1;
|
||||
|
||||
_dns_request_post(&context);
|
||||
return _dns_server_reply_all_pending_list(request, &context);
|
||||
@@ -1800,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,
|
||||
dns_type_t addr_type)
|
||||
dns_type_t addr_type, int ping_time)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_ip_address *addr_map = NULL;
|
||||
int addr_len = 0;
|
||||
|
||||
if (ping_time == 0) {
|
||||
ping_time = -1;
|
||||
}
|
||||
|
||||
if (addr_type == DNS_T_A) {
|
||||
addr_len = DNS_RR_A_LEN;
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
@@ -1846,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->hitnum = 1;
|
||||
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);
|
||||
if (dns_conf_force_no_cname == 0) {
|
||||
safe_strncpy(addr_map->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
@@ -2028,6 +2143,11 @@ static void _dns_server_request_release_complete(struct dns_request *request, in
|
||||
_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);
|
||||
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
|
||||
{
|
||||
@@ -2486,14 +2606,14 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
|
||||
if (request->has_ip == 0) {
|
||||
request->has_ip = 1;
|
||||
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) {
|
||||
request->has_cname = 1;
|
||||
safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
}
|
||||
} else {
|
||||
if (ttl < request->ip_ttl) {
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(ttl);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2508,7 +2628,7 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_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);
|
||||
return -1;
|
||||
}
|
||||
@@ -2563,14 +2683,14 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
|
||||
if (request->has_ip == 0) {
|
||||
request->has_ip = 1;
|
||||
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) {
|
||||
request->has_cname = 1;
|
||||
safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
}
|
||||
} else {
|
||||
if (ttl < request->ip_ttl) {
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(ttl);
|
||||
request->ip_ttl = _dns_server_get_conf_ttl(request, ttl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2585,7 +2705,7 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
|
||||
}
|
||||
|
||||
/* 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);
|
||||
return -1;
|
||||
}
|
||||
@@ -2665,7 +2785,7 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
} break;
|
||||
case DNS_T_SOA: {
|
||||
@@ -2679,6 +2799,12 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
|
||||
"%d, minimum: %d",
|
||||
domain, request->qtype, request->soa.mname, request->soa.rname, request->soa.serial,
|
||||
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);
|
||||
if ((soa_num >= (dns_server_num() / 3) + 1 || soa_num > 4) && atomic_read(&request->ip_map_num) <= 0) {
|
||||
request->ip_ttl = ttl;
|
||||
@@ -2861,7 +2987,8 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2872,7 +2999,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
|
||||
memcpy(request->ip_addr, addr, DNS_RR_A_LEN);
|
||||
/* 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->rcode = packet->head.rcode;
|
||||
} break;
|
||||
@@ -2891,7 +3018,8 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2901,7 +3029,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
}
|
||||
|
||||
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->rcode = packet->head.rcode;
|
||||
} break;
|
||||
@@ -2926,7 +3054,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
}
|
||||
|
||||
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;
|
||||
} break;
|
||||
case DNS_T_SOA: {
|
||||
@@ -2961,16 +3089,19 @@ static int _dns_server_reply_passthrough(struct dns_server_post_context *context
|
||||
|
||||
_dns_server_get_answer(context);
|
||||
|
||||
_dns_result_callback(context);
|
||||
|
||||
_dns_cache_reply_packet(context);
|
||||
|
||||
if (_dns_server_setup_ipset_nftset_packet(context) != 0) {
|
||||
tlog(TLOG_DEBUG, "setup ipset failed.");
|
||||
}
|
||||
|
||||
_dns_result_callback(context);
|
||||
|
||||
_dns_server_audit_log(context);
|
||||
|
||||
/* reply child request */
|
||||
_dns_result_child_post(context);
|
||||
|
||||
if (request->conn && context->do_reply == 1) {
|
||||
/* When passthrough, modify the id to be the id of the client request. */
|
||||
struct dns_update_param param;
|
||||
@@ -2990,6 +3121,7 @@ static void _dns_server_query_end(struct dns_request *request)
|
||||
{
|
||||
int ip_num = 0;
|
||||
int request_wait = 0;
|
||||
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
ip_num = atomic_read(&request->ip_map_num);
|
||||
/* if adblock ip address exist */
|
||||
@@ -3001,6 +3133,7 @@ static void _dns_server_query_end(struct dns_request *request)
|
||||
/* Not need to wait check result if only has one ip address */
|
||||
if (ip_num == 1 && request_wait == 1) {
|
||||
if (request->dualstack_selection_query == 1) {
|
||||
_dns_server_request_complete(request);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -3095,7 +3228,7 @@ static int dns_server_resolve_callback(const char *domain, dns_result_type rtype
|
||||
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) {
|
||||
ttl = dns_conf_rr_ttl_reply_max;
|
||||
}
|
||||
@@ -3707,6 +3840,310 @@ errout:
|
||||
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)
|
||||
{
|
||||
struct dns_qtype_soa_list *soa_list = NULL;
|
||||
@@ -4385,6 +4822,10 @@ static int _dns_server_do_query(struct dns_request *request, int skip_notify_eve
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (_dns_server_process_cname(request) != 0) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
// setup options
|
||||
_dns_server_setup_query_option(request, &options);
|
||||
|
||||
@@ -4409,6 +4850,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. */
|
||||
_dns_server_query_dualstack(request);
|
||||
|
||||
if (_dns_server_process_dns64(request) != 0) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
clean_exit:
|
||||
return 0;
|
||||
errout:
|
||||
@@ -4774,7 +5219,7 @@ static int _dns_server_tcp_recv(struct dns_server_conn_tcp_client *tcpclient)
|
||||
if (errno == EAGAIN) {
|
||||
return RECV_ERROR_AGAIN;
|
||||
}
|
||||
|
||||
|
||||
if (errno == ECONNRESET) {
|
||||
return RECV_ERROR_CLOSE;
|
||||
}
|
||||
@@ -5137,7 +5582,7 @@ static void _dns_server_period_run(unsigned int msec)
|
||||
struct dns_request *tmp = NULL;
|
||||
LIST_HEAD(check_list);
|
||||
|
||||
if (msec % 10 == 0) {
|
||||
if ((msec % 10) == 0) {
|
||||
_dns_server_period_run_second();
|
||||
}
|
||||
|
||||
@@ -5227,11 +5672,12 @@ int dns_server_run(void)
|
||||
expect_time -= cnt * sleep;
|
||||
sleep_time -= cnt * sleep;
|
||||
}
|
||||
last = now;
|
||||
|
||||
if (now >= expect_time) {
|
||||
msec++;
|
||||
_dns_server_period_run(msec);
|
||||
if (last != now) {
|
||||
_dns_server_period_run(msec);
|
||||
}
|
||||
sleep_time = sleep - (now - expect_time);
|
||||
if (sleep_time < 0) {
|
||||
sleep_time = 0;
|
||||
@@ -5250,6 +5696,7 @@ int dns_server_run(void)
|
||||
pthread_mutex_unlock(&server.request_list_lock);
|
||||
expect_time += sleep;
|
||||
}
|
||||
last = now;
|
||||
|
||||
num = epoll_wait(server.epoll_fd, events, DNS_MAX_EVENTS, sleep_time);
|
||||
if (num < 0) {
|
||||
|
||||
@@ -1780,10 +1780,11 @@ static void *_fast_ping_work(void *arg)
|
||||
sleep_time = 0;
|
||||
}
|
||||
}
|
||||
last = now;
|
||||
|
||||
if (now >= expect_time) {
|
||||
_fast_ping_period_run();
|
||||
if (last != now) {
|
||||
_fast_ping_period_run();
|
||||
}
|
||||
sleep_time = sleep - (now - expect_time);
|
||||
if (sleep_time < 0) {
|
||||
sleep_time = 0;
|
||||
@@ -1791,6 +1792,7 @@ static void *_fast_ping_work(void *arg)
|
||||
}
|
||||
expect_time += sleep;
|
||||
}
|
||||
last = now;
|
||||
|
||||
pthread_mutex_lock(&ping.map_lock);
|
||||
if (hash_empty(ping.addrmap)) {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define MAX_LINE_LEN 1024
|
||||
#define MAX_LINE_LEN 8192
|
||||
#define MAX_KEY_LEN 64
|
||||
#define CONF_INT_MAX (~(1 << 31))
|
||||
#define CONF_INT_MIN (1 << 31)
|
||||
|
||||
@@ -32,6 +32,16 @@ const char *conf_get_conf_file(void)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
file_path_dir[PATH_MAX - 1] = 0;
|
||||
dirname(file_path_dir);
|
||||
get_dir_name(file_path_dir);
|
||||
if (file_path_dir[0] == '\0') {
|
||||
strncpy(fullpath, path, path_len);
|
||||
return fullpath;
|
||||
@@ -299,7 +309,7 @@ static int load_conf_printf(const char *file, int lineno, int ret)
|
||||
static int load_conf_file(const char *file, struct config_item *items, conf_error_handler handler)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char line[MAX_LINE_LEN];
|
||||
char line[MAX_LINE_LEN + MAX_KEY_LEN];
|
||||
char key[MAX_KEY_LEN];
|
||||
char value[MAX_LINE_LEN];
|
||||
int filed_num = 0;
|
||||
@@ -309,6 +319,8 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
||||
int ret = 0;
|
||||
int call_ret = 0;
|
||||
int line_no = 0;
|
||||
int line_len = 0;
|
||||
int read_len = 0;
|
||||
|
||||
if (handler == NULL) {
|
||||
handler = load_conf_printf;
|
||||
@@ -320,9 +332,17 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
||||
}
|
||||
|
||||
line_no = 0;
|
||||
while (fgets(line, MAX_LINE_LEN, fp)) {
|
||||
while (fgets(line + line_len, MAX_LINE_LEN - line_len, fp)) {
|
||||
line_no++;
|
||||
filed_num = sscanf(line, "%63s %1023[^\r\n]s", key, value);
|
||||
read_len = strnlen(line + line_len, sizeof(line));
|
||||
if (read_len >= 2 && *(line + line_len + read_len - 2) == '\\') {
|
||||
line_len += read_len - 2;
|
||||
line[line_len] = '\0';
|
||||
continue;
|
||||
}
|
||||
line_len = 0;
|
||||
|
||||
filed_num = sscanf(line, "%63s %8192[^\r\n]s", key, value);
|
||||
if (filed_num <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#define MAX_LINE_LEN 1024
|
||||
#define MAX_KEY_LEN 64
|
||||
#define SMARTDNS_PID_FILE "/var/run/smartdns.pid"
|
||||
#define TMP_BUFF_LEN_32 32
|
||||
@@ -270,6 +269,7 @@ static int _smartdns_add_servers(void)
|
||||
flags.server_flag = dns_conf_servers[i].server_flag;
|
||||
flags.result_flag = dns_conf_servers[i].result_flag;
|
||||
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));
|
||||
ret = dns_client_add_server(dns_conf_servers[i].server, dns_conf_servers[i].port, dns_conf_servers[i].type,
|
||||
&flags);
|
||||
@@ -543,7 +543,7 @@ static int _smartdns_create_logdir(void)
|
||||
int gid = 0;
|
||||
char logdir[PATH_MAX] = {0};
|
||||
safe_strncpy(logdir, _smartdns_log_path(), PATH_MAX);
|
||||
dirname(logdir);
|
||||
dir_name(logdir);
|
||||
|
||||
if (access(logdir, F_OK) == 0) {
|
||||
return 0;
|
||||
|
||||
11
src/util.c
11
src/util.c
@@ -29,6 +29,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <libgen.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/netlink.h>
|
||||
@@ -109,6 +110,16 @@ unsigned long get_tick_count(void)
|
||||
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)
|
||||
{
|
||||
struct sockaddr_storage *addr_store = (struct sockaddr_storage *)addr;
|
||||
|
||||
@@ -55,6 +55,8 @@ void bug_ext(const char *file, int line, const char *func, const char *errfmt, .
|
||||
|
||||
unsigned long get_tick_count(void);
|
||||
|
||||
char *dir_name(char *path);
|
||||
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user