Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2593b62aa | ||
|
|
f671c34e7c | ||
|
|
dad31179d2 | ||
|
|
410047822d | ||
|
|
f38d16a069 | ||
|
|
c8734d603b | ||
|
|
bd31cc0a36 | ||
|
|
5a356e577d | ||
|
|
7d02843fea | ||
|
|
b9429e04d2 | ||
|
|
bea238e7ae | ||
|
|
ad4c2144da | ||
|
|
04985216a8 | ||
|
|
324aa2d77d | ||
|
|
bc379a3c3e | ||
|
|
f6b9a1b81a | ||
|
|
f619ca8f68 | ||
|
|
42a4fdebfd | ||
|
|
85d011eae8 | ||
|
|
934701941b | ||
|
|
9974c50dbb | ||
|
|
93af473e08 | ||
|
|
76d5322676 | ||
|
|
facf672081 | ||
|
|
5558e38cb4 | ||
|
|
ffd3cb2db5 | ||
|
|
91ee65231e | ||
|
|
7b8ff57773 | ||
|
|
391ef310b4 | ||
|
|
51e1ba6897 | ||
|
|
efc18996a8 | ||
|
|
9bc857f628 | ||
|
|
8523f26c62 | ||
|
|
6c800ea12f | ||
|
|
eeaadcf313 | ||
|
|
ccb47ef327 | ||
|
|
a13433abac | ||
|
|
799d19f233 | ||
|
|
0fa17063c0 |
0
.clang-format
Executable file → Normal file
0
.clang-format
Executable file → Normal file
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
||||
*.o
|
||||
.DS_Store
|
||||
*.swp.
|
||||
systemd/smartdns.service
|
||||
|
||||
36
ReadMe.md
36
ReadMe.md
@@ -17,6 +17,8 @@ SmartDNS 同时支持指定特定域名 IP 地址,并高性匹配,可达到
|
||||
- [特性](#特性)
|
||||
- [架构](#架构)
|
||||
- [下载](#下载)
|
||||
- [使用官方安装源](#使用官方安装源)
|
||||
- [手工下载安装](#手工下载安装)
|
||||
- [安装和使用](#安装和使用)
|
||||
- [标准 Linux 系统 / 树莓派](#标准-linux-系统--树莓派)
|
||||
- [OpenWrt](#openwrt)
|
||||
@@ -121,6 +123,9 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
9. **高性能、占用资源少**
|
||||
多线程异步 IO 模式,cache 缓存查询结果。
|
||||
|
||||
10. **主流系统官方支持**
|
||||
主流路由系统官方软件源安装smartdns。
|
||||
|
||||
## 架构
|
||||
|
||||

|
||||
@@ -132,6 +137,19 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
|
||||
## 下载
|
||||
|
||||
### 使用官方安装源
|
||||
|
||||
smartdns已经合入主流系统的软件仓库,可以直接使用系统安装命令直接安装。
|
||||
|
||||
系统|安装方式|说明|
|
||||
--|--|--
|
||||
openwrt|opkg update</br>opkg install luci-app-smartdns</br>opkg install smartdns|22.03之后的系统。软件源路径:https://downloads.openwrt.org/releases/
|
||||
ddwrt|官方最新固件service页面->SmartDNS Resolver->启用。|选择界面参考:https://forum.dd-wrt.com/demo/Services.html
|
||||
debian|apt-get install smartdns|
|
||||
entware|ipkg update</br>ipkg install smartdns|软件源路径:https://bin.entware.net/
|
||||
|
||||
### 手工下载安装
|
||||
|
||||
--------------
|
||||
|
||||
下载对应系统或固件版本的 SmartDNS 安装包,对应关系如下。
|
||||
@@ -497,8 +515,8 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
| 键名 | 功能说明 | 默认值 | 可用值/要求 | 举例 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| server-name | DNS 服务器名称 | 操作系统主机名 / smartdns | 符合主机名规格的字符串 | server-name smartdns |
|
||||
| bind | DNS 监听端口号 | [::]:53 | 可绑定多个端口。<br>IP:PORT: 服务器 IP:端口号<br>[-group]: 请求时使用的 DNS 服务器组<br>[-no-rule-addr]:跳过 address 规则<br>[-no-rule-nameserver]:跳过 Nameserver 规则<br>[-no-rule-ipset]:跳过 ipset 规则<br>[-no-rule-soa]:跳过 SOA(#) 规则<br>[-no-dualstack-selection]:停用双栈测速<br>[-no-speed-check]:停用测速<br>[-no-cache]:停止缓存 | bind :53 |
|
||||
| bind-tcp | DNS TCP 监听端口号 | [::]:53 | 可绑定多个端口。<br>IP:PORT: 服务器 IP:端口号<br>[-group]: 请求时使用的 DNS 服务器组<br>[-no-rule-addr]:跳过 address 规则<br>[-no-rule-nameserver]:跳过 nameserver 规则<br>[-no-rule-ipset]:跳过 ipset 规则。<br>[-no-rule-soa]:跳过 SOA(#) 规则<br>[-no-dualstack-selection]:停用双栈测速<br>[-no-speed-check]:停用测速<br>[-no-cache]:停止缓存 | bind-tcp :53 |
|
||||
| bind | DNS 监听端口号 | [::]:53 | 可绑定多个端口。<br>IP:PORT: 服务器 IP:端口号<br>[-group]: 请求时使用的 DNS 服务器组<br>[-no-rule-addr]:跳过 address 规则<br>[-no-rule-nameserver]:跳过 Nameserver 规则<br>[-no-rule-ipset]:跳过 ipset 和 nftset 规则<br>[-no-rule-soa]:跳过 SOA(#) 规则<br>[-no-dualstack-selection]:停用双栈测速<br>[-no-speed-check]:停用测速<br>[-no-cache]:停止缓存 | bind :53 |
|
||||
| bind-tcp | DNS TCP 监听端口号 | [::]:53 | 可绑定多个端口。<br>IP:PORT: 服务器 IP:端口号<br>[-group]: 请求时使用的 DNS 服务器组<br>[-no-rule-addr]:跳过 address 规则<br>[-no-rule-nameserver]:跳过 nameserver 规则<br>[-no-rule-ipset]:跳过 ipset 和 nftset 规则。<br>[-no-rule-soa]:跳过 SOA(#) 规则<br>[-no-dualstack-selection]:停用双栈测速<br>[-no-speed-check]:停用测速<br>[-no-cache]:停止缓存 | bind-tcp :53 |
|
||||
| cache-size | 域名结果缓存个数 | 512 | 大于等于 0 的数字 | cache-size 512 |
|
||||
| cache-persist | 是否持久化缓存 | 自动。<br>当 cache-file 所在的位置有超过 128 MB 的可用空间时启用,否则禁用。 | [yes\|no] | cache-persist yes |
|
||||
| cache-file | 缓存持久化文件路径 | /tmp/smartdns.cache | 合法路径字符串 | cache-file /tmp/smartdns.cache |
|
||||
@@ -520,16 +538,19 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
| conf-file | 附加配置文件 | 无 | 合法路径字符串 | conf-file /etc/smartdns/smartdns.more.conf |
|
||||
| server | 上游 UDP DNS | 无 | 可重复。<br>[ip][:port]:服务器 IP:端口(可选)<br>[-blacklist-ip]:配置 IP 过滤结果。<br>[-whitelist-ip]:指定仅接受参数中配置的 IP 范围<br>[-group [group] ...]:DNS 服务器所属组,比如 office 和 foreign,和 nameserver 配套使用<br>[-exclude-default-group]:将 DNS 服务器从默认组中排除 | server 8.8.8.8:53 -blacklist-ip -group g1 |
|
||||
| server-tcp | 上游 TCP DNS | 无 | 可重复。<br>[ip][:port]:服务器 IP:端口(可选)<br>[-blacklist-ip]:配置 IP 过滤结果<br>[-whitelist-ip]:指定仅接受参数中配置的 IP 范围。<br>[-group [group] ...]:DNS 服务器所属组,比如 office 和 foreign,和 nameserver 配套使用<br>[-exclude-default-group]:将 DNS 服务器从默认组中排除 | server-tcp 8.8.8.8:53 |
|
||||
| server-tls | 上游 TLS DNS | 无 | 可重复。<br>[ip][:port]:服务器 IP:端口(可选)<br>[-spki-pin [sha256-pin]]:TLS 合法性校验 SPKI 值,base64 编码的 sha256 SPKI pin 值<br>[-host-name]:TLS SNI 名称<br>[-tls-host-verify]:TLS 证书主机名校验<br> [-no-check-certificate]:跳过证书校验<br>[-blacklist-ip]:配置 IP 过滤结果<br>[-whitelist-ip]:仅接受参数中配置的 IP 范围<br>[-group [group] ...]:DNS 服务器所属组,比如 office 和 foreign,和 nameserver 配套使用<br>[-exclude-default-group]:将 DNS 服务器从默认组中排除 | server-tls 8.8.8.8:853 |
|
||||
| server-tls | 上游 TLS DNS | 无 | 可重复。<br>[ip][:port]:服务器 IP:端口(可选)<br>[-spki-pin [sha256-pin]]:TLS 合法性校验 SPKI 值,base64 编码的 sha256 SPKI pin 值<br>[-host-name]:TLS SNI 名称, 名称设置为-,表示停用SNI名称<br>[-tls-host-verify]:TLS 证书主机名校验<br> [-no-check-certificate]:跳过证书校验<br>[-blacklist-ip]:配置 IP 过滤结果<br>[-whitelist-ip]:仅接受参数中配置的 IP 范围<br>[-group [group] ...]:DNS 服务器所属组,比如 office 和 foreign,和 nameserver 配套使用<br>[-exclude-default-group]:将 DNS 服务器从默认组中排除 | server-tls 8.8.8.8:853 |
|
||||
| server-https | 上游 HTTPS DNS | 无 | 可重复。<br>https://[host][:port]/path:服务器 IP:端口(可选)<br>[-spki-pin [sha256-pin]]:TLS 合法性校验 SPKI 值,base64 编码的 sha256 SPKI pin 值<br>[-host-name]:TLS SNI 名称<br>[-http-host]:http 协议头主机名<br>[-tls-host-verify]:TLS 证书主机名校验<br> [-no-check-certificate]:跳过证书校验<br>[-blacklist-ip]:配置 IP 过滤结果<br>[-whitelist-ip]:仅接受参数中配置的 IP 范围。<br>[-group [group] ...]:DNS 服务器所属组,比如 office 和 foreign,和 nameserver 配套使用<br>[-exclude-default-group]:将 DNS 服务器从默认组中排除 | server-https https://cloudflare-dns.com/dns-query |
|
||||
| speed-check-mode | 测速模式选择 | 无 | [ping\|tcp:[80]\|none] | speed-check-mode ping,tcp:80,tcp:443 |
|
||||
| response-mode | 首次查询响应模式 | first-ping |模式:[fisrt-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 |
|
||||
| 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-timeout | 设置 ipset 超时功能启用 | 自动 | [yes] | ipset-timeout 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>[-d\|-dualstack-ip-selection]:参考 dualstack-ip-selection | 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等需要指定域名的地方使用,使用方式为 /domain-set:[name]/| domain-set -name set -type list -file /path/to/list <br> address /domain-set:set/1.2.4.8 |
|
||||
| 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#mytab#dns4,#6:- |
|
||||
| nftset-timeout | 设置 nftset 超时功能启用 | no | [yes\|no] | nftset-timeout yes |
|
||||
| nftset-debug | 设置 nftset 调试功能启用 | no | [yes\|no] | nftset-debug yes |
|
||||
| domain-rules | 设置域名规则 | 无 | domain-rules /domain/ [-rules...]<br>[-c\|-speed-check-mode]:测速模式,参考 speed-check-mode 配置<br>[-a\|-address]:参考 address 配置<br>[-n\|-nameserver]:参考 nameserver 配置<br>[-p\|-ipset]:参考ipset配置<br>[-t\|-nftset]:参考nftset配置<br>[-d\|-dualstack-ip-selection]:参考 dualstack-ip-selection | 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 |
|
||||
| whitelist-ip | 白名单 IP 地址 | 无 | [ip/subnet],可重复 | whitelist-ip 1.2.3.4/16 |
|
||||
@@ -723,6 +744,9 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
...
|
||||
```
|
||||
|
||||
14. 更多问题
|
||||
如有更多问题,请查阅或提交issue: [https://github.com/pymumu/smartdns/issues](https://github.com/pymumu/smartdns/issues)
|
||||
|
||||
## 编译
|
||||
|
||||
SmartDNS 提供了编译软件包的脚本(`package/build-pkg.sh`),支持编译 LuCI、Debian、OpenWrt 和 Optware 安装包。
|
||||
|
||||
63
ReadMe_en.md
Executable file → Normal file
63
ReadMe_en.md
Executable file → Normal file
@@ -9,19 +9,27 @@ Support Raspberry Pi, openwrt, ASUS router, Windows and other devices.
|
||||
|
||||
## Table Of Content
|
||||
|
||||
1. [Software Show](#software-show)
|
||||
1. [Features](#features)
|
||||
1. [Architecture](#architecture)
|
||||
1. [Usage](#usage)
|
||||
1. [Download the package](#download-the-package)
|
||||
1. [Standard Linux system installation/Raspberry Pi, X86_64 system](#standard-linux-system-installation/raspberry-pi,-x86_64-system)
|
||||
1. [openwrt/LEDE](#openwrt/lede)
|
||||
1. [ASUS router native firmware / Merlin firmware](#asus-router-native-firmware-/-merlin-firmware)
|
||||
1. [optware/entware](#optware/entware)
|
||||
1. [Windows 10 WSL Installation/WSL ubuntu](#windows-10-wsl-installation/wsl-ubuntu)
|
||||
1. [Configuration parameter](#configuration-parameter)
|
||||
1. [Donate](#Donate)
|
||||
1. [FAQ](#FAQ)
|
||||
- [SmartDNS](#smartdns)
|
||||
- [Table Of Content](#table-of-content)
|
||||
- [Software Show](#software-show)
|
||||
- [Features](#features)
|
||||
- [Architecture](#architecture)
|
||||
- [Usage](#usage)
|
||||
- [Use official installation source](#use-official-installation-source)
|
||||
- [Download the package](#download-the-package)
|
||||
- [Standard Linux system installation/Raspberry Pi, X86_64 system](#standard-linux-system-installationraspberry-pi-x86_64-system)
|
||||
- [openwrt](#openwrt)
|
||||
- [ASUS router native firmware / Merlin firmware](#asus-router-native-firmware--merlin-firmware)
|
||||
- [optware/entware](#optwareentware)
|
||||
- [Windows 10 WSL Installation/WSL ubuntu](#windows-10-wsl-installationwsl-ubuntu)
|
||||
- [Configuration parameter](#configuration-parameter)
|
||||
- [FAQ](#faq)
|
||||
- [Compile](#compile)
|
||||
- [Donate](#donate)
|
||||
- [PayPal](#paypal)
|
||||
- [Alipay](#alipay)
|
||||
- [Wechat](#wechat)
|
||||
- [Open Source License](#open-source-license)
|
||||
|
||||
## Software Show
|
||||
|
||||
@@ -121,6 +129,17 @@ From the comparison, smartdns found the fastest IP address to visit www.baidu.co
|
||||
|
||||
## Usage
|
||||
|
||||
### Use official installation source
|
||||
|
||||
smartdns can already be installed using system package management tools.
|
||||
|
||||
System|Installation|Instructions|
|
||||
--|--|--
|
||||
openwrt|opkg update</br>opkg install luci-app-smartdns</br>opkg install smartdns|systems after 22.03. Software source: https://downloads.openwrt.org/releases/
|
||||
ddwrt|latest firmware. goto services page abd enable SmartDNS Resolver. |Demo: https://forum.dd-wrt.com/demo/Services.html
|
||||
debian|apt-get install smartdns|
|
||||
entware|ipkg update</br>ipkg install smartdns|Software source: https://bin.entware.net/
|
||||
|
||||
### Download the package
|
||||
|
||||
--------------
|
||||
@@ -455,8 +474,8 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|parameter|Parameter function|Default value|Value type|Example|
|
||||
|--|--|--|--|--|
|
||||
|server-name|DNS name|host name/smartdns|any string like hosname|server-name smartdns
|
||||
|bind|DNS listening port number|[::]:53|Support binding multiple ports<br>`IP:PORT`: server IP, port number. <br>`[-group]`: The DNS server group used when requesting. <br>`[-no-rule-addr]`: Skip the address rule. <br>`[-no-rule-nameserver]`: Skip the Nameserver rule. <br>`[-no-rule-ipset]`: Skip the Ipset rule. <br>`[-no-rule-soa]`: Skip address SOA(#) rules.<br>`[-no-dualstack-selection]`: Disable dualstack ip selection.<br>`[-no-speed-check]`: Disable speed measurement. <br>`[-no-cache]`: stop caching |bind :53
|
||||
|bind-tcp|TCP mode DNS listening port number|[::]:53|Support binding multiple ports<br>`IP:PORT`: server IP, port number. <br>`[-group]`: The DNS server group used when requesting. <br>`[-no-rule-addr]`: Skip the address rule. <br>`[-no-rule-nameserver]`: Skip the Nameserver rule. <br>`[-no-rule-ipset]`: Skip the Ipset rule. <br>`[-no-rule-soa]`: Skip address SOA(#) rules.<br>`[-no-dualstack-selection]`: Disable dualstack ip selection.<br>`[-no-speed-check]`: Disable speed measurement. <br>`[-no-cache]`: stop caching |bind-tcp :53
|
||||
|bind|DNS listening port number|[::]:53|Support binding multiple ports<br>`IP:PORT`: server IP, port number. <br>`[-group]`: The DNS server group used when requesting. <br>`[-no-rule-addr]`: Skip the address rule. <br>`[-no-rule-nameserver]`: Skip the Nameserver rule. <br>`[-no-rule-ipset]`: Skip the Ipset or nftset rules. <br>`[-no-rule-soa]`: Skip address SOA(#) rules.<br>`[-no-dualstack-selection]`: Disable dualstack ip selection.<br>`[-no-speed-check]`: Disable speed measurement. <br>`[-no-cache]`: stop caching |bind :53
|
||||
|bind-tcp|TCP mode DNS listening port number|[::]:53|Support binding multiple ports<br>`IP:PORT`: server IP, port number. <br>`[-group]`: The DNS server group used when requesting. <br>`[-no-rule-addr]`: Skip the address rule. <br>`[-no-rule-nameserver]`: Skip the Nameserver rule. <br>`[-no-rule-ipset]`: Skip the Ipset or nftset rules. <br>`[-no-rule-soa]`: Skip address SOA(#) rules.<br>`[-no-dualstack-selection]`: Disable dualstack ip selection.<br>`[-no-speed-check]`: Disable speed measurement. <br>`[-no-cache]`: stop caching |bind-tcp :53
|
||||
|cache-size|Domain name result cache number|512|integer|cache-size 512
|
||||
|cache-persist|enable persist cache|Auto: Enabled if the location of `cache-file` has more than 128MB of free space.|[yes\|no]|cache-persist yes
|
||||
|cache-file|cache persist file|/tmp/smartdns.cache|路径|cache-file /tmp/smartdns.cache
|
||||
@@ -478,16 +497,19 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|conf-file|additional conf file|None|File path|conf-file /etc/smartdns/smartdns.more.conf
|
||||
|server|Upstream UDP DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server 8.8.8.8:53 -blacklist-ip
|
||||
|server-tcp|Upstream TCP DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-tcp 8.8.8.8:53
|
||||
|server-tls|Upstream TLS DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name. <br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-tls 8.8.8.8:853
|
||||
|server-tls|Upstream TLS DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name. `-` to disable SNI name.<br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-tls 8.8.8.8:853
|
||||
|server-https|Upstream HTTPS DNS server|None|Repeatable <br>`https://[host][:port]/path`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name<br>`[-http-host]`:http header host. <br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-https https://cloudflare-dns.com/dns-query
|
||||
|speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:80,tcp:443
|
||||
|response-mode|First query response mode|first-ping|Mode: [fisrt-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
|
||||
|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|auto|[yes]|ipset-timeout 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 `ipset`<br>`[-d\|-dualstack-ip-selection]`: same as parameter `dualstack-ip-selection`|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, example: /domain-set:[name]/ | domain-set -name set -type list -file /path/to/list <br> address /domain-set:set/1.2.4.8 |
|
||||
|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#mytab#dns4,#6:-
|
||||
|nftset-timeout|nftset timeout enable|no|[yes\|no]|nftset-timeout yes
|
||||
|nftset-debug|nftset debug enable|no|[yes\|no]|nftset-debug yes
|
||||
|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br>`[-c\|-speed-check-mode]`: set speed check 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`|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
|
||||
|whitelist-ip|ip whitelist|None|[ip/subnet], Repeatable,When the filtering server responds IPs in the IP whitelist, only result in whitelist will be accepted| whitelist-ip 1.2.3.4/16
|
||||
@@ -664,6 +686,9 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
...
|
||||
````
|
||||
|
||||
1. More questions
|
||||
More questions, please read issue: [https://github.com/pymumu/smartdns/issues](https://github.com/pymumu/smartdns/issues)
|
||||
|
||||
## Compile
|
||||
|
||||
smartdns contains scripts for compiling packages, supports compiling luci, debian, openwrt, opare installation packages, and can execute `package/build-pkg.sh` compilation.
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# server-name smartdns
|
||||
#
|
||||
|
||||
# whether resolv local hostname to ip address
|
||||
# resolv-hostname yes
|
||||
|
||||
# dns server run user
|
||||
# user [username]
|
||||
# example: run as nobody
|
||||
@@ -23,7 +26,7 @@
|
||||
# -group: set domain request to use the appropriate server group.
|
||||
# -no-rule-addr: skip address rule.
|
||||
# -no-rule-nameserver: skip nameserver rule.
|
||||
# -no-rule-ipset: skip ipset rule.
|
||||
# -no-rule-ipset: skip ipset rule or nftset rule.
|
||||
# -no-speed-check: do not check speed.
|
||||
# -no-cache: skip cache.
|
||||
# -no-rule-soa: Skip address SOA(#) rules.
|
||||
@@ -93,6 +96,7 @@ cache-size 16384
|
||||
# force specific qtype return soa
|
||||
# force-qtype-SOA [qtypeid |...]
|
||||
# force-qtype-SOA 65 28
|
||||
force-qtype-SOA 65
|
||||
|
||||
# Enable IPV4, IPV6 dual stack IP optimization selection strategy
|
||||
# dualstack-ip-selection-threshold [num] (0~1000)
|
||||
@@ -130,6 +134,7 @@ cache-size 16384
|
||||
# log-size: size of each log file, support k,m,g
|
||||
# log-num: number of logs
|
||||
log-level info
|
||||
|
||||
# log-file /var/log/smartdns/smartdns.log
|
||||
# log-size 128k
|
||||
# log-num 2
|
||||
@@ -210,6 +215,18 @@ log-level info
|
||||
# ipset /www.example.com/block, set ipset with ipset name of block
|
||||
# ipset /www.example.com/-, ignore this domain
|
||||
|
||||
# enable nftset timeout by ttl feature
|
||||
# nftset-timeout [yes]
|
||||
|
||||
# enable nftset debug, check nftset setting result, output log when error.
|
||||
# nftset-debug [no]
|
||||
|
||||
# specific nftset to domain
|
||||
# nftset /domain/[#4:ip#table#set,#6:ipv6#table#setv6]
|
||||
# nftset /www.example.com/ip#table#set, equivalent to 'nft add element ip table set { ... }'
|
||||
# nftset /www.example.com/-, ignore this domain
|
||||
# nftset /www.example.com/#6:-, ignore ipv6
|
||||
|
||||
# set domain rules
|
||||
# domain-rules /domain/ [-speed-check-mode [...]]
|
||||
# rules:
|
||||
@@ -218,6 +235,7 @@ log-level info
|
||||
# [-a] -address [address|-]: same as address option
|
||||
# [-n] -nameserver [group|-]: same as nameserver option
|
||||
# [-p] -ipset [ipset|-]: same as ipset option
|
||||
# [-t] -nftset [nftset|-]: same as nftset option
|
||||
# [-d] -dualstack-ip-selection [yes|no]: same as dualstack-ip-selection option
|
||||
|
||||
# collection of domains
|
||||
|
||||
@@ -81,7 +81,7 @@ build()
|
||||
|
||||
main()
|
||||
{
|
||||
OPTS=`getopt -o o:h --long arch:,filearch:,ver:,platform:,cross-tool:,static,only-package,outputdir: \
|
||||
OPTS=`getopt -o o:h --long arch:,filearch:,ver:,platform:,cross-tool:,with-nftables,static,only-package,outputdir: \
|
||||
-n "" -- "$@"`
|
||||
|
||||
if [ "$#" -le "1" ]; then
|
||||
|
||||
@@ -65,9 +65,31 @@ clean_service()
|
||||
|
||||
get_systemd_path()
|
||||
{
|
||||
service="`systemctl --no-legend| grep '\.service' | head -n 1 | awk '{print $1}'`"
|
||||
SERVICE_PATH="`systemctl show $service | grep FragmentPath | awk -F'=' '{print $2}'`"
|
||||
dirname $SERVICE_PATH
|
||||
service="`systemctl --no-legend| grep '\.service' | head -n 1 | awk '{print $1}' 2>/dev/null`"
|
||||
SERVICE_PATH="`systemctl show $service | grep FragmentPath | awk -F'=' '{print $2}' 2>/dev/null`"
|
||||
if [ ! -z "$SERVICE_PATH" ]; then
|
||||
SERVICE_PATH="`dirname $SERVICE_PATH 2>/dev/null`"
|
||||
if [ -d "$SERVICE_PATH" ]; then
|
||||
echo "$SERVICE_PATH"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
SERVICE_PATH="`pkg-config systemd --variable=systemdsystemunitdir 2>/dev/null`"
|
||||
if [ ! -z "$SERVICE_PATH" ]; then
|
||||
if [ -d "$SERVICE_PATH" ]; then
|
||||
echo "$SERVICE_PATH"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
SERVICE_PATH="/lib/systemd/system"
|
||||
if [ ! -d "$SERVICE_PATH" ]; then
|
||||
echo "$SERVICE_PATH"
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
install_files()
|
||||
@@ -106,6 +128,7 @@ install_files()
|
||||
if [ $ISSYSTEMD -eq 0 ]; then
|
||||
SYSTEM_UNIT_PATH="`get_systemd_path`"
|
||||
if [ -z "$SYSTEM_UNIT_PATH" ]; then
|
||||
echo "cannot find systemd path"
|
||||
return 1
|
||||
fi
|
||||
install -v -m 0644 -t $PREFIX$SYSTEM_UNIT_PATH systemd/smartdns.service
|
||||
|
||||
@@ -38,7 +38,7 @@ end
|
||||
function act_status()
|
||||
local e={}
|
||||
local ipv6_server;
|
||||
local dnsmasq_server = luci.sys.exec("uci get dhcp.@dnsmasq[0].server")
|
||||
local dnsmasq_server = smartdns.get_config_option("dhcp", "dnsmasq", "server", {nil})[1]
|
||||
local auto_set_dnsmasq = smartdns.get_config_option("smartdns", "smartdns", "auto_set_dnsmasq", nil);
|
||||
|
||||
e.auto_set_dnsmasq = auto_set_dnsmasq
|
||||
@@ -47,7 +47,7 @@ function act_status()
|
||||
if e.local_port ~= nil and e.local_port ~= "53" and auto_set_dnsmasq ~= nil and auto_set_dnsmasq == "1" then
|
||||
local str;
|
||||
str = "127.0.0.1#" .. e.local_port
|
||||
if string.sub(dnsmasq_server,1,string.len(str)) ~= str then
|
||||
if dnsmasq_server ~= str then
|
||||
e.dnsmasq_redirect_failure = 1
|
||||
end
|
||||
end
|
||||
|
||||
@@ -126,7 +126,7 @@ o = s:taboption("settings", Flag, "force_https_soa", translate("Force HTTPS SOA"
|
||||
o.rmempty = false
|
||||
o.default = o.enabled
|
||||
o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "0"
|
||||
return Flag.cfgvalue(...) or "1"
|
||||
end
|
||||
|
||||
---- rr-ttl
|
||||
|
||||
@@ -184,6 +184,12 @@ msgstr "解析本地主机名"
|
||||
msgid "Resolve local hostnames by reading Dnsmasq lease file."
|
||||
msgstr "读取Dnsmasq的租约文件解析本地主机名。"
|
||||
|
||||
msgid "Restart"
|
||||
msgstr "重启"
|
||||
|
||||
msgid "Restart Service"
|
||||
msgstr "重启服务"
|
||||
|
||||
msgid "Second Server Settings"
|
||||
msgstr "第二DNS服务器"
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
"description": "Grant access to LuCI app smartdns",
|
||||
"read": {
|
||||
"file": {
|
||||
"/etc/smartdns/*": [ "read" ],
|
||||
"/usr/sbin/smartdns": [ "exec" ]
|
||||
"/etc/smartdns/*": [ "read" ]
|
||||
},
|
||||
"ubus": {
|
||||
"service": [ "list" ]
|
||||
@@ -13,7 +12,8 @@
|
||||
},
|
||||
"write": {
|
||||
"file": {
|
||||
"/etc/smartdns/*": [ "write" ]
|
||||
"/etc/smartdns/*": [ "write" ],
|
||||
"/etc/init.d/smartdns restart": [ "exec" ]
|
||||
},
|
||||
"uci": [ "smartdns" ]
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
'require view';
|
||||
'require poll';
|
||||
'require rpc';
|
||||
'require ui';
|
||||
|
||||
var conf = 'smartdns';
|
||||
var callServiceList = rpc.declare({
|
||||
@@ -32,6 +33,7 @@ var callServiceList = rpc.declare({
|
||||
params: ['name'],
|
||||
expect: { '': {} }
|
||||
});
|
||||
var pollAdded = false;
|
||||
|
||||
function getServiceStatus() {
|
||||
return L.resolveDefault(callServiceList(conf), {})
|
||||
@@ -106,14 +108,16 @@ return view.extend({
|
||||
view.innerHTML = smartdnsRenderStatus(res);
|
||||
});
|
||||
}
|
||||
poll.add(renderStatus, 1);
|
||||
|
||||
return E('div', { class: 'cbi-map' },
|
||||
E('div', { class: 'cbi-section' }, [
|
||||
E('div', { id: 'service_status' },
|
||||
_('Collecting data ...'))
|
||||
])
|
||||
);
|
||||
if (pollAdded == false) {
|
||||
poll.add(renderStatus, 1);
|
||||
pollAdded = true;
|
||||
}
|
||||
|
||||
return E('div', { class: 'cbi-section' }, [
|
||||
E('div', { id: 'service_status' },
|
||||
_('Collecting data ...'))
|
||||
]);
|
||||
}
|
||||
|
||||
// Basic;
|
||||
@@ -192,7 +196,7 @@ return view.extend({
|
||||
// Force HTTPS SOA
|
||||
o = s.taboption("settings", form.Flag, "force_https_soa", _("Force HTTPS SOA"), _("Force HTTPS SOA."));
|
||||
o.rmempty = false;
|
||||
o.default = o.disabled;
|
||||
o.default = o.enabled;
|
||||
|
||||
// rr-ttl;
|
||||
o = s.taboption("settings", form.Value, "rr_ttl", _("Domain TTL"), _("TTL for all domain result."));
|
||||
@@ -296,7 +300,12 @@ return view.extend({
|
||||
return fs.trimmed('/etc/smartdns/custom.conf');
|
||||
};
|
||||
o.write = function (section_id, formvalue) {
|
||||
return fs.write('/etc/smartdns/custom.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
|
||||
return this.cfgvalue(section_id).then(function (value) {
|
||||
if (value == formvalue) {
|
||||
return
|
||||
}
|
||||
return fs.write('/etc/smartdns/custom.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
|
||||
});
|
||||
};
|
||||
|
||||
o = s.taboption("custom", form.Flag, "coredump", _("Generate Coredump"),
|
||||
@@ -435,7 +444,12 @@ return view.extend({
|
||||
return fs.trimmed('/etc/smartdns/address.conf');
|
||||
};
|
||||
o.write = function (section_id, formvalue) {
|
||||
return fs.write('/etc/smartdns/address.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
|
||||
return this.cfgvalue(section_id).then(function (value) {
|
||||
if (value == formvalue) {
|
||||
return
|
||||
}
|
||||
return fs.write('/etc/smartdns/address.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
|
||||
});
|
||||
};
|
||||
|
||||
// IP Blacklist;
|
||||
@@ -447,7 +461,12 @@ return view.extend({
|
||||
return fs.trimmed('/etc/smartdns/blacklist-ip.conf');
|
||||
};
|
||||
o.write = function (section_id, formvalue) {
|
||||
return fs.write('/etc/smartdns/blacklist-ip.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
|
||||
return this.cfgvalue(section_id).then(function (value) {
|
||||
if (value == formvalue) {
|
||||
return
|
||||
}
|
||||
return fs.write('/etc/smartdns/blacklist-ip.conf', formvalue.trim().replace(/\r\n/g, '\n') + '\n');
|
||||
});
|
||||
};
|
||||
|
||||
// Doman addresss;
|
||||
@@ -471,6 +490,17 @@ return view.extend({
|
||||
window.open("https://pymumu.github.io/smartdns/#donate", '_blank');
|
||||
};
|
||||
|
||||
o = s.option(form.DummyValue, "_restart", _("Restart Service"));
|
||||
o.renderWidget = function () {
|
||||
return E('button', {
|
||||
'class': 'btn cbi-button cbi-button-apply',
|
||||
'id': 'btn_restart',
|
||||
'click': ui.createHandlerFn(this, function () {
|
||||
return fs.exec('/etc/init.d/smartdns', ['restart'])
|
||||
.catch(function (e) { ui.addNotification(null, E('p', e.message), 'error') });
|
||||
})
|
||||
}, [_("Restart")]);
|
||||
}
|
||||
return m.render();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
START=99
|
||||
START=19
|
||||
NAME=smartdns
|
||||
USE_PROCD=1
|
||||
SERVICE_USE_PID=1
|
||||
@@ -31,6 +31,7 @@ CUSTOM_CONF="$SMARTDNS_CONF_DIR/custom.conf"
|
||||
SMARTDNS_CONF_TMP="${SMARTDNS_CONF}.tmp"
|
||||
COREDUMP="0"
|
||||
RESPAWN="1"
|
||||
DO_RELOAD="0"
|
||||
|
||||
set_forward_dnsmasq()
|
||||
{
|
||||
@@ -48,7 +49,7 @@ set_forward_dnsmasq()
|
||||
uci -q set dhcp.@dnsmasq[0].rebind_protection=0
|
||||
uci -q set dhcp.@dnsmasq[0].domainneeded=0
|
||||
uci commit dhcp
|
||||
/etc/init.d/dnsmasq restart
|
||||
/etc/init.d/dnsmasq reload
|
||||
}
|
||||
|
||||
stop_forward_dnsmasq()
|
||||
@@ -66,7 +67,7 @@ stop_forward_dnsmasq()
|
||||
uci -q set dhcp.@dnsmasq[0].rebind_protection=1
|
||||
uci -q set dhcp.@dnsmasq[0].domainneeded=1
|
||||
uci commit dhcp
|
||||
[ "$norestart" != "1" ] && /etc/init.d/dnsmasq restart
|
||||
[ "$norestart" != "1" ] && /etc/init.d/dnsmasq reload
|
||||
}
|
||||
|
||||
set_main_dns()
|
||||
@@ -79,7 +80,7 @@ set_main_dns()
|
||||
[ -z "$hostip" ] && return
|
||||
[ "$dnsmasq_port" = "53" ] && {
|
||||
uci -q set dhcp.@dnsmasq[0].port=0
|
||||
uci -q set dhcp.lan.dhcp_option="6,$hostip"
|
||||
uci -q add_list dhcp.lan.dhcp_option="6,$hostip"
|
||||
}
|
||||
|
||||
# for some third-party firmware
|
||||
@@ -90,12 +91,13 @@ set_main_dns()
|
||||
}
|
||||
|
||||
uci commit dhcp
|
||||
/etc/init.d/dnsmasq restart
|
||||
/etc/init.d/dnsmasq reload
|
||||
}
|
||||
|
||||
stop_main_dns()
|
||||
{
|
||||
local norestart="$1"
|
||||
hostip="$(uci -q get network.lan.ipaddr)"
|
||||
dnsmasq_port="$(uci -q get dhcp.@dnsmasq[0].port)"
|
||||
redir_dns="$(uci -q get dhcp.@dnsmasq[0].old_dns_redirect)"
|
||||
[ "$dnsmasq_port" != "0" ] && return
|
||||
@@ -104,9 +106,9 @@ stop_main_dns()
|
||||
uci -q delete dhcp.@dnsmasq[0].old_dns_redirect
|
||||
}
|
||||
uci -q delete dhcp.@dnsmasq[0].port
|
||||
uci -q delete dhcp.lan.dhcp_option
|
||||
uci -q del_list dhcp.lan.dhcp_option="6,$hostip"
|
||||
uci commit dhcp
|
||||
[ "$norestart" != "1" ] && /etc/init.d/dnsmasq restart
|
||||
[ "$norestart" != "1" ] && /etc/init.d/dnsmasq reload
|
||||
}
|
||||
|
||||
clear_iptable()
|
||||
@@ -314,7 +316,7 @@ load_service()
|
||||
config_get force_aaaa_soa "$section" "force_aaaa_soa" "0"
|
||||
[ "$force_aaaa_soa" = "1" ] && qtype_soa_list="$qtype_soa_list 28"
|
||||
|
||||
config_get force_https_soa "$section" "force_https_soa" "0"
|
||||
config_get force_https_soa "$section" "force_https_soa" "1"
|
||||
[ "$force_https_soa" = "1" ] && qtype_soa_list="$qtype_soa_list 65"
|
||||
|
||||
config_get auto_set_dnsmasq "$section" "auto_set_dnsmasq" "1"
|
||||
@@ -452,10 +454,16 @@ load_service()
|
||||
unload_service()
|
||||
{
|
||||
local section="$1"
|
||||
|
||||
[ "$DO_RELOAD" = "1" ] && return 0
|
||||
|
||||
config_get_bool enabled "$section" "enabled" '0'
|
||||
dnsmasq_port="$(uci -q get dhcp.@dnsmasq[0].port)"
|
||||
config_get port "$section" "port" "53"
|
||||
config_get old_port "$section" "old_port" "0"
|
||||
config_get auto_set_dnsmasq "$section" "auto_set_dnsmasq" "0"
|
||||
config_get old_enabled "$section" "old_enabled" "0"
|
||||
config_get old_port "$section" "old_port" "0"
|
||||
config_get old_auto_set_dnsmasq "$section" "old_auto_set_dnsmasq" "0"
|
||||
[ -z "${dnsmasq_port}" ] && dnsmasq_port="53"
|
||||
|
||||
[ "$enabled" = "1" ] && {
|
||||
@@ -479,6 +487,8 @@ start_service()
|
||||
|
||||
reload_service()
|
||||
{
|
||||
DO_RELOAD="1"
|
||||
stop
|
||||
start
|
||||
DO_RELOAD="0"
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
BIN=smartdns
|
||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o
|
||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o lib/nftset.o
|
||||
OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o $(OBJS_LIB)
|
||||
|
||||
# cflags
|
||||
@@ -41,7 +41,7 @@ endif
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
|
||||
$(BIN) : $(OBJS)
|
||||
$(CC) $(OBJS) -o $@ $(LDFLAGS)
|
||||
|
||||
|
||||
406
src/dns.c
406
src/dns.c
@@ -542,6 +542,106 @@ static int _dns_get_rr_head(struct dns_context *context, char *domain, int maxsi
|
||||
return len;
|
||||
}
|
||||
|
||||
struct dns_rr_nested *dns_add_rr_nested_start(struct dns_rr_nested *rr_nested_buffer, struct dns_packet *packet,
|
||||
dns_rr_type type, dns_type_t rtype, const char *domain, int ttl)
|
||||
{
|
||||
int len = 0;
|
||||
memset(rr_nested_buffer, 0, sizeof(*rr_nested_buffer));
|
||||
rr_nested_buffer->type = type;
|
||||
int ret = 0;
|
||||
|
||||
/* resource record */
|
||||
/* |domain |
|
||||
* |qtype | qclass |
|
||||
* | ttl |
|
||||
* | rrlen | rrdata |
|
||||
*/
|
||||
ret = _dns_add_rrs_start(packet, &rr_nested_buffer->context);
|
||||
if (ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
rr_nested_buffer->rr_start = rr_nested_buffer->context.ptr;
|
||||
|
||||
/* add rr head */
|
||||
len = _dns_add_rr_head(&rr_nested_buffer->context, domain, rtype, DNS_C_IN, ttl, 0);
|
||||
if (len < 0) {
|
||||
return NULL;
|
||||
}
|
||||
rr_nested_buffer->rr_len_ptr = rr_nested_buffer->context.ptr - 2;
|
||||
rr_nested_buffer->rr_head_len = len;
|
||||
|
||||
return rr_nested_buffer;
|
||||
}
|
||||
|
||||
int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, void *data, int data_len)
|
||||
{
|
||||
if (rr_nested == NULL || data == NULL || data_len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_dns_left_len(&rr_nested->context) < data_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(rr_nested->context.ptr, data, data_len);
|
||||
rr_nested->context.ptr += data_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_add_rr_nested_end(struct dns_rr_nested *rr_nested, dns_type_t rtype)
|
||||
{
|
||||
if (rr_nested == NULL || rr_nested->rr_start == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int len = rr_nested->context.ptr - rr_nested->rr_start;
|
||||
unsigned char *ptr = rr_nested->rr_len_ptr;
|
||||
if (ptr == NULL || _dns_left_len(&rr_nested->context) < 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_dns_write_short(&ptr, len - rr_nested->rr_head_len);
|
||||
|
||||
return _dns_rr_add_end(rr_nested->context.packet, rr_nested->type, rtype, len);
|
||||
}
|
||||
|
||||
void *dns_get_rr_nested_start(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, int *ttl, int *rr_len)
|
||||
{
|
||||
struct dns_context data_context;
|
||||
int qclass = 0;
|
||||
int ret = 0;
|
||||
|
||||
_dns_init_context_by_rrs(rrs, &data_context);
|
||||
ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, qtype, &qclass, ttl, rr_len);
|
||||
if (ret < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qclass != DNS_C_IN) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*rr_len < 2) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return data_context.ptr;
|
||||
}
|
||||
|
||||
void *dns_get_rr_nested_next(struct dns_rrs *rrs, void *rr_nested, int rr_nested_len)
|
||||
{
|
||||
void *end = rrs->data + rrs->len;
|
||||
void *p = rr_nested + rr_nested_len;
|
||||
if (p == end) {
|
||||
return NULL;
|
||||
} else if (p > end) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static int _dns_add_RAW(struct dns_packet *packet, dns_rr_type rrtype, dns_type_t rtype, const char *domain, int ttl,
|
||||
const void *raw, int raw_len)
|
||||
{
|
||||
@@ -966,6 +1066,155 @@ int dns_get_OPT_TCP_KEEYALIVE(struct dns_rrs *rrs, unsigned short *opt_code, uns
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_add_HTTPS_start(struct dns_rr_nested *svcparam_buffer, struct dns_packet *packet, dns_rr_type type,
|
||||
const char *domain, int ttl, int priority, const char *target)
|
||||
{
|
||||
svcparam_buffer = dns_add_rr_nested_start(svcparam_buffer, packet, type, DNS_T_HTTPS, domain, ttl);
|
||||
if (svcparam_buffer == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int target_len = strnlen(target, DNS_MAX_CNAME_LEN) + 1;
|
||||
if (_dns_left_len(&svcparam_buffer->context) < 2 + target_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add rr data */
|
||||
_dns_write_short(&svcparam_buffer->context.ptr, priority);
|
||||
safe_strncpy((char *)svcparam_buffer->context.ptr, target, target_len);
|
||||
svcparam_buffer->context.ptr += target_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_HTTPS_add_raw(struct dns_rr_nested *svcparam, unsigned short key, unsigned char *value, unsigned short len)
|
||||
{
|
||||
if (_dns_left_len(&svcparam->context) < 2 + len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_add_rr_nested_memcpy(svcparam, &key, 2);
|
||||
dns_add_rr_nested_memcpy(svcparam, &len, 2);
|
||||
dns_add_rr_nested_memcpy(svcparam, value, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_HTTPS_add_port(struct dns_rr_nested *svcparam, unsigned short port)
|
||||
{
|
||||
if (_dns_left_len(&svcparam->context) < 6) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned short value = DNS_HTTPS_T_PORT;
|
||||
dns_add_rr_nested_memcpy(svcparam, &value, 2);
|
||||
value = 2;
|
||||
dns_add_rr_nested_memcpy(svcparam, &value, 2);
|
||||
value = htons(port);
|
||||
dns_add_rr_nested_memcpy(svcparam, &value, 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_HTTPS_add_ech(struct dns_rr_nested *svcparam, void *ech, int ech_len)
|
||||
{
|
||||
if (_dns_left_len(&svcparam->context) < 2 + 2 + ech_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned short value = DNS_HTTPS_T_ECH;
|
||||
dns_add_rr_nested_memcpy(svcparam, &value, 2);
|
||||
|
||||
value = ech_len;
|
||||
dns_add_rr_nested_memcpy(svcparam, &value, 2);
|
||||
dns_add_rr_nested_memcpy(svcparam, ech, ech_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_A_LEN], int addr_num)
|
||||
{
|
||||
if (_dns_left_len(&svcparam->context) < 4 + addr_num * DNS_RR_A_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned short value = DNS_HTTPS_T_IPV4HINT;
|
||||
dns_add_rr_nested_memcpy(svcparam, &value, 2);
|
||||
|
||||
value = addr_num * DNS_RR_A_LEN;
|
||||
dns_add_rr_nested_memcpy(svcparam, &value, 2);
|
||||
|
||||
for (int i = 0; i < addr_num; i++) {
|
||||
dns_add_rr_nested_memcpy(svcparam, addr[i], DNS_RR_A_LEN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_AAAA_LEN], int addr_num)
|
||||
{
|
||||
if (_dns_left_len(&svcparam->context) < 4 + addr_num * DNS_RR_AAAA_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned short value = DNS_HTTPS_T_IPV6HINT;
|
||||
dns_add_rr_nested_memcpy(svcparam, &value, 2);
|
||||
|
||||
value = addr_num * DNS_RR_AAAA_LEN;
|
||||
dns_add_rr_nested_memcpy(svcparam, &value, 2);
|
||||
|
||||
for (int i = 0; i < addr_num; i++) {
|
||||
dns_add_rr_nested_memcpy(svcparam, addr[i], DNS_RR_AAAA_LEN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_add_HTTPS_end(struct dns_rr_nested *svcparam)
|
||||
{
|
||||
return dns_add_rr_nested_end(svcparam, DNS_T_HTTPS);
|
||||
}
|
||||
|
||||
struct dns_https_param *dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl,
|
||||
int *priority, char *target, int target_size)
|
||||
{
|
||||
int qtype = 0;
|
||||
unsigned char *data = NULL;
|
||||
int rr_len = 0;
|
||||
|
||||
data = dns_get_rr_nested_start(rrs, domain, maxsize, &qtype, ttl, &rr_len);
|
||||
if (data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qtype != DNS_T_HTTPS) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (rr_len < 2) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*priority = _dns_read_short(&data);
|
||||
rr_len -= 2;
|
||||
if (rr_len <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int len = strnlen((char *)data, rr_len);
|
||||
safe_strncpy(target, (char *)data, target_size);
|
||||
data += len + 1;
|
||||
rr_len -= len + 1;
|
||||
if (rr_len <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (struct dns_https_param *)data;
|
||||
}
|
||||
|
||||
struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *param)
|
||||
{
|
||||
return dns_get_rr_nested_next(rrs, param, sizeof(struct dns_https_param) + param->len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Format:
|
||||
* |DNS_NAME\0(string)|qtype(short)|qclass(short)|
|
||||
@@ -1624,7 +1873,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
opt_len = _dns_read_short(&context->ptr);
|
||||
|
||||
if (_dns_left_len(context) < opt_len) {
|
||||
tlog(TLOG_ERROR, "read opt data failed, opt_code = %d, opt_le = %d", opt_code, opt_len);
|
||||
tlog(TLOG_ERROR, "read opt data failed, opt_code = %d, opt_len = %d", opt_code, opt_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1652,6 +1901,9 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
return -1;
|
||||
}
|
||||
} break;
|
||||
case DNS_OPT_T_PADDING:
|
||||
context->ptr += opt_len;
|
||||
break;
|
||||
default:
|
||||
context->ptr += opt_len;
|
||||
tlog(TLOG_DEBUG, "DNS opt type = %d not supported", opt_code);
|
||||
@@ -1662,6 +1914,139 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_encode_HTTPS(struct dns_context *context, struct dns_rrs *rrs)
|
||||
{
|
||||
int ret = 0;
|
||||
int qtype = 0;
|
||||
int qclass = 0;
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
char target[DNS_MAX_CNAME_LEN] = {0};
|
||||
unsigned char *rr_len_ptr = NULL;
|
||||
unsigned char *start = NULL;
|
||||
unsigned char *rr_start = NULL;
|
||||
int ttl = 0;
|
||||
int priority = 0;
|
||||
struct dns_https_param *param = NULL;
|
||||
|
||||
param = dns_get_HTTPS_svcparm_start(rrs, domain, DNS_MAX_CNAME_LEN, &ttl, &priority, target, DNS_MAX_CNAME_LEN);
|
||||
if (param == NULL) {
|
||||
tlog(TLOG_ERROR, "get https param failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, 0, &rr_len_ptr);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rr_start = context->ptr;
|
||||
if (_dns_left_len(context) < 2) {
|
||||
tlog(TLOG_ERROR, "left len is invalid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_dns_write_short(&context->ptr, priority);
|
||||
ret = _dns_encode_domain(context, target);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
start = context->ptr;
|
||||
for (; param != NULL; param = dns_get_HTTPS_svcparm_next(rrs, param)) {
|
||||
if (context->ptr - start > rrs->len || _dns_left_len(context) <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_dns_write_short(&context->ptr, param->key);
|
||||
_dns_write_short(&context->ptr, param->len);
|
||||
switch (param->key) {
|
||||
case DNS_HTTPS_T_MANDATORY:
|
||||
case DNS_HTTPS_T_NO_DEFAULT_ALPN:
|
||||
case DNS_HTTPS_T_ALPN:
|
||||
case DNS_HTTPS_T_PORT:
|
||||
case DNS_HTTPS_T_IPV4HINT:
|
||||
case DNS_HTTPS_T_ECH:
|
||||
case DNS_HTTPS_T_IPV6HINT: {
|
||||
memcpy(context->ptr, param->value, param->len);
|
||||
context->ptr += param->len;
|
||||
} break;
|
||||
default:
|
||||
/* skip unknown key */
|
||||
context->ptr -= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_dns_write_short(&rr_len_ptr, context->ptr - rr_start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_decode_HTTPS(struct dns_context *context, const char *domain, dns_rr_type type, unsigned int ttl,
|
||||
int rr_len)
|
||||
{
|
||||
unsigned char *start = context->ptr;
|
||||
|
||||
struct dns_packet *packet = context->packet;
|
||||
int ret = 0;
|
||||
unsigned short priority;
|
||||
unsigned short key;
|
||||
unsigned short value_len;
|
||||
unsigned char *value = NULL;
|
||||
char target[DNS_MAX_CNAME_LEN] = {0};
|
||||
struct dns_rr_nested param;
|
||||
|
||||
if (rr_len < 2) {
|
||||
tlog(TLOG_DEBUG, "https len is invalid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
priority = _dns_read_short(&context->ptr);
|
||||
ret = _dns_decode_domain(context, target, sizeof(target));
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_add_HTTPS_start(¶m, packet, DNS_RRS_AN, domain, ttl, priority, target);
|
||||
|
||||
while (context->ptr - start < rr_len) {
|
||||
if (_dns_left_len(context) < 4) {
|
||||
tlog(TLOG_WARN, "data length is invalid, %d:%d", _dns_left_len(context),
|
||||
(int)(context->ptr - context->data));
|
||||
return -1;
|
||||
}
|
||||
key = _dns_read_short(&context->ptr);
|
||||
value_len = _dns_read_short(&context->ptr);
|
||||
value = context->ptr;
|
||||
|
||||
if (_dns_left_len(context) < value_len) {
|
||||
tlog(TLOG_ERROR, "read https data failed, svcParam key = %d, https_len = %d", key, value_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case DNS_HTTPS_T_MANDATORY:
|
||||
case DNS_HTTPS_T_ALPN:
|
||||
case DNS_HTTPS_T_NO_DEFAULT_ALPN:
|
||||
case DNS_HTTPS_T_PORT:
|
||||
case DNS_HTTPS_T_IPV4HINT:
|
||||
case DNS_HTTPS_T_ECH:
|
||||
case DNS_HTTPS_T_IPV6HINT: {
|
||||
dns_HTTPS_add_raw(¶m, key, value, value_len);
|
||||
} break;
|
||||
default:
|
||||
tlog(TLOG_DEBUG, "DNS HTTPS key = %d not supported", key);
|
||||
break;
|
||||
}
|
||||
|
||||
context->ptr += value_len;
|
||||
}
|
||||
|
||||
dns_add_HTTPS_end(¶m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_decode_qd(struct dns_context *context)
|
||||
{
|
||||
struct dns_packet *packet = context->packet;
|
||||
@@ -1805,6 +2190,19 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
|
||||
dns_set_OPT_payload_size(packet, qclass);
|
||||
} break;
|
||||
case DNS_T_HTTPS: {
|
||||
unsigned char *https_start = context->ptr;
|
||||
ret = _dns_decode_HTTPS(context, domain, type, ttl, rr_len);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_DEBUG, "decode HTTPS failed, %s", domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (context->ptr - https_start != rr_len) {
|
||||
tlog(TLOG_DEBUG, "opt length mismatch, %s\n", domain);
|
||||
return -1;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
unsigned char raw_data[1024];
|
||||
if (_dns_left_len(context) < rr_len || rr_len >= (int)sizeof(raw_data)) {
|
||||
@@ -1883,6 +2281,12 @@ static int _dns_encode_an(struct dns_context *context, struct dns_rrs *rrs)
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DNS_T_HTTPS:
|
||||
ret = _dns_encode_HTTPS(context, rrs);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = _dns_encode_raw(context, rrs);
|
||||
if (ret < 0) {
|
||||
|
||||
63
src/dns.h
63
src/dns.h
@@ -73,12 +73,25 @@ typedef enum dns_type {
|
||||
} dns_type_t;
|
||||
|
||||
typedef enum dns_opt_code {
|
||||
DNS_OPT_T_ECS = 8, // OPT ECS
|
||||
DNS_OPT_T_COOKIE = 10, //OPT Cookie
|
||||
DNS_OPT_T_ECS = 8, // OPT ECS
|
||||
DNS_OPT_T_COOKIE = 10, // OPT Cookie
|
||||
DNS_OPT_T_TCP_KEEPALIVE = 11,
|
||||
DNS_OPT_T_PADDING = 12,
|
||||
DNS_OPT_T_ALL = 255
|
||||
} dns_opt_code_t;
|
||||
|
||||
/* https://datatracker.ietf.org/doc/draft-ietf-dnsop-svcb-https/11/ */
|
||||
typedef enum dns_htts_svcparam {
|
||||
DNS_HTTPS_T_MANDATORY = 0,
|
||||
DNS_HTTPS_T_ALPN = 1,
|
||||
DNS_HTTPS_T_NO_DEFAULT_ALPN = 2,
|
||||
DNS_HTTPS_T_PORT = 3,
|
||||
DNS_HTTPS_T_IPV4HINT = 4,
|
||||
DNS_HTTPS_T_ECH = 5,
|
||||
DNS_HTTPS_T_IPV6HINT = 6,
|
||||
DNS_HTTPS_T_ALL = 255
|
||||
} dns_htts_svcparam_t;
|
||||
|
||||
typedef enum dns_opcode {
|
||||
DNS_OP_QUERY = 0,
|
||||
DNS_OP_IQUERY = 1,
|
||||
@@ -183,7 +196,7 @@ struct dns_opt_ecs {
|
||||
unsigned char source_prefix;
|
||||
unsigned char scope_prefix;
|
||||
unsigned char addr[DNS_RR_AAAA_LEN];
|
||||
} __attribute__((packed));;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* OPT COOLIE */
|
||||
struct dns_opt_cookie {
|
||||
@@ -199,9 +212,31 @@ struct dns_opt {
|
||||
unsigned char data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dns_rr_nested {
|
||||
struct dns_context context;
|
||||
unsigned char *rr_start;
|
||||
unsigned char *rr_len_ptr;
|
||||
unsigned short rr_head_len;
|
||||
dns_rr_type type;
|
||||
};
|
||||
|
||||
struct dns_https_param {
|
||||
unsigned short key;
|
||||
unsigned short len;
|
||||
unsigned char value[0];
|
||||
};
|
||||
|
||||
struct dns_rrs *dns_get_rrs_next(struct dns_packet *packet, struct dns_rrs *rrs);
|
||||
struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, int *count);
|
||||
|
||||
struct dns_rr_nested *dns_add_rr_nested_start(struct dns_rr_nested *rr_nested_buffer, struct dns_packet *packet,
|
||||
dns_rr_type type, dns_type_t rtype, const char *domain, int ttl);
|
||||
int dns_add_rr_nested_end(struct dns_rr_nested *rr_nested, dns_type_t rtype);
|
||||
int dns_add_rr_nested_memcpy(struct dns_rr_nested *rr_nested, void *data, int data_len);
|
||||
|
||||
void *dns_get_rr_nested_start(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, int *ttl, int *rr_len);
|
||||
void *dns_get_rr_nested_next(struct dns_rrs *rrs, void *rr_nested, int rr_nested_len);
|
||||
|
||||
/*
|
||||
* Question
|
||||
*/
|
||||
@@ -214,7 +249,8 @@ int dns_get_domain(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, i
|
||||
int dns_add_CNAME(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname);
|
||||
int dns_get_CNAME(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size);
|
||||
|
||||
int dns_add_A(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, unsigned char addr[DNS_RR_A_LEN]);
|
||||
int dns_add_A(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl,
|
||||
unsigned char addr[DNS_RR_A_LEN]);
|
||||
int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[DNS_RR_A_LEN]);
|
||||
|
||||
int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, char *cname);
|
||||
@@ -239,6 +275,25 @@ int dns_get_OPT_ECS(struct dns_rrs *rrs, unsigned short *opt_code, unsigned shor
|
||||
int dns_add_OPT_TCP_KEEYALIVE(struct dns_packet *packet, unsigned short timeout);
|
||||
int dns_get_OPT_TCP_KEEYALIVE(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len,
|
||||
unsigned short *timeout);
|
||||
|
||||
int dns_add_HTTPS_start(struct dns_rr_nested *svcparam_buffer, struct dns_packet *packet,
|
||||
dns_rr_type type, const char *domain, int ttl, int priority,
|
||||
const char *target);
|
||||
int dns_HTTPS_add_raw(struct dns_rr_nested *svcparam, unsigned short key, unsigned char *value, unsigned short len);
|
||||
int dns_HTTPS_add_port(struct dns_rr_nested *svcparam, unsigned short port);
|
||||
int dns_HTTPS_add_alpn(struct dns_rr_nested *svcparam, const char *alpn);
|
||||
int dns_HTTPS_add_no_default_alpn(struct dns_rr_nested *svcparam);
|
||||
int dns_HTTPS_add_ipv4hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_A_LEN],
|
||||
int addr_num);
|
||||
int dns_HTTPS_add_ipv6hint(struct dns_rr_nested *svcparam, unsigned char addr[][DNS_RR_AAAA_LEN],
|
||||
int addr_num);
|
||||
int dns_HTTPS_add_ech(struct dns_rr_nested *svcparam, void *ech, int ech_len);
|
||||
int dns_add_HTTPS_end(struct dns_rr_nested *svcparam);
|
||||
|
||||
struct dns_https_param *dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl,
|
||||
int *priority, char *target, int target_size);
|
||||
struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *parm);
|
||||
|
||||
/*
|
||||
* Packet operation
|
||||
*/
|
||||
|
||||
117
src/dns_cache.c
117
src/dns_cache.c
@@ -30,7 +30,7 @@
|
||||
#define DNS_CACHE_HITNUM_STEP_MAX 6
|
||||
|
||||
struct dns_cache_head {
|
||||
DECLARE_HASHTABLE(cache_hash, 10);
|
||||
DECLARE_HASHTABLE(cache_hash, 16);
|
||||
struct list_head cache_list;
|
||||
struct list_head inactive_list;
|
||||
atomic_t num;
|
||||
@@ -128,14 +128,14 @@ enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data)
|
||||
return cache_data->head.cache_type;
|
||||
}
|
||||
|
||||
uint32_t dns_cache_get_query_flag(struct dns_cache_data *cache_data)
|
||||
uint32_t dns_cache_get_query_flag(struct dns_cache *dns_cache)
|
||||
{
|
||||
return cache_data->head.query_flag;
|
||||
return dns_cache->info.query_flag;
|
||||
}
|
||||
|
||||
const char *dns_cache_get_dns_group_name(struct dns_cache_data *cache_data)
|
||||
const char *dns_cache_get_dns_group_name(struct dns_cache *dns_cache)
|
||||
{
|
||||
return cache_data->head.dns_group_name;
|
||||
return dns_cache->info.dns_group_name;
|
||||
}
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data)
|
||||
@@ -161,8 +161,7 @@ struct dns_cache_data *dns_cache_new_data(void)
|
||||
return (struct dns_cache_data *)cache_addr;
|
||||
}
|
||||
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl)
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, char *cname, int cname_ttl)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
goto errout;
|
||||
@@ -185,13 +184,6 @@ void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, struct dns_cache_q
|
||||
cache_addr->addr_data.cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
if (query_option) {
|
||||
cache_addr->head.query_flag = query_option->query_flag;
|
||||
if (query_option->dns_group_name) {
|
||||
safe_strncpy(cache_addr->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
cache_addr->addr_data.soa = 1;
|
||||
cache_addr->head.cache_type = CACHE_TYPE_ADDR;
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
@@ -199,8 +191,8 @@ errout:
|
||||
return;
|
||||
}
|
||||
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl, unsigned char *addr, int addr_len)
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, char *cname, int cname_ttl, unsigned char *addr,
|
||||
int addr_len)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
goto errout;
|
||||
@@ -224,21 +216,13 @@ void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, struct dns_cache_
|
||||
cache_addr->addr_data.cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
if (query_option) {
|
||||
cache_addr->head.query_flag = query_option->query_flag;
|
||||
if (query_option->dns_group_name) {
|
||||
safe_strncpy(cache_addr->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
cache_addr->head.cache_type = CACHE_TYPE_ADDR;
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
errout:
|
||||
return;
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(struct dns_cache_query_option *query_option, void *packet,
|
||||
size_t packet_len)
|
||||
struct dns_cache_data *dns_cache_new_data_packet(void *packet, size_t packet_len)
|
||||
{
|
||||
struct dns_cache_packet *cache_packet = NULL;
|
||||
size_t data_size = 0;
|
||||
@@ -255,19 +239,13 @@ struct dns_cache_data *dns_cache_new_data_packet(struct dns_cache_query_option *
|
||||
memcpy(cache_packet->data, packet, packet_len);
|
||||
memset(&cache_packet->head, 0, sizeof(cache_packet->head));
|
||||
|
||||
if (query_option) {
|
||||
cache_packet->head.query_flag = query_option->query_flag;
|
||||
if (query_option->dns_group_name) {
|
||||
strncpy(cache_packet->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN - 1);
|
||||
}
|
||||
}
|
||||
cache_packet->head.cache_type = CACHE_TYPE_PACKET;
|
||||
cache_packet->head.size = packet_len;
|
||||
|
||||
return (struct dns_cache_data *)cache_packet;
|
||||
}
|
||||
|
||||
static int _dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, int inactive,
|
||||
static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int speed, int inactive,
|
||||
struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
@@ -278,9 +256,9 @@ static int _dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed
|
||||
}
|
||||
|
||||
/* lookup existing cache */
|
||||
dns_cache = dns_cache_lookup(domain, qtype);
|
||||
dns_cache = dns_cache_lookup(cache_key);
|
||||
if (dns_cache == NULL) {
|
||||
return dns_cache_insert(domain, ttl, qtype, speed, cache_data);
|
||||
return dns_cache_insert(cache_key, ttl, speed, cache_data);
|
||||
}
|
||||
|
||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||
@@ -291,7 +269,8 @@ static int _dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
dns_cache->del_pending = 0;
|
||||
dns_cache->info.ttl = ttl;
|
||||
dns_cache->info.qtype = qtype;
|
||||
dns_cache->info.qtype = cache_key->qtype;
|
||||
dns_cache->info.query_flag = cache_key->query_flag;
|
||||
dns_cache->info.ttl = ttl;
|
||||
dns_cache->info.speed = speed;
|
||||
old_cache_data = dns_cache->cache_data;
|
||||
@@ -314,31 +293,42 @@ static int _dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
int dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
return _dns_cache_replace(domain, ttl, qtype, speed, 0, cache_data);
|
||||
return _dns_cache_replace(cache_key, ttl, speed, 0, cache_data);
|
||||
}
|
||||
|
||||
int dns_cache_replace_inactive(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
int dns_cache_replace_inactive(struct dns_cache_key *cache_key, int ttl, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
return _dns_cache_replace(domain, ttl, qtype, speed, 1, cache_data);
|
||||
return _dns_cache_replace(cache_key, ttl, speed, 1, cache_data);
|
||||
}
|
||||
|
||||
static void _dns_cache_remove_by_domain(const char *domain, dns_type_t qtype)
|
||||
static void _dns_cache_remove_by_domain(struct dns_cache_key *cache_key)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
key = hash_string(domain);
|
||||
key = jhash(&qtype, sizeof(qtype), key);
|
||||
key = hash_string(cache_key->domain);
|
||||
key = jhash(&cache_key->qtype, sizeof(cache_key->qtype), key);
|
||||
key = hash_string_initval(cache_key->dns_group_name, key);
|
||||
key = jhash(&cache_key->query_flag, sizeof(cache_key->query_flag), key);
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_for_each_possible(dns_cache_head.cache_hash, dns_cache, node, key)
|
||||
{
|
||||
if (dns_cache->info.qtype != qtype) {
|
||||
if (dns_cache->info.qtype != cache_key->qtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(domain, dns_cache->info.domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||
if (dns_cache->info.query_flag != cache_key->query_flag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(cache_key->domain, dns_cache->info.domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(dns_cache->info.dns_group_name, cache_key->dns_group_name, DNS_MAX_CNAME_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -355,7 +345,12 @@ static int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
/* if cache already exists, free */
|
||||
_dns_cache_remove_by_domain(info->domain, info->qtype);
|
||||
struct dns_cache_key cache_key;
|
||||
cache_key.qtype = info->qtype;
|
||||
cache_key.query_flag = info->query_flag;
|
||||
cache_key.domain = info->domain;
|
||||
cache_key.dns_group_name = info->dns_group_name;
|
||||
_dns_cache_remove_by_domain(&cache_key);
|
||||
|
||||
dns_cache = malloc(sizeof(*dns_cache));
|
||||
if (dns_cache == NULL) {
|
||||
@@ -365,6 +360,8 @@ static int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data
|
||||
memset(dns_cache, 0, sizeof(*dns_cache));
|
||||
key = hash_string(info->domain);
|
||||
key = jhash(&info->qtype, sizeof(info->qtype), key);
|
||||
key = hash_string_initval(info->dns_group_name, key);
|
||||
key = jhash(&info->query_flag, sizeof(info->query_flag), key);
|
||||
atomic_set(&dns_cache->ref, 1);
|
||||
memcpy(&dns_cache->info, info, sizeof(*info));
|
||||
dns_cache->del_pending = 0;
|
||||
@@ -393,11 +390,11 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
int dns_cache_insert(struct dns_cache_key *cache_key, int ttl, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache_info info;
|
||||
|
||||
if (cache_data == NULL || domain == NULL) {
|
||||
if (cache_data == NULL || cache_key == NULL || cache_key->dns_group_name == NULL || cache_key->domain == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -411,8 +408,10 @@ int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
}
|
||||
|
||||
info.hitnum = 3;
|
||||
safe_strncpy(info.domain, domain, DNS_MAX_CNAME_LEN);
|
||||
info.qtype = qtype;
|
||||
safe_strncpy(info.domain, cache_key->domain, DNS_MAX_CNAME_LEN);
|
||||
info.qtype = cache_key->qtype;
|
||||
safe_strncpy(info.dns_group_name, cache_key->dns_group_name, DNS_GROUP_NAME_LEN);
|
||||
info.query_flag = cache_key->query_flag;
|
||||
info.ttl = ttl;
|
||||
info.hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
||||
info.speed = speed;
|
||||
@@ -422,7 +421,7 @@ int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
return _dns_cache_insert(&info, cache_data, &dns_cache_head.cache_list);
|
||||
}
|
||||
|
||||
struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
struct dns_cache *dns_cache_lookup(struct dns_cache_key *cache_key)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
@@ -433,19 +432,29 @@ struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = hash_string(domain);
|
||||
key = jhash(&qtype, sizeof(qtype), key);
|
||||
key = hash_string(cache_key->domain);
|
||||
key = jhash(&cache_key->qtype, sizeof(cache_key->qtype), key);
|
||||
key = hash_string_initval(cache_key->dns_group_name, key);
|
||||
key = jhash(&cache_key->query_flag, sizeof(cache_key->query_flag), key);
|
||||
|
||||
time(&now);
|
||||
/* find cache */
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_for_each_possible(dns_cache_head.cache_hash, dns_cache, node, key)
|
||||
{
|
||||
if (dns_cache->info.qtype != qtype) {
|
||||
if (dns_cache->info.qtype != cache_key->qtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(domain, dns_cache->info.domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||
if (strncmp(cache_key->domain, dns_cache->info.domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(cache_key->dns_group_name, dns_cache->info.dns_group_name, DNS_GROUP_NAME_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cache_key->query_flag != dns_cache->info.query_flag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "atomic.h"
|
||||
#include "dns.h"
|
||||
#include "dns_conf.h"
|
||||
#include "hash.h"
|
||||
#include "hashtable.h"
|
||||
#include "list.h"
|
||||
@@ -48,15 +49,8 @@ enum CACHE_RECORD_TYPE {
|
||||
CACHE_RECORD_TYPE_INACTIVE,
|
||||
};
|
||||
|
||||
struct dns_cache_query_option {
|
||||
uint32_t query_flag;
|
||||
const char *dns_group_name;
|
||||
};
|
||||
|
||||
struct dns_cache_data_head {
|
||||
enum CACHE_TYPE cache_type;
|
||||
uint32_t query_flag;
|
||||
char dns_group_name[DNS_CACHE_GROUP_NAME_LEN];
|
||||
int is_soa;
|
||||
ssize_t size;
|
||||
};
|
||||
@@ -87,13 +81,15 @@ struct dns_cache_packet {
|
||||
|
||||
struct dns_cache_info {
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
dns_type_t qtype;
|
||||
char dns_group_name[DNS_GROUP_NAME_LEN];
|
||||
uint32_t query_flag;
|
||||
int ttl;
|
||||
int hitnum;
|
||||
int speed;
|
||||
int hitnum_update_add;
|
||||
time_t insert_time;
|
||||
time_t replace_time;
|
||||
dns_type_t qtype;
|
||||
};
|
||||
|
||||
struct dns_cache_record {
|
||||
@@ -120,26 +116,32 @@ struct dns_cache_file {
|
||||
uint32_t cache_number;
|
||||
};
|
||||
|
||||
struct dns_cache_key {
|
||||
const char *domain;
|
||||
dns_type_t qtype;
|
||||
const char *dns_group_name;
|
||||
uint32_t query_flag;
|
||||
};
|
||||
|
||||
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data);
|
||||
|
||||
uint32_t dns_cache_get_query_flag(struct dns_cache_data *cache_data);
|
||||
uint32_t dns_cache_get_query_flag(struct dns_cache *dns_cache);
|
||||
|
||||
const char *dns_cache_get_dns_group_name(struct dns_cache_data *cache_data);
|
||||
const char *dns_cache_get_dns_group_name(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data);
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(struct dns_cache_query_option *query_option, void *packet,
|
||||
size_t packet_len);
|
||||
struct dns_cache_data *dns_cache_new_data_packet(void *packet, size_t packet_len);
|
||||
|
||||
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
|
||||
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
int dns_cache_replace(struct dns_cache_key *key, int ttl, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
int dns_cache_replace_inactive(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
int dns_cache_replace_inactive(struct dns_cache_key *key, int ttl, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
int dns_cache_insert(struct dns_cache_key *key, int ttl, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype);
|
||||
struct dns_cache *dns_cache_lookup(struct dns_cache_key *key);
|
||||
|
||||
void dns_cache_delete(struct dns_cache *dns_cache);
|
||||
|
||||
@@ -166,11 +168,10 @@ struct dns_cache_data *dns_cache_new_data(void);
|
||||
|
||||
struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl, unsigned char *addr, int addr_len);
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, char *cname, int cname_ttl, unsigned char *addr,
|
||||
int addr_len);
|
||||
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl);
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, char *cname, int cname_ttl);
|
||||
|
||||
void dns_cache_destroy(void);
|
||||
|
||||
|
||||
@@ -184,8 +184,9 @@ struct dns_client {
|
||||
int ssl_verify_skip;
|
||||
|
||||
/* query list */
|
||||
pthread_mutex_t dns_request_lock;
|
||||
struct list_head dns_request_list;
|
||||
pthread_cond_t run_cond;
|
||||
atomic_t run_period;
|
||||
atomic_t dns_server_num;
|
||||
|
||||
/* ECS */
|
||||
@@ -1312,7 +1313,12 @@ static int _dns_client_server_pending(char *server_ip, int port, dns_server_type
|
||||
|
||||
pthread_mutex_lock(&pending_server_mutex);
|
||||
list_add_tail(&pending->list, &pending_servers);
|
||||
atomic_set(&client.run_period, 1);
|
||||
pthread_mutex_unlock(&pending_server_mutex);
|
||||
|
||||
pthread_mutex_lock(&client.domain_map_lock);
|
||||
pthread_cond_signal(&client.run_cond);
|
||||
pthread_mutex_unlock(&client.domain_map_lock);
|
||||
return 0;
|
||||
errout:
|
||||
if (pending) {
|
||||
@@ -3129,7 +3135,13 @@ int dns_client_query(const char *domain, int qtype, dns_client_callback callback
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&client.domain_map_lock);
|
||||
list_add_tail(&query->dns_request_list, &client.dns_request_list);
|
||||
if (hash_hashed(&query->domain_node)) {
|
||||
if (list_empty(&client.dns_request_list)) {
|
||||
pthread_cond_signal(&client.run_cond);
|
||||
}
|
||||
|
||||
list_add_tail(&query->dns_request_list, &client.dns_request_list);
|
||||
}
|
||||
pthread_mutex_unlock(&client.domain_map_lock);
|
||||
|
||||
tlog(TLOG_INFO, "send request %s, qtype %d, id %d\n", domain, qtype, query->sid);
|
||||
@@ -3262,6 +3274,12 @@ static void _dns_client_add_pending_servers(void)
|
||||
dely = 0;
|
||||
|
||||
pthread_mutex_lock(&pending_server_mutex);
|
||||
if (list_empty(&pending_servers)) {
|
||||
atomic_set(&client.run_period, 0);
|
||||
} else {
|
||||
atomic_set(&client.run_period, 1);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(pending, tmp, &pending_servers, list)
|
||||
{
|
||||
list_add(&pending->retry_list, &retry_list);
|
||||
@@ -3402,15 +3420,25 @@ static void *_dns_client_work(void *arg)
|
||||
int num = 0;
|
||||
int i = 0;
|
||||
unsigned long now = {0};
|
||||
unsigned long last = {0};
|
||||
unsigned int sleep = 100;
|
||||
int sleep_time = 0;
|
||||
unsigned long expect_time = 0;
|
||||
|
||||
sleep_time = sleep;
|
||||
now = get_tick_count() - sleep;
|
||||
last = now;
|
||||
expect_time = now + sleep;
|
||||
while (atomic_read(&client.run)) {
|
||||
now = get_tick_count();
|
||||
if (sleep_time > 0) {
|
||||
sleep_time -= now - last;
|
||||
if (sleep_time <= 0) {
|
||||
sleep_time = 0;
|
||||
}
|
||||
}
|
||||
last = now;
|
||||
|
||||
if (now >= expect_time) {
|
||||
_dns_client_period_run();
|
||||
sleep_time = sleep - (now - expect_time);
|
||||
@@ -3421,6 +3449,15 @@ static void *_dns_client_work(void *arg)
|
||||
expect_time += sleep;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&client.domain_map_lock);
|
||||
if (list_empty(&client.dns_request_list) && atomic_read(&client.run_period) == 0) {
|
||||
pthread_cond_wait(&client.run_cond, &client.domain_map_lock);
|
||||
expect_time = get_tick_count();
|
||||
pthread_mutex_unlock(&client.domain_map_lock);
|
||||
continue;
|
||||
}
|
||||
pthread_mutex_unlock(&client.domain_map_lock);
|
||||
|
||||
num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, sleep_time);
|
||||
if (num < 0) {
|
||||
usleep(100000);
|
||||
@@ -3496,6 +3533,7 @@ int dns_client_init(void)
|
||||
memset(&client, 0, sizeof(client));
|
||||
pthread_attr_init(&attr);
|
||||
atomic_set(&client.dns_server_num, 0);
|
||||
atomic_set(&client.run_period, 0);
|
||||
|
||||
epollfd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if (epollfd < 0) {
|
||||
@@ -3511,6 +3549,8 @@ int dns_client_init(void)
|
||||
hash_init(client.group);
|
||||
INIT_LIST_HEAD(&client.dns_request_list);
|
||||
|
||||
pthread_cond_init(&client.run_cond, NULL);
|
||||
|
||||
if (dns_client_add_group(DNS_SERVER_GROUP_DEFAULT) != 0) {
|
||||
tlog(TLOG_ERROR, "add default server group failed.");
|
||||
goto errout;
|
||||
@@ -3542,6 +3582,7 @@ errout:
|
||||
|
||||
pthread_mutex_destroy(&client.server_list_lock);
|
||||
pthread_mutex_destroy(&client.domain_map_lock);
|
||||
pthread_cond_destroy(&client.run_cond);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -3551,6 +3592,9 @@ void dns_client_exit(void)
|
||||
if (client.tid) {
|
||||
void *ret = NULL;
|
||||
atomic_set(&client.run, 0);
|
||||
pthread_mutex_lock(&client.domain_map_lock);
|
||||
pthread_cond_signal(&client.run_cond);
|
||||
pthread_mutex_unlock(&client.domain_map_lock);
|
||||
pthread_join(client.tid, &ret);
|
||||
client.tid = 0;
|
||||
}
|
||||
@@ -3563,6 +3607,7 @@ void dns_client_exit(void)
|
||||
|
||||
pthread_mutex_destroy(&client.server_list_lock);
|
||||
pthread_mutex_destroy(&client.domain_map_lock);
|
||||
pthread_cond_destroy(&client.run_cond);
|
||||
if (client.ssl_ctx) {
|
||||
SSL_CTX_free(client.ssl_ctx);
|
||||
client.ssl_ctx = NULL;
|
||||
|
||||
259
src/dns_conf.c
259
src/dns_conf.c
@@ -40,6 +40,11 @@ struct dns_ipset_table {
|
||||
};
|
||||
static struct dns_ipset_table dns_ipset_table;
|
||||
|
||||
struct dns_nftset_table {
|
||||
DECLARE_HASHTABLE(nftset, 8);
|
||||
};
|
||||
static struct dns_nftset_table dns_nftset_table;
|
||||
|
||||
struct dns_qtype_soa_table dns_qtype_soa_table;
|
||||
|
||||
struct dns_domain_set_rule_table dns_domain_set_rule_table;
|
||||
@@ -83,6 +88,7 @@ int dns_conf_serve_expired_reply_ttl = 3;
|
||||
struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
char dns_conf_server_name[DNS_MAX_SERVER_NAME_LEN];
|
||||
int dns_conf_server_num;
|
||||
int dns_conf_resolv_hostname = 1;
|
||||
|
||||
struct dns_domain_check_orders dns_conf_check_orders = {
|
||||
.orders =
|
||||
@@ -132,6 +138,8 @@ int dns_conf_local_ttl;
|
||||
int dns_conf_force_AAAA_SOA;
|
||||
int dns_conf_force_no_cname;
|
||||
int dns_conf_ipset_timeout_enable;
|
||||
int dns_conf_nftset_timeout_enable;
|
||||
int dns_conf_nftset_debug_enable;
|
||||
|
||||
char dns_conf_user[DNS_CONF_USRNAME_LEN];
|
||||
|
||||
@@ -169,6 +177,10 @@ static void *_new_dns_rule(enum domain_rule domain_rule)
|
||||
case DOMAIN_RULE_IPSET_IPV6:
|
||||
size = sizeof(struct dns_ipset_rule);
|
||||
break;
|
||||
case DOMAIN_RULE_NFTSET_IP:
|
||||
case DOMAIN_RULE_NFTSET_IP6:
|
||||
size = sizeof(struct dns_nftset_rule);
|
||||
break;
|
||||
case DOMAIN_RULE_NAMESERVER:
|
||||
size = sizeof(struct dns_nameserver_rule);
|
||||
break;
|
||||
@@ -423,6 +435,9 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
}
|
||||
case 'h': {
|
||||
safe_strncpy(server->hostname, optarg, DNS_MAX_CNAME_LEN);
|
||||
if (strncmp(server->hostname, "-", 2) == 0) {
|
||||
server->hostname[0] = '\0';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'H': {
|
||||
@@ -518,7 +533,8 @@ static void _config_address_destroy(radix_node_t *node, void *cbctx)
|
||||
node->data = NULL;
|
||||
}
|
||||
|
||||
static int _config_domain_set_rule_add_ext(char *set_name, enum domain_rule type, void *rule, unsigned int flags, int is_clear_flag)
|
||||
static int _config_domain_set_rule_add_ext(char *set_name, enum domain_rule type, void *rule, unsigned int flags,
|
||||
int is_clear_flag)
|
||||
{
|
||||
struct dns_domain_set_rule *set_rule = NULL;
|
||||
struct dns_domain_set_rule_list *set_rule_list = NULL;
|
||||
@@ -851,6 +867,174 @@ errout:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _config_nftset_table_destroy(void)
|
||||
{
|
||||
struct dns_nftset_name *nftset = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
unsigned long i = 0;
|
||||
|
||||
hash_for_each_safe(dns_nftset_table.nftset, i, tmp, nftset, node)
|
||||
{
|
||||
hlist_del_init(&nftset->node);
|
||||
free(nftset);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dns_nftset_name *_dns_conf_get_nftable(const char *familyname, const char *tablename,
|
||||
const char *setname)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_nftset_name *nftset_name = NULL;
|
||||
|
||||
if (familyname == NULL || tablename == NULL || setname == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *hasher[4] = {familyname, tablename, setname, NULL};
|
||||
|
||||
key = hash_string_array(hasher);
|
||||
hash_for_each_possible(dns_nftset_table.nftset, nftset_name, node, key)
|
||||
{
|
||||
if (strncmp(nftset_name->nftfamilyname, familyname, DNS_MAX_NFTSET_FAMILYLEN) == 0 &&
|
||||
strncmp(nftset_name->nfttablename, tablename, DNS_MAX_NFTSET_NAMELEN) == 0 &&
|
||||
strncmp(nftset_name->nftsetname, setname, DNS_MAX_NFTSET_NAMELEN) == 0) {
|
||||
return nftset_name;
|
||||
}
|
||||
}
|
||||
|
||||
nftset_name = malloc(sizeof(*nftset_name));
|
||||
if (nftset_name == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
safe_strncpy(nftset_name->nftfamilyname, familyname, DNS_MAX_NFTSET_FAMILYLEN);
|
||||
safe_strncpy(nftset_name->nfttablename, tablename, DNS_MAX_NFTSET_NAMELEN);
|
||||
safe_strncpy(nftset_name->nftsetname, setname, DNS_MAX_NFTSET_NAMELEN);
|
||||
hash_add(dns_nftset_table.nftset, &nftset_name->node, key);
|
||||
|
||||
return nftset_name;
|
||||
errout:
|
||||
if (nftset_name) {
|
||||
free(nftset_name);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _conf_domain_rule_nftset(char *domain, const char *nftsetname)
|
||||
{
|
||||
struct dns_nftset_rule *nftset_rule = NULL;
|
||||
const struct dns_nftset_name *nftset = NULL;
|
||||
char *copied_name = NULL;
|
||||
enum domain_rule type = 0;
|
||||
int ignore_flag = 0;
|
||||
char *setname = NULL;
|
||||
char *tablename = NULL;
|
||||
char *family = NULL;
|
||||
|
||||
copied_name = strdup(nftsetname);
|
||||
|
||||
if (copied_name == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
for (char *tok = strtok(copied_name, ","); tok; tok = strtok(NULL, ",")) {
|
||||
char *saveptr = NULL;
|
||||
char *tok_set = NULL;
|
||||
nftset_rule = NULL;
|
||||
|
||||
if (strncmp(tok, "#4:", 3U) == 0) {
|
||||
type = DOMAIN_RULE_NFTSET_IP;
|
||||
ignore_flag = DOMAIN_FLAG_NFTSET_IP_IGN;
|
||||
} else if (strncmp(tok, "#6:", 3U) == 0) {
|
||||
type = DOMAIN_RULE_NFTSET_IP6;
|
||||
ignore_flag = DOMAIN_FLAG_NFTSET_IP6_IGN;
|
||||
} else if (strncmp(tok, "-", 2U) == 0) {
|
||||
_config_domain_rule_flag_set(domain, DOMAIN_FLAG_NFTSET_INET_IGN, 0);
|
||||
continue;
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tok_set = tok + 3;
|
||||
|
||||
if (strncmp(tok_set, "-", 2U) == 0) {
|
||||
_config_domain_rule_flag_set(domain, ignore_flag, 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 ipset domain */
|
||||
nftset = _dns_conf_get_nftable(family, tablename, setname);
|
||||
if (nftset == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
nftset_rule = _new_dns_rule(type);
|
||||
if (nftset_rule == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
nftset_rule->nfttablename = nftset->nfttablename;
|
||||
nftset_rule->nftsetname = nftset->nftsetname;
|
||||
nftset_rule->familyname = nftset->nftfamilyname;
|
||||
|
||||
if (_config_domain_rule_add(domain, type, nftset_rule) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
_dns_rule_put(&nftset_rule->head);
|
||||
}
|
||||
|
||||
goto clear;
|
||||
|
||||
errout:
|
||||
tlog(TLOG_ERROR, "add nftset %s %s failed", domain, nftsetname);
|
||||
|
||||
if (nftset_rule) {
|
||||
_dns_rule_put(&nftset_rule->head);
|
||||
}
|
||||
|
||||
clear:
|
||||
if (copied_name) {
|
||||
free(copied_name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _config_nftset(void *data, int argc, char *argv[])
|
||||
{
|
||||
char domain[DNS_MAX_CONF_CNAME_LEN];
|
||||
char *value = argv[1];
|
||||
|
||||
if (argc <= 1) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_get_domain(value, domain, DNS_MAX_CONF_CNAME_LEN, &value) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return _conf_domain_rule_nftset(domain, value);
|
||||
errout:
|
||||
tlog(TLOG_ERROR, "add nftset %s failed", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _conf_domain_rule_address(char *domain, const char *domain_address)
|
||||
{
|
||||
struct dns_rule_address_IPV4 *address_ipv4 = NULL;
|
||||
@@ -981,6 +1165,11 @@ errout:
|
||||
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));
|
||||
}
|
||||
|
||||
static int _config_speed_check_mode_parser(struct dns_domain_check_orders *check_orders, const char *mode)
|
||||
{
|
||||
char tmpbuff[DNS_MAX_OPT_LEN];
|
||||
@@ -991,6 +1180,7 @@ static int _config_speed_check_mode_parser(struct dns_domain_check_orders *check
|
||||
int i = 0;
|
||||
|
||||
safe_strncpy(tmpbuff, mode, DNS_MAX_OPT_LEN);
|
||||
_config_speed_check_mode_clear(check_orders);
|
||||
|
||||
ptr = tmpbuff;
|
||||
do {
|
||||
@@ -1663,6 +1853,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
{"speed-check-mode", required_argument, NULL, 'c'},
|
||||
{"address", required_argument, NULL, 'a'},
|
||||
{"ipset", required_argument, NULL, 'p'},
|
||||
{"nftset", required_argument, NULL, 't'},
|
||||
{"nameserver", required_argument, NULL, 'n'},
|
||||
{"dualstack-ip-selection", required_argument, NULL, 'd'},
|
||||
{NULL, no_argument, NULL, 0}
|
||||
@@ -1748,6 +1939,19 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
|
||||
|
||||
break;
|
||||
}
|
||||
case 't': {
|
||||
const char *nftsetname = optarg;
|
||||
if (nftsetname == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_conf_domain_rule_nftset(domain, nftsetname) != 0) {
|
||||
tlog(TLOG_ERROR, "add nftset rule failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2121,26 +2325,42 @@ static int _config_log_level(void *data, int argc, char *argv[])
|
||||
static void _config_setup_smartdns_domain(void)
|
||||
{
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
/* get local host name */
|
||||
if (getdomainname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
||||
gethostname(hostname, DNS_MAX_CNAME_LEN);
|
||||
char domainname[DNS_MAX_CNAME_LEN];
|
||||
|
||||
hostname[0] = '\0';
|
||||
domainname[0] = '\0';
|
||||
|
||||
/* get local domain name */
|
||||
if (getdomainname(domainname, DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
/* check domain is valid */
|
||||
if (strncmp(domainname, "(none)", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
domainname[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* get host name again */
|
||||
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
gethostname(hostname, DNS_MAX_CNAME_LEN);
|
||||
if (gethostname(hostname, DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
/* check hostname is valid */
|
||||
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
hostname[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* if hostname is (none), return smartdns */
|
||||
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
safe_strncpy(hostname, "smartdns", DNS_MAX_CNAME_LEN);
|
||||
if (dns_conf_resolv_hostname == 1) {
|
||||
/* add hostname to rule table */
|
||||
if (hostname[0] != '\0') {
|
||||
_config_domain_rule_flag_set(hostname, DOMAIN_FLAG_SMARTDNS_DOMAIN, 0);
|
||||
}
|
||||
|
||||
/* add domainname to rule table */
|
||||
if (domainname[0] != '\0') {
|
||||
char full_domain[DNS_MAX_CNAME_LEN];
|
||||
snprintf(full_domain, DNS_MAX_CNAME_LEN, "%.64s.%.128s", hostname, domainname);
|
||||
_config_domain_rule_flag_set(full_domain, DOMAIN_FLAG_SMARTDNS_DOMAIN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (hostname[0] != '\0') {
|
||||
_config_domain_rule_flag_set(hostname, DOMAIN_FLAG_SMARTDNS_DOMAIN, 0);
|
||||
}
|
||||
|
||||
if (dns_conf_server_name[0] != '\0') {
|
||||
/* add server name to rule table */
|
||||
if (dns_conf_server_name[0] != '\0' && strncmp(dns_conf_server_name, "smartdns", DNS_MAX_CNAME_LEN - 1) != 0) {
|
||||
_config_domain_rule_flag_set(dns_conf_server_name, DOMAIN_FLAG_SMARTDNS_DOMAIN, 0);
|
||||
}
|
||||
|
||||
@@ -2149,6 +2369,7 @@ static void _config_setup_smartdns_domain(void)
|
||||
|
||||
static struct config_item _config_item[] = {
|
||||
CONF_STRING("server-name", (char *)dns_conf_server_name, DNS_MAX_SERVER_NAME_LEN),
|
||||
CONF_YESNO("resolv-hostname", &dns_conf_resolv_hostname),
|
||||
CONF_CUSTOM("bind", _config_bind_ip_udp, NULL),
|
||||
CONF_CUSTOM("bind-tcp", _config_bind_ip_tcp, NULL),
|
||||
CONF_CUSTOM("server", _config_server_udp, NULL),
|
||||
@@ -2159,6 +2380,9 @@ static struct config_item _config_item[] = {
|
||||
CONF_CUSTOM("address", _config_address, NULL),
|
||||
CONF_YESNO("ipset-timeout", &dns_conf_ipset_timeout_enable),
|
||||
CONF_CUSTOM("ipset", _config_ipset, 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("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),
|
||||
@@ -2365,6 +2589,7 @@ static int _dns_server_load_conf_init(void)
|
||||
art_tree_init(&dns_conf_domain_rule);
|
||||
|
||||
hash_init(dns_ipset_table.ipset);
|
||||
hash_init(dns_nftset_table.nftset);
|
||||
hash_init(dns_qtype_soa_table.qtype);
|
||||
hash_init(dns_group_table.group);
|
||||
hash_init(dns_hosts_table.hosts);
|
||||
@@ -2372,8 +2597,6 @@ static int _dns_server_load_conf_init(void)
|
||||
hash_init(dns_domain_set_rule_table.rule_list);
|
||||
hash_init(dns_domain_set_name_table.names);
|
||||
|
||||
_config_setup_smartdns_domain();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2383,6 +2606,7 @@ void dns_server_load_exit(void)
|
||||
Destroy_Radix(dns_conf_address_rule.ipv4, _config_address_destroy, NULL);
|
||||
Destroy_Radix(dns_conf_address_rule.ipv6, _config_address_destroy, NULL);
|
||||
_config_ipset_table_destroy();
|
||||
_config_nftset_table_destroy();
|
||||
_config_group_table_destroy();
|
||||
_config_ptr_table_destroy();
|
||||
_config_host_table_destroy();
|
||||
@@ -2456,6 +2680,7 @@ errout:
|
||||
|
||||
static int _dns_conf_load_post(void)
|
||||
{
|
||||
_config_setup_smartdns_domain();
|
||||
_dns_conf_speed_check_mode_verify();
|
||||
|
||||
if (dns_conf_cachesize == 0 && dns_conf_response_mode == DNS_RESPONSE_MODE_FASTEST_RESPONSE) {
|
||||
|
||||
@@ -38,6 +38,8 @@ extern "C" {
|
||||
#define DNS_MAX_SERVER_NAME_LEN 128
|
||||
#define DNS_MAX_PTR_LEN 128
|
||||
#define DNS_MAX_IPSET_NAMELEN 32
|
||||
#define DNS_MAX_NFTSET_FAMILYLEN 8
|
||||
#define DNS_MAX_NFTSET_NAMELEN 256
|
||||
#define DNS_GROUP_NAME_LEN 32
|
||||
#define DNS_NAX_GROUP_NUMBER 16
|
||||
#define DNS_MAX_IPLEN 64
|
||||
@@ -62,6 +64,8 @@ enum domain_rule {
|
||||
DOMAIN_RULE_IPSET,
|
||||
DOMAIN_RULE_IPSET_IPV4,
|
||||
DOMAIN_RULE_IPSET_IPV6,
|
||||
DOMAIN_RULE_NFTSET_IP,
|
||||
DOMAIN_RULE_NFTSET_IP6,
|
||||
DOMAIN_RULE_NAMESERVER,
|
||||
DOMAIN_RULE_CHECKSPEED,
|
||||
DOMAIN_RULE_MAX,
|
||||
@@ -90,6 +94,9 @@ typedef enum {
|
||||
#define DOMAIN_FLAG_NAMESERVER_IGNORE (1 << 9)
|
||||
#define DOMAIN_FLAG_DUALSTACK_SELECT (1 << 10)
|
||||
#define DOMAIN_FLAG_SMARTDNS_DOMAIN (1 << 11)
|
||||
#define DOMAIN_FLAG_NFTSET_INET_IGN (1 << 12)
|
||||
#define DOMAIN_FLAG_NFTSET_IP_IGN (1 << 13)
|
||||
#define DOMAIN_FLAG_NFTSET_IP6_IGN (1 << 14)
|
||||
|
||||
#define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0)
|
||||
|
||||
@@ -135,9 +142,24 @@ struct dns_ipset_rule {
|
||||
const char *ipsetname;
|
||||
};
|
||||
|
||||
struct dns_nftset_name {
|
||||
struct hlist_node node;
|
||||
char nftfamilyname[DNS_MAX_NFTSET_FAMILYLEN];
|
||||
char nfttablename[DNS_MAX_NFTSET_NAMELEN];
|
||||
char nftsetname[DNS_MAX_NFTSET_NAMELEN];
|
||||
};
|
||||
|
||||
struct dns_nftset_rule {
|
||||
struct dns_rule head;
|
||||
const char *familyname;
|
||||
const char *nfttablename;
|
||||
const char *nftsetname;
|
||||
};
|
||||
|
||||
struct dns_domain_rule {
|
||||
struct dns_rule head;
|
||||
struct dns_rule *rules[DOMAIN_RULE_MAX];
|
||||
int is_sub_rule[DOMAIN_RULE_MAX];
|
||||
};
|
||||
|
||||
struct dns_nameserver_rule {
|
||||
@@ -366,6 +388,8 @@ extern int dns_conf_rr_ttl_min;
|
||||
extern int dns_conf_rr_ttl_max;
|
||||
extern int dns_conf_force_AAAA_SOA;
|
||||
extern int dns_conf_ipset_timeout_enable;
|
||||
extern int dns_conf_nftset_timeout_enable;
|
||||
extern int dns_conf_nftset_debug_enable;
|
||||
extern int dns_conf_local_ttl;
|
||||
|
||||
extern int dns_conf_force_no_cname;
|
||||
|
||||
465
src/dns_server.c
465
src/dns_server.c
@@ -28,6 +28,7 @@
|
||||
#include "fast_ping.h"
|
||||
#include "hashtable.h"
|
||||
#include "list.h"
|
||||
#include "nftset.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
#include <errno.h>
|
||||
@@ -40,6 +41,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
@@ -154,6 +156,8 @@ struct dns_request_pending_list {
|
||||
pthread_mutex_t request_list_lock;
|
||||
unsigned short qtype;
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
uint32_t server_flags;
|
||||
char dns_group_name[DNS_GROUP_NAME_LEN];
|
||||
struct list_head request_list;
|
||||
struct hlist_node node;
|
||||
};
|
||||
@@ -176,11 +180,13 @@ struct dns_request {
|
||||
/* dns query */
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
dns_type_t qtype;
|
||||
int qclass;
|
||||
unsigned long send_tick;
|
||||
unsigned short id;
|
||||
unsigned short rcode;
|
||||
unsigned short ss_family;
|
||||
char remote_server_fail;
|
||||
char skip_qtype_soa;
|
||||
socklen_t addr_len;
|
||||
union {
|
||||
struct sockaddr_in in;
|
||||
@@ -246,6 +252,7 @@ struct dns_request {
|
||||
struct dns_server {
|
||||
atomic_t run;
|
||||
int epoll_fd;
|
||||
int event_fd;
|
||||
struct list_head conn_list;
|
||||
|
||||
/* dns request list */
|
||||
@@ -269,7 +276,14 @@ static void _dns_server_request_get(struct dns_request *request);
|
||||
static void _dns_server_request_release(struct dns_request *request);
|
||||
static void _dns_server_request_release_complete(struct dns_request *request, int do_complete);
|
||||
static int _dns_server_reply_passthrouth(struct dns_server_post_context *context);
|
||||
static int _dns_server_do_query(struct dns_request *request);
|
||||
static int _dns_server_do_query(struct dns_request *request, int skip_notify_event);
|
||||
|
||||
static void _dns_server_wakup_thread(void)
|
||||
{
|
||||
uint64_t u = 1;
|
||||
int unused __attribute__((unused));
|
||||
unused = write(server.event_fd, &u, sizeof(u));
|
||||
}
|
||||
|
||||
static int _dns_server_forward_request(unsigned char *inpacket, int inpacket_len)
|
||||
{
|
||||
@@ -325,6 +339,15 @@ static void *_dns_server_get_dns_rule(struct dns_request *request, enum domain_r
|
||||
return request->domain_rule.rules[rule];
|
||||
}
|
||||
|
||||
static int _dns_server_is_dns_rule_extact_match(struct dns_request *request, enum domain_rule rule)
|
||||
{
|
||||
if (rule >= DOMAIN_RULE_MAX || request == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return request->domain_rule.is_sub_rule[rule] == 0;
|
||||
}
|
||||
|
||||
static void _dns_server_set_dualstack_selection(struct dns_request *request)
|
||||
{
|
||||
struct dns_rule_flags *rule_flag = NULL;
|
||||
@@ -364,12 +387,6 @@ static int _dns_server_is_return_soa(struct dns_request *request)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_AAAA) {
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_FORCE_AAAA_SOA) == 0 || dns_conf_force_AAAA_SOA == 1) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
rule_flag = _dns_server_get_dns_rule(request, DOMAIN_RULE_FLAGS);
|
||||
if (rule_flag) {
|
||||
flags = rule_flag->flags;
|
||||
@@ -377,11 +394,39 @@ static int _dns_server_is_return_soa(struct dns_request *request)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((flags & DOMAIN_FLAG_ADDR_IPV4_SOA) && (request->qtype == DNS_T_A)) {
|
||||
return 1;
|
||||
if (flags & DOMAIN_FLAG_ADDR_IGN) {
|
||||
request->skip_qtype_soa = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((flags & DOMAIN_FLAG_ADDR_IPV6_SOA) && (request->qtype == DNS_T_AAAA)) {
|
||||
switch (request->qtype) {
|
||||
case DNS_T_A:
|
||||
if (flags & DOMAIN_FLAG_ADDR_IPV4_SOA) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_ADDR_IPV4_IGN) {
|
||||
request->skip_qtype_soa = 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case DNS_T_AAAA:
|
||||
if (flags & DOMAIN_FLAG_ADDR_IPV6_SOA) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_ADDR_IPV6_IGN) {
|
||||
request->skip_qtype_soa = 1;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_AAAA) {
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_FORCE_AAAA_SOA) == 0 || dns_conf_force_AAAA_SOA == 1) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -783,7 +828,7 @@ static int _dns_setup_dns_packet(struct dns_server_post_context *context)
|
||||
}
|
||||
|
||||
/* add request domain */
|
||||
ret = dns_add_domain(context->packet, request->domain, context->qtype, DNS_C_IN);
|
||||
ret = dns_add_domain(context->packet, request->domain, context->qtype, request->qclass);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -896,10 +941,57 @@ static int _dns_server_reply_udp(struct dns_request *request, struct dns_server_
|
||||
unsigned char *inpacket, int inpacket_len)
|
||||
{
|
||||
int send_len = 0;
|
||||
struct iovec iovec[1];
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
char msg_control[64];
|
||||
|
||||
if (atomic_read(&server.run) == 0 || inpacket == NULL || inpacket_len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
iovec[0].iov_base = inpacket;
|
||||
iovec[0].iov_len = inpacket_len;
|
||||
memset(msg_control, 0, sizeof(msg_control));
|
||||
msg.msg_iov = iovec;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = msg_control;
|
||||
msg.msg_controllen = sizeof(msg_control);
|
||||
msg.msg_flags = 0;
|
||||
msg.msg_name = &request->addr;
|
||||
msg.msg_namelen = request->addr_len;
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if (request->localaddr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *s4 = (struct sockaddr_in *)&request->localaddr;
|
||||
cmsg->cmsg_level = SOL_IP;
|
||||
cmsg->cmsg_type = IP_PKTINFO;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||
msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
|
||||
|
||||
struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
||||
memset(pktinfo, 0, sizeof(*pktinfo));
|
||||
pktinfo->ipi_spec_dst = s4->sin_addr;
|
||||
} else if (request->localaddr.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)&request->localaddr;
|
||||
cmsg->cmsg_level = IPPROTO_IPV6;
|
||||
cmsg->cmsg_type = IPV6_PKTINFO;
|
||||
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||
msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
|
||||
|
||||
struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
|
||||
memset(pktinfo, 0, sizeof(*pktinfo));
|
||||
pktinfo->ipi6_addr = s6->sin6_addr;
|
||||
} else {
|
||||
goto use_send;
|
||||
}
|
||||
|
||||
send_len = sendmsg(udpserver->head.fd, &msg, 0);
|
||||
if (send_len == inpacket_len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
use_send:
|
||||
send_len = sendto(udpserver->head.fd, inpacket, inpacket_len, 0, &request->addr, request->addr_len);
|
||||
if (send_len != inpacket_len) {
|
||||
tlog(TLOG_ERROR, "send failed, %s", strerror(errno));
|
||||
@@ -950,8 +1042,6 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
|
||||
speed = request->ping_time;
|
||||
|
||||
if (has_soa) {
|
||||
struct dns_cache_query_option cache_option;
|
||||
|
||||
if (request->dualstack_selection && request->has_ip && request->qtype == DNS_T_AAAA) {
|
||||
ttl = _dns_server_get_conf_ttl(request->ip_ttl);
|
||||
} else {
|
||||
@@ -961,27 +1051,31 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
|
||||
}
|
||||
}
|
||||
|
||||
cache_option.query_flag = request->server_flags;
|
||||
cache_option.dns_group_name = 0;
|
||||
dns_cache_set_data_soa(cache_data, &cache_option, request->cname, request->ttl_cname);
|
||||
dns_cache_set_data_soa(cache_data, request->cname, request->ttl_cname);
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "cache %s qtype: %d ttl: %d\n", request->domain, qtype, ttl);
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
struct dns_cache_key cache_key;
|
||||
cache_key.dns_group_name = request->dns_group_name;
|
||||
cache_key.domain = request->domain;
|
||||
cache_key.qtype = request->qtype;
|
||||
cache_key.query_flag = request->server_flags;
|
||||
|
||||
if (request->prefetch) {
|
||||
if (request->prefetch_expired_domain == 0) {
|
||||
if (dns_cache_replace(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
if (dns_cache_replace(&cache_key, ttl, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
if (dns_cache_replace_inactive(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
if (dns_cache_replace_inactive(&cache_key, ttl, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* insert result to cache */
|
||||
if (dns_cache_insert(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
if (dns_cache_insert(&cache_key, ttl, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
@@ -998,7 +1092,6 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
||||
{
|
||||
struct dns_packet *packet = context->packet;
|
||||
struct dns_packet *cname_packet = NULL;
|
||||
struct dns_cache_query_option cache_option;
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
@@ -1097,9 +1190,7 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
||||
return -1;
|
||||
}
|
||||
|
||||
cache_option.query_flag = request->server_flags;
|
||||
cache_option.dns_group_name = request->dns_group_name;
|
||||
cache_packet = dns_cache_new_data_packet(&cache_option, inpacket_buff, inpacket_len);
|
||||
cache_packet = dns_cache_new_data_packet(inpacket_buff, inpacket_len);
|
||||
if (cache_packet == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1114,19 +1205,25 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
||||
tlog(TLOG_DEBUG, "Cache CNAME: %s, qtype: %d, speed: %d", request->cname, request->qtype, speed);
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
struct dns_cache_key cache_key;
|
||||
cache_key.dns_group_name = request->dns_group_name;
|
||||
cache_key.domain = request->cname;
|
||||
cache_key.qtype = context->qtype;
|
||||
cache_key.query_flag = request->server_flags;
|
||||
|
||||
if (request->prefetch) {
|
||||
if (request->prefetch_expired_domain == 0) {
|
||||
if (dns_cache_replace(request->cname, ttl, context->qtype, speed, cache_packet) != 0) {
|
||||
if (dns_cache_replace(&cache_key, ttl, speed, cache_packet) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
if (dns_cache_replace_inactive(request->cname, ttl, context->qtype, speed, cache_packet) != 0) {
|
||||
if (dns_cache_replace_inactive(&cache_key, ttl, speed, cache_packet) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* insert result to cache */
|
||||
if (dns_cache_insert(request->cname, ttl, context->qtype, speed, cache_packet) != 0) {
|
||||
if (dns_cache_insert(&cache_key, ttl, speed, cache_packet) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
@@ -1142,25 +1239,28 @@ errout:
|
||||
|
||||
static int _dns_cache_packet(struct dns_server_post_context *context)
|
||||
{
|
||||
struct dns_cache_query_option cache_option;
|
||||
struct dns_request *request = context->request;
|
||||
|
||||
cache_option.query_flag = request->server_flags;
|
||||
cache_option.dns_group_name = request->dns_group_name;
|
||||
struct dns_cache_data *cache_packet =
|
||||
dns_cache_new_data_packet(&cache_option, context->inpacket, context->inpacket_len);
|
||||
struct dns_cache_data *cache_packet = dns_cache_new_data_packet(context->inpacket, context->inpacket_len);
|
||||
if (cache_packet == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
|
||||
struct dns_cache_key cache_key;
|
||||
cache_key.dns_group_name = request->dns_group_name;
|
||||
cache_key.domain = request->domain;
|
||||
cache_key.qtype = context->qtype;
|
||||
cache_key.query_flag = request->server_flags;
|
||||
|
||||
if (request->prefetch) {
|
||||
if (dns_cache_replace(request->domain, context->reply_ttl, context->qtype, -1, cache_packet) != 0) {
|
||||
if (dns_cache_replace(&cache_key, context->reply_ttl, -1, cache_packet) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
/* insert result to cache */
|
||||
if (dns_cache_insert(request->domain, context->reply_ttl, context->qtype, -1, cache_packet) != 0) {
|
||||
if (dns_cache_insert(&cache_key, context->reply_ttl, -1, cache_packet) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
@@ -1259,12 +1359,18 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (context->packet->head.rcode == DNS_RC_SERVFAIL || context->packet->head.rcode == DNS_RC_NXDOMAIN) {
|
||||
if (context->packet->head.rcode == DNS_RC_SERVFAIL || context->packet->head.rcode == DNS_RC_NXDOMAIN ||
|
||||
context->packet->head.rcode == DNS_RC_NOTIMP) {
|
||||
context->reply_ttl = DNS_SERVER_FAIL_TTL;
|
||||
/* Do not cache record if cannot connect to remote */
|
||||
if (request->remote_server_fail == 0 && context->packet->head.rcode == DNS_RC_SERVFAIL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (context->packet->head.rcode == DNS_RC_NOTIMP) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _dns_cache_packet(context);
|
||||
}
|
||||
|
||||
@@ -1272,11 +1378,7 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
|
||||
return _dns_cache_specify_packet(context);
|
||||
}
|
||||
|
||||
struct dns_cache_query_option cache_option;
|
||||
cache_option.query_flag = request->server_flags;
|
||||
cache_option.dns_group_name = request->dns_group_name;
|
||||
struct dns_cache_data *cache_packet =
|
||||
dns_cache_new_data_packet(&cache_option, context->inpacket, context->inpacket_len);
|
||||
struct dns_cache_data *cache_packet = dns_cache_new_data_packet(context->inpacket, context->inpacket_len);
|
||||
if (cache_packet == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1298,7 +1400,7 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_setup_ipset_packet(struct dns_server_post_context *context)
|
||||
static int _dns_server_setup_ipset_nftset_packet(struct dns_server_post_context *context)
|
||||
{
|
||||
int ttl = 0;
|
||||
struct dns_request *request = context->request;
|
||||
@@ -1311,6 +1413,8 @@ static int _dns_server_setup_ipset_packet(struct dns_server_post_context *contex
|
||||
struct dns_ipset_rule *ipset_rule = NULL;
|
||||
struct dns_ipset_rule *ipset_rule_v4 = NULL;
|
||||
struct dns_ipset_rule *ipset_rule_v6 = NULL;
|
||||
struct dns_nftset_rule *nftset_ip = NULL;
|
||||
struct dns_nftset_rule *nftset_ip6 = NULL;
|
||||
struct dns_rule_flags *rule_flags = NULL;
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_IPSET) == 0) {
|
||||
@@ -1330,14 +1434,24 @@ static int _dns_server_setup_ipset_packet(struct dns_server_post_context *contex
|
||||
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
|
||||
ipset_rule = _dns_server_get_dns_rule(request, DOMAIN_RULE_IPSET);
|
||||
}
|
||||
|
||||
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 (!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 || ipset_rule_v4 || ipset_rule_v6)) {
|
||||
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 (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_NFTSET_IP6_IGN) == 0) {
|
||||
nftset_ip6 = _dns_server_get_dns_rule(request, DOMAIN_RULE_NFTSET_IP6);
|
||||
}
|
||||
|
||||
if (!(ipset_rule || ipset_rule_v4 || ipset_rule_v6 || nftset_ip || nftset_ip6)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1354,14 +1468,21 @@ static int _dns_server_setup_ipset_packet(struct dns_server_post_context *contex
|
||||
dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
|
||||
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
|
||||
if (rule == NULL) {
|
||||
break;
|
||||
if (rule != NULL) {
|
||||
/* add IPV4 to ipset */
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH: domain: %s, ipset: %s, IP: %d.%d.%d.%d", request->domain,
|
||||
rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
|
||||
ipset_add(rule->ipsetname, addr, DNS_RR_A_LEN, request->ip_ttl * 2);
|
||||
}
|
||||
|
||||
/* add IPV4 to ipset */
|
||||
ipset_add(rule->ipsetname, addr, DNS_RR_A_LEN, request->ip_ttl * 2);
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH: domain: %s, ipset: %s, IP: %d.%d.%d.%d", request->domain,
|
||||
rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
|
||||
if (nftset_ip != NULL) {
|
||||
/* add IPV4 to ipset */
|
||||
tlog(TLOG_DEBUG, "NFTSET-MATCH: domain: %s, nftset: %s %s %s, IP: %d.%d.%d.%d", request->domain,
|
||||
nftset_ip->familyname, nftset_ip->nfttablename, nftset_ip->nftsetname, addr[0], addr[1],
|
||||
addr[2], addr[3]);
|
||||
nftset_add(nftset_ip->familyname, nftset_ip->nfttablename, nftset_ip->nftsetname, addr,
|
||||
DNS_RR_A_LEN, request->ip_ttl * 2);
|
||||
}
|
||||
} break;
|
||||
case DNS_T_AAAA: {
|
||||
unsigned char addr[16];
|
||||
@@ -1372,16 +1493,27 @@ static int _dns_server_setup_ipset_packet(struct dns_server_post_context *contex
|
||||
dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
|
||||
rule = ipset_rule_v6 ? ipset_rule_v6 : ipset_rule;
|
||||
if (rule == NULL) {
|
||||
break;
|
||||
if (rule != NULL) {
|
||||
tlog(TLOG_DEBUG,
|
||||
"IPSET-MATCH: domain: %s, ipset: %s, IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, rule->ipsetname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
|
||||
addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14],
|
||||
addr[15]);
|
||||
ipset_add(rule->ipsetname, addr, DNS_RR_AAAA_LEN, request->ip_ttl * 2);
|
||||
}
|
||||
|
||||
ipset_add(rule->ipsetname, addr, DNS_RR_AAAA_LEN, request->ip_ttl * 2);
|
||||
tlog(TLOG_DEBUG,
|
||||
"IPSET-MATCH: domain: %s, ipset: %s, IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, rule->ipsetname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6],
|
||||
addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
|
||||
if (nftset_ip6 != NULL) {
|
||||
/* add IPV6 to ipset */
|
||||
tlog(TLOG_DEBUG,
|
||||
"NFTSET-MATCH: domain: %s, nftset: %s %s %s, IP: "
|
||||
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
|
||||
request->domain, nftset_ip6->familyname, nftset_ip6->nfttablename, nftset_ip6->nftsetname,
|
||||
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9],
|
||||
addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
|
||||
nftset_add(nftset_ip6->familyname, nftset_ip6->nfttablename, nftset_ip6->nftsetname, addr,
|
||||
DNS_RR_AAAA_LEN, request->ip_ttl * 2);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
@@ -1420,7 +1552,7 @@ static int _dns_request_post(struct dns_server_post_context *context)
|
||||
}
|
||||
|
||||
/* setup ipset */
|
||||
_dns_server_setup_ipset_packet(context);
|
||||
_dns_server_setup_ipset_nftset_packet(context);
|
||||
|
||||
if (context->do_reply == 0) {
|
||||
return 0;
|
||||
@@ -1913,7 +2045,9 @@ static int _dns_server_set_to_pending_list(struct dns_request *request)
|
||||
}
|
||||
|
||||
key = hash_string(request->domain);
|
||||
key = hash_string_initval(request->dns_group_name, key);
|
||||
key = jhash(&(request->qtype), sizeof(request->qtype), key);
|
||||
key = jhash(&(request->server_flags), sizeof(request->server_flags), key);
|
||||
pthread_mutex_lock(&server.request_pending_lock);
|
||||
hash_for_each_possible(server.request_pending, pending_list_tmp, node, key)
|
||||
{
|
||||
@@ -1921,6 +2055,14 @@ static int _dns_server_set_to_pending_list(struct dns_request *request)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (request->server_flags != pending_list_tmp->server_flags) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(request->dns_group_name, pending_list_tmp->dns_group_name) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(request->domain, pending_list_tmp->domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -1941,7 +2083,9 @@ static int _dns_server_set_to_pending_list(struct dns_request *request)
|
||||
INIT_LIST_HEAD(&pending_list->request_list);
|
||||
INIT_HLIST_NODE(&pending_list->node);
|
||||
pending_list->qtype = request->qtype;
|
||||
pending_list->server_flags = request->server_flags;
|
||||
safe_strncpy(pending_list->domain, request->domain, DNS_MAX_CNAME_LEN);
|
||||
safe_strncpy(pending_list->dns_group_name, request->dns_group_name, DNS_GROUP_NAME_LEN);
|
||||
hash_add(server.request_pending, &pending_list->node, key);
|
||||
request->request_pending_list = pending_list;
|
||||
} else {
|
||||
@@ -1981,6 +2125,7 @@ static struct dns_request *_dns_server_new_request(void)
|
||||
request->dualstack_selection_ping_time = -1;
|
||||
request->rcode = DNS_RC_SERVFAIL;
|
||||
request->conn = NULL;
|
||||
request->qclass = DNS_C_IN;
|
||||
request->result_callback = NULL;
|
||||
request->check_order_list = &dns_conf_check_orders;
|
||||
INIT_LIST_HEAD(&request->list);
|
||||
@@ -2459,6 +2604,10 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
|
||||
}
|
||||
|
||||
request->remote_server_fail = 0;
|
||||
if (request->rcode == DNS_RC_SERVFAIL) {
|
||||
request->rcode = packet->head.rcode;
|
||||
}
|
||||
|
||||
for (j = 1; j < DNS_RRS_END; j++) {
|
||||
rrs = dns_get_rrs_start(packet, j, &rr_count);
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
|
||||
@@ -2495,6 +2644,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);
|
||||
tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", name, ttl, cname);
|
||||
} break;
|
||||
case DNS_T_SOA: {
|
||||
@@ -2547,6 +2697,10 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, const
|
||||
}
|
||||
|
||||
request->remote_server_fail = 0;
|
||||
if (request->rcode == DNS_RC_SERVFAIL) {
|
||||
request->rcode = packet->head.rcode;
|
||||
}
|
||||
|
||||
for (j = 1; j < DNS_RRS_END; j++) {
|
||||
rrs = dns_get_rrs_start(packet, j, &rr_count);
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
|
||||
@@ -2769,7 +2923,7 @@ static int _dns_server_reply_passthrouth(struct dns_server_post_context *context
|
||||
|
||||
_dns_cache_reply_packet(context);
|
||||
|
||||
if (_dns_server_setup_ipset_packet(context) != 0) {
|
||||
if (_dns_server_setup_ipset_nftset_packet(context) != 0) {
|
||||
tlog(TLOG_DEBUG, "setup ipset failed.");
|
||||
}
|
||||
|
||||
@@ -2815,6 +2969,7 @@ static void _dns_server_query_end(struct dns_request *request)
|
||||
request->has_ping_result = 1;
|
||||
_dns_server_request_complete(request);
|
||||
}
|
||||
|
||||
out:
|
||||
_dns_server_request_release(request);
|
||||
}
|
||||
@@ -3161,33 +3316,40 @@ static int _dns_server_process_local_ptr(struct dns_request *request)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
char full_hostname[DNS_MAX_CNAME_LEN];
|
||||
if (dns_conf_server_name[0] == 0) {
|
||||
/* get local host name */
|
||||
if (getdomainname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
||||
if (gethostname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
||||
return -1;
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
char domainname[DNS_MAX_CNAME_LEN];
|
||||
|
||||
/* get local domain name */
|
||||
if (getdomainname(domainname, DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
/* check domain is valid */
|
||||
if (strncmp(domainname, "(none)", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
domainname[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* get host name again */
|
||||
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
if (gethostname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
||||
return -1;
|
||||
if (gethostname(hostname, DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
/* check hostname is valid */
|
||||
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
hostname[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* if hostname is (none), return smartdns */
|
||||
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
safe_strncpy(hostname, "smartdns", DNS_MAX_CNAME_LEN);
|
||||
if (hostname[0] != '\0' && domainname[0] != '\0') {
|
||||
snprintf(full_hostname, sizeof(full_hostname), "%.64s.%.128s", hostname, domainname);
|
||||
} else if (hostname[0] != '\0') {
|
||||
safe_strncpy(full_hostname, hostname, DNS_MAX_CNAME_LEN);
|
||||
} else {
|
||||
safe_strncpy(full_hostname, "smartdns", DNS_MAX_CNAME_LEN);
|
||||
}
|
||||
} else {
|
||||
/* return configured server name */
|
||||
safe_strncpy(hostname, dns_conf_server_name, DNS_MAX_CNAME_LEN);
|
||||
safe_strncpy(full_hostname, dns_conf_server_name, DNS_MAX_CNAME_LEN);
|
||||
}
|
||||
|
||||
request->has_ptr = 1;
|
||||
safe_strncpy(request->ptr_hostname, hostname, DNS_MAX_CNAME_LEN);
|
||||
safe_strncpy(request->ptr_hostname, full_hostname, DNS_MAX_CNAME_LEN);
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
return 0;
|
||||
@@ -3268,12 +3430,20 @@ static void _dns_server_update_rule_by_flags(struct dns_request *request)
|
||||
request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV6] = NULL;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_NFTSET_IP_IGN || flags & DOMAIN_FLAG_NFTSET_INET_IGN) {
|
||||
request->domain_rule.rules[DOMAIN_RULE_NFTSET_IP] = NULL;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_NFTSET_IP6_IGN || flags & DOMAIN_FLAG_NFTSET_INET_IGN) {
|
||||
request->domain_rule.rules[DOMAIN_RULE_NFTSET_IP6] = NULL;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_NAMESERVER_IGNORE) {
|
||||
request->domain_rule.rules[DOMAIN_RULE_NAMESERVER] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int _dns_server_get_rules(unsigned char *key, uint32_t key_len, void *value, void *arg)
|
||||
static int _dns_server_get_rules(unsigned char *key, uint32_t key_len, int is_subkey, void *value, void *arg)
|
||||
{
|
||||
struct rule_walk_args *walk_args = arg;
|
||||
struct dns_request *request = walk_args->args;
|
||||
@@ -3289,6 +3459,7 @@ static int _dns_server_get_rules(unsigned char *key, uint32_t key_len, void *val
|
||||
}
|
||||
|
||||
request->domain_rule.rules[i] = domain_rule->rules[i];
|
||||
request->domain_rule.is_sub_rule[i] = is_subkey;
|
||||
walk_args->key[i] = key;
|
||||
walk_args->key_len[i] = key_len;
|
||||
}
|
||||
@@ -3459,6 +3630,10 @@ static int _dns_server_qtype_soa(struct dns_request *request)
|
||||
{
|
||||
struct dns_qtype_soa_list *soa_list = NULL;
|
||||
|
||||
if (request->skip_qtype_soa) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t key = hash_32_generic(request->qtype, 32);
|
||||
hash_for_each_possible(dns_qtype_soa_table.qtype, soa_list, node, key)
|
||||
{
|
||||
@@ -3628,7 +3803,13 @@ static int _dns_server_process_cache(struct dns_request *request)
|
||||
goto out;
|
||||
}
|
||||
|
||||
dns_cache = dns_cache_lookup(request->domain, request->qtype);
|
||||
struct dns_cache_key cache_key;
|
||||
cache_key.dns_group_name = request->dns_group_name;
|
||||
cache_key.domain = request->domain;
|
||||
cache_key.qtype = request->qtype;
|
||||
cache_key.query_flag = request->server_flags;
|
||||
|
||||
dns_cache = dns_cache_lookup(&cache_key);
|
||||
if (dns_cache == NULL) {
|
||||
goto out;
|
||||
}
|
||||
@@ -3651,7 +3832,8 @@ static int _dns_server_process_cache(struct dns_request *request)
|
||||
goto out;
|
||||
}
|
||||
|
||||
dualstack_dns_cache = dns_cache_lookup(request->domain, dualstack_qtype);
|
||||
cache_key.qtype = dualstack_qtype;
|
||||
dualstack_dns_cache = dns_cache_lookup(&cache_key);
|
||||
if (dualstack_dns_cache && dns_cache_is_soa(dualstack_dns_cache) == 0 &&
|
||||
(dualstack_dns_cache->info.speed > 0)) {
|
||||
|
||||
@@ -3691,8 +3873,8 @@ out_update_cache:
|
||||
dns_query_options.server_flags = request->server_flags;
|
||||
dns_query_options.dns_group_name = request->dns_group_name;
|
||||
if (request->conn == NULL) {
|
||||
dns_query_options.server_flags = dns_cache_get_query_flag(dns_cache->cache_data);
|
||||
dns_query_options.dns_group_name = dns_cache_get_dns_group_name(dns_cache->cache_data);
|
||||
dns_query_options.server_flags = dns_cache_get_query_flag(dns_cache);
|
||||
dns_query_options.dns_group_name = dns_cache_get_dns_group_name(dns_cache);
|
||||
}
|
||||
|
||||
dns_query_options.ecs_enable_flag = 0;
|
||||
@@ -3828,6 +4010,10 @@ static int _dns_server_process_smartdns_domain(struct dns_request *request)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_dns_server_is_dns_rule_extact_match(request, DOMAIN_RULE_FLAGS) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
flags = rule_flag->flags;
|
||||
if (!(flags & DOMAIN_FLAG_SMARTDNS_DOMAIN)) {
|
||||
return -1;
|
||||
@@ -4018,7 +4204,7 @@ static int _dns_server_query_dualstack(struct dns_request *request)
|
||||
request_dualstack->dualstack_request = request;
|
||||
_dns_server_request_set_callback(request_dualstack, dns_server_dualstack_callback, request);
|
||||
request->request_wait++;
|
||||
ret = _dns_server_do_query(request_dualstack);
|
||||
ret = _dns_server_do_query(request_dualstack, 0);
|
||||
if (ret != 0) {
|
||||
request->request_wait--;
|
||||
tlog(TLOG_ERROR, "do query %s type %d failed.\n", request->domain, qtype);
|
||||
@@ -4038,7 +4224,7 @@ errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_server_do_query(struct dns_request *request)
|
||||
static int _dns_server_do_query(struct dns_request *request, int skip_notify_event)
|
||||
{
|
||||
int ret = -1;
|
||||
const char *group_name = NULL;
|
||||
@@ -4114,6 +4300,9 @@ static int _dns_server_do_query(struct dns_request *request)
|
||||
_dns_server_setup_query_option(request, &options);
|
||||
|
||||
pthread_mutex_lock(&server.request_list_lock);
|
||||
if (list_empty(&server.request_list) && skip_notify_event == 1) {
|
||||
_dns_server_wakup_thread();
|
||||
}
|
||||
list_add_tail(&request->list, &server.request_list);
|
||||
pthread_mutex_unlock(&server.request_list_lock);
|
||||
|
||||
@@ -4138,6 +4327,20 @@ errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_server_check_request_supported(struct dns_request *request, struct dns_packet *packet)
|
||||
{
|
||||
if (request->qclass != DNS_C_IN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (packet->head.opcode != DNS_OP_QUERY) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_parser_request(struct dns_request *request, struct dns_packet *packet)
|
||||
{
|
||||
struct dns_rrs *rrs = NULL;
|
||||
@@ -4170,6 +4373,11 @@ static int _dns_server_parser_request(struct dns_request *request, struct dns_pa
|
||||
break;
|
||||
}
|
||||
|
||||
request->qclass = qclass;
|
||||
if (_dns_server_check_request_supported(request, packet) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* get request opts */
|
||||
rr_count = 0;
|
||||
rrs = dns_get_rrs_start(packet, DNS_RRS_OPT, &rr_count);
|
||||
@@ -4188,6 +4396,7 @@ static int _dns_server_parser_request(struct dns_request *request, struct dns_pa
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
request->rcode = DNS_RC_NOTIMP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -4227,6 +4436,11 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memcpy(&request->localaddr, local, local_len);
|
||||
_dns_server_request_set_client(request, conn);
|
||||
_dns_server_request_set_client_addr(request, from, from_len);
|
||||
_dns_server_request_set_id(request, packet->head.id);
|
||||
|
||||
if (_dns_server_parser_request(request, packet) != 0) {
|
||||
tlog(TLOG_DEBUG, "parser request failed.");
|
||||
ret = RECV_ERROR_INVALID_PACKET;
|
||||
@@ -4235,11 +4449,7 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
|
||||
|
||||
tlog(TLOG_INFO, "query server %s from %s, qtype = %d\n", request->domain, name, request->qtype);
|
||||
|
||||
memcpy(&request->localaddr, local, local_len);
|
||||
_dns_server_request_set_client(request, conn);
|
||||
_dns_server_request_set_client_addr(request, from, from_len);
|
||||
_dns_server_request_set_id(request, packet->head.id);
|
||||
ret = _dns_server_do_query(request);
|
||||
ret = _dns_server_do_query(request, 1);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "do query %s failed.\n", request->domain);
|
||||
goto errout;
|
||||
@@ -4291,7 +4501,7 @@ static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expi
|
||||
request->qtype = qtype;
|
||||
_dns_server_setup_server_query_options(request, server_query_option);
|
||||
_dns_server_request_set_enable_prefetch(request, expired_domain);
|
||||
ret = _dns_server_do_query(request);
|
||||
ret = _dns_server_do_query(request, 0);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "do query %s failed.\n", request->domain);
|
||||
goto errout;
|
||||
@@ -4323,7 +4533,7 @@ int dns_server_query(const char *domain, int qtype, struct dns_server_query_opti
|
||||
request->qtype = qtype;
|
||||
_dns_server_setup_server_query_options(request, server_query_option);
|
||||
_dns_server_request_set_callback(request, callback, user_ptr);
|
||||
ret = _dns_server_do_query(request);
|
||||
ret = _dns_server_do_query(request, 0);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "do query %s failed.\n", domain);
|
||||
goto errout;
|
||||
@@ -4726,8 +4936,8 @@ static void _dns_server_prefetch_domain(struct dns_cache *dns_cache)
|
||||
/* start prefetch domain */
|
||||
tlog(TLOG_DEBUG, "prefetch by cache %s, qtype %d, ttl %d, hitnum %d", dns_cache->info.domain, dns_cache->info.qtype,
|
||||
dns_cache->info.ttl, hitnum);
|
||||
server_query_option.dns_group_name = dns_cache_get_dns_group_name(dns_cache->cache_data);
|
||||
server_query_option.server_flags = dns_cache_get_query_flag(dns_cache->cache_data);
|
||||
server_query_option.dns_group_name = dns_cache_get_dns_group_name(dns_cache);
|
||||
server_query_option.server_flags = dns_cache_get_query_flag(dns_cache);
|
||||
server_query_option.ecs_enable_flag = 0;
|
||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 0, &server_query_option) != 0) {
|
||||
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
|
||||
@@ -4741,8 +4951,8 @@ static void _dns_server_prefetch_expired_domain(struct dns_cache *dns_cache)
|
||||
dns_cache->info.qtype, dns_cache->info.ttl);
|
||||
|
||||
struct dns_server_query_option server_query_option;
|
||||
server_query_option.dns_group_name = dns_cache_get_dns_group_name(dns_cache->cache_data);
|
||||
server_query_option.server_flags = dns_cache_get_query_flag(dns_cache->cache_data);
|
||||
server_query_option.dns_group_name = dns_cache_get_dns_group_name(dns_cache);
|
||||
server_query_option.server_flags = dns_cache_get_query_flag(dns_cache);
|
||||
server_query_option.ecs_enable_flag = 0;
|
||||
|
||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 1, &server_query_option) != 0) {
|
||||
@@ -4829,14 +5039,12 @@ static void _dns_server_period_run_second(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void _dns_server_period_run(void)
|
||||
static void _dns_server_period_run(unsigned int msec)
|
||||
{
|
||||
struct dns_request *request = NULL;
|
||||
struct dns_request *tmp = NULL;
|
||||
static unsigned int msec = 0;
|
||||
LIST_HEAD(check_list);
|
||||
|
||||
msec++;
|
||||
if (msec % 10 == 0) {
|
||||
_dns_server_period_run_second();
|
||||
}
|
||||
@@ -4904,22 +5112,50 @@ int dns_server_run(void)
|
||||
int num = 0;
|
||||
int i = 0;
|
||||
unsigned long now = {0};
|
||||
unsigned long last = {0};
|
||||
unsigned int msec = 0;
|
||||
int sleep = 100;
|
||||
int sleep_time = 0;
|
||||
unsigned long expect_time = 0;
|
||||
|
||||
sleep_time = sleep;
|
||||
now = get_tick_count() - sleep;
|
||||
last = now;
|
||||
expect_time = now + sleep;
|
||||
while (atomic_read(&server.run)) {
|
||||
now = get_tick_count();
|
||||
if (sleep_time > 0) {
|
||||
sleep_time -= now - last;
|
||||
if (sleep_time <= 0) {
|
||||
sleep_time = 0;
|
||||
}
|
||||
|
||||
int cnt = sleep_time / sleep;
|
||||
msec -= cnt;
|
||||
expect_time -= cnt * sleep;
|
||||
sleep_time -= cnt * sleep;
|
||||
}
|
||||
last = now;
|
||||
|
||||
if (now >= expect_time) {
|
||||
_dns_server_period_run();
|
||||
msec++;
|
||||
_dns_server_period_run(msec);
|
||||
sleep_time = sleep - (now - expect_time);
|
||||
if (sleep_time < 0) {
|
||||
sleep_time = 0;
|
||||
expect_time = now;
|
||||
}
|
||||
|
||||
/* When server is idle, the sleep time is 1000ms, to reduce CPU usage */
|
||||
pthread_mutex_lock(&server.request_list_lock);
|
||||
if (list_empty(&server.request_list)) {
|
||||
int cnt = 10 - (msec % 10) - 1;
|
||||
sleep_time += sleep * cnt;
|
||||
msec += cnt;
|
||||
/* sleep to next second */
|
||||
expect_time += sleep * cnt;
|
||||
}
|
||||
pthread_mutex_unlock(&server.request_list_lock);
|
||||
expect_time += sleep;
|
||||
}
|
||||
|
||||
@@ -4935,6 +5171,14 @@ int dns_server_run(void)
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
struct epoll_event *event = &events[i];
|
||||
/* read event */
|
||||
if (event->data.fd == server.event_fd) {
|
||||
uint64_t value;
|
||||
int unused __attribute__((unused));
|
||||
unused = read(server.event_fd, &value, sizeof(uint64_t));
|
||||
continue;
|
||||
}
|
||||
|
||||
struct dns_server_conn_head *conn_head = event->data.ptr;
|
||||
if (conn_head == NULL) {
|
||||
tlog(TLOG_ERROR, "invalid fd\n");
|
||||
@@ -5258,6 +5502,31 @@ static int _dns_server_cache_save(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_init_wakeup_event(void)
|
||||
{
|
||||
int fdevent = -1;
|
||||
fdevent = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
if (fdevent < 0) {
|
||||
tlog(TLOG_ERROR, "create eventfd failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
struct epoll_event event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN | EPOLLERR;
|
||||
event.data.fd = fdevent;
|
||||
if (epoll_ctl(server.epoll_fd, EPOLL_CTL_ADD, fdevent, &event) != 0) {
|
||||
tlog(TLOG_ERROR, "set eventfd failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
server.event_fd = fdevent;
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_server_init(void)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
@@ -5308,6 +5577,11 @@ int dns_server_init(void)
|
||||
tlog(TLOG_INFO, "%s",
|
||||
(is_ipv6_ready) ? "IPV6 is ready, enable IPV6 features" : "IPV6 is not ready, disable IPV6 features");
|
||||
|
||||
if (_dns_server_init_wakeup_event() != 0) {
|
||||
tlog(TLOG_ERROR, "init wakeup event failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
atomic_set(&server.run, 0);
|
||||
@@ -5327,10 +5601,15 @@ errout:
|
||||
void dns_server_stop(void)
|
||||
{
|
||||
atomic_set(&server.run, 0);
|
||||
_dns_server_wakup_thread();
|
||||
}
|
||||
|
||||
void dns_server_exit(void)
|
||||
{
|
||||
if (server.event_fd > 0) {
|
||||
close(server.event_fd);
|
||||
server.event_fd = -1;
|
||||
}
|
||||
_dns_server_close_socket();
|
||||
_dns_server_cache_save();
|
||||
_dns_server_request_remove_all();
|
||||
|
||||
282
src/fast_ping.c
282
src/fast_ping.c
@@ -19,6 +19,7 @@
|
||||
#include "fast_ping.h"
|
||||
#include "atomic.h"
|
||||
#include "hashtable.h"
|
||||
#include "list.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
#include <arpa/inet.h>
|
||||
@@ -36,6 +37,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
@@ -62,6 +65,9 @@ struct ping_dns_head {
|
||||
unsigned short ancount;
|
||||
unsigned short aucount;
|
||||
unsigned short adcount;
|
||||
char qd_name;
|
||||
unsigned short q_qtype;
|
||||
unsigned short q_qclass;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef enum FAST_PING_TYPE {
|
||||
@@ -123,6 +129,15 @@ struct ping_host_struct {
|
||||
struct fast_ping_packet packet;
|
||||
};
|
||||
|
||||
struct fast_ping_notify_event {
|
||||
struct list_head list;
|
||||
struct ping_host_struct *ping_host;
|
||||
FAST_PING_RESULT ping_result;
|
||||
unsigned int seq;
|
||||
int ttl;
|
||||
struct timeval tvresult;
|
||||
};
|
||||
|
||||
struct fast_ping_struct {
|
||||
atomic_t run;
|
||||
pthread_t tid;
|
||||
@@ -140,6 +155,12 @@ struct fast_ping_struct {
|
||||
int fd_udp6;
|
||||
struct ping_host_struct udp6_host;
|
||||
|
||||
int event_fd;
|
||||
pthread_t notify_tid;
|
||||
pthread_cond_t notify_cond;
|
||||
pthread_mutex_t notify_lock;
|
||||
struct list_head notify_event_list;
|
||||
|
||||
pthread_mutex_t map_lock;
|
||||
DECLARE_HASHTABLE(addrmap, 6);
|
||||
};
|
||||
@@ -148,6 +169,15 @@ static struct fast_ping_struct ping;
|
||||
static atomic_t ping_sid = ATOMIC_INIT(0);
|
||||
static int bool_print_log = 1;
|
||||
|
||||
static void _fast_ping_host_put(struct ping_host_struct *ping_host);
|
||||
|
||||
static void _fast_ping_wakup_thread(void)
|
||||
{
|
||||
uint64_t u = 1;
|
||||
int unused __attribute__((unused));
|
||||
unused = write(ping.event_fd, &u, sizeof(u));
|
||||
}
|
||||
|
||||
static uint16_t _fast_ping_checksum(uint16_t *header, size_t len)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
@@ -365,6 +395,53 @@ static void _fast_ping_close_host_sock(struct ping_host_struct *ping_host)
|
||||
ping_host->fd = -1;
|
||||
}
|
||||
|
||||
static void _fast_ping_release_notify_event(struct fast_ping_notify_event *ping_notify_event)
|
||||
{
|
||||
pthread_mutex_lock(&ping.notify_lock);
|
||||
list_del_init(&ping_notify_event->list);
|
||||
pthread_mutex_unlock(&ping.notify_lock);
|
||||
|
||||
if (ping_notify_event->ping_host) {
|
||||
_fast_ping_host_put(ping_notify_event->ping_host);
|
||||
ping_notify_event->ping_host = NULL;
|
||||
}
|
||||
free(ping_notify_event);
|
||||
}
|
||||
|
||||
static int _fast_ping_send_notify_event(struct ping_host_struct *ping_host, FAST_PING_RESULT ping_result,
|
||||
unsigned int seq, int ttl, struct timeval *tvresult)
|
||||
{
|
||||
struct fast_ping_notify_event *notify_event = NULL;
|
||||
|
||||
notify_event = malloc(sizeof(struct fast_ping_notify_event));
|
||||
if (notify_event == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memset(notify_event, 0, sizeof(struct fast_ping_notify_event));
|
||||
INIT_LIST_HEAD(¬ify_event->list);
|
||||
notify_event->seq = seq;
|
||||
notify_event->ttl = ttl;
|
||||
notify_event->ping_result = ping_result;
|
||||
notify_event->tvresult = *tvresult;
|
||||
|
||||
pthread_mutex_lock(&ping.notify_lock);
|
||||
if (list_empty(&ping.notify_event_list)) {
|
||||
pthread_cond_signal(&ping.notify_cond);
|
||||
}
|
||||
list_add_tail(¬ify_event->list, &ping.notify_event_list);
|
||||
notify_event->ping_host = ping_host;
|
||||
_fast_ping_host_get(ping_host);
|
||||
pthread_mutex_unlock(&ping.notify_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (notify_event) {
|
||||
_fast_ping_release_notify_event(notify_event);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _fast_ping_host_put(struct ping_host_struct *ping_host)
|
||||
{
|
||||
int ref_cnt = atomic_dec_and_test(&ping_host->ref);
|
||||
@@ -387,8 +464,7 @@ static void _fast_ping_host_put(struct ping_host_struct *ping_host)
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len,
|
||||
ping_host->seq, ping_host->ttl, &tv, ping_host->error, ping_host->userptr);
|
||||
_fast_ping_send_notify_event(ping_host, PING_RESULT_END, ping_host->seq, ping_host->ttl, &tv);
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "ping %s end, id %d", ping_host->host, ping_host->sid);
|
||||
@@ -414,8 +490,7 @@ static void _fast_ping_host_remove(struct ping_host_struct *ping_host)
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len,
|
||||
ping_host->seq, ping_host->ttl, &tv, ping_host->error, ping_host->userptr);
|
||||
_fast_ping_send_notify_event(ping_host, PING_RESULT_END, ping_host->seq, ping_host->ttl, &tv);
|
||||
}
|
||||
|
||||
_fast_ping_host_put(ping_host);
|
||||
@@ -537,6 +612,11 @@ static int _fast_ping_sendping_udp(struct ping_host_struct *ping_host)
|
||||
memset(&dns_head, 0, sizeof(dns_head));
|
||||
dns_head.id = htons(ping_host->sid);
|
||||
dns_head.flag = flag;
|
||||
dns_head.qdcount = htons(1);
|
||||
dns_head.qd_name = 0;
|
||||
dns_head.q_qtype = htons(2); /* DNS_T_NS */
|
||||
dns_head.q_qclass = htons(1);
|
||||
|
||||
gettimeofday(&ping_host->last, NULL);
|
||||
len = sendto(fd, &dns_head, sizeof(dns_head), 0, &ping_host->addr, ping_host->addr_len);
|
||||
if (len < 0 || len != sizeof(dns_head)) {
|
||||
@@ -646,6 +726,8 @@ static int _fast_ping_sendping(struct ping_host_struct *ping_host)
|
||||
if (ret != 0) {
|
||||
ping_host->error = errno;
|
||||
return ret;
|
||||
} else {
|
||||
ping_host->error = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1122,6 +1204,9 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c
|
||||
|
||||
pthread_mutex_lock(&ping.map_lock);
|
||||
_fast_ping_host_get(ping_host);
|
||||
if (hash_empty(ping.addrmap)) {
|
||||
_fast_ping_wakup_thread();
|
||||
}
|
||||
hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
|
||||
ping_host->run = 1;
|
||||
pthread_mutex_unlock(&ping.map_lock);
|
||||
@@ -1194,7 +1279,7 @@ static struct fast_ping_packet *_fast_ping_icmp6_packet(struct ping_host_struct
|
||||
|
||||
packet->ttl = hops;
|
||||
if (icmp6->icmp6_type != ICMP6_ECHO_REPLY) {
|
||||
tlog(TLOG_DEBUG, "icmp6 type faild, %d:%d", icmp6->icmp6_type, ICMP6_ECHO_REPLY);
|
||||
errno = ENETUNREACH;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1235,7 +1320,7 @@ static struct fast_ping_packet *_fast_ping_icmp_packet(struct ping_host_struct *
|
||||
}
|
||||
|
||||
if (icmp->icmp_type != ICMP_ECHOREPLY) {
|
||||
tlog(TLOG_DEBUG, "icmp type faild, %d:%d", icmp->icmp_type, ICMP_ECHOREPLY);
|
||||
errno = ENETUNREACH;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1317,6 +1402,10 @@ static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct ti
|
||||
packet = _fast_ping_recv_packet(ping_host, &msg, inpacket, len, now);
|
||||
if (packet == NULL) {
|
||||
char name[PING_MAX_HOSTLEN];
|
||||
if (errno == ENETUNREACH) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "recv ping packet from %s failed.",
|
||||
gethost_by_addr(name, sizeof(name), (struct sockaddr *)&from));
|
||||
goto errout;
|
||||
@@ -1353,9 +1442,8 @@ static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct ti
|
||||
recv_ping_host->ttl = packet->ttl;
|
||||
tv_sub(&tvresult, tvsend);
|
||||
if (recv_ping_host->ping_callback) {
|
||||
recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr,
|
||||
recv_ping_host->addr_len, recv_ping_host->seq, recv_ping_host->ttl, &tvresult,
|
||||
ping_host->error, recv_ping_host->userptr);
|
||||
_fast_ping_send_notify_event(recv_ping_host, PING_RESULT_RESPONSE, recv_ping_host->seq, recv_ping_host->ttl,
|
||||
&tvresult);
|
||||
}
|
||||
|
||||
recv_ping_host->send = 0;
|
||||
@@ -1388,9 +1476,7 @@ static int _fast_ping_process_tcp(struct ping_host_struct *ping_host, struct epo
|
||||
}
|
||||
tv_sub(&tvresult, tvsend);
|
||||
if (ping_host->ping_callback) {
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr,
|
||||
ping_host->addr_len, ping_host->seq, ping_host->ttl, &tvresult, ping_host->error,
|
||||
ping_host->userptr);
|
||||
_fast_ping_send_notify_event(ping_host, PING_RESULT_RESPONSE, ping_host->seq, ping_host->ttl, &tvresult);
|
||||
}
|
||||
|
||||
ping_host->send = 0;
|
||||
@@ -1484,9 +1570,8 @@ static int _fast_ping_process_udp(struct ping_host_struct *ping_host, struct tim
|
||||
tvsend = &recv_ping_host->last;
|
||||
tv_sub(&tvresult, tvsend);
|
||||
if (recv_ping_host->ping_callback) {
|
||||
recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr,
|
||||
recv_ping_host->addr_len, recv_ping_host->seq, recv_ping_host->ttl, &tvresult,
|
||||
ping_host->error, recv_ping_host->userptr);
|
||||
_fast_ping_send_notify_event(recv_ping_host, PING_RESULT_RESPONSE, recv_ping_host->seq, recv_ping_host->ttl,
|
||||
&tvresult);
|
||||
}
|
||||
|
||||
recv_ping_host->send = 0;
|
||||
@@ -1593,9 +1678,7 @@ static void _fast_ping_period_run(void)
|
||||
tv_sub(&interval, &ping_host->last);
|
||||
millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000;
|
||||
if (millisecond >= ping_host->timeout && ping_host->send == 1) {
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr,
|
||||
ping_host->addr_len, ping_host->seq, ping_host->ttl, &interval, ping_host->error,
|
||||
ping_host->userptr);
|
||||
_fast_ping_send_notify_event(ping_host, PING_RESULT_TIMEOUT, ping_host->seq, ping_host->ttl, &interval);
|
||||
ping_host->send = 0;
|
||||
}
|
||||
|
||||
@@ -1621,22 +1704,84 @@ static void _fast_ping_period_run(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void _fast_ping_process_notify_event(struct fast_ping_notify_event *ping_notify_event)
|
||||
{
|
||||
struct ping_host_struct *ping_host = ping_notify_event->ping_host;
|
||||
if (ping_host == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ping_host->ping_callback(ping_host, ping_host->host, ping_notify_event->ping_result, &ping_host->addr,
|
||||
ping_host->addr_len, ping_notify_event->seq, ping_notify_event->ttl,
|
||||
&ping_notify_event->tvresult, ping_host->error, ping_host->userptr);
|
||||
}
|
||||
|
||||
static void *_fast_ping_notify_worker(void *arg)
|
||||
{
|
||||
struct fast_ping_notify_event *ping_notify_event = NULL;
|
||||
|
||||
while (atomic_read(&ping.run)) {
|
||||
pthread_mutex_lock(&ping.notify_lock);
|
||||
if (list_empty(&ping.notify_event_list)) {
|
||||
pthread_cond_wait(&ping.notify_cond, &ping.notify_lock);
|
||||
}
|
||||
|
||||
ping_notify_event = list_first_entry_or_null(&ping.notify_event_list, struct fast_ping_notify_event, list);
|
||||
if (ping_notify_event) {
|
||||
list_del_init(&ping_notify_event->list);
|
||||
}
|
||||
pthread_mutex_unlock(&ping.notify_lock);
|
||||
|
||||
if (ping_notify_event == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_fast_ping_process_notify_event(ping_notify_event);
|
||||
_fast_ping_release_notify_event(ping_notify_event);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void _fast_ping_remove_all_notify_event(void)
|
||||
{
|
||||
struct fast_ping_notify_event *notify_event = NULL;
|
||||
struct fast_ping_notify_event *tmp = NULL;
|
||||
list_for_each_entry_safe(notify_event, tmp, &ping.notify_event_list, list)
|
||||
{
|
||||
_fast_ping_process_notify_event(notify_event);
|
||||
_fast_ping_release_notify_event(notify_event);
|
||||
}
|
||||
}
|
||||
|
||||
static void *_fast_ping_work(void *arg)
|
||||
{
|
||||
struct epoll_event events[PING_MAX_EVENTS + 1];
|
||||
int num = 0;
|
||||
int i = 0;
|
||||
unsigned long now = {0};
|
||||
unsigned long last = {0};
|
||||
struct timeval tvnow = {0};
|
||||
int sleep = 100;
|
||||
int sleep_time = 0;
|
||||
unsigned long expect_time = 0;
|
||||
|
||||
setpriority(PRIO_PROCESS, 0, -5);
|
||||
|
||||
sleep_time = sleep;
|
||||
now = get_tick_count() - sleep;
|
||||
last = now;
|
||||
expect_time = now + sleep;
|
||||
while (atomic_read(&ping.run)) {
|
||||
now = get_tick_count();
|
||||
if (sleep_time > 0) {
|
||||
sleep_time -= now - last;
|
||||
if (sleep_time <= 0) {
|
||||
sleep_time = 0;
|
||||
}
|
||||
}
|
||||
last = now;
|
||||
|
||||
if (now >= expect_time) {
|
||||
_fast_ping_period_run();
|
||||
sleep_time = sleep - (now - expect_time);
|
||||
@@ -1647,12 +1792,22 @@ static void *_fast_ping_work(void *arg)
|
||||
expect_time += sleep;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ping.map_lock);
|
||||
if (hash_empty(ping.addrmap)) {
|
||||
sleep_time = -1;
|
||||
}
|
||||
pthread_mutex_unlock(&ping.map_lock);
|
||||
|
||||
num = epoll_wait(ping.epoll_fd, events, PING_MAX_EVENTS, sleep_time);
|
||||
if (num < 0) {
|
||||
usleep(100000);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sleep_time == -1) {
|
||||
expect_time = get_tick_count();
|
||||
}
|
||||
|
||||
if (num == 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -1660,6 +1815,14 @@ static void *_fast_ping_work(void *arg)
|
||||
gettimeofday(&tvnow, NULL);
|
||||
for (i = 0; i < num; i++) {
|
||||
struct epoll_event *event = &events[i];
|
||||
/* read event */
|
||||
if (event->data.fd == ping.event_fd) {
|
||||
uint64_t value;
|
||||
int unused __attribute__((unused));
|
||||
unused = read(ping.event_fd, &value, sizeof(uint64_t));
|
||||
continue;
|
||||
}
|
||||
|
||||
struct ping_host_struct *ping_host = (struct ping_host_struct *)event->data.ptr;
|
||||
_fast_ping_process(ping_host, event, &tvnow);
|
||||
}
|
||||
@@ -1671,6 +1834,31 @@ static void *_fast_ping_work(void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _fast_ping_init_wakeup_event(void)
|
||||
{
|
||||
int fdevent = -1;
|
||||
fdevent = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
if (fdevent < 0) {
|
||||
tlog(TLOG_ERROR, "create eventfd failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
struct epoll_event event;
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN | EPOLLERR;
|
||||
event.data.fd = fdevent;
|
||||
if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fdevent, &event) != 0) {
|
||||
tlog(TLOG_ERROR, "set eventfd failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ping.event_fd = fdevent;
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fast_ping_init(void)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
@@ -1693,32 +1881,67 @@ int fast_ping_init(void)
|
||||
|
||||
pthread_mutex_init(&ping.map_lock, NULL);
|
||||
pthread_mutex_init(&ping.lock, NULL);
|
||||
pthread_mutex_init(&ping.notify_lock, NULL);
|
||||
pthread_cond_init(&ping.notify_cond, NULL);
|
||||
|
||||
INIT_LIST_HEAD(&ping.notify_event_list);
|
||||
|
||||
hash_init(ping.addrmap);
|
||||
ping.epoll_fd = epollfd;
|
||||
ping.no_unprivileged_ping = !has_unprivileged_ping();
|
||||
ping.ident = (getpid() & 0XFFFF);
|
||||
atomic_set(&ping.run, 1);
|
||||
|
||||
ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "create ping work thread failed, %s\n", strerror(errno));
|
||||
tlog(TLOG_ERROR, "create ping work thread failed, %s\n", strerror(ret));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = pthread_create(&ping.notify_tid, &attr, _fast_ping_notify_worker, NULL);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "create ping notifyer work thread failed, %s\n", strerror(ret));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ping.epoll_fd = epollfd;
|
||||
ret = _fast_ping_init_wakeup_event();
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "init wakeup event failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (ping.notify_tid) {
|
||||
void *retval = NULL;
|
||||
atomic_set(&ping.run, 0);
|
||||
pthread_cond_signal(&ping.notify_cond);
|
||||
pthread_join(ping.notify_tid, &retval);
|
||||
ping.notify_tid = 0;
|
||||
}
|
||||
|
||||
if (ping.tid) {
|
||||
void *retval = NULL;
|
||||
atomic_set(&ping.run, 0);
|
||||
_fast_ping_wakup_thread();
|
||||
pthread_join(ping.tid, &retval);
|
||||
ping.tid = 0;
|
||||
}
|
||||
|
||||
if (epollfd) {
|
||||
if (epollfd > 0) {
|
||||
close(epollfd);
|
||||
}
|
||||
|
||||
if (ping.event_fd) {
|
||||
close(ping.event_fd);
|
||||
ping.event_fd = -1;
|
||||
}
|
||||
|
||||
pthread_cond_destroy(&ping.notify_cond);
|
||||
pthread_mutex_destroy(&ping.notify_lock);
|
||||
pthread_mutex_destroy(&ping.lock);
|
||||
pthread_mutex_destroy(&ping.map_lock);
|
||||
memset(&ping, 0, sizeof(ping));
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1748,16 +1971,33 @@ static void _fast_ping_close_fds(void)
|
||||
|
||||
void fast_ping_exit(void)
|
||||
{
|
||||
if (ping.notify_tid) {
|
||||
void *retval = NULL;
|
||||
atomic_set(&ping.run, 0);
|
||||
pthread_cond_signal(&ping.notify_cond);
|
||||
pthread_join(ping.notify_tid, &retval);
|
||||
ping.notify_tid = 0;
|
||||
}
|
||||
|
||||
if (ping.tid) {
|
||||
void *ret = NULL;
|
||||
atomic_set(&ping.run, 0);
|
||||
_fast_ping_wakup_thread();
|
||||
pthread_join(ping.tid, &ret);
|
||||
ping.tid = 0;
|
||||
}
|
||||
|
||||
if (ping.event_fd > 0) {
|
||||
close(ping.event_fd);
|
||||
ping.event_fd = -1;
|
||||
}
|
||||
|
||||
_fast_ping_close_fds();
|
||||
_fast_ping_remove_all();
|
||||
_fast_ping_remove_all_notify_event();
|
||||
|
||||
pthread_cond_destroy(&ping.notify_cond);
|
||||
pthread_mutex_destroy(&ping.notify_lock);
|
||||
pthread_mutex_destroy(&ping.lock);
|
||||
pthread_mutex_destroy(&ping.map_lock);
|
||||
}
|
||||
|
||||
@@ -200,10 +200,11 @@ void *art_substring(const art_tree *t, const unsigned char *str, int str_len, un
|
||||
* @arg t The tree
|
||||
* @arg str The key
|
||||
* @arg str_len The length of the key
|
||||
* @arg is_subkey is sub key or not
|
||||
* @return NULL if the item was not found, otherwise
|
||||
* the value pointer is returned.
|
||||
*/
|
||||
typedef int (*walk_func)(unsigned char *key, uint32_t key_len, void *value, void *arg);
|
||||
typedef int (*walk_func)(unsigned char *key, uint32_t key_len, int is_subkey, void *value, void *arg);
|
||||
void art_substring_walk(const art_tree *t, const unsigned char *str, int str_len, walk_func func, void *arg);
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _GENERIC_HASH_H
|
||||
#define _GENERIC_HASH_H
|
||||
|
||||
@@ -30,7 +29,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef BITS_PER_LONG
|
||||
# define BITS_PER_LONG __WORDSIZE
|
||||
#define BITS_PER_LONG __WORDSIZE
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -39,14 +38,12 @@
|
||||
* more efficiently than using fls() and fls64()
|
||||
* - the arch is not required to handle n==0 if implementing the fallback
|
||||
*/
|
||||
static inline __attribute__((const))
|
||||
int __ilog2_u32(uint32_t n)
|
||||
static inline __attribute__((const)) int __ilog2_u32(uint32_t n)
|
||||
{
|
||||
return fls(n) - 1;
|
||||
}
|
||||
|
||||
static inline __attribute__((const))
|
||||
int __ilog2_u64(uint64_t n)
|
||||
static inline __attribute__((const)) int __ilog2_u64(uint64_t n)
|
||||
{
|
||||
return fls64(n) - 1;
|
||||
}
|
||||
@@ -61,78 +58,73 @@ int __ilog2_u64(uint64_t n)
|
||||
*
|
||||
* selects the appropriately-sized optimised version depending on sizeof(n)
|
||||
*/
|
||||
#define ilog2(n) \
|
||||
( \
|
||||
__builtin_constant_p(n) ? ( \
|
||||
(n) < 2 ? 0 : \
|
||||
(n) & (1ULL << 63) ? 63 : \
|
||||
(n) & (1ULL << 62) ? 62 : \
|
||||
(n) & (1ULL << 61) ? 61 : \
|
||||
(n) & (1ULL << 60) ? 60 : \
|
||||
(n) & (1ULL << 59) ? 59 : \
|
||||
(n) & (1ULL << 58) ? 58 : \
|
||||
(n) & (1ULL << 57) ? 57 : \
|
||||
(n) & (1ULL << 56) ? 56 : \
|
||||
(n) & (1ULL << 55) ? 55 : \
|
||||
(n) & (1ULL << 54) ? 54 : \
|
||||
(n) & (1ULL << 53) ? 53 : \
|
||||
(n) & (1ULL << 52) ? 52 : \
|
||||
(n) & (1ULL << 51) ? 51 : \
|
||||
(n) & (1ULL << 50) ? 50 : \
|
||||
(n) & (1ULL << 49) ? 49 : \
|
||||
(n) & (1ULL << 48) ? 48 : \
|
||||
(n) & (1ULL << 47) ? 47 : \
|
||||
(n) & (1ULL << 46) ? 46 : \
|
||||
(n) & (1ULL << 45) ? 45 : \
|
||||
(n) & (1ULL << 44) ? 44 : \
|
||||
(n) & (1ULL << 43) ? 43 : \
|
||||
(n) & (1ULL << 42) ? 42 : \
|
||||
(n) & (1ULL << 41) ? 41 : \
|
||||
(n) & (1ULL << 40) ? 40 : \
|
||||
(n) & (1ULL << 39) ? 39 : \
|
||||
(n) & (1ULL << 38) ? 38 : \
|
||||
(n) & (1ULL << 37) ? 37 : \
|
||||
(n) & (1ULL << 36) ? 36 : \
|
||||
(n) & (1ULL << 35) ? 35 : \
|
||||
(n) & (1ULL << 34) ? 34 : \
|
||||
(n) & (1ULL << 33) ? 33 : \
|
||||
(n) & (1ULL << 32) ? 32 : \
|
||||
(n) & (1ULL << 31) ? 31 : \
|
||||
(n) & (1ULL << 30) ? 30 : \
|
||||
(n) & (1ULL << 29) ? 29 : \
|
||||
(n) & (1ULL << 28) ? 28 : \
|
||||
(n) & (1ULL << 27) ? 27 : \
|
||||
(n) & (1ULL << 26) ? 26 : \
|
||||
(n) & (1ULL << 25) ? 25 : \
|
||||
(n) & (1ULL << 24) ? 24 : \
|
||||
(n) & (1ULL << 23) ? 23 : \
|
||||
(n) & (1ULL << 22) ? 22 : \
|
||||
(n) & (1ULL << 21) ? 21 : \
|
||||
(n) & (1ULL << 20) ? 20 : \
|
||||
(n) & (1ULL << 19) ? 19 : \
|
||||
(n) & (1ULL << 18) ? 18 : \
|
||||
(n) & (1ULL << 17) ? 17 : \
|
||||
(n) & (1ULL << 16) ? 16 : \
|
||||
(n) & (1ULL << 15) ? 15 : \
|
||||
(n) & (1ULL << 14) ? 14 : \
|
||||
(n) & (1ULL << 13) ? 13 : \
|
||||
(n) & (1ULL << 12) ? 12 : \
|
||||
(n) & (1ULL << 11) ? 11 : \
|
||||
(n) & (1ULL << 10) ? 10 : \
|
||||
(n) & (1ULL << 9) ? 9 : \
|
||||
(n) & (1ULL << 8) ? 8 : \
|
||||
(n) & (1ULL << 7) ? 7 : \
|
||||
(n) & (1ULL << 6) ? 6 : \
|
||||
(n) & (1ULL << 5) ? 5 : \
|
||||
(n) & (1ULL << 4) ? 4 : \
|
||||
(n) & (1ULL << 3) ? 3 : \
|
||||
(n) & (1ULL << 2) ? 2 : \
|
||||
1 ) : \
|
||||
(sizeof(n) <= 4) ? \
|
||||
__ilog2_u32(n) : \
|
||||
__ilog2_u64(n) \
|
||||
)
|
||||
|
||||
#define ilog2(n) \
|
||||
(__builtin_constant_p(n) ? ((n) < 2 ? 0 \
|
||||
: (n) & (1ULL << 63) ? 63 \
|
||||
: (n) & (1ULL << 62) ? 62 \
|
||||
: (n) & (1ULL << 61) ? 61 \
|
||||
: (n) & (1ULL << 60) ? 60 \
|
||||
: (n) & (1ULL << 59) ? 59 \
|
||||
: (n) & (1ULL << 58) ? 58 \
|
||||
: (n) & (1ULL << 57) ? 57 \
|
||||
: (n) & (1ULL << 56) ? 56 \
|
||||
: (n) & (1ULL << 55) ? 55 \
|
||||
: (n) & (1ULL << 54) ? 54 \
|
||||
: (n) & (1ULL << 53) ? 53 \
|
||||
: (n) & (1ULL << 52) ? 52 \
|
||||
: (n) & (1ULL << 51) ? 51 \
|
||||
: (n) & (1ULL << 50) ? 50 \
|
||||
: (n) & (1ULL << 49) ? 49 \
|
||||
: (n) & (1ULL << 48) ? 48 \
|
||||
: (n) & (1ULL << 47) ? 47 \
|
||||
: (n) & (1ULL << 46) ? 46 \
|
||||
: (n) & (1ULL << 45) ? 45 \
|
||||
: (n) & (1ULL << 44) ? 44 \
|
||||
: (n) & (1ULL << 43) ? 43 \
|
||||
: (n) & (1ULL << 42) ? 42 \
|
||||
: (n) & (1ULL << 41) ? 41 \
|
||||
: (n) & (1ULL << 40) ? 40 \
|
||||
: (n) & (1ULL << 39) ? 39 \
|
||||
: (n) & (1ULL << 38) ? 38 \
|
||||
: (n) & (1ULL << 37) ? 37 \
|
||||
: (n) & (1ULL << 36) ? 36 \
|
||||
: (n) & (1ULL << 35) ? 35 \
|
||||
: (n) & (1ULL << 34) ? 34 \
|
||||
: (n) & (1ULL << 33) ? 33 \
|
||||
: (n) & (1ULL << 32) ? 32 \
|
||||
: (n) & (1ULL << 31) ? 31 \
|
||||
: (n) & (1ULL << 30) ? 30 \
|
||||
: (n) & (1ULL << 29) ? 29 \
|
||||
: (n) & (1ULL << 28) ? 28 \
|
||||
: (n) & (1ULL << 27) ? 27 \
|
||||
: (n) & (1ULL << 26) ? 26 \
|
||||
: (n) & (1ULL << 25) ? 25 \
|
||||
: (n) & (1ULL << 24) ? 24 \
|
||||
: (n) & (1ULL << 23) ? 23 \
|
||||
: (n) & (1ULL << 22) ? 22 \
|
||||
: (n) & (1ULL << 21) ? 21 \
|
||||
: (n) & (1ULL << 20) ? 20 \
|
||||
: (n) & (1ULL << 19) ? 19 \
|
||||
: (n) & (1ULL << 18) ? 18 \
|
||||
: (n) & (1ULL << 17) ? 17 \
|
||||
: (n) & (1ULL << 16) ? 16 \
|
||||
: (n) & (1ULL << 15) ? 15 \
|
||||
: (n) & (1ULL << 14) ? 14 \
|
||||
: (n) & (1ULL << 13) ? 13 \
|
||||
: (n) & (1ULL << 12) ? 12 \
|
||||
: (n) & (1ULL << 11) ? 11 \
|
||||
: (n) & (1ULL << 10) ? 10 \
|
||||
: (n) & (1ULL << 9) ? 9 \
|
||||
: (n) & (1ULL << 8) ? 8 \
|
||||
: (n) & (1ULL << 7) ? 7 \
|
||||
: (n) & (1ULL << 6) ? 6 \
|
||||
: (n) & (1ULL << 5) ? 5 \
|
||||
: (n) & (1ULL << 4) ? 4 \
|
||||
: (n) & (1ULL << 3) ? 3 \
|
||||
: (n) & (1ULL << 2) ? 2 \
|
||||
: 1) \
|
||||
: (sizeof(n) <= 4) ? __ilog2_u32(n) \
|
||||
: __ilog2_u64(n))
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_32
|
||||
@@ -219,16 +211,36 @@ static inline uint32_t hash32_ptr(const void *ptr)
|
||||
return (uint32_t)val;
|
||||
}
|
||||
|
||||
static inline uint32_t hash_string_initval(const char *s, uint32_t initval)
|
||||
{
|
||||
uint32_t h = initval;
|
||||
|
||||
while (*s) {
|
||||
h = h * 31 + *s;
|
||||
s++;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline uint32_t hash_string(const char *s)
|
||||
{
|
||||
uint32_t h = 0;
|
||||
return hash_string_initval(s, 0);
|
||||
}
|
||||
|
||||
while (*s) {
|
||||
h = h * 31 + *s;
|
||||
s++;
|
||||
}
|
||||
static inline uint32_t hash_string_array(const char **a)
|
||||
{
|
||||
uint32_t h = 0;
|
||||
|
||||
return h;
|
||||
const char *s;
|
||||
while ((s = *a++)) {
|
||||
while (*s) {
|
||||
h = h * 31 + *s;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
#endif /* _GENERIC_HASH_H */
|
||||
|
||||
36
src/include/nftset.h
Normal file
36
src/include/nftset.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2022 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _NFTSET_H
|
||||
#define _NFTSET_H
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int nftset_add(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
|
||||
int addr_len, unsigned long timeout);
|
||||
|
||||
int nftset_del(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
|
||||
int addr_len);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !_NFTSET_H
|
||||
@@ -1090,7 +1090,7 @@ void art_substring_walk(const art_tree *t, const unsigned char *str, int str_len
|
||||
// Check if the expanded path matches
|
||||
if (!str_prefix_matches((art_leaf*)n, str, str_len)) {
|
||||
found = (art_leaf*)n;
|
||||
stop_search = func(found->key, found->key_len, found->value, arg);
|
||||
stop_search = func(found->key, found->key_len, found->key_len != (uint32_t)str_len, found->value, arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1103,7 +1103,7 @@ void art_substring_walk(const art_tree *t, const unsigned char *str, int str_len
|
||||
// Check if the expanded path matches
|
||||
if (!str_prefix_matches((art_leaf*)m, str, str_len)) {
|
||||
found = (art_leaf*)m;
|
||||
stop_search = func(found->key, found->key_len, found->value, arg);
|
||||
stop_search = func(found->key, found->key_len, found->key_len != (uint32_t)str_len, found->value, arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
616
src/lib/nftset.c
Normal file
616
src/lib/nftset.c
Normal file
@@ -0,0 +1,616 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2022 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include "nftset.h"
|
||||
#include "../dns_conf.h"
|
||||
#include "../tlog.h"
|
||||
#include <errno.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <memory.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#ifdef NFNL_SUBSYS_NFTABLES
|
||||
#include <linux/netfilter/nf_tables.h>
|
||||
|
||||
struct nlmsgreq {
|
||||
struct nlmsghdr h;
|
||||
struct nfgenmsg m;
|
||||
};
|
||||
|
||||
enum { PAYLOAD_MAX = 2048 };
|
||||
|
||||
static int nftset_fd;
|
||||
|
||||
static int _nftset_get_nffamily_from_str(const char *family)
|
||||
{
|
||||
if (strncmp(family, "inet", sizeof("inet")) == 0) {
|
||||
return NFPROTO_INET;
|
||||
} else if (strncmp(family, "ip", sizeof("ip")) == 0) {
|
||||
return NFPROTO_IPV4;
|
||||
} else if (strncmp(family, "ip6", sizeof("ip6")) == 0) {
|
||||
return NFPROTO_IPV6;
|
||||
} else if (strncmp(family, "arp", sizeof("arp")) == 0) {
|
||||
return NFPROTO_ARP;
|
||||
} else if (strncmp(family, "netdev", sizeof("netdev")) == 0) {
|
||||
return NFPROTO_NETDEV;
|
||||
} else if (strncmp(family, "bridge", sizeof("bridge")) == 0) {
|
||||
return NFPROTO_BRIDGE;
|
||||
} else if (strncmp(family, "decnet", sizeof("decnet")) == 0) {
|
||||
return NFPROTO_DECNET;
|
||||
} else {
|
||||
return NFPROTO_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
static struct rtattr *_nftset_nlmsg_tail(struct nlmsghdr *n)
|
||||
{
|
||||
return (struct rtattr *)((uint8_t *)n + NLMSG_ALIGN(n->nlmsg_len));
|
||||
}
|
||||
|
||||
static int _nftset_addattr(struct nlmsghdr *n, int maxlen, __u16 type, const void *data, __u16 alen)
|
||||
{
|
||||
const __u16 len = RTA_LENGTH(alen);
|
||||
const ssize_t newlen = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
|
||||
|
||||
if (newlen > maxlen) {
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct rtattr *attr = _nftset_nlmsg_tail(n);
|
||||
attr->rta_len = len;
|
||||
attr->rta_type = type;
|
||||
|
||||
void *rta_data = RTA_DATA(attr);
|
||||
|
||||
memcpy(rta_data, data, alen);
|
||||
memset((uint8_t *)rta_data + alen, 0, RTA_ALIGN(len) - len);
|
||||
|
||||
n->nlmsg_len = newlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nftset_addattr_string(struct nlmsghdr *n, int maxlen, __u16 type, const char *s)
|
||||
{
|
||||
return _nftset_addattr(n, maxlen, type, s, strlen(s) + 1);
|
||||
}
|
||||
|
||||
static int __attribute__((unused)) _nftset_addattr_uint32(struct nlmsghdr *n, int maxlen, __u16 type, const uint32_t v)
|
||||
{
|
||||
return _nftset_addattr(n, maxlen, type, &v, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
static int __attribute__((unused)) _nftset_addattr_uint16(struct nlmsghdr *n, int maxlen, __u16 type, const uint16_t v)
|
||||
{
|
||||
return _nftset_addattr(n, maxlen, type, &v, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
static int __attribute__((unused)) _nftset_addattr_uint8(struct nlmsghdr *n, int maxlen, __u16 type, const uint8_t v)
|
||||
{
|
||||
return _nftset_addattr(n, maxlen, type, &v, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
static struct rtattr *_nftset_addattr_nest(struct nlmsghdr *n, int maxlen, __u16 type)
|
||||
{
|
||||
struct rtattr *attr = _nftset_nlmsg_tail(n);
|
||||
|
||||
if (-1 == _nftset_addattr(n, maxlen, type, NULL, 0)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
static void _nftset_addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
|
||||
{
|
||||
const void *tail = _nftset_nlmsg_tail(n);
|
||||
nest->rta_len = (uint8_t *)tail - (uint8_t *)nest;
|
||||
}
|
||||
|
||||
static int _nftset_start_batch(void *buf, void **nextbuf)
|
||||
{
|
||||
struct nlmsgreq *req = (struct nlmsgreq *)buf;
|
||||
memset(buf, 0, sizeof(struct nlmsgreq));
|
||||
|
||||
req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
|
||||
req->h.nlmsg_flags = NLM_F_REQUEST;
|
||||
req->h.nlmsg_type = NFNL_MSG_BATCH_BEGIN;
|
||||
req->h.nlmsg_seq = time(NULL);
|
||||
|
||||
req->m.res_id = NFNL_SUBSYS_NFTABLES;
|
||||
|
||||
if (nextbuf) {
|
||||
*nextbuf = (uint8_t *)buf + req->h.nlmsg_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nftset_end_batch(void *buf, void **nextbuf)
|
||||
{
|
||||
struct nlmsgreq *req = (struct nlmsgreq *)buf;
|
||||
memset(buf, 0, sizeof(struct nlmsgreq));
|
||||
|
||||
req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
|
||||
req->h.nlmsg_flags = NLM_F_REQUEST;
|
||||
req->h.nlmsg_type = NFNL_MSG_BATCH_END;
|
||||
req->h.nlmsg_seq = time(NULL);
|
||||
|
||||
req->m.res_id = NFNL_SUBSYS_NFTABLES;
|
||||
|
||||
if (nextbuf) {
|
||||
*nextbuf = (uint8_t *)buf + req->h.nlmsg_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nftset_socket_init(void)
|
||||
{
|
||||
struct sockaddr_nl addr = {0};
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_pid = 0;
|
||||
int fd = 0;
|
||||
|
||||
if (nftset_fd > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fd = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, NETLINK_NETFILTER);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind(fd, (struct sockaddr *)(&addr), sizeof(addr)) < 0) {
|
||||
close(fd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
nftset_fd = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nftset_socket_request(void *msg, int msg_len, void *ret_msg, int ret_msg_len)
|
||||
{
|
||||
int ret = -1;
|
||||
struct pollfd pfds;
|
||||
int do_recv = 0;
|
||||
int last_errno = 0;
|
||||
int len = 0;
|
||||
|
||||
if (_nftset_socket_init() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* clear pending error message*/
|
||||
for (;;) {
|
||||
uint8_t buff[1024];
|
||||
ret = recv(nftset_fd, buff, sizeof(buff), MSG_DONTWAIT);
|
||||
if (ret < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
len = send(nftset_fd, msg, msg_len, 0);
|
||||
if (len == msg_len) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
|
||||
struct timespec waiter;
|
||||
waiter.tv_sec = 0;
|
||||
waiter.tv_nsec = 10000;
|
||||
nanosleep(&waiter, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret_msg == NULL || ret_msg_len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
pfds.fd = nftset_fd;
|
||||
pfds.events = POLLIN;
|
||||
pfds.revents = 0;
|
||||
ret = poll(&pfds, 1, 100);
|
||||
if (ret <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((pfds.revents & POLLIN) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(ret_msg, 0, ret_msg_len);
|
||||
len = 0;
|
||||
for (;;) {
|
||||
ret = recv(nftset_fd, ret_msg + len, ret_msg_len - len, 0);
|
||||
if (ret < 0) {
|
||||
if (errno == EAGAIN && do_recv == 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == EAGAIN && last_errno != 0) {
|
||||
errno = last_errno;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
do_recv = 1;
|
||||
len += ret;
|
||||
|
||||
struct nlmsghdr *nlh = (struct nlmsghdr *)ret_msg;
|
||||
if (nlh->nlmsg_type == NLMSG_ERROR) {
|
||||
struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(nlh);
|
||||
if (err->error != 0) {
|
||||
errno = -err->error;
|
||||
last_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type & (NFNL_SUBSYS_NFTABLES << 8)) {
|
||||
if (nlh->nlmsg_type & NLMSG_DONE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nftset_socket_send(void *msg, int msg_len)
|
||||
{
|
||||
char recvbuff[1024];
|
||||
|
||||
if (dns_conf_nftset_debug_enable == 0) {
|
||||
return _nftset_socket_request(msg, msg_len, NULL, 0);
|
||||
}
|
||||
|
||||
return _nftset_socket_request(msg, msg_len, recvbuff, sizeof(recvbuff));
|
||||
}
|
||||
|
||||
static int _nftset_get_nftset(int nffamily, const char *table_name, const char *setname, void *buf, void **nextbuf)
|
||||
{
|
||||
struct nlmsgreq *req = (struct nlmsgreq *)buf;
|
||||
memset(buf, 0, sizeof(struct nlmsgreq));
|
||||
|
||||
req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
|
||||
req->h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
req->h.nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | NFT_MSG_GETSET;
|
||||
req->h.nlmsg_seq = time(NULL);
|
||||
|
||||
req->m.nfgen_family = nffamily;
|
||||
req->m.res_id = NFNL_SUBSYS_NFTABLES;
|
||||
req->m.version = 0;
|
||||
|
||||
struct nlmsghdr *n = &req->h;
|
||||
|
||||
_nftset_addattr_string(n, PAYLOAD_MAX, NFTA_SET_ELEM_LIST_SET, setname);
|
||||
_nftset_addattr_string(n, PAYLOAD_MAX, NFTA_SET_ELEM_LIST_TABLE, table_name);
|
||||
|
||||
if (nextbuf) {
|
||||
*nextbuf = (uint8_t *)buf + req->h.nlmsg_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nftset_get_flags(int nffamily, const char *tablename, const char *setname, uint32_t *flags)
|
||||
{
|
||||
uint8_t buf[PAYLOAD_MAX];
|
||||
uint8_t result[PAYLOAD_MAX];
|
||||
void *next = buf;
|
||||
int buffer_len = 0;
|
||||
|
||||
if (flags == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_nftset_get_nftset(nffamily, tablename, setname, next, &next);
|
||||
buffer_len = (uint8_t *)next - buf;
|
||||
int ret = _nftset_socket_request(buf, buffer_len, result, sizeof(result));
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct nlmsghdr *nlh = (struct nlmsghdr *)result;
|
||||
struct nfgenmsg *nfmsg = (struct nfgenmsg *)NLMSG_DATA(nlh);
|
||||
struct nfattr *nfa = (struct nfattr *)NFM_NFA(nfmsg);
|
||||
*flags = 0;
|
||||
for (; NFA_OK(nfa, nlh->nlmsg_len); nfa = NFA_NEXT(nfa, nlh->nlmsg_len)) {
|
||||
if (nfa->nfa_type == NFTA_SET_FLAGS) {
|
||||
*flags = ntohl(*(uint32_t *)NFA_DATA(nfa));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nftset_del_element(int nffamily, const char *table_name, const char *setname, const void *data,
|
||||
int data_len, const void *data_interval, int data_interval_len, void *buf,
|
||||
void **nextbuf)
|
||||
{
|
||||
struct nlmsgreq *req = (struct nlmsgreq *)buf;
|
||||
memset(buf, 0, sizeof(struct nlmsgreq));
|
||||
|
||||
req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
|
||||
req->h.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
|
||||
req->h.nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | NFT_MSG_DELSETELEM;
|
||||
req->h.nlmsg_seq = time(NULL);
|
||||
|
||||
if (dns_conf_nftset_debug_enable) {
|
||||
req->h.nlmsg_flags |= NLM_F_ACK;
|
||||
}
|
||||
|
||||
req->m.nfgen_family = nffamily;
|
||||
|
||||
struct nlmsghdr *n = &req->h;
|
||||
|
||||
_nftset_addattr_string(n, PAYLOAD_MAX, NFTA_SET_ELEM_LIST_TABLE, table_name);
|
||||
_nftset_addattr_string(n, PAYLOAD_MAX, NFTA_SET_ELEM_LIST_SET, setname);
|
||||
struct rtattr *nest_list = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_SET_ELEM_LIST_ELEMENTS);
|
||||
struct rtattr *nest_elem = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED);
|
||||
|
||||
struct rtattr *nest_elem_key = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_SET_ELEM_KEY);
|
||||
_nftset_addattr(n, PAYLOAD_MAX, NFTA_DATA_VALUE, data, data_len);
|
||||
_nftset_addattr_nest_end(n, nest_elem_key);
|
||||
_nftset_addattr_nest_end(n, nest_elem);
|
||||
|
||||
/* interval attribute */
|
||||
if (data_interval && data_interval_len > 0) {
|
||||
struct rtattr *nest_interval_end = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_LIST_ELEM);
|
||||
_nftset_addattr_uint32(n, PAYLOAD_MAX, NFTA_SET_ELEM_FLAGS, htonl(NFT_SET_ELEM_INTERVAL_END));
|
||||
struct rtattr *nest_elem_interval_key = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_SET_ELEM_KEY);
|
||||
|
||||
_nftset_addattr(n, PAYLOAD_MAX, NFTA_DATA_VALUE, data_interval, data_interval_len);
|
||||
_nftset_addattr_nest_end(n, nest_elem_interval_key);
|
||||
_nftset_addattr_nest_end(n, nest_interval_end);
|
||||
}
|
||||
|
||||
_nftset_addattr_nest_end(n, nest_list);
|
||||
|
||||
if (nextbuf) {
|
||||
*nextbuf = (uint8_t *)buf + req->h.nlmsg_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nftset_add_element(int nffamily, const char *table_name, const char *setname, const void *data,
|
||||
int data_len, const void *data_interval, int data_interval_len, unsigned long timeout,
|
||||
void *buf, void **nextbuf)
|
||||
{
|
||||
struct nlmsgreq *req = (struct nlmsgreq *)buf;
|
||||
memset(buf, 0, sizeof(struct nlmsgreq));
|
||||
|
||||
req->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
|
||||
req->h.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
|
||||
req->h.nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | NFT_MSG_NEWSETELEM;
|
||||
req->h.nlmsg_seq = time(NULL);
|
||||
|
||||
if (dns_conf_nftset_debug_enable) {
|
||||
req->h.nlmsg_flags |= NLM_F_ACK;
|
||||
}
|
||||
|
||||
req->m.nfgen_family = nffamily;
|
||||
|
||||
struct nlmsghdr *n = &req->h;
|
||||
|
||||
_nftset_addattr_string(n, PAYLOAD_MAX, NFTA_SET_ELEM_LIST_TABLE, table_name);
|
||||
_nftset_addattr_string(n, PAYLOAD_MAX, NFTA_SET_ELEM_LIST_SET, setname);
|
||||
struct rtattr *nest_list = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_SET_ELEM_LIST_ELEMENTS);
|
||||
|
||||
struct rtattr *nest_elem = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_LIST_ELEM);
|
||||
struct rtattr *nest_elem_key = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_SET_ELEM_KEY);
|
||||
_nftset_addattr(n, PAYLOAD_MAX, NFTA_DATA_VALUE, data, data_len);
|
||||
_nftset_addattr_nest_end(n, nest_elem_key);
|
||||
if (timeout > 0) {
|
||||
uint64_t timeout_value = htobe64(timeout * 1000);
|
||||
_nftset_addattr(n, PAYLOAD_MAX, NFTA_SET_ELEM_TIMEOUT, &timeout_value, sizeof(timeout_value));
|
||||
}
|
||||
_nftset_addattr_nest_end(n, nest_elem);
|
||||
|
||||
/* interval attribute */
|
||||
if (data_interval && data_interval_len > 0) {
|
||||
struct rtattr *nest_interval_end = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_LIST_ELEM);
|
||||
_nftset_addattr_uint32(n, PAYLOAD_MAX, NFTA_SET_ELEM_FLAGS, htonl(NFT_SET_ELEM_INTERVAL_END));
|
||||
struct rtattr *nest_elem_interval_key = _nftset_addattr_nest(n, PAYLOAD_MAX, NLA_F_NESTED | NFTA_SET_ELEM_KEY);
|
||||
|
||||
_nftset_addattr(n, PAYLOAD_MAX, NFTA_DATA_VALUE, data_interval, data_interval_len);
|
||||
_nftset_addattr_nest_end(n, nest_elem_interval_key);
|
||||
_nftset_addattr_nest_end(n, nest_interval_end);
|
||||
}
|
||||
|
||||
_nftset_addattr_nest_end(n, nest_list);
|
||||
|
||||
if (nextbuf) {
|
||||
*nextbuf = (uint8_t *)buf + req->h.nlmsg_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nftset_process_setflags(uint32_t flags, const unsigned char addr[], int addr_len, unsigned long *timeout,
|
||||
uint8_t **interval_addr, int *interval_addr_len)
|
||||
{
|
||||
uint8_t *addr_end = *interval_addr;
|
||||
|
||||
if ((flags & NFT_SET_TIMEOUT) == 0 && timeout != NULL) {
|
||||
*timeout = 0;
|
||||
}
|
||||
|
||||
if ((flags & NFT_SET_INTERVAL) && addr_end != NULL) {
|
||||
if (addr_len == 4) {
|
||||
addr_end[0] = addr[0];
|
||||
addr_end[1] = addr[1];
|
||||
addr_end[2] = addr[2];
|
||||
addr_end[3] = addr[3] + 1;
|
||||
if (addr_end[3] == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*interval_addr_len = 4;
|
||||
} else if (addr_len == 16) {
|
||||
memcpy(addr_end, addr, 16);
|
||||
addr_end[15] = addr[15] + 1;
|
||||
if (addr_end[15] == 0) {
|
||||
return -1;
|
||||
}
|
||||
*interval_addr_len = 16;
|
||||
}
|
||||
} else {
|
||||
*interval_addr = NULL;
|
||||
*interval_addr_len = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nftset_del(int nffamily, const char *tablename, const char *setname, const unsigned char addr[],
|
||||
int addr_len, const unsigned char addr_end[], int addr_end_len)
|
||||
{
|
||||
uint8_t buf[PAYLOAD_MAX];
|
||||
void *next = buf;
|
||||
int buffer_len = 0;
|
||||
|
||||
_nftset_start_batch(next, &next);
|
||||
_nftset_del_element(nffamily, tablename, setname, addr, addr_len, addr_end, addr_end_len, next, &next);
|
||||
_nftset_end_batch(next, &next);
|
||||
buffer_len = (uint8_t *)next - buf;
|
||||
return _nftset_socket_send(buf, buffer_len);
|
||||
}
|
||||
|
||||
int nftset_del(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
|
||||
int addr_len)
|
||||
{
|
||||
int nffamily = _nftset_get_nffamily_from_str(familyname);
|
||||
|
||||
uint8_t addr_end_buff[16] = {0};
|
||||
uint8_t *addr_end = addr_end_buff;
|
||||
uint32_t flags = 0;
|
||||
int addr_end_len = 0;
|
||||
int ret = -1;
|
||||
|
||||
ret = _nftset_get_flags(nffamily, tablename, setname, &flags);
|
||||
if (ret == 0) {
|
||||
ret = _nftset_process_setflags(flags, addr, addr_len, 0, &addr_end, &addr_end_len);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
addr_end = NULL;
|
||||
addr_end_len = 0;
|
||||
}
|
||||
|
||||
ret = _nftset_del(nffamily, tablename, setname, addr, addr_len, addr_end, addr_end_len);
|
||||
if (ret != 0 && errno != ENOENT) {
|
||||
tlog(TLOG_ERROR, "nftset delete failed, family:%s, table:%s, set:%s, error:%s", familyname, tablename, setname,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nftset_add(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
|
||||
int addr_len, unsigned long timeout)
|
||||
{
|
||||
uint8_t buf[PAYLOAD_MAX];
|
||||
uint8_t addr_end_buff[16] = {0};
|
||||
uint8_t *addr_end = addr_end_buff;
|
||||
uint32_t flags = 0;
|
||||
int addr_end_len = 0;
|
||||
void *next = buf;
|
||||
int buffer_len = 0;
|
||||
int ret = -1;
|
||||
int nffamily = _nftset_get_nffamily_from_str(familyname);
|
||||
|
||||
if (dns_conf_nftset_timeout_enable == 0) {
|
||||
timeout = 0;
|
||||
}
|
||||
|
||||
ret = _nftset_get_flags(nffamily, tablename, setname, &flags);
|
||||
if (ret == 0) {
|
||||
ret = _nftset_process_setflags(flags, addr, addr_len, &timeout, &addr_end, &addr_end_len);
|
||||
if (ret != 0) {
|
||||
if (dns_conf_nftset_debug_enable) {
|
||||
tlog(TLOG_ERROR, "nftset add failed, family:%s, table:%s, set:%s, error:%s", familyname, tablename,
|
||||
setname, "ip is invalid");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
addr_end = NULL;
|
||||
addr_end_len = 0;
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
_nftset_del(nffamily, tablename, setname, addr, addr_len, addr_end, addr_end_len);
|
||||
}
|
||||
|
||||
_nftset_start_batch(next, &next);
|
||||
_nftset_add_element(nffamily, tablename, setname, addr, addr_len, addr_end, addr_end_len, timeout, next, &next);
|
||||
_nftset_end_batch(next, &next);
|
||||
buffer_len = (uint8_t *)next - buf;
|
||||
|
||||
ret = _nftset_socket_send(buf, buffer_len);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "nftset add failed, family:%s, table:%s, set:%s, error:%s", familyname, tablename, setname,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int nftset_add(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
|
||||
int addr_len, unsigned long timeout)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nftset_del(const char *familyname, const char *tablename, const char *setname, const unsigned char addr[],
|
||||
int addr_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <ucontext.h>
|
||||
@@ -99,7 +100,7 @@ out:
|
||||
|
||||
static int drop_root_privilege(void)
|
||||
{
|
||||
struct __user_cap_data_struct cap;
|
||||
struct __user_cap_data_struct cap[2];
|
||||
struct __user_cap_header_struct header;
|
||||
#ifdef _LINUX_CAPABILITY_VERSION_3
|
||||
header.version = _LINUX_CAPABILITY_VERSION_3;
|
||||
@@ -115,16 +116,20 @@ static int drop_root_privilege(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (capget(&header, &cap) < 0) {
|
||||
memset(cap, 0, sizeof(cap));
|
||||
if (capget(&header, cap) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
|
||||
cap.effective |= (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN);
|
||||
cap.permitted |= (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
cap[i].effective = (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN | 1 << CAP_NET_BIND_SERVICE);
|
||||
cap[i].permitted = (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN | 1 << CAP_NET_BIND_SERVICE);
|
||||
}
|
||||
|
||||
unused = setgid(gid);
|
||||
unused = setuid(uid);
|
||||
if (capset(&header, &cap) < 0) {
|
||||
if (capset(&header, cap) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -138,7 +143,7 @@ static void _help(void)
|
||||
char *help = ""
|
||||
"Usage: smartdns [OPTION]...\n"
|
||||
"Start smartdns server.\n"
|
||||
" -f run forground.\n"
|
||||
" -f run foreground.\n"
|
||||
" -c [conf] config file.\n"
|
||||
" -p [pid] pid file path, '-' means don't create pid file.\n"
|
||||
" -S ignore segment fault signal.\n"
|
||||
@@ -508,17 +513,28 @@ static int _smartdns_create_logdir(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set_rlimit(void)
|
||||
{
|
||||
struct rlimit value;
|
||||
value.rlim_cur = 40;
|
||||
value.rlim_max = 40;
|
||||
setrlimit(RLIMIT_NICE, &value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _smartdns_init_pre(void)
|
||||
{
|
||||
_smartdns_create_logdir();
|
||||
|
||||
_set_rlimit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
int is_forground = 0;
|
||||
int is_foreground = 0;
|
||||
int opt = 0;
|
||||
char config_file[MAX_LINE_LEN];
|
||||
char pid_file[MAX_LINE_LEN];
|
||||
@@ -535,7 +551,7 @@ int main(int argc, char *argv[])
|
||||
while ((opt = getopt(argc, argv, "fhc:p:SvxN:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
is_forground = 1;
|
||||
is_foreground = 1;
|
||||
break;
|
||||
case 'c':
|
||||
snprintf(config_file, sizeof(config_file), "%s", optarg);
|
||||
@@ -568,7 +584,7 @@ int main(int argc, char *argv[])
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (is_forground == 0) {
|
||||
if (is_foreground == 0) {
|
||||
if (daemon(0, 0) < 0) {
|
||||
fprintf(stderr, "run daemon process failed, %s\n", strerror(errno));
|
||||
return 1;
|
||||
|
||||
62
src/util.c
62
src/util.c
@@ -18,10 +18,11 @@
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "util.h"
|
||||
#include "dns_conf.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
@@ -30,6 +31,7 @@
|
||||
#include <linux/capability.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ssl.h>
|
||||
@@ -1371,6 +1373,62 @@ static int _dns_debug_display(struct dns_packet *packet)
|
||||
inet_ntop(AF_INET6, addr, req_host, sizeof(req_host));
|
||||
printf("domain: %s AAAA: %s TTL:%d\n", name, req_host, ttl);
|
||||
} break;
|
||||
case DNS_T_HTTPS: {
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
char target[DNS_MAX_CNAME_LEN] = {0};
|
||||
struct dns_https_param *p = NULL;
|
||||
int priority = 0;
|
||||
|
||||
p = dns_get_HTTPS_svcparm_start(rrs, name, DNS_MAX_CNAME_LEN, &ttl, &priority, target,
|
||||
DNS_MAX_CNAME_LEN);
|
||||
if (p == NULL) {
|
||||
printf("get HTTPS svcparm failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
printf("domain: %s HTTPS: %s TTL: %d priority: %d\n", name, target, ttl, priority);
|
||||
|
||||
for (; p; p = dns_get_HTTPS_svcparm_next(rrs, p)) {
|
||||
switch (p->key) {
|
||||
case DNS_HTTPS_T_MANDATORY: {
|
||||
printf(" HTTPS: mandatory: %s\n", p->value);
|
||||
} break;
|
||||
case DNS_HTTPS_T_ALPN: {
|
||||
printf(" HTTPS: alpn: %s\n", p->value);
|
||||
} break;
|
||||
case DNS_HTTPS_T_NO_DEFAULT_ALPN: {
|
||||
printf(" HTTPS: no_default_alpn: %s\n", p->value);
|
||||
} break;
|
||||
case DNS_HTTPS_T_PORT: {
|
||||
int port = *(unsigned short *)(p->value);
|
||||
printf(" HTTPS: port: %d\n", port);
|
||||
} break;
|
||||
case DNS_HTTPS_T_IPV4HINT: {
|
||||
printf(" HTTPS: ipv4hint: %d\n", p->len / 4);
|
||||
for (int k = 0; k < p->len / 4; k++) {
|
||||
char ip[16] = {0};
|
||||
inet_ntop(AF_INET, p->value + k * 4, ip, sizeof(ip));
|
||||
printf(" ipv4: %s\n", ip);
|
||||
}
|
||||
} break;
|
||||
case DNS_HTTPS_T_ECH: {
|
||||
printf(" HTTPS: ech: ");
|
||||
for (int k = 0; k < p->len; k++) {
|
||||
printf("%02x ", p->value[k]);
|
||||
}
|
||||
printf("\n");
|
||||
} break;
|
||||
case DNS_HTTPS_T_IPV6HINT: {
|
||||
printf(" HTTPS: ipv6hint: %d\n", p->len / 16);
|
||||
for (int k = 0; k < p->len / 16; k++) {
|
||||
char ip[64] = {0};
|
||||
inet_ntop(AF_INET6, p->value + k * 16, ip, sizeof(ip));
|
||||
printf(" ipv6: %s\n", ip);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case DNS_T_NS: {
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
@@ -1454,4 +1512,4 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -46,9 +46,7 @@ extern "C" {
|
||||
#define MAX_IP_LEN 64
|
||||
|
||||
#ifndef BASE_FILE_NAME
|
||||
#define BASE_FILE_NAME \
|
||||
(__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \
|
||||
: __FILE__)
|
||||
#define BASE_FILE_NAME (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
#endif
|
||||
#define BUG(format, ...) bug_ext(BASE_FILE_NAME, __LINE__, __func__, format, ##__VA_ARGS__)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user