Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21ba047075 | ||
|
|
9f3926e048 | ||
|
|
e8b920fb18 | ||
|
|
a1150a7ceb | ||
|
|
e1ffe29fca | ||
|
|
d9dd02c9b0 | ||
|
|
c7d304423e | ||
|
|
87d8739ecd | ||
|
|
452438a0af | ||
|
|
0085abdfdd | ||
|
|
46d3acdb8f | ||
|
|
36ddca0491 | ||
|
|
f02dffdf95 | ||
|
|
10ea3e6f3f | ||
|
|
7add2b82ae | ||
|
|
05a24264aa | ||
|
|
8e73eea8ec | ||
|
|
c3ac0c2f17 | ||
|
|
210e0a9a6f | ||
|
|
9092d9f683 | ||
|
|
5057a8e45d | ||
|
|
1600eaed1f | ||
|
|
65ede47cf7 | ||
|
|
6e5fc54439 | ||
|
|
71e110748b | ||
|
|
0112d12693 | ||
|
|
0a236acc56 | ||
|
|
050aedadd4 | ||
|
|
7241b24a57 | ||
|
|
5e12611157 | ||
|
|
7f5e0ef4e0 | ||
|
|
bb1c4d2bfa | ||
|
|
dd4372a961 | ||
|
|
73d4e9f822 | ||
|
|
95a5b1e5e3 | ||
|
|
143d82ce1a | ||
|
|
4028887167 | ||
|
|
1674c3d8c9 |
76
ReadMe.md
76
ReadMe.md
@@ -85,8 +85,8 @@ From the comparison, smartdns found the fastest IP address to visit www.baidu.co
|
||||
5. **Domain name high performance rule filtering**
|
||||
Support domain name suffix matching mode, simplify filtering configuration, filter 200,000 recording and take time <1ms.
|
||||
|
||||
6. **Linux multi-platform support**
|
||||
Support standard Linux system (Raspberry Pi), openwrt system various firmware, ASUS router native firmware.
|
||||
6. **Linux/Windows multi-platform support**
|
||||
Support standard Linux system (Raspberry Pi), openwrt system various firmware, ASUS router native firmware. Support Windows 10 WSL (Windows Subsystem for Linux).
|
||||
|
||||
7. **Support IPV4, IPV6 dual stack**
|
||||
Support IPV4, IPV6 network, support query A, AAAA record, dual-stack IP selection.
|
||||
@@ -114,14 +114,17 @@ Download the matching version of the SmartDNS installation package. The correspo
|
||||
|system |package|Description
|
||||
|-----|-----|-----
|
||||
|Standard Linux system (Raspberry Pi)| smartdns.xxxxxxxx.armhf.deb|Support Raspberry Pi Raspbian stretch, Debian 9 system.
|
||||
|Standard Linux system (x86_64)| smartdns.xxxxxxxx.x86_64.tar.gz|Support for x86_64 systems.
|
||||
|Standard Linux system (x86_64)| smartdns.xxxxxxxx.x86_64.tar.gz|Support for x86_64 Linux systems.
|
||||
|Windows 10 WSL (Ubuntu)| smartdns.xxxxxxxx.x86_64.tar.gz|Windows 10 WSL ubuntu.
|
||||
|Standard Linux system (x86)| smartdns.xxxxxxxx.x86.tar.gz|Support for x86_64 systems.
|
||||
|ASUS native firmware (optware)|smartdns.xxxxxxx.mipsbig.ipk|Systems that support the MIPS big-end architecture, such as RT-AC55U, RT-AC66U.
|
||||
|ASUS native firmware (optware)|smartdns.xxxxxxx.mipsel.ipk|System that supports the MIPS little endian architecture, such as the RT-AC68U.
|
||||
|ASUS native firmware (optware)|smartdns.xxxxxxx.arm.ipk|System that supports the ARM small endian architecture, such as the RT-AC88U.
|
||||
|ASUS native firmware (optware)|smartdns.xxxxxxx.mipsel.ipk|System that supports the MIPS little endian architecture.
|
||||
|ASUS native firmware (optware)|smartdns.xxxxxxx.arm.ipk|System that supports the ARM small endian architecture, such as the RT-AC88U, RT-AC68U.
|
||||
|Padavan|smartdns.xxxxxxx.mipselsf.ipk|padavan Firmware.
|
||||
|openwrt 15.01|smartdns.xxxxxxxx.ar71xx.ipk|Support AR71XX MIPS system.
|
||||
|openwrt 15.01|smartdns.xxxxxxxx.ramips_24kec.ipk|Support small-end routers such as MT762X
|
||||
|openwrt 15.01(Pandora)|smartdns.xxxxxxxx.mipsel_24kec_dsp.ipk|Support for Pandora firmware of MT7620 series
|
||||
|openwrt 15.01(Pandora)|smartdns.xxxxxxxx.mips_74kc_dsp2.ipk|Support for Pandora firmware of AR71xx series
|
||||
|openwrt 18.06|smartdns.xxxxxxxx.mips_24kc.ipk|Support AR71XX MIPS system.
|
||||
|openwrt 18.06|smartdns.xxxxxxxx.mipsel_24kc.ipk|Support small-end routers such as MT726X
|
||||
|openwrt 18.06|smartdns.xxxxxxxx.x86_64.ipk|Support x86_64 router
|
||||
@@ -367,6 +370,61 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
\\192.168.1.1\sda1\asusware.mipsbig\etc\init.d
|
||||
```
|
||||
|
||||
### Windows 10 WSL Installation(WSL ubuntu)
|
||||
|
||||
--------------
|
||||
|
||||
1. Install Windows 10 WSL ubuntu
|
||||
|
||||
Install the Windows 10 WSL environment and select Ubuntu as default distribution. Please refer to [WSL installation instructions](https://docs.microsoft.com/en-us/windows/wsl/install-win10) for installation steps
|
||||
|
||||
1. Install smartdns
|
||||
|
||||
download install package `smartdns.xxxxxxxx.x86_64.tar.gz`,and unzip to the `D:\` directory, after decompression, the directory is as follows:
|
||||
|
||||
```shell
|
||||
D:\SMARTDNS
|
||||
├─etc
|
||||
│ ├─default
|
||||
│ ├─init.d
|
||||
│ └─smartdns
|
||||
├─package
|
||||
│ └─windows
|
||||
├─src
|
||||
└─systemd
|
||||
|
||||
```
|
||||
|
||||
Double-click `install.bat` in the `D:\smartdns\package\windows` directory for installation. Please enter the password for `WLS ubuntu` when input password.
|
||||
|
||||
1. Configuration
|
||||
|
||||
Edit `smartdns.conf` configuration file in `D:\smartdns\etc\smartdns` directory, you can configure the upstream server to smartdns. Refer to the `Configuration Parameters` for specific configuration parameters.
|
||||
In general, you only need to add `server [IP]:port`, `server-tcp [IP]:port` configuration items.
|
||||
Configure as many upstream DNS servers as possible, including servers at home and abroad. Please refer to the `Configuration Parameters` section for configuration parameters.
|
||||
|
||||
1. Start Service
|
||||
|
||||
Double-click `reload.bat` in the `D:\smartdns\package\windows` directory for reload.
|
||||
|
||||
1. Forwarding DNS request to SmartDNS
|
||||
|
||||
Modify the default DNS server for Windows to `127.0.0.1`, with these steps referred to [IP configuration](https://support.microsoft.com/en-us/help/15089/windows-change-tcp-ip-settings)
|
||||
|
||||
1. Check if the service is configured successfully
|
||||
|
||||
Query domain name with `nslookup -querytype=ptr 0.0.0.0`
|
||||
Check if the `name` item in the command result is displayed as `smartdns` or `hostname`, such as `smartdns`
|
||||
|
||||
```shell
|
||||
pi@raspberrypi:~/code/smartdns_build $ nslookup -querytype=ptr 0.0.0.0
|
||||
Server: 192.168.1.1
|
||||
Address: 192.168.1.1#53
|
||||
|
||||
Non-authoritative answer:
|
||||
0.0.0.0.in-addr.arpa name = smartdns.
|
||||
```
|
||||
|
||||
## Configuration parameter
|
||||
|
||||
|parameter|Parameter function|Default value|Value type|Example|
|
||||
@@ -391,13 +449,15 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|server|Upstream UDP DNS server|None|[ip][:port] [-blacklist-ip][-check-edns], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server 8.8.8.8:53 -blacklist-ip -check-edns
|
||||
|server-tcp|Upstream TCP DNS server|None|[IP][:port] [-blacklist-ip][-check-edns], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server-tcp 8.8.8.8:53
|
||||
|server-tls|Upstream TLS DNS server|None|[IP][:port] [-blacklist-ip][-check-edns], Repeatable, blacklist-ip parameter represents filtering the result of IPs with blacklist-ip configuration.| server-tls 8.8.8.8:853
|
||||
|address|Domain IP address|None|address /domain/ip| address /www.example.com/1.2.3.4
|
||||
|ipset|Domain IPSet|None|ipset /domain/ipset|ipset /www.example.com/pass
|
||||
|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
|
||||
|ipset|Domain IPSet|None|ipset /domain/[ipset\|-], `-` for ignore|ipset /www.example.com/pass
|
||||
|ipset-timeout|ipset timeout enable|auto|[yes]|ipset-timeout yes
|
||||
|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
|
||||
|blacklist-ip|ip blacklist|None|[ip/subnet], Repeatable,When the filtering server responds IPs in the IP blacklist, The result will be discarded directly| blacklist-ip 1.2.3.4/16
|
||||
|force-AAAA-SOA|force AAAA query return SOA|no|[yes\|no]|force-AAAA-SOA yes
|
||||
|dualstack-ip-selection|Dualstack ip selection|no|[yes\|no]|dualstack-ip-selection yes
|
||||
|dualstack-ip-selection-threshold|Dualstack ip select threadhold|100ms|millisecond|dualstack-ip-selection-threshold [1-1000]
|
||||
|dualstack-ip-selection-threshold|Dualstack ip select threadhold|30ms|millisecond|dualstack-ip-selection-threshold [0-1000]
|
||||
|
||||
## [Donate](#Donate)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# SmartDNS
|
||||
|
||||

|
||||
SmartDNS是一个运行在本地的DNS服务器,SmartDNS接受本地客户端的DNS查询请求,从多个上游DNS服务器获取DNS查询结果,并将访问速度最快的结果返回个客户端,避免DNS污染,提高网络访问速度。
|
||||
SmartDNS是一个运行在本地的DNS服务器,SmartDNS接受本地客户端的DNS查询请求,从多个上游DNS服务器获取DNS查询结果,并将访问速度最快的结果返回给客户端,避免DNS污染,提高网络访问速度。
|
||||
同时支持指定特定域名IP地址,并高性匹配,达到过滤广告的效果。
|
||||
与dnsmasq的all-servers不同,smartdns返回的是访问速度最快的解析结果。
|
||||
|
||||
@@ -85,8 +85,8 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
5. **域名高性能后缀匹配**
|
||||
支持域名后缀匹配模式,简化过滤配置,过滤20万条记录时间<1ms
|
||||
|
||||
6. **Linux多平台支持**
|
||||
支持标准Linux系统(树莓派),openwrt系统各种固件,华硕路由器原生固件。
|
||||
6. **Linux/Windows多平台支持**
|
||||
支持标准Linux系统(树莓派),openwrt系统各种固件,华硕路由器原生固件。以及支持Windows 10 WSL (Windows Subsystem for Linux)。
|
||||
|
||||
7. **支持IPV4, IPV6双栈**
|
||||
支持IPV4,IPV6网络,支持查询A, AAAA记录,支持双栈IP速度优化。
|
||||
@@ -114,14 +114,17 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
|系统 |安装包|说明
|
||||
|-----|-----|-----
|
||||
|标准Linux系统(树莓派)| smartdns.xxxxxxxx.armhf.deb|支持树莓派Raspbian stretch,Debian 9系统。
|
||||
|标准Linux系统(x86_64)| smartdns.xxxxxxxx.x86_64.tar.gz|支持x86_64系统。
|
||||
|标准Linux系统(x86_64)| smartdns.xxxxxxxx.x86_64.tar.gz|支持x86_64 Linux 系统。
|
||||
|Windows 10 WSL (ubuntu)| smartdns.xxxxxxxx.x86_64.tar.gz|支持Windows 10 WSL ubuntu系统。
|
||||
|标准Linux系统(x86)| smartdns.xxxxxxxx.x86.tar.gz|支持x86系统。
|
||||
|华硕原生固件(optware)|smartdns.xxxxxxx.mipsbig.ipk|支持MIPS大端架构的系统,如RT-AC55U, RT-AC66U.
|
||||
|华硕原生固件(optware)|smartdns.xxxxxxx.mipsel.ipk|支持MIPS小端架构的系统,如RT-AC68U。
|
||||
|华硕原生固件(optware)|smartdns.xxxxxxx.arm.ipk|支持arm小端架构的系统,如RT-AC88U。
|
||||
|华硕原生固件(optware)|smartdns.xxxxxxx.mipsel.ipk|支持MIPS小端架构的系统。
|
||||
|华硕原生固件(optware)|smartdns.xxxxxxx.arm.ipk|支持arm小端架构的系统,如RT-AC68U。
|
||||
|Padavan|smartdns.xxxxxxx.mipselsf.ipk|padavan固件。
|
||||
|openwrt 15.01|smartdns.xxxxxxxx.ar71xx.ipk|支持AR71XX MIPS系统。
|
||||
|openwrt 15.01|smartdns.xxxxxxxx.ramips_24kec.ipk|支持MT762X等小端路由器
|
||||
|openwrt 15.01(潘多拉)|smartdns.xxxxxxxx.mipsel_24kec_dsp.ipk|支持MT7620系列的潘多拉固件
|
||||
|openwrt 15.01(潘多拉)|smartdns.xxxxxxxx.mips_74kc_dsp2.ipk|支持AR71xx系列的潘多拉固件
|
||||
|openwrt 18.06|smartdns.xxxxxxxx.mips_24kc.ipk|支持AR71XX MIPS系统。
|
||||
|openwrt 18.06|smartdns.xxxxxxxx.mipsel_24kc.ipk|支持MT726X等小端路由器
|
||||
|openwrt 18.06|smartdns.xxxxxxxx.x86_64.ipk|支持x86_64路由器
|
||||
@@ -367,6 +370,62 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
\\192.168.1.1\sda1\asusware.mipsbig\etc\init.d
|
||||
```
|
||||
|
||||
### Windows 10 WSL安装(WSL ubuntu)
|
||||
|
||||
--------------
|
||||
|
||||
1. 安装Windows 10 WSL ubuntu系统
|
||||
|
||||
安装Windows 10 WSL运行环境,发行版本选择ubuntu系统。安装步骤请参考[WSL安装说明](https://docs.microsoft.com/en-us/windows/wsl/install-win10)
|
||||
|
||||
1. 安装smartdns
|
||||
|
||||
下载安装包`smartdns.xxxxxxxx.x86_64.tar.gz`,并解压到D盘根目录。解压后目录如下:
|
||||
|
||||
```shell
|
||||
D:\SMARTDNS
|
||||
├─etc
|
||||
│ ├─default
|
||||
│ ├─init.d
|
||||
│ └─smartdns
|
||||
├─package
|
||||
│ └─windows
|
||||
├─src
|
||||
└─systemd
|
||||
|
||||
```
|
||||
|
||||
双击`D:\smartdns\package\windows`目录下的`install.bat`进行安装。要求输入密码时,请输入`WLS ubuntu`的密码。
|
||||
|
||||
1. 修改配置
|
||||
|
||||
记事本打开`D:\smartdns\etc\smartdns`目录中的`smartdns.conf`配置文件配置smartdns。具体配置参数参考`配置参数`说明。
|
||||
一般情况下,只需要增加`server [IP]:port`, `server-tcp [IP]:port`配置项,
|
||||
尽可能配置多个上游DNS服务器,包括国内外的服务器。配置参数请查看`配置参数`章节。
|
||||
|
||||
1. 重新加载配置
|
||||
|
||||
双击`D:\smartdns\package\windows`目录下的`reload.bat`进行安装。要求输入密码时,请输入`WLS ubuntu`的密码。
|
||||
|
||||
1. 将DNS请求转发的SmartDNS解析。
|
||||
|
||||
将Windows的默认DNS服务器修改为`127.0.0.1`,具体步骤参考[IP配置](https://support.microsoft.com/zh-cn/help/15089/windows-change-tcp-ip-settings)
|
||||
|
||||
1. 检测服务是否配置成功。
|
||||
|
||||
使用`nslookup -querytype=ptr 0.0.0.0`查询域名
|
||||
看命令结果中的`name`项目是否显示为`smartdns`或`主机名`,如`smartdns`则表示生效
|
||||
|
||||
```shell
|
||||
pi@raspberrypi:~/code/smartdns_build $ nslookup -querytype=ptr 0.0.0.0
|
||||
Server: 192.168.1.1
|
||||
Address: 192.168.1.1#53
|
||||
|
||||
Non-authoritative answer:
|
||||
0.0.0.0.in-addr.arpa name = smartdns.
|
||||
```
|
||||
|
||||
|
||||
## 配置参数
|
||||
|
||||
|参数|功能|默认值|配置值|例子|
|
||||
@@ -391,13 +450,15 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
|server|上游UDP DNS|无|[ip][:port] [-blacklist-ip][-check-edns],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server 8.8.8.8:53 -blacklist-ip -check-edns
|
||||
|server-tcp|上游TCP DNS|无|[IP][:port] [-blacklist-ip][-check-edns],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server-tcp 8.8.8.8:53
|
||||
|server-tls|上游TLS DNS|无|[IP][:port] [-blacklist-ip][-check-edns],可重复,blacklist-ip参数指定使用blacklist-ip配置IP过滤结果| server-tls 8.8.8.8:853
|
||||
|address|指定域名IP地址|无|address /domain/ip| address /www.example.com/1.2.3.4
|
||||
|ipset|域名IPSET|None|ipset /domain/ipset|ipset /www.example.com/pass
|
||||
|address|指定域名IP地址|无|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-`表示忽略, `#`表示返回SOA, `4`表示IPV4, `6`表示IPV6| address /www.example.com/1.2.3.4
|
||||
|ipset|域名IPSET|None|ipset /domain/[ipset\|-], `-`表示忽略|ipset /www.example.com/pass
|
||||
|ipset-timeout|设置IPSET超时功能启用|auto|[yes]|ipset-timeout yes
|
||||
|bogus-nxdomain|假冒IP地址过滤|无|[ip/subnet],可重复| bogus-nxdomain 1.2.3.4/16
|
||||
|ignore-ip|忽略IP地址|无|[ip/subnet],可重复| ignore-ip 1.2.3.4/16
|
||||
|blacklist-ip|黑名单IP地址|无|[ip/subnet],可重复| blacklist-ip 1.2.3.4/16
|
||||
|force-AAAA-SOA|强制AAAA地址返回SOA|no|[yes\|no]|force-AAAA-SOA yes
|
||||
|dualstack-ip-selection|双栈IP优选|no|[yes\|no]|dualstack-ip-selection yes
|
||||
|dualstack-ip-selection-threshold|双栈IP优选阈值|100ms|毫秒|dualstack-ip-selection-threshold [1-1000]
|
||||
|dualstack-ip-selection-threshold|双栈IP优选阈值|30ms|毫秒|dualstack-ip-selection-threshold [0-1000]
|
||||
|
||||
## [Donate](#Donate)
|
||||
|
||||
|
||||
@@ -36,18 +36,21 @@ cache-size 512
|
||||
# List of IPs that will be filtered when nameserver is configured -blacklist-ip parameter
|
||||
# blacklist-ip [ip/subnet]
|
||||
|
||||
# List of IPs that will be ignored
|
||||
# ignore-ip [ip/subnet]
|
||||
|
||||
# force AAAA query return SOA
|
||||
# force-AAAA-SOA [yes|no]
|
||||
|
||||
# Enable IPV4, IPV6 dual stack IP optimization selection strategy
|
||||
# dualstack-ip-selection-threshold [num] (1~1000)
|
||||
# dualstack-ip-selection-threshold [num] (0~1000)
|
||||
# dualstack-ip-selection [yes|no]
|
||||
# dualstack-ip-selection yes
|
||||
|
||||
# edns client subnet
|
||||
# edns-client-subnet-ipv4 [ip/subnet]
|
||||
# edns-client-subnet-ipv6 [ip/subnet]
|
||||
# edns-client-subnet-ipv4 192.168.1.1/24
|
||||
# edns-client-subnet [ip/subnet]
|
||||
# edns-client-subnet 192.168.1.1/24
|
||||
# edns-client-subnet [8::8]/56
|
||||
|
||||
# ttl for all resource record
|
||||
# rr-ttl: ttl for all record
|
||||
@@ -94,9 +97,15 @@ log-level info
|
||||
# server-tls 1.0.0.1
|
||||
|
||||
# specific address to domain
|
||||
# address /domain/ip
|
||||
# address /www.example.com/1.2.3.4
|
||||
# address /domain/[ip|-|-4|-6|#|#4|#6]
|
||||
# address /www.example.com/1.2.3.4, return ip 1.2.3.4 to client
|
||||
# address /www.example.com/-, ignore address, query from upstream, suffix 4, for ipv4, 6 for ipv6, none for all
|
||||
# address /www.example.com/#, return SOA to client, suffix 4, for ipv4, 6 for ipv6, none for all
|
||||
|
||||
# enable ipset timeout by ttl feature
|
||||
# ipset-timeout [yes]
|
||||
|
||||
# specific ipset to domain
|
||||
# ipset /domain/ipset
|
||||
# ipset /www.example.com/block
|
||||
# ipset /domain/[ipset|-]
|
||||
# ipset /www.example.com/block, set ipset with ipset name of block
|
||||
# ipset /www.example.com/-, ignore this domain
|
||||
40
install
40
install
@@ -4,6 +4,7 @@
|
||||
#
|
||||
|
||||
INST_DIR=$(cd $(dirname $0);pwd)
|
||||
ISWSL=1 # 1 means not WSL, 0 means wsl
|
||||
|
||||
showhelp()
|
||||
{
|
||||
@@ -18,7 +19,7 @@ showhelp()
|
||||
start_service()
|
||||
{
|
||||
if [ $ISSYSTEMD -ne 0 ]; then
|
||||
chkconfig smartdns on
|
||||
chkconfig smartdns on >/dev/null 2>&1
|
||||
service smartdns start
|
||||
return $?
|
||||
fi
|
||||
@@ -32,7 +33,7 @@ stop_service()
|
||||
{
|
||||
if [ $ISSYSTEMD -ne 0 ]; then
|
||||
service smartdns stop
|
||||
chkconfig smartdns off
|
||||
chkconfig smartdns off >/dev/null 2>&1
|
||||
return 0
|
||||
fi
|
||||
|
||||
@@ -101,13 +102,17 @@ install_files()
|
||||
uninstall_smartdns()
|
||||
{
|
||||
if [ -z "$PREFIX" ]; then
|
||||
stop_service
|
||||
stop_service 2>/dev/null
|
||||
fi
|
||||
rm -f $PREFIX$SMARTDNS_CONF_DIR/smartdns.conf
|
||||
rmdir $PREFIX$SMARTDNS_CONF_DIR
|
||||
rmdir $PREFIX$SMARTDNS_CONF_DIR 2>/dev/null
|
||||
rm -f $PREFIX/usr/sbin/smartdns
|
||||
rm -f $PREFIX/etc/default/smartdns
|
||||
|
||||
if [ $ISWSL -eq 0 ]; then
|
||||
sed -i '\#%sudo ALL=NOPASSWD: /etc/init.d/smartdns#d' /etc/sudoers 2>/dev/null
|
||||
fi
|
||||
|
||||
if [ $ISSYSTEMD -eq 0 ]; then
|
||||
SYSTEM_UNIT_PATH="`get_systemd_path`"
|
||||
if [ ! -z "$SYSTEM_UNIT_PATH" ]; then
|
||||
@@ -125,6 +130,12 @@ install_smartdns()
|
||||
{
|
||||
local ret
|
||||
|
||||
which smartdns >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Already installed."
|
||||
return 1
|
||||
fi
|
||||
|
||||
install_files
|
||||
ret=$?
|
||||
if [ $ret -ne 0 ]; then
|
||||
@@ -136,17 +147,34 @@ install_smartdns()
|
||||
start_service
|
||||
fi
|
||||
|
||||
if [ $ISWSL -eq 0 ]; then
|
||||
grep "%sudo ALL=NOPASSWD: /etc/init.d/smartdns" /etc/sudoers >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "%sudo ALL=NOPASSWD: /etc/init.d/smartdns" >> /etc/sudoers
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
init_dir()
|
||||
{
|
||||
local ID=`id -u`
|
||||
if [ $ID -ne 0 ]; then
|
||||
echo "Please run as root."
|
||||
return 1
|
||||
fi
|
||||
|
||||
SMARTDNS_CONF_DIR=$PREFIX/etc/smartdns
|
||||
SMARTDNS_INIT_DIR=$PREFIX/etc/init.d
|
||||
which systemctl >/dev/null 2>&1
|
||||
ISSYSTEMD="$?"
|
||||
# Running under WSL (Windows Subsystem for Linux)?
|
||||
cat /proc/version | grep Microsoft >/dev/null 2>&1;
|
||||
if [ $? -eq 0 ]; then
|
||||
ISSYSTEMD=1
|
||||
ISWSL=0
|
||||
fi
|
||||
|
||||
cd $INST_DIR
|
||||
}
|
||||
|
||||
@@ -67,6 +67,12 @@ msgstr "双栈IP优选"
|
||||
msgid "Enable IP selection between IPV4 and IPV6"
|
||||
msgstr "启用或禁用IPV4,IPV6间的IP优选策略。"
|
||||
|
||||
msgid "Domain prefetch"
|
||||
msgstr "域名预加载"
|
||||
|
||||
msgid "Enable domain prefetch, accelerate domain response speed."
|
||||
msgstr "启用域名预加载,加速域名响应速度。"
|
||||
|
||||
msgid "Redirect"
|
||||
msgstr "重定向"
|
||||
|
||||
|
||||
@@ -60,6 +60,14 @@ o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "0"
|
||||
end
|
||||
|
||||
---- Domain prefetch load
|
||||
o = s:taboption("settings", Flag, "prefetch_domain", translate("Domain prefetch"), translate("Enable domain prefetch, accelerate domain response speed."))
|
||||
o.rmempty = false
|
||||
o.default = o.disabled
|
||||
o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "0"
|
||||
end
|
||||
|
||||
---- Redirect
|
||||
o = s:taboption("settings", ListValue, "redirect", translate("Redirect"), translate("SmartDNS redirect mode"))
|
||||
o.placeholder = "none"
|
||||
|
||||
@@ -63,7 +63,7 @@ build()
|
||||
tar zcf $ROOT/data.tar.gz -C root .
|
||||
tar zcf $OUTPUTDIR/luci-app-smartdns.$VER.$ARCH.ipk control.tar.gz data.tar.gz debian-binary
|
||||
|
||||
#rm -fr $ROOT/
|
||||
rm -fr $ROOT/
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
# Add domains which you want to force to an IP address here.
|
||||
# The example below send any host in example.com to a local webserver.
|
||||
# address /example.com/127.0.0.1
|
||||
# address /domain/[ip|-|-4|-6|#|#4|#6]
|
||||
# address /www.example.com/1.2.3.4, return ip 1.2.3.4 to client
|
||||
# address /www.example.com/-, ignore address, query from upstream, suffix 4, for ipv4, 6 for ipv6, none for all
|
||||
# address /www.example.com/#, return SOA to client, suffix 4, for ipv4, 6 for ipv6, none for all
|
||||
|
||||
# specific ipset to domain
|
||||
# ipset /domain/[ipset|-]
|
||||
# ipset /www.example.com/block, set ipset with ipset name of block
|
||||
# ipset /www.example.com/-, ignore this domain
|
||||
@@ -217,6 +217,11 @@ load_service() {
|
||||
conf_append "dualstack-ip-selection" "yes"
|
||||
fi
|
||||
|
||||
config_get "prefetch_domain" "$section" "prefetch_domain" "0"
|
||||
if [ "$prefetch_domain" = "1" ]; then
|
||||
conf_append "prefetch-domain" "yes"
|
||||
fi
|
||||
|
||||
SMARTDNS_PORT="$port"
|
||||
|
||||
config_get "cache_size" "$section" "cache_size" ""
|
||||
|
||||
@@ -2,8 +2,20 @@
|
||||
|
||||
SMARTDNS_BIN=/opt/usr/sbin/smartdns
|
||||
SMARTDNS_CONF=/opt/etc/smartdns/smartdns.conf
|
||||
DNSMASQ_CONF=/etc/dnsmasq.conf
|
||||
SMARTDNS_PID="/var/run/smartdns.pid"
|
||||
SMARTDNS_PORT=535
|
||||
SMARTDNS_OPT=/opt/etc/smartdns/smartdns-opt.conf
|
||||
# workmode
|
||||
# 0: run as port only
|
||||
# 1: redirect port
|
||||
# 2: replace
|
||||
SMARTDNS_WORKMODE="1"
|
||||
|
||||
if [ -f "$SMARTDNS_OPT" ]; then
|
||||
. $SMARTDNS_OPT
|
||||
fi
|
||||
|
||||
|
||||
set_iptable()
|
||||
{
|
||||
@@ -38,16 +50,165 @@ clear_iptable()
|
||||
|
||||
}
|
||||
|
||||
restart_dnsmasq()
|
||||
{
|
||||
CMD="`ps | grep " dnsmasq" | grep -v grep`"
|
||||
if [ -z "$CMD" ]; then
|
||||
CMD="`ps ax | grep dnsmasq | grep -v grep`"
|
||||
fi
|
||||
|
||||
if [ -z "$CMD" ]; then
|
||||
echo "cannot find dnsmasq"
|
||||
return 1
|
||||
fi
|
||||
|
||||
PID=`echo "$CMD" | awk '{print $1}'`
|
||||
if [ ! -d "/proc/$PID" ]; then
|
||||
echo "dnsmasq is not running"
|
||||
return 1
|
||||
fi
|
||||
|
||||
kill -9 $PID
|
||||
|
||||
DNSMASQ_CMD="`echo $CMD | awk '{for(i=5; i<=NF;i++)printf \$i " "}'`"
|
||||
|
||||
$DNSMASQ_CMD
|
||||
}
|
||||
|
||||
get_server_ip()
|
||||
{
|
||||
IPS="`ifconfig | grep "inet addr" | grep -v ":127" | grep "Bcast" | awk '{print $2}' | awk -F: '{print $2}'`"
|
||||
LOCAL_SERVER_IP=""
|
||||
for IP in $IPS
|
||||
do
|
||||
N=3
|
||||
while [ $N -gt 0 ]
|
||||
do
|
||||
ADDR=`echo $IP | awk -F. "{for(i=1;i<=$N;i++)printf \\$i\".\"}"`
|
||||
grep "dhcp-range=" $DNSMASQ_CONF | grep $ADDR >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
SERVER_TAG="`grep "^dhcp-range *=" $DNSMASQ_CONF | grep $ADDR | awk -F= '{print $2}' | awk -F, '{print $1}'`"
|
||||
LOCAL_SERVER_IP="$IP"
|
||||
return 0
|
||||
fi
|
||||
N="`expr $N - 1`"
|
||||
done
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
set_dnsmasq()
|
||||
{
|
||||
local RESTART_DNSMASQ=0
|
||||
local LOCAL_SERVER_IP=""
|
||||
local SERVER_TAG=""
|
||||
get_server_ip
|
||||
if [ "$LOCAL_SERVER_IP" ] && [ "$SERVER_TAG" ]; then
|
||||
grep "dhcp-option *=" $DNSMASQ_CONF | grep "$SERVER_TAG,6,$LOCAL_SERVER_IP" > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
sed -i "/^dhcp-option *=$SERVER_TAG,6,/d" $DNSMASQ_CONF
|
||||
echo "dhcp-option=$SERVER_TAG,6,$LOCAL_SERVER_IP" >> $DNSMASQ_CONF
|
||||
RESTART_DNSMASQ=1
|
||||
fi
|
||||
fi
|
||||
|
||||
grep "^port *=0" $DNSMASQ_CONF > /dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
sed -i "/^port *=/d" $DNSMASQ_CONF
|
||||
echo "port=0" >> $DNSMASQ_CONF
|
||||
RESTART_DNSMASQ=1
|
||||
fi
|
||||
|
||||
if [ $RESTART_DNSMASQ -ne 0 ]; then
|
||||
restart_dnsmasq
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
clear_dnsmasq()
|
||||
{
|
||||
local RESTART_DNSMASQ=0
|
||||
local LOCAL_SERVER_IP=""
|
||||
local SERVER_TAG=""
|
||||
get_server_ip
|
||||
if [ "$LOCAL_SERVER_IP" ] && [ "$SERVER_TAG" ]; then
|
||||
grep "dhcp-option *=" $DNSMASQ_CONF | grep "$SERVER_TAG,6,$LOCAL_SERVER_IP" > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
sed -i "/^dhcp-option *=$SERVER_TAG,6,/d" $DNSMASQ_CONF
|
||||
RESTART_DNSMASQ=1
|
||||
fi
|
||||
fi
|
||||
|
||||
grep "^port *=" $DNSMASQ_CONF > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
sed -i "/^port *=/d" $DNSMASQ_CONF
|
||||
RESTART_DNSMASQ=1
|
||||
fi
|
||||
|
||||
if [ $RESTART_DNSMASQ -ne 0 ]; then
|
||||
restart_dnsmasq
|
||||
fi
|
||||
}
|
||||
|
||||
set_smartdns_port()
|
||||
{
|
||||
if [ "$SMARTDNS_WORKMODE" = "0" ]; then
|
||||
return 0
|
||||
elif [ "$SMARTDNS_WORKMODE" = "1" ]; then
|
||||
sed -i "s/^\(bind .*\):53 *\(.*\)\$/\1:$SMARTDNS_PORT \2/g" $SMARTDNS_CONF
|
||||
sed -i "s/^\(bind-tcp .*\):53 *\(.*\)\$/\1:$SMARTDNS_PORT \2/g" $SMARTDNS_CONF
|
||||
elif [ "$SMARTDNS_WORKMODE" = "2" ]; then
|
||||
sed -i "s/^\(bind .*\):$SMARTDNS_PORT *\(.*\)\$/\1:53 \2/g" $SMARTDNS_CONF
|
||||
sed -i "s/^\(bind-tcp .*\):$SMARTDNS_PORT *\(.*\)\$/\1:53 \2/g" $SMARTDNS_CONF
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
set_rule()
|
||||
{
|
||||
if [ "$SMARTDNS_WORKMODE" = "0" ]; then
|
||||
return 0
|
||||
elif [ "$SMARTDNS_WORKMODE" = "1" ]; then
|
||||
set_iptable
|
||||
return $?
|
||||
elif [ "$SMARTDNS_WORKMODE" = "2" ]; then
|
||||
set_dnsmasq
|
||||
return $?
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
clear_rule()
|
||||
{
|
||||
if [ "$SMARTDNS_WORKMODE" = "0" ]; then
|
||||
return 0
|
||||
elif [ "$SMARTDNS_WORKMODE" = "1" ]; then
|
||||
clear_iptable
|
||||
return $?
|
||||
elif [ "$SMARTDNS_WORKMODE" = "2" ]; then
|
||||
clear_dnsmasq
|
||||
return $?
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
set_iptable
|
||||
set_rule
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
set_smartdns_port
|
||||
$SMARTDNS_BIN -c $SMARTDNS_CONF -p $SMARTDNS_PID
|
||||
if [ $? -ne 0 ]; then
|
||||
clear_iptable
|
||||
clear_rule
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
@@ -65,7 +226,7 @@ case "$1" in
|
||||
return 0;
|
||||
;;
|
||||
stop)
|
||||
clear_iptable
|
||||
clear_rule
|
||||
pid="`cat $SMARTDNS_PID | head -n 1 2>/dev/null`"
|
||||
if [ -z "$pid" ]; then
|
||||
echo "smartdns not running."
|
||||
@@ -78,7 +239,7 @@ case "$1" in
|
||||
|
||||
kill -9 $pid 2>/dev/null
|
||||
;;
|
||||
force-reload|restart)
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
@@ -89,7 +250,7 @@ case "$1" in
|
||||
nvram set apps_state_action=install
|
||||
nvram set apps_u2ec_ex=2
|
||||
;;
|
||||
firewall-start)
|
||||
firewall-start|reload|force-reload|reconfigure)
|
||||
$0 restart
|
||||
;;
|
||||
*)
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/opt/etc/smartdns/smartdns.conf
|
||||
/opt/etc/smartdns/smartdns-opt.conf
|
||||
|
||||
@@ -5,6 +5,7 @@ VER="`date +"1.%Y.%m.%d-%H%M"`"
|
||||
SMARTDNS_DIR=$CURR_DIR/../../
|
||||
SMARTDNS_BIN=$SMARTDNS_DIR/src/smartdns
|
||||
SMARTDNS_CONF=$SMARTDNS_DIR/etc/smartdns/smartdns.conf
|
||||
SMARTDNS_OPT=$CURR_DIR/smartdns-opt.conf
|
||||
|
||||
showhelp()
|
||||
{
|
||||
@@ -29,10 +30,10 @@ build()
|
||||
mkdir $ROOT/opt/etc/smartdns/ -p
|
||||
|
||||
cp $SMARTDNS_CONF $ROOT/opt/etc/smartdns/
|
||||
cp $SMARTDNS_OPT $ROOT/opt/etc/smartdns/
|
||||
cp $CURR_DIR/S50smartdns $ROOT/opt/etc/init.d/
|
||||
cp $SMARTDNS_BIN $ROOT/opt/usr/sbin
|
||||
|
||||
sed -i "s/^\(bind .*\):53/\1:535/g" $ROOT/opt/etc/smartdns/smartdns.conf
|
||||
sed -i "s/# *server-name smartdns/server-name smartdns/g" $ROOT/opt/etc/smartdns/smartdns.conf
|
||||
sed -i "s/^Architecture.*/Architecture: $ARCH/g" $ROOT/control/control
|
||||
sed -i "s/Version:.*/Version: $VER/" $ROOT/control/control
|
||||
|
||||
8
package/optware/smartdns-opt.conf
Normal file
8
package/optware/smartdns-opt.conf
Normal file
@@ -0,0 +1,8 @@
|
||||
# workmode
|
||||
# 0: run as port only
|
||||
# 1: redirect port
|
||||
# 2: replace
|
||||
SMARTDNS_WORKMODE="1"
|
||||
|
||||
# smartdns port
|
||||
SMARTDNS_PORT="535"
|
||||
21
package/windows/install.bat
Normal file
21
package/windows/install.bat
Normal file
@@ -0,0 +1,21 @@
|
||||
@echo off
|
||||
set "CURR_PATH=%~dp0"
|
||||
set "STARTUP_PATH=%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
|
||||
FOR /F %%i IN ('wsl pwd') DO @set DIR_IN_WSL=%%i
|
||||
|
||||
wsl sudo %DIR_IN_WSL%/../../install -i
|
||||
IF NOT %ERRORLEVEL% == 0 (
|
||||
echo Install smartdns failed.
|
||||
pause
|
||||
exit 1
|
||||
)
|
||||
|
||||
copy %CURR_PATH%\wsl-run.vbs "%STARTUP_PATH%/"
|
||||
IF NOT %ERRORLEVEL% == 0 (
|
||||
echo Install startupt script failed.
|
||||
pause
|
||||
exit 1
|
||||
)
|
||||
|
||||
echo Install smartdns success
|
||||
pause
|
||||
21
package/windows/reload.bat
Normal file
21
package/windows/reload.bat
Normal file
@@ -0,0 +1,21 @@
|
||||
@echo off
|
||||
set "CURR_PATH=%~dp0"
|
||||
set "STARTUP_PATH=%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
|
||||
FOR /F %%i IN ('wsl pwd') DO @set DIR_IN_WSL=%%i
|
||||
|
||||
wsl sudo cp -avf %DIR_IN_WSL%/../../etc/smartdns/* /etc/smartdns/
|
||||
IF NOT %ERRORLEVEL% == 0 (
|
||||
echo copy smartdns configuration file failed.
|
||||
pause
|
||||
exit 1
|
||||
)
|
||||
|
||||
wsl sudo /etc/init.d/smartdns restart
|
||||
IF NOT %ERRORLEVEL% == 0 (
|
||||
echo reload smartdns failed.
|
||||
pause
|
||||
exit 1
|
||||
)
|
||||
|
||||
echo reload smartdns success
|
||||
pause
|
||||
22
package/windows/uninstall.bat
Normal file
22
package/windows/uninstall.bat
Normal file
@@ -0,0 +1,22 @@
|
||||
@echo off
|
||||
set "CURR_PATH=%~dp0"
|
||||
set "STARTUP_PATH=%userprofile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
|
||||
FOR /F %%i IN ('wsl pwd') DO @set DIR_IN_WSL=%%i
|
||||
|
||||
wsl sudo %DIR_IN_WSL%/../../install -u
|
||||
IF NOT %ERRORLEVEL% == 0 (
|
||||
echo Uninstall smartdns failed.
|
||||
pause
|
||||
exit 1
|
||||
)
|
||||
|
||||
del "%STARTUP_PATH%\wsl-run.vbs"
|
||||
IF NOT %ERRORLEVEL% == 0 (
|
||||
echo Uninstall startup script failed.
|
||||
pause
|
||||
exit 1
|
||||
)
|
||||
|
||||
echo uninstall success
|
||||
|
||||
pause
|
||||
2
package/windows/wsl-run.vbs
Normal file
2
package/windows/wsl-run.vbs
Normal file
@@ -0,0 +1,2 @@
|
||||
Set ws = WScript.CreateObject("WScript.Shell")
|
||||
ws.run "wsl sudo /etc/init.d/smartdns restart", vbhide
|
||||
@@ -2,10 +2,10 @@
|
||||
BIN=smartdns
|
||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.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 $(OBJS_LIB)
|
||||
CFLAGS +=-O2 -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing
|
||||
CFLAGS +=-O2 -g -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing
|
||||
CFLAGS +=-Iinclude
|
||||
CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
|
||||
CXXFLAGS=-O2 -Wall -std=c++11
|
||||
CXXFLAGS=-O2 -g -Wall -std=c++11
|
||||
CXXFLAGS +=-Iinclude
|
||||
LDFLAGS += -lpthread -lssl -lcrypto
|
||||
|
||||
|
||||
62
src/dns.c
62
src/dns.c
@@ -144,8 +144,8 @@ unsigned char *_dns_add_rrs_start(struct dns_packet *packet, int *maxlen)
|
||||
unsigned char *end = packet->data + packet->len;
|
||||
|
||||
rrs = (struct dns_rrs *)end;
|
||||
*maxlen = packet->size - packet->len - sizeof(*packet);
|
||||
if (packet->len >= packet->size - sizeof(*packet)) {
|
||||
*maxlen = packet->size - packet->len - sizeof(*packet) - sizeof(*rrs);
|
||||
if (*maxlen <= 0) {
|
||||
/* if size exceeds max packet size, return NULL */
|
||||
return NULL;
|
||||
}
|
||||
@@ -163,7 +163,7 @@ int dns_rr_add_end(struct dns_packet *packet, int type, dns_type_t rtype, int le
|
||||
unsigned short *start;
|
||||
|
||||
rrs = (struct dns_rrs *)end;
|
||||
if (packet->len + len > packet->size - sizeof(*packet)) {
|
||||
if (packet->len + len > packet->size - sizeof(*packet) - sizeof(*rrs)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ int _dns_add_qr_head(struct dns_data_context *data_context, char *domain, int qt
|
||||
* |qtype | qclass |
|
||||
*/
|
||||
while (1) {
|
||||
if (_dns_data_left_len(data_context) < 1) {
|
||||
if (_dns_data_left_len(data_context) < 4) {
|
||||
return -1;
|
||||
}
|
||||
*data_context->ptr = *domain;
|
||||
@@ -259,8 +259,8 @@ int _dns_get_qr_head(struct dns_data_context *data_context, char *domain, int ma
|
||||
/* |domain |
|
||||
* |qtype | qclass |
|
||||
*/
|
||||
for (i = 0; i < maxsize; i++) {
|
||||
if (_dns_data_left_len(data_context) < 1) {
|
||||
for (i = 0; i < maxsize - 1; i++) {
|
||||
if (_dns_data_left_len(data_context) < 4) {
|
||||
return -1;
|
||||
}
|
||||
*domain = *data_context->ptr;
|
||||
@@ -275,6 +275,8 @@ int _dns_get_qr_head(struct dns_data_context *data_context, char *domain, int ma
|
||||
data_context->ptr++;
|
||||
}
|
||||
|
||||
*domain = '\0';
|
||||
|
||||
if (_dns_data_left_len(data_context) < 4) {
|
||||
return -1;
|
||||
}
|
||||
@@ -841,10 +843,11 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz
|
||||
int len = *(context->ptr);
|
||||
unsigned char *ptr = context->ptr;
|
||||
int is_compressed = 0;
|
||||
int ptr_jump = 0;
|
||||
|
||||
/*[len]string[len]string...[0]0 */
|
||||
while (1) {
|
||||
if (ptr > context->data + context->maxsize || ptr < context->data) {
|
||||
if (ptr > context->data + context->maxsize || ptr < context->data || output_len >= size - 1 || ptr_jump > 4) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -877,13 +880,17 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz
|
||||
return -1;
|
||||
}
|
||||
is_compressed = 1;
|
||||
ptr_jump++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr_jump = 0;
|
||||
|
||||
/* change [len] to '.' */
|
||||
if (output_len > 0) {
|
||||
*output = '.';
|
||||
output++;
|
||||
output_len += 1;
|
||||
}
|
||||
|
||||
if (ptr > context->data + context->maxsize) {
|
||||
@@ -1422,6 +1429,12 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
}
|
||||
opt_code = dns_read_short(&context->ptr);
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "opt type %d", opt_code);
|
||||
switch (opt_code) {
|
||||
case DNS_OPT_T_ECS: {
|
||||
@@ -1586,6 +1599,10 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
dns_set_OPT_payload_size(packet, qclass);
|
||||
} break;
|
||||
default:
|
||||
if (_dns_left_len(context) < rr_len) {
|
||||
tlog(TLOG_DEBUG, "length mitchmatch\n");
|
||||
return -1;
|
||||
}
|
||||
context->ptr += rr_len;
|
||||
tlog(TLOG_DEBUG, "DNS type = %d not supported", qtype);
|
||||
break;
|
||||
@@ -1661,41 +1678,46 @@ static int _dns_decode_body(struct dns_context *context)
|
||||
struct dns_head *head = &packet->head;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
int count = 0;
|
||||
|
||||
for (i = 0; i < head->qdcount; i++) {
|
||||
count = head->qdcount;
|
||||
head->qdcount = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = _dns_decode_qd(context);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_DEBUG, "decode qd failed.");
|
||||
return -1;
|
||||
}
|
||||
head->qdcount--;
|
||||
}
|
||||
|
||||
for (i = 0; i < head->ancount; i++) {
|
||||
count = head->ancount;
|
||||
head->ancount = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = _dns_decode_an(context, DNS_RRS_AN);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_DEBUG, "decode an failed.");
|
||||
return -1;
|
||||
}
|
||||
head->ancount--;
|
||||
}
|
||||
|
||||
for (i = 0; i < head->nscount; i++) {
|
||||
count = head->nscount;
|
||||
head->nscount = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = _dns_decode_an(context, DNS_RRS_NS);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_DEBUG, "decode ns failed.");
|
||||
return -1;
|
||||
}
|
||||
head->nscount--;
|
||||
}
|
||||
|
||||
for (i = 0; i < head->nrcount; i++) {
|
||||
count = head->nrcount;
|
||||
head->nrcount = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = _dns_decode_an(context, DNS_RRS_NR);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_DEBUG, "decode nr failed.");
|
||||
return -1;
|
||||
}
|
||||
head->nrcount--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1761,6 +1783,10 @@ static int _dns_encode_body(struct dns_context *context)
|
||||
int dns_packet_init(struct dns_packet *packet, int size, struct dns_head *head)
|
||||
{
|
||||
struct dns_head *init_head = &packet->head;
|
||||
if (size < sizeof(*packet)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(packet, 0, size);
|
||||
packet->size = size;
|
||||
init_head->id = head->id;
|
||||
@@ -1796,7 +1822,11 @@ int dns_decode(struct dns_packet *packet, int maxsize, unsigned char *data, int
|
||||
context.ptr = data;
|
||||
context.maxsize = size;
|
||||
|
||||
dns_packet_init(packet, maxsize, head);
|
||||
ret = dns_packet_init(packet, maxsize, head);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = _dns_decode_head(&context);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
|
||||
@@ -31,7 +31,7 @@ struct dns_cache *_dns_cache_last(void)
|
||||
|
||||
struct dns_cache *_dns_cache_first(void)
|
||||
{
|
||||
return list_first_entry(&dns_cache_head.cache_list, struct dns_cache, list);
|
||||
return list_first_entry_or_null(&dns_cache_head.cache_list, struct dns_cache, list);
|
||||
}
|
||||
|
||||
void _dns_cache_delete(struct dns_cache *dns_cache)
|
||||
@@ -59,6 +59,13 @@ void dns_cache_release(struct dns_cache *dns_cache)
|
||||
_dns_cache_delete(dns_cache);
|
||||
}
|
||||
|
||||
void _dns_cache_remove(struct dns_cache *dns_cache)
|
||||
{
|
||||
hash_del(&dns_cache->node);
|
||||
list_del_init(&dns_cache->list);
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
|
||||
int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr, int addr_len)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
@@ -72,10 +79,17 @@ int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_typ
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||
ttl = DNS_CACHE_TTL_MIN;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
dns_cache->ttl = ttl;
|
||||
dns_cache->qtype = qtype;
|
||||
dns_cache->ttl = ttl;
|
||||
dns_cache->del_pending = 0;
|
||||
time(&dns_cache->insert_time);
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
if (qtype == DNS_T_A) {
|
||||
if (addr_len != DNS_RR_A_LEN) {
|
||||
goto errout;
|
||||
@@ -116,6 +130,7 @@ int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type
|
||||
|
||||
dns_cache = dns_cache_lookup(domain, qtype);
|
||||
if (dns_cache) {
|
||||
dns_cache_delete(dns_cache);
|
||||
dns_cache_release(dns_cache);
|
||||
dns_cache = NULL;
|
||||
}
|
||||
@@ -125,12 +140,18 @@ int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||
ttl = DNS_CACHE_TTL_MIN;
|
||||
}
|
||||
|
||||
key = hash_string(domain);
|
||||
key = jhash(&qtype, sizeof(qtype), key);
|
||||
strncpy(dns_cache->domain, domain, DNS_MAX_CNAME_LEN);
|
||||
dns_cache->cname[0] = 0;
|
||||
dns_cache->qtype = qtype;
|
||||
dns_cache->ttl = ttl;
|
||||
dns_cache->hitnum = 2;
|
||||
dns_cache->del_pending = 0;
|
||||
atomic_set(&dns_cache->ref, 1);
|
||||
time(&dns_cache->insert_time);
|
||||
if (qtype == DNS_T_A) {
|
||||
@@ -161,7 +182,9 @@ int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type
|
||||
if (dns_cache_head.num > dns_cache_head.size) {
|
||||
struct dns_cache *del_cache;
|
||||
del_cache = _dns_cache_first();
|
||||
dns_cache_release(del_cache);
|
||||
if (del_cache) {
|
||||
_dns_cache_remove(del_cache);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
@@ -206,10 +229,10 @@ struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
|
||||
if (dns_cache_ret) {
|
||||
if (now - dns_cache_ret->insert_time > dns_cache_ret->ttl) {
|
||||
_dns_cache_delete(dns_cache_ret);
|
||||
_dns_cache_remove(dns_cache_ret);
|
||||
dns_cache_ret = NULL;
|
||||
} else {
|
||||
atomic_inc(&dns_cache_ret->ref);
|
||||
dns_cache_get(dns_cache_ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,10 +258,8 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache)
|
||||
void dns_cache_delete(struct dns_cache *dns_cache)
|
||||
{
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_del(&dns_cache->node);
|
||||
list_del_init(&dns_cache->list);
|
||||
_dns_cache_remove(dns_cache);
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
|
||||
void dns_cache_update(struct dns_cache *dns_cache)
|
||||
@@ -247,6 +268,7 @@ void dns_cache_update(struct dns_cache *dns_cache)
|
||||
if (!list_empty(&dns_cache->list)) {
|
||||
list_del_init(&dns_cache->list);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
dns_cache->hitnum++;
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
}
|
||||
@@ -268,31 +290,26 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list)
|
||||
{
|
||||
ttl = dns_cache->insert_time + dns_cache->ttl - now;
|
||||
if (ttl > 0) {
|
||||
if (ttl < ttl_pre) {
|
||||
if (callback) {
|
||||
list_add_tail(&dns_cache->check_list, &checklist);
|
||||
dns_cache_get(dns_cache);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
if (ttl > 0 && ttl < ttl_pre) {
|
||||
if (callback && dns_cache->del_pending == 0) {
|
||||
list_add_tail(&dns_cache->check_list, &checklist);
|
||||
dns_cache_get(dns_cache);
|
||||
dns_cache->del_pending = 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
hash_del(&dns_cache->node);
|
||||
list_del_init(&dns_cache->list);
|
||||
dns_cache_release(dns_cache);
|
||||
if (ttl < 0) {
|
||||
_dns_cache_remove(dns_cache);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
list_for_each_entry_safe(dns_cache, tmp, &checklist, check_list)
|
||||
{
|
||||
callback(dns_cache);
|
||||
list_del_init(&dns_cache->check_list);
|
||||
if (callback) {
|
||||
callback(dns_cache);
|
||||
}
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "list.h"
|
||||
#include <time.h>
|
||||
|
||||
#define DNS_CACHE_TTL_MIN 30
|
||||
|
||||
struct dns_cache {
|
||||
struct hlist_node node;
|
||||
struct list_head list;
|
||||
@@ -17,6 +19,8 @@ struct dns_cache {
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
unsigned int cname_ttl;
|
||||
unsigned int ttl;
|
||||
int hitnum;
|
||||
int del_pending;
|
||||
time_t insert_time;
|
||||
dns_type_t qtype;
|
||||
union {
|
||||
|
||||
728
src/dns_client.c
728
src/dns_client.c
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ typedef enum {
|
||||
DNS_SERVER_UDP,
|
||||
DNS_SERVER_TCP,
|
||||
DNS_SERVER_TLS,
|
||||
DNS_SERVER_HTTPS,
|
||||
DNS_SERVER_TYPE_END,
|
||||
} dns_server_type_t;
|
||||
|
||||
|
||||
275
src/dns_conf.c
275
src/dns_conf.c
@@ -8,6 +8,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#define DEFAULT_DNS_CACHE_SIZE 512
|
||||
|
||||
@@ -34,16 +35,18 @@ size_t dns_conf_audit_size = 1024 * 1024;
|
||||
int dns_conf_audit_num = 2;
|
||||
|
||||
art_tree dns_conf_domain_rule;
|
||||
radix_tree_t *dns_conf_address_rule;
|
||||
struct dns_conf_address_rule dns_conf_address_rule;
|
||||
|
||||
int dns_conf_dualstack_ip_selection;
|
||||
int dns_conf_dualstack_ip_selection_threshold = 100;
|
||||
int dns_conf_dualstack_ip_selection_threshold = 30;
|
||||
|
||||
int dns_conf_rr_ttl;
|
||||
int dns_conf_rr_ttl_min;
|
||||
int dns_conf_rr_ttl_max;
|
||||
int dns_conf_force_AAAA_SOA;
|
||||
|
||||
int dns_conf_ipset_timeout_enable;
|
||||
|
||||
struct dns_edns_client_subnet dns_conf_ipv4_ecs;
|
||||
struct dns_edns_client_subnet dns_conf_ipv6_ecs;
|
||||
|
||||
@@ -92,7 +95,7 @@ int config_server(int argc, char *argv[], dns_server_type_t type, int default_po
|
||||
}
|
||||
|
||||
ttl = atoi(optarg);
|
||||
if (ttl < 0 || ttl > 255) {
|
||||
if (ttl < -255 || ttl > 255) {
|
||||
tlog(TLOG_ERROR, "ttl value is invalid.");
|
||||
return -1;
|
||||
}
|
||||
@@ -213,7 +216,59 @@ errout:
|
||||
free(add_domain_rule);
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "add doamin %s failed", domain);
|
||||
tlog(TLOG_ERROR, "add doamin %s rule failed", domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_domain_rule_flag_set(char *domain, unsigned int flag)
|
||||
{
|
||||
struct dns_domain_rule *domain_rule = NULL;
|
||||
struct dns_domain_rule *old_domain_rule = NULL;
|
||||
struct dns_domain_rule *add_domain_rule = NULL;
|
||||
struct dns_rule_flags *rule_flags = NULL;
|
||||
|
||||
char domain_key[DNS_MAX_CONF_CNAME_LEN];
|
||||
int len = 0;
|
||||
|
||||
len = strlen(domain);
|
||||
reverse_string(domain_key, domain, len);
|
||||
domain_key[len] = '.';
|
||||
len++;
|
||||
domain_key[len] = 0;
|
||||
|
||||
domain_rule = art_search(&dns_conf_domain_rule, (unsigned char *)domain_key, len);
|
||||
if (domain_rule == NULL) {
|
||||
add_domain_rule = malloc(sizeof(*add_domain_rule));
|
||||
if (add_domain_rule == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memset(add_domain_rule, 0, sizeof(*add_domain_rule));
|
||||
domain_rule = add_domain_rule;
|
||||
}
|
||||
|
||||
if (domain_rule->rules[DOMAIN_RULE_FLAGS] == NULL) {
|
||||
rule_flags = malloc(sizeof(*rule_flags));
|
||||
rule_flags->flags = 0;
|
||||
domain_rule->rules[DOMAIN_RULE_FLAGS] = rule_flags;
|
||||
}
|
||||
|
||||
rule_flags = domain_rule->rules[DOMAIN_RULE_FLAGS];
|
||||
rule_flags->flags |= flag;
|
||||
|
||||
if (add_domain_rule) {
|
||||
old_domain_rule = art_insert(&dns_conf_domain_rule, (unsigned char *)domain_key, len, add_domain_rule);
|
||||
if (old_domain_rule) {
|
||||
free(old_domain_rule);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (add_domain_rule) {
|
||||
free(add_domain_rule);
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "add doamin %s rule failed", domain);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -301,18 +356,26 @@ int config_ipset(void *data, int argc, char *argv[])
|
||||
goto errout;
|
||||
}
|
||||
|
||||
strncpy(ipsetname, end + 1, DNS_MAX_IPSET_NAMELEN);
|
||||
ipset = dns_conf_get_ipset(ipsetname);
|
||||
if (ipset == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
if (strncmp(end + 1, "-", sizeof("-")) != 0) {
|
||||
strncpy(ipsetname, end + 1, DNS_MAX_IPSET_NAMELEN);
|
||||
ipset = dns_conf_get_ipset(ipsetname);
|
||||
if (ipset == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ipset_rule = malloc(sizeof(*ipset_rule));
|
||||
if (ipset_rule == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
ipset_rule = malloc(sizeof(*ipset_rule));
|
||||
if (ipset_rule == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ipset_rule->ipsetname = ipset;
|
||||
ipset_rule->ipsetname = ipset;
|
||||
} else {
|
||||
if (config_domain_rule_flag_set(domain, DOMAIN_FLAG_IPSET_IGNORE) != 0 ) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (config_domain_rule_add(domain, DOMAIN_RULE_IPSET, ipset_rule) != 0) {
|
||||
goto errout;
|
||||
@@ -343,6 +406,7 @@ int config_address(void *data, int argc, char *argv[])
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
enum domain_rule type = 0;
|
||||
unsigned int flag = 0;
|
||||
|
||||
if (argc <= 1) {
|
||||
goto errout;
|
||||
@@ -368,51 +432,85 @@ int config_address(void *data, int argc, char *argv[])
|
||||
memcpy(domain, begin, len);
|
||||
domain[len] = 0;
|
||||
|
||||
if (parse_ip(end + 1, ip, &port) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr_in;
|
||||
address_ipv4 = malloc(sizeof(*address_ipv4));
|
||||
if (address_ipv4 == NULL) {
|
||||
if (*(end + 1) == '#') {
|
||||
if (strncmp(end + 1, "#4", sizeof("#4")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV4_SOA;
|
||||
} else if (strncmp(end + 1, "#6", sizeof("#6")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV6_SOA;
|
||||
} else if (strncmp(end + 1, "#", sizeof("#")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_SOA;
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
addr_in = (struct sockaddr_in *)&addr;
|
||||
memcpy(address_ipv4->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
|
||||
type = DOMAIN_RULE_ADDRESS_IPV4;
|
||||
address = address_ipv4;
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6;
|
||||
addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
if (config_domain_rule_flag_set(domain, flag) != 0 ) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else if (*(end + 1) == '-') {
|
||||
if (strncmp(end + 1, "-4", sizeof("-4")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV4_IGN;
|
||||
} else if (strncmp(end + 1, "-6", sizeof("-6")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IPV6_IGN;
|
||||
} else if (strncmp(end + 1, "-", sizeof("-")) == 0) {
|
||||
flag = DOMAIN_FLAG_ADDR_IGN;
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (config_domain_rule_flag_set(domain, flag) != 0 ) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
if (parse_ip(end + 1, ip, &port) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr_in;
|
||||
address_ipv4 = malloc(sizeof(*address_ipv4));
|
||||
if (address_ipv4 == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memcpy(address_ipv4->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
|
||||
|
||||
addr_in = (struct sockaddr_in *)&addr;
|
||||
memcpy(address_ipv4->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
|
||||
type = DOMAIN_RULE_ADDRESS_IPV4;
|
||||
address = address_ipv4;
|
||||
} else {
|
||||
address_ipv6 = malloc(sizeof(*address_ipv6));
|
||||
if (address_ipv6 == NULL) {
|
||||
goto errout;
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6;
|
||||
addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
address_ipv4 = malloc(sizeof(*address_ipv4));
|
||||
if (address_ipv4 == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memcpy(address_ipv4->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
|
||||
type = DOMAIN_RULE_ADDRESS_IPV4;
|
||||
address = address_ipv4;
|
||||
} else {
|
||||
address_ipv6 = malloc(sizeof(*address_ipv6));
|
||||
if (address_ipv6 == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memcpy(address_ipv6->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
|
||||
type = DOMAIN_RULE_ADDRESS_IPV6;
|
||||
address = address_ipv6;
|
||||
}
|
||||
memcpy(address_ipv6->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
|
||||
type = DOMAIN_RULE_ADDRESS_IPV6;
|
||||
address = address_ipv6;
|
||||
} break;
|
||||
default:
|
||||
goto errout;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if (config_domain_rule_add(domain, type, address) != 0) {
|
||||
goto errout;
|
||||
@@ -443,18 +541,28 @@ int config_server_tls(void *data, int argc, char *argv[])
|
||||
return config_server(argc, argv, DNS_SERVER_TLS, DEFAULT_DNS_TLS_PORT);
|
||||
}
|
||||
|
||||
radix_node_t *create_addr_node(radix_tree_t *tree, char *addr)
|
||||
radix_node_t *create_addr_node(char *addr)
|
||||
{
|
||||
radix_node_t *node;
|
||||
void *p;
|
||||
prefix_t prefix;
|
||||
const char *errmsg = NULL;
|
||||
radix_tree_t *tree = NULL;
|
||||
|
||||
p = prefix_pton(addr, -1, &prefix, &errmsg);
|
||||
if (p == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (prefix.family) {
|
||||
case AF_INET:
|
||||
tree = dns_conf_address_rule.ipv4;
|
||||
break;
|
||||
case AF_INET6:
|
||||
tree = dns_conf_address_rule.ipv6;
|
||||
break;
|
||||
}
|
||||
|
||||
node = radix_lookup(tree, &prefix);
|
||||
return node;
|
||||
}
|
||||
@@ -464,7 +572,7 @@ int config_iplist_rule(char *subnet, enum address_rule rule)
|
||||
radix_node_t *node = NULL;
|
||||
struct dns_ip_address_rule *ip_rule = NULL;
|
||||
|
||||
node = create_addr_node(dns_conf_address_rule, subnet);
|
||||
node = create_addr_node(subnet);
|
||||
if (node == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -488,6 +596,8 @@ int config_iplist_rule(char *subnet, enum address_rule rule)
|
||||
case ADDRESS_RULE_BOGUS:
|
||||
ip_rule->bogus = 1;
|
||||
break;
|
||||
case ADDRESS_RULE_IP_IGNORE:
|
||||
ip_rule->ip_ignore = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -511,12 +621,21 @@ int conf_bogus_nxdomain(void *data, int argc, char *argv[])
|
||||
return config_iplist_rule(argv[1], ADDRESS_RULE_BOGUS);
|
||||
}
|
||||
|
||||
int conf_ip_ignore(void *data, int argc, char *argv[])
|
||||
{
|
||||
if (argc <= 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return config_iplist_rule(argv[1], ADDRESS_RULE_IP_IGNORE);
|
||||
}
|
||||
|
||||
int conf_edns_client_subnet(void *data, int argc, char *argv[])
|
||||
{
|
||||
char *slash = NULL;
|
||||
char *value = NULL;
|
||||
int subnet = 0;
|
||||
struct dns_edns_client_subnet *ecs = data;
|
||||
struct dns_edns_client_subnet *ecs = NULL;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
|
||||
@@ -540,6 +659,17 @@ int conf_edns_client_subnet(void *data, int argc, char *argv[])
|
||||
goto errout;
|
||||
}
|
||||
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET:
|
||||
ecs = &dns_conf_ipv4_ecs;
|
||||
break;
|
||||
case AF_INET6:
|
||||
ecs = &dns_conf_ipv6_ecs;
|
||||
break;
|
||||
default:
|
||||
goto errout;
|
||||
}
|
||||
|
||||
strncpy(ecs->ip, value, DNS_MAX_IPLEN);
|
||||
ecs->subnet = subnet;
|
||||
ecs->enable = 1;
|
||||
@@ -578,12 +708,13 @@ struct config_item config_item[] = {
|
||||
CONF_CUSTOM("server-tcp", config_server_tcp, NULL),
|
||||
CONF_CUSTOM("server-tls", config_server_tls, NULL),
|
||||
CONF_CUSTOM("address", config_address, NULL),
|
||||
CONF_YESNO("ipset-timeout", &dns_conf_ipset_timeout_enable),
|
||||
CONF_CUSTOM("ipset", config_ipset, NULL),
|
||||
CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),
|
||||
CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX),
|
||||
CONF_YESNO("prefetch-domain", &dns_conf_prefetch),
|
||||
CONF_YESNO("dualstack-ip-selection", &dns_conf_dualstack_ip_selection),
|
||||
CONF_INT("dualstack-ip-selection-threshold", &dns_conf_dualstack_ip_selection_threshold, 1, 1000),
|
||||
CONF_INT("dualstack-ip-selection-threshold", &dns_conf_dualstack_ip_selection_threshold, 0, 1000),
|
||||
CONF_CUSTOM("log-level", config_log_level, NULL),
|
||||
CONF_STRING("log-file", (char *)dns_conf_log_file, DNS_MAX_PATH),
|
||||
CONF_SIZE("log-size", &dns_conf_log_size, 0, 1024 * 1024 * 1024),
|
||||
@@ -598,12 +729,27 @@ struct config_item config_item[] = {
|
||||
CONF_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA),
|
||||
CONF_CUSTOM("blacklist-ip", config_blacklist_ip, NULL),
|
||||
CONF_CUSTOM("bogus-nxdomain", conf_bogus_nxdomain, NULL),
|
||||
CONF_CUSTOM("edns-client-subnet-ipv4", conf_edns_client_subnet, &dns_conf_ipv6_ecs),
|
||||
CONF_CUSTOM("edns-client-subnet-ipv6", conf_edns_client_subnet, &dns_conf_ipv6_ecs),
|
||||
CONF_CUSTOM("ignore-ip", conf_ip_ignore, NULL),
|
||||
CONF_CUSTOM("edns-client-subnet", conf_edns_client_subnet, NULL),
|
||||
CONF_CUSTOM("conf-file", config_addtional_file, NULL),
|
||||
CONF_END(),
|
||||
};
|
||||
|
||||
int conf_printf(const char *file, int lineno, int ret)
|
||||
{
|
||||
if (ret == CONF_RET_ERR) {
|
||||
tlog(TLOG_ERROR, "process config file '%s' failed at line %d.", file, lineno);
|
||||
syslog(LOG_NOTICE, "process config file '%s' failed at line %d.", file, lineno);
|
||||
return -1;
|
||||
} else if (ret == CONF_RET_WARN) {
|
||||
tlog(TLOG_WARN, "process config file '%s' failed at line %d.", file, lineno);
|
||||
syslog(LOG_NOTICE, "process config file '%s' failed at line %d.", file, lineno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_addtional_file(void *data, int argc, char *argv[])
|
||||
{
|
||||
char *file_path = argv[1];
|
||||
@@ -613,17 +759,20 @@ int config_addtional_file(void *data, int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
return load_conf(file_path, config_item);
|
||||
return load_conf(file_path, config_item, conf_printf);
|
||||
}
|
||||
|
||||
int _dns_server_load_conf_init(void)
|
||||
{
|
||||
dns_conf_address_rule = New_Radix();
|
||||
art_tree_init(&dns_conf_domain_rule);
|
||||
if (dns_conf_address_rule == NULL) {
|
||||
dns_conf_address_rule.ipv4 = New_Radix();
|
||||
dns_conf_address_rule.ipv6 = New_Radix();
|
||||
if (dns_conf_address_rule.ipv4 == NULL || dns_conf_address_rule.ipv6 == NULL) {
|
||||
tlog(TLOG_WARN, "init radix tree failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
art_tree_init(&dns_conf_domain_rule);
|
||||
|
||||
hash_init(dns_ipset_table.ipset);
|
||||
|
||||
return 0;
|
||||
@@ -632,13 +781,17 @@ int _dns_server_load_conf_init(void)
|
||||
void dns_server_load_exit(void)
|
||||
{
|
||||
config_domain_destroy();
|
||||
Destroy_Radix(dns_conf_address_rule, config_address_destroy, NULL);
|
||||
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();
|
||||
}
|
||||
|
||||
int dns_server_load_conf(const char *file)
|
||||
{
|
||||
int ret = 0;
|
||||
_dns_server_load_conf_init();
|
||||
|
||||
return load_conf(file, config_item);
|
||||
openlog ("smartdns", LOG_CONS | LOG_NDELAY, LOG_LOCAL1);
|
||||
ret = load_conf(file, config_item, conf_printf);
|
||||
closelog();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -22,12 +22,25 @@
|
||||
#define SMARTDNS_AUDIT_FILE "/var/log/smartdns-audit.log"
|
||||
|
||||
enum domain_rule {
|
||||
DOMAIN_RULE_ADDRESS_IPV4 = 1,
|
||||
DOMAIN_RULE_ADDRESS_IPV6 = 2,
|
||||
DOMAIN_RULE_IPSET = 3,
|
||||
DOMAIN_RULE_FLAGS = 0,
|
||||
DOMAIN_RULE_ADDRESS_IPV4,
|
||||
DOMAIN_RULE_ADDRESS_IPV6,
|
||||
DOMAIN_RULE_IPSET,
|
||||
DOMAIN_RULE_MAX,
|
||||
};
|
||||
|
||||
#define DOMAIN_FLAG_ADDR_SOA (1 << 0)
|
||||
#define DOMAIN_FLAG_ADDR_IPV4_SOA (1 << 1)
|
||||
#define DOMAIN_FLAG_ADDR_IPV6_SOA (1 << 2)
|
||||
#define DOMAIN_FLAG_ADDR_IGN (1 << 3)
|
||||
#define DOMAIN_FLAG_ADDR_IPV4_IGN (1 << 4)
|
||||
#define DOMAIN_FLAG_ADDR_IPV6_IGN (1 << 5)
|
||||
#define DOMAIN_FLAG_IPSET_IGNORE (1 << 6)
|
||||
|
||||
struct dns_rule_flags {
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
struct dns_address_IPV4 {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
};
|
||||
@@ -71,11 +84,13 @@ struct dns_bogus_ip_address {
|
||||
enum address_rule {
|
||||
ADDRESS_RULE_BLACKLIST = 1,
|
||||
ADDRESS_RULE_BOGUS = 2,
|
||||
ADDRESS_RULE_IP_IGNORE = 3,
|
||||
};
|
||||
|
||||
struct dns_ip_address_rule {
|
||||
unsigned int blacklist : 1;
|
||||
unsigned int bogus : 1;
|
||||
unsigned int ip_ignore : 1;
|
||||
};
|
||||
|
||||
struct dns_edns_client_subnet {
|
||||
@@ -84,6 +99,11 @@ struct dns_edns_client_subnet {
|
||||
int subnet;
|
||||
};
|
||||
|
||||
struct dns_conf_address_rule {
|
||||
radix_tree_t *ipv4;
|
||||
radix_tree_t *ipv6;
|
||||
};
|
||||
|
||||
extern char dns_conf_server_ip[DNS_MAX_IPLEN];
|
||||
extern char dns_conf_server_tcp_ip[DNS_MAX_IPLEN];
|
||||
extern int dns_conf_tcp_idle_time;
|
||||
@@ -104,7 +124,7 @@ extern int dns_conf_audit_num;
|
||||
|
||||
extern char dns_conf_server_name[DNS_MAX_CONF_CNAME_LEN];
|
||||
extern art_tree dns_conf_domain_rule;
|
||||
extern radix_tree_t *dns_conf_address_rule;
|
||||
extern struct dns_conf_address_rule dns_conf_address_rule;
|
||||
|
||||
extern int dns_conf_dualstack_ip_selection;
|
||||
extern int dns_conf_dualstack_ip_selection_threshold;
|
||||
@@ -113,6 +133,7 @@ extern int dns_conf_rr_ttl;
|
||||
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 struct dns_edns_client_subnet dns_conf_ipv4_ecs;
|
||||
extern struct dns_edns_client_subnet dns_conf_ipv6_ecs;
|
||||
|
||||
267
src/dns_server.c
267
src/dns_server.c
@@ -93,6 +93,7 @@ struct dns_server {
|
||||
struct dns_ip_address {
|
||||
struct hlist_node node;
|
||||
int hitnum;
|
||||
unsigned long recv_tick;
|
||||
dns_type_t addr_type;
|
||||
union {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
@@ -185,13 +186,15 @@ static void _dns_server_audit_log(struct dns_request *request)
|
||||
return;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_AAAA) {
|
||||
if (request->qtype == DNS_T_AAAA && request->has_ipv6) {
|
||||
snprintf(req_result, sizeof(req_result), "%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", request->ipv6_addr[0],
|
||||
request->ipv6_addr[1], request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5], request->ipv6_addr[6],
|
||||
request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10], request->ipv6_addr[11], request->ipv6_addr[12],
|
||||
request->ipv6_addr[13], request->ipv6_addr[14], request->ipv6_addr[15]);
|
||||
} else if (request->qtype == DNS_T_A) {
|
||||
} else if (request->qtype == DNS_T_A && request->has_ipv4) {
|
||||
snprintf(req_result, sizeof(req_result), "%d.%d.%d.%d", request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
} else if (request->has_soa) {
|
||||
return;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -378,6 +381,11 @@ static int _dns_reply_inpacket(struct dns_request *request, unsigned char *inpac
|
||||
struct dns_server_conn *client = request->client;
|
||||
int ret = 0;
|
||||
|
||||
if (client == NULL) {
|
||||
tlog(TLOG_ERROR, "client is invalid, domain: %s", request->domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (client->type == DNS_SERVER_UDP) {
|
||||
ret = _dns_server_reply_udp(request, client, inpacket, inpacket_len);
|
||||
} else if (client->type == DNS_SERVER_TCP) {
|
||||
@@ -400,6 +408,10 @@ static int _dns_reply(struct dns_request *request)
|
||||
int ret = 0;
|
||||
int encode_len = 0;
|
||||
|
||||
if (request->client == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_dns_server_audit_log(request);
|
||||
|
||||
memset(&head, 0, sizeof(head));
|
||||
@@ -462,26 +474,34 @@ static int _dns_server_reply_SOA(int rcode, struct dns_request *request, struct
|
||||
static int _dns_setup_ipset(struct dns_request *request)
|
||||
{
|
||||
struct dns_ipset_rule *ipset_rule = NULL;
|
||||
struct dns_rule_flags *rule_flags = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (request->domain_rule == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rule_flags = request->domain_rule->rules[DOMAIN_RULE_FLAGS];
|
||||
if (rule_flags) {
|
||||
if (rule_flags->flags & DOMAIN_FLAG_IPSET_IGNORE) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ipset_rule = request->domain_rule->rules[DOMAIN_RULE_IPSET];
|
||||
if (ipset_rule == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (request->has_ipv4 && request->qtype == DNS_T_A) {
|
||||
ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN);
|
||||
ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
|
||||
}
|
||||
|
||||
if (request->has_ipv6 && request->qtype == DNS_T_AAAA) {
|
||||
if (request->has_ipv4) {
|
||||
ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN);
|
||||
ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
|
||||
}
|
||||
ret |= ipset_add(ipset_rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN);
|
||||
ret |= ipset_add(ipset_rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "IPSET-MATCH: domain:%s, ipset:%s, result: %d", request->domain, ipset_rule->ipsetname, ret);
|
||||
@@ -508,10 +528,10 @@ int _dns_server_request_complete(struct dns_request *request)
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_A) {
|
||||
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0], request->ipv4_addr[1],
|
||||
request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
|
||||
if (request->has_ipv4) {
|
||||
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0], request->ipv4_addr[1],
|
||||
request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
|
||||
if (request->has_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) {
|
||||
request->ttl_v4 = DNS_SERVER_TMOUT_TTL;
|
||||
}
|
||||
@@ -521,25 +541,34 @@ int _dns_server_request_complete(struct dns_request *request)
|
||||
} else {
|
||||
dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN);
|
||||
}
|
||||
|
||||
request->has_soa = 0;
|
||||
}
|
||||
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
tlog(TLOG_INFO, "result: %s, rcode: %d, %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", request->domain, request->rcode,
|
||||
if (request->has_ipv4 && request->ping_ttl_v4 > 0) {
|
||||
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0], request->ipv4_addr[1],
|
||||
request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
|
||||
if ((request->ping_ttl_v4 + (dns_conf_dualstack_ip_selection_threshold * 10)) < request->ping_ttl_v6 || request->ping_ttl_v6 < 0) {
|
||||
tlog(TLOG_DEBUG, "Force IPV4 perfered.");
|
||||
if (request->prefetch) {
|
||||
dns_cache_replace(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN);
|
||||
} else {
|
||||
dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN);
|
||||
}
|
||||
|
||||
return _dns_server_reply_SOA(DNS_RC_NOERROR, request, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (request->has_ipv6) {
|
||||
tlog(TLOG_INFO, "result: %s, rcode: %d, %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", request->domain, request->rcode,
|
||||
request->ipv6_addr[0], request->ipv6_addr[1], request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5],
|
||||
request->ipv6_addr[6], request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10], request->ipv6_addr[11],
|
||||
request->ipv6_addr[12], request->ipv6_addr[13], request->ipv6_addr[14], request->ipv6_addr[15]);
|
||||
|
||||
if (request->has_ipv4) {
|
||||
dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_AAAA, request->ipv4_addr, DNS_RR_A_LEN);
|
||||
|
||||
if (((request->ping_ttl_v4 + (dns_conf_dualstack_ip_selection_threshold * 10) < request->ping_ttl_v6) && (request->ping_ttl_v4 > 0)) ||
|
||||
(request->ping_ttl_v6 == -1)) {
|
||||
tlog(TLOG_DEBUG, "Force IPV4 perfered.");
|
||||
return _dns_server_reply_SOA(DNS_RC_NOERROR, request, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (request->has_ipv6) {
|
||||
if (request->has_ping_result == 0 && request->ttl_v6 > DNS_SERVER_TMOUT_TTL) {
|
||||
request->ttl_v6 = DNS_SERVER_TMOUT_TTL;
|
||||
}
|
||||
@@ -549,14 +578,22 @@ int _dns_server_request_complete(struct dns_request *request)
|
||||
} else {
|
||||
dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v6, DNS_T_AAAA, request->ipv6_addr, DNS_RR_AAAA_LEN);
|
||||
}
|
||||
|
||||
request->has_ipv4 = 0;
|
||||
request->has_soa = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (request->has_soa) {
|
||||
tlog(TLOG_INFO, "result: %s, qtype: %d, SOA", request->domain, request->qtype);
|
||||
}
|
||||
|
||||
_dns_setup_ipset(request);
|
||||
|
||||
if (request->prefetch) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_dns_setup_ipset(request);
|
||||
_dns_reply(request);
|
||||
|
||||
return 0;
|
||||
@@ -575,12 +612,15 @@ void _dns_server_request_remove(struct dns_request *request)
|
||||
_dns_server_request_release(request);
|
||||
}
|
||||
|
||||
void _dns_server_select_maxhit_ipaddress(struct dns_request *request)
|
||||
void _dns_server_select_possible_ipaddress(struct dns_request *request)
|
||||
{
|
||||
int maxhit = 0;
|
||||
int bucket = 0;
|
||||
unsigned long max_recv_tick = 0;
|
||||
struct dns_ip_address *addr_map;
|
||||
struct dns_ip_address *maxhit_addr_map = NULL;
|
||||
struct dns_ip_address *last_recv_addr_map = NULL;
|
||||
struct dns_ip_address *selected_addr_map = NULL;
|
||||
struct hlist_node *tmp;
|
||||
|
||||
if (atomic_read(&request->notified) > 0) {
|
||||
@@ -593,27 +633,42 @@ void _dns_server_select_maxhit_ipaddress(struct dns_request *request)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addr_map->hitnum <= maxhit) {
|
||||
continue;
|
||||
if (addr_map->recv_tick - request->send_tick > max_recv_tick) {
|
||||
max_recv_tick = addr_map->recv_tick - request->send_tick;
|
||||
last_recv_addr_map = addr_map;
|
||||
}
|
||||
|
||||
maxhit = addr_map->hitnum;
|
||||
maxhit_addr_map = addr_map;
|
||||
if (addr_map->hitnum > maxhit) {
|
||||
maxhit = addr_map->hitnum;
|
||||
maxhit_addr_map = addr_map;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxhit_addr_map == NULL || maxhit == 1) {
|
||||
if (maxhit_addr_map && maxhit > 1) {
|
||||
selected_addr_map = maxhit_addr_map;
|
||||
} else if (last_recv_addr_map) {
|
||||
selected_addr_map = last_recv_addr_map;
|
||||
}
|
||||
|
||||
if (selected_addr_map == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "select best ip address, %s", request->domain);
|
||||
switch (request->qtype) {
|
||||
case DNS_T_A: {
|
||||
memcpy(request->ipv4_addr, maxhit_addr_map->ipv4_addr, DNS_RR_A_LEN);
|
||||
memcpy(request->ipv4_addr, selected_addr_map->ipv4_addr, DNS_RR_A_LEN);
|
||||
request->ttl_v4 = DNS_SERVER_TMOUT_TTL;
|
||||
tlog(TLOG_DEBUG, "possible result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0], request->ipv4_addr[1],
|
||||
request->ipv4_addr[2], request->ipv4_addr[3]);
|
||||
} break;
|
||||
case DNS_T_AAAA: {
|
||||
memcpy(request->ipv6_addr, maxhit_addr_map->ipv6_addr, DNS_RR_AAAA_LEN);
|
||||
memcpy(request->ipv6_addr, selected_addr_map->ipv6_addr, DNS_RR_AAAA_LEN);
|
||||
request->ttl_v6 = DNS_SERVER_TMOUT_TTL;
|
||||
tlog(TLOG_DEBUG, "possible result: %s, rcode: %d, %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", request->domain, request->rcode,
|
||||
request->ipv6_addr[0], request->ipv6_addr[1], request->ipv6_addr[2], request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5],
|
||||
request->ipv6_addr[6], request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10], request->ipv6_addr[11],
|
||||
request->ipv6_addr[12], request->ipv6_addr[13], request->ipv6_addr[14], request->ipv6_addr[15]);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
@@ -640,7 +695,7 @@ void _dns_server_request_release(struct dns_request *request)
|
||||
pthread_mutex_unlock(&server.request_list_lock);
|
||||
|
||||
/* Select max hit ip address, and return to client */
|
||||
_dns_server_select_maxhit_ipaddress(request);
|
||||
_dns_server_select_possible_ipaddress(request);
|
||||
|
||||
_dns_server_request_complete(request);
|
||||
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
|
||||
@@ -677,6 +732,8 @@ void _dns_server_ping_result(struct ping_host_struct *ping_host, const char *hos
|
||||
_dns_server_request_release(request);
|
||||
fast_ping_stop(ping_host);
|
||||
return;
|
||||
} else if (result == PING_RESULT_TIMEOUT) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int rtt = tv->tv_sec * 10000 + tv->tv_usec / 100;
|
||||
@@ -691,8 +748,10 @@ void _dns_server_ping_result(struct ping_host_struct *ping_host, const char *hos
|
||||
memcpy(request->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
|
||||
}
|
||||
|
||||
if (dns_conf_dualstack_ip_selection == 1 && request->qtype == DNS_T_AAAA) {
|
||||
threshold = dns_conf_dualstack_ip_selection_threshold * 10;
|
||||
if (request->qtype == DNS_T_AAAA && dns_conf_dualstack_ip_selection == 1) {
|
||||
if (request->ping_ttl_v6 < 0 && request->has_soa == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
@@ -717,9 +776,9 @@ void _dns_server_ping_result(struct ping_host_struct *ping_host, const char *hos
|
||||
}
|
||||
if (result == PING_RESULT_RESPONSE) {
|
||||
request->has_ping_result = 1;
|
||||
tlog(TLOG_DEBUG, "from %15s: seq=%d time=%d\n", host, seqno, rtt);
|
||||
tlog(TLOG_DEBUG, "from %s: seq=%d time=%d\n", host, seqno, rtt);
|
||||
} else {
|
||||
tlog(TLOG_DEBUG, "from %15s: seq=%d timeout\n", host, seqno);
|
||||
tlog(TLOG_DEBUG, "from %s: seq=%d timeout\n", host, seqno);
|
||||
}
|
||||
|
||||
if (rtt < threshold) {
|
||||
@@ -727,7 +786,7 @@ void _dns_server_ping_result(struct ping_host_struct *ping_host, const char *hos
|
||||
} else if (rtt < (get_tick_count() - request->send_tick) * 10) {
|
||||
may_complete = 1;
|
||||
}
|
||||
|
||||
|
||||
if (may_complete && request->has_ping_result == 1) {
|
||||
_dns_server_request_complete(request);
|
||||
_dns_server_request_remove(request);
|
||||
@@ -764,12 +823,14 @@ int _dns_ip_address_check_add(struct dns_request *request, unsigned char *addr,
|
||||
if (addr_type == DNS_T_A) {
|
||||
if (memcmp(addr_map->ipv4_addr, addr, addr_len) == 0) {
|
||||
addr_map->hitnum++;
|
||||
addr_map->recv_tick = get_tick_count();
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
return -1;
|
||||
}
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
if (memcmp(addr_map->ipv6_addr, addr, addr_len) == 0) {
|
||||
addr_map->hitnum++;
|
||||
addr_map->recv_tick = get_tick_count();
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
return -1;
|
||||
}
|
||||
@@ -786,6 +847,7 @@ int _dns_ip_address_check_add(struct dns_request *request, unsigned char *addr,
|
||||
|
||||
addr_map->addr_type = addr_type;
|
||||
addr_map->hitnum = 1;
|
||||
addr_map->recv_tick = get_tick_count();
|
||||
memcpy(addr_map->addr, addr, addr_len);
|
||||
hash_add(request->ip_map, &addr_map->node, key);
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
@@ -817,7 +879,17 @@ static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char
|
||||
return -1;
|
||||
}
|
||||
|
||||
node = radix_search_best(dns_conf_address_rule, &prefix);
|
||||
switch (prefix.family) {
|
||||
case AF_INET:
|
||||
node = radix_search_best(dns_conf_address_rule.ipv4, &prefix);
|
||||
break;
|
||||
case AF_INET6:
|
||||
node = radix_search_best(dns_conf_address_rule.ipv6, &prefix);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (node == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -837,8 +909,13 @@ static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (rule->ip_ignore) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
return -1;
|
||||
skip:
|
||||
return -2;
|
||||
match:
|
||||
if (request->rcode == DNS_RC_SERVFAIL) {
|
||||
request->rcode = DNS_RC_NXDOMAIN;
|
||||
@@ -857,6 +934,7 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
|
||||
struct dns_rrs *rrs = NULL;
|
||||
int ping_timeout = DNS_PING_TIMEOUT;
|
||||
unsigned long now = get_tick_count();
|
||||
int ip_check_result = 0;
|
||||
|
||||
if (packet->head.rcode != DNS_RC_NOERROR && packet->head.rcode != DNS_RC_NXDOMAIN) {
|
||||
if (request->rcode == DNS_RC_SERVFAIL) {
|
||||
@@ -893,9 +971,13 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
|
||||
tlog(TLOG_DEBUG, "domain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]);
|
||||
|
||||
/* ip rule check */
|
||||
if (_dns_server_ip_rule_check(request, addr, 4, DNS_T_A, result_flag) == 0) {
|
||||
ip_check_result = _dns_server_ip_rule_check(request, addr, 4, DNS_T_A, result_flag);
|
||||
if (ip_check_result == 0) {
|
||||
_dns_server_request_release(request);
|
||||
break;
|
||||
} else if (ip_check_result == -2) {
|
||||
_dns_server_request_release(request);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(request->cname, name, DNS_MAX_CNAME_LEN) != 0) {
|
||||
@@ -944,9 +1026,13 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
|
||||
tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", name, ttl, 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 (_dns_server_ip_rule_check(request, addr, 16, DNS_T_AAAA, result_flag) == 0) {
|
||||
ip_check_result = _dns_server_ip_rule_check(request, addr, 16, DNS_T_AAAA, result_flag);
|
||||
if (ip_check_result == 0) {
|
||||
_dns_server_request_release(request);
|
||||
break;
|
||||
} else if (ip_check_result == -2) {
|
||||
_dns_server_request_release(request);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(name, domain, DNS_MAX_CNAME_LEN) != 0 && strncmp(request->cname, name, DNS_MAX_CNAME_LEN) != 0) {
|
||||
@@ -995,11 +1081,11 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
|
||||
request->has_soa = 1;
|
||||
request->rcode = packet->head.rcode;
|
||||
dns_get_SOA(rrs, name, 128, &ttl, &request->soa);
|
||||
tlog(TLOG_INFO, "SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, expire: %d, minimum: %d", request->soa.mname,
|
||||
request->soa.rname, request->soa.serial, request->soa.refresh, request->soa.retry, request->soa.expire, request->soa.minimum);
|
||||
tlog(TLOG_DEBUG, "domain: %s, qtype: %d, SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, expire: %d, minimum: %d", domain, request->qtype,
|
||||
request->soa.mname, request->soa.rname, request->soa.serial, request->soa.refresh, request->soa.retry, request->soa.expire, request->soa.minimum);
|
||||
} break;
|
||||
default:
|
||||
tlog(TLOG_INFO, "%s, qtype: %d", name, rrs->type);
|
||||
tlog(TLOG_DEBUG, "%s, qtype: %d", name, rrs->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1022,6 +1108,20 @@ static int dns_server_update_reply_packet_id(struct dns_request *request, unsign
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_reply_passthrouth(struct dns_request *request, struct dns_packet *packet, unsigned char *inpacket, int inpacket_len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (atomic_inc_return(&request->notified) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dns_server_update_reply_packet_id(request, inpacket, inpacket_len);
|
||||
ret = _dns_reply_inpacket(request, inpacket, inpacket_len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dns_server_resolve_callback(char *domain, dns_result_type rtype, unsigned int result_flag, struct dns_packet *packet, unsigned char *inpacket,
|
||||
int inpacket_len, void *user_ptr)
|
||||
{
|
||||
@@ -1035,9 +1135,7 @@ static int dns_server_resolve_callback(char *domain, dns_result_type rtype, unsi
|
||||
|
||||
if (rtype == DNS_QUERY_RESULT) {
|
||||
if (request->passthrough) {
|
||||
dns_server_update_reply_packet_id(request, inpacket, inpacket_len);
|
||||
_dns_reply_inpacket(request, inpacket, inpacket_len);
|
||||
return 0;
|
||||
return _dns_server_reply_passthrouth(request, packet, inpacket, inpacket_len);
|
||||
}
|
||||
|
||||
_dns_server_process_answer(request, domain, packet, result_flag);
|
||||
@@ -1119,7 +1217,7 @@ static int _dns_server_process_ptr(struct dns_request *request, struct dns_packe
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr(request->domain, "0.0.0.0") != NULL) {
|
||||
if (strstr(request->domain, "0.0.0.0.in-addr.arpa") != NULL) {
|
||||
found = 1;
|
||||
}
|
||||
|
||||
@@ -1187,6 +1285,59 @@ static struct dns_domain_rule *_dns_server_get_domain_rule(char *domain)
|
||||
return domain_rule;
|
||||
}
|
||||
|
||||
static int _dns_server_pre_process_rule_flags(struct dns_request *request, struct dns_packet *packet)
|
||||
{
|
||||
struct dns_rule_flags *rule_flag = NULL;
|
||||
unsigned int flags = 0;
|
||||
if (request->domain_rule == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
rule_flag = request->domain_rule->rules[DOMAIN_RULE_FLAGS];
|
||||
if (rule_flag == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
flags = rule_flag->flags;
|
||||
if (flags & DOMAIN_FLAG_ADDR_IGN) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_ADDR_SOA) {
|
||||
_dns_server_reply_SOA(DNS_RC_NOERROR, request, packet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (request->qtype) {
|
||||
case DNS_T_A:
|
||||
if (flags & DOMAIN_FLAG_ADDR_IPV4_IGN) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_ADDR_IPV4_SOA) {
|
||||
_dns_server_reply_SOA(DNS_RC_NOERROR, request, packet);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case DNS_T_AAAA:
|
||||
if (flags & DOMAIN_FLAG_ADDR_IPV6_IGN) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (flags & DOMAIN_FLAG_ADDR_IPV6_SOA) {
|
||||
_dns_server_reply_SOA(DNS_RC_NOERROR, request, packet);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto errout;
|
||||
break;
|
||||
}
|
||||
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_process_address(struct dns_request *request, struct dns_packet *packet)
|
||||
{
|
||||
struct dns_address_IPV4 *address_ipv4 = NULL;
|
||||
@@ -1270,6 +1421,9 @@ static int _dns_server_process_cache(struct dns_request *request, struct dns_pac
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (dns_cache) {
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1289,6 +1443,7 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
||||
|
||||
_dns_server_client_get(client);
|
||||
|
||||
tlog(TLOG_DEBUG, "recv query packet from %s, len = %d", gethost_by_addr(name, (struct sockaddr *)from, from_len), inpacket_len);
|
||||
decode_len = dns_decode(packet, DNS_PACKSIZE, inpacket, inpacket_len);
|
||||
if (decode_len < 0) {
|
||||
tlog(TLOG_ERROR, "decode failed.\n");
|
||||
@@ -1360,6 +1515,7 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
||||
_dns_server_reply_SOA(DNS_RC_NOERROR, request, packet);
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
tlog(TLOG_DEBUG, "unsupport qtype: %d, domain: %s", qtype, request->domain);
|
||||
@@ -1367,6 +1523,10 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
||||
break;
|
||||
}
|
||||
|
||||
if (_dns_server_pre_process_rule_flags(request, packet) == 0) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (_dns_server_process_address(request, packet) == 0) {
|
||||
goto clean_exit;
|
||||
}
|
||||
@@ -1375,7 +1535,7 @@ static int _dns_server_recv(struct dns_server_conn *client, unsigned char *inpac
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
tlog(TLOG_INFO, "query server %s from %s, qtype = %d\n", request->domain, gethost_by_addr(name, (struct sockaddr *)from, from_len), qtype);
|
||||
tlog(TLOG_INFO, "query server %s from %s, qtype = %d\n", request->domain, name, qtype);
|
||||
|
||||
_dns_server_request_get(request);
|
||||
pthread_mutex_lock(&server.request_list_lock);
|
||||
@@ -1444,6 +1604,8 @@ static int _dns_server_prefetch_request(char *domain, dns_type_t qtype)
|
||||
hash_init(request->ip_map);
|
||||
strncpy(request->domain, domain, DNS_MAX_CNAME_LEN);
|
||||
|
||||
request->domain_rule = _dns_server_get_domain_rule(request->domain);
|
||||
|
||||
tlog(TLOG_INFO, "prefetch domain %s, qtype = %d\n", request->domain, qtype);
|
||||
|
||||
_dns_server_request_get(request);
|
||||
@@ -1718,7 +1880,6 @@ void _dns_server_tcp_ping_check(struct dns_request *request)
|
||||
{
|
||||
struct dns_ip_address *addr_map;
|
||||
int bucket = 0;
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
char ip[DNS_MAX_CNAME_LEN] = {0};
|
||||
|
||||
if (request->has_ping_result) {
|
||||
@@ -1742,7 +1903,7 @@ void _dns_server_tcp_ping_check(struct dns_request *request)
|
||||
} break;
|
||||
case DNS_T_AAAA: {
|
||||
_dns_server_request_get(request);
|
||||
sprintf(name, "[%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x]:80", addr_map->ipv6_addr[0], addr_map->ipv6_addr[1],
|
||||
sprintf(ip, "[%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x]:80", addr_map->ipv6_addr[0], addr_map->ipv6_addr[1],
|
||||
addr_map->ipv6_addr[2], addr_map->ipv6_addr[3], addr_map->ipv6_addr[4], addr_map->ipv6_addr[5], addr_map->ipv6_addr[6],
|
||||
addr_map->ipv6_addr[7], addr_map->ipv6_addr[8], addr_map->ipv6_addr[9], addr_map->ipv6_addr[10], addr_map->ipv6_addr[11],
|
||||
addr_map->ipv6_addr[12], addr_map->ipv6_addr[13], addr_map->ipv6_addr[14], addr_map->ipv6_addr[15]);
|
||||
@@ -1762,7 +1923,13 @@ void _dns_server_tcp_ping_check(struct dns_request *request)
|
||||
|
||||
void _dns_server_prefetch_domain(struct dns_cache *dns_cache)
|
||||
{
|
||||
tlog(TLOG_DEBUG, "prefetch by cache %s, qtype %d, ttl %d", dns_cache->domain, dns_cache->qtype, dns_cache->ttl);
|
||||
if (dns_cache->hitnum <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
dns_cache->hitnum--;
|
||||
|
||||
tlog(TLOG_DEBUG, "prefetch by cache %s, qtype %d, ttl %d, hitnum %d", dns_cache->domain, dns_cache->qtype, dns_cache->ttl, dns_cache->hitnum);
|
||||
if (_dns_server_prefetch_request(dns_cache->domain, dns_cache->qtype) != 0) {
|
||||
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->domain, dns_cache->qtype);
|
||||
}
|
||||
|
||||
@@ -351,6 +351,7 @@ static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
|
||||
icmp6->icmp6_seq = htons(ping_host->seq);
|
||||
|
||||
gettimeofday(&packet->msg.tv, 0);
|
||||
gettimeofday(&ping_host->last, 0);
|
||||
packet->msg.sid = ping_host->sid;
|
||||
packet->msg.cookie = ping_host->cookie;
|
||||
packet->msg.seq = ping_host->seq;
|
||||
@@ -397,6 +398,7 @@ static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
|
||||
icmp->icmp_seq = htons(ping_host->seq);
|
||||
|
||||
gettimeofday(&packet->msg.tv, 0);
|
||||
gettimeofday(&ping_host->last, 0);
|
||||
packet->msg.sid = ping_host->sid;
|
||||
packet->msg.seq = ping_host->seq;
|
||||
packet->msg.cookie = ping_host->cookie;
|
||||
@@ -425,6 +427,7 @@ static int _fast_ping_sendping_udp(struct ping_host_struct *ping_host)
|
||||
struct ping_dns_head dns_head;
|
||||
int len;
|
||||
int flag = 0;
|
||||
int fd = 0;
|
||||
|
||||
flag |= (0 << 15) & 0x8000;
|
||||
flag |= (2 << 11) & 0x7800;
|
||||
@@ -434,11 +437,20 @@ static int _fast_ping_sendping_udp(struct ping_host_struct *ping_host)
|
||||
flag |= (0 << 7) & 0x0080;
|
||||
flag |= (0 << 0) & 0x000F;
|
||||
|
||||
if (ping_host->type == FAST_PING_UDP) {
|
||||
fd = ping.fd_udp;
|
||||
} else if (ping_host->type == FAST_PING_UDP6) {
|
||||
fd = ping.fd_udp6;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ping_host->seq++;
|
||||
memset(&dns_head, 0, sizeof(dns_head));
|
||||
dns_head.id = htons(ping_host->sid);
|
||||
dns_head.flag = flag;
|
||||
len = sendto(ping.fd_udp, &dns_head, sizeof(dns_head), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
||||
gettimeofday(&ping_host->last, 0);
|
||||
len = sendto(fd, &dns_head, sizeof(dns_head), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
||||
if (len < 0 || len != sizeof(dns_head)) {
|
||||
int err = errno;
|
||||
if (errno == ENETUNREACH || errno == EINVAL) {
|
||||
@@ -493,9 +505,10 @@ static int _fast_ping_sendping_tcp(struct ping_host_struct *ping_host)
|
||||
}
|
||||
}
|
||||
|
||||
gettimeofday(&ping_host->last, 0);
|
||||
ping_host->fd = fd;
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN | EPOLLOUT;
|
||||
event.events = EPOLLIN | EPOLLOUT | EPOLLERR;
|
||||
event.data.ptr = ping_host;
|
||||
if (epoll_ctl(ping.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
|
||||
ping_host->fd = -1;
|
||||
@@ -515,6 +528,7 @@ errout:
|
||||
static int _fast_ping_sendping(struct ping_host_struct *ping_host)
|
||||
{
|
||||
int ret = -1;
|
||||
gettimeofday(&ping_host->last, 0);
|
||||
|
||||
if (ping_host->type == FAST_PING_ICMP) {
|
||||
ret = _fast_ping_sendping_v4(ping_host);
|
||||
@@ -522,12 +536,11 @@ static int _fast_ping_sendping(struct ping_host_struct *ping_host)
|
||||
ret = _fast_ping_sendping_v6(ping_host);
|
||||
} else if (ping_host->type == FAST_PING_TCP) {
|
||||
ret = _fast_ping_sendping_tcp(ping_host);
|
||||
} else if (ping_host->type == FAST_PING_UDP) {
|
||||
} else if (ping_host->type == FAST_PING_UDP || ping_host->type == FAST_PING_UDP6) {
|
||||
ret = _fast_ping_sendping_udp(ping_host);
|
||||
}
|
||||
|
||||
ping_host->send = 1;
|
||||
gettimeofday(&ping_host->last, 0);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
@@ -652,6 +665,7 @@ static int _fast_ping_create_udp_sock(FAST_PING_TYPE type)
|
||||
}
|
||||
|
||||
udp_host = &ping.udp_host;
|
||||
udp_host->type = FAST_PING_UDP;
|
||||
break;
|
||||
case FAST_PING_UDP6:
|
||||
fd = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||
@@ -661,6 +675,10 @@ static int _fast_ping_create_udp_sock(FAST_PING_TYPE type)
|
||||
}
|
||||
|
||||
udp_host = &ping.udp6_host;
|
||||
udp_host->type = FAST_PING_UDP6;
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_2292HOPLIMIT, &on, sizeof(on));
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
@@ -677,7 +695,6 @@ static int _fast_ping_create_udp_sock(FAST_PING_TYPE type)
|
||||
}
|
||||
|
||||
udp_host->fd = fd;
|
||||
udp_host->type = FAST_PING_UDP;
|
||||
return fd;
|
||||
|
||||
errout:
|
||||
@@ -829,7 +846,6 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c
|
||||
socktype = SOCK_DGRAM;
|
||||
snprintf(port_str, MAX_IP_LEN, "%d", port);
|
||||
service = port_str;
|
||||
ping_type = FAST_PING_UDP;
|
||||
|
||||
if (_fast_ping_create_udp(ping_type) < 0) {
|
||||
goto errout;
|
||||
@@ -1136,6 +1152,7 @@ static int _fast_ping_process_tcp(struct ping_host_struct *ping_host, struct epo
|
||||
if (getsockopt(ping_host->fd, SOL_SOCKET, SO_ERROR, (char *)&connect_error, &len) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (connect_error != 0 && connect_error != ECONNREFUSED) {
|
||||
goto errout;
|
||||
}
|
||||
@@ -1148,6 +1165,8 @@ static int _fast_ping_process_tcp(struct ping_host_struct *ping_host, struct epo
|
||||
|
||||
ping_host->send = 0;
|
||||
|
||||
_fast_ping_close_host_sock(ping_host);
|
||||
|
||||
if (ping_host->count == 1) {
|
||||
_fast_ping_host_remove(ping_host);
|
||||
}
|
||||
@@ -1194,9 +1213,15 @@ static int _fast_ping_process_udp(struct ping_host_struct *ping_host, struct tim
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
||||
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) {
|
||||
uint8_t *ttlPtr = (uint8_t *)CMSG_DATA(cmsg);
|
||||
ttl = *ttlPtr;
|
||||
break;
|
||||
if (cmsg->cmsg_len >= sizeof(int)) {
|
||||
int *ttlPtr = (int *)CMSG_DATA(cmsg);
|
||||
ttl = *ttlPtr;
|
||||
}
|
||||
} else if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
|
||||
if (cmsg->cmsg_len >= sizeof(int)) {
|
||||
int *ttlPtr = (int *)CMSG_DATA(cmsg);
|
||||
ttl = *ttlPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1256,6 +1281,7 @@ static int _fast_ping_process(struct ping_host_struct *ping_host, struct epoll_e
|
||||
case FAST_PING_TCP:
|
||||
ret = _fast_ping_process_tcp(ping_host, event, now);
|
||||
break;
|
||||
case FAST_PING_UDP6:
|
||||
case FAST_PING_UDP:
|
||||
ret = _fast_ping_process_udp(ping_host, now);
|
||||
break;
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
#define CONF_INT_MAX (~(1 << 31))
|
||||
#define CONF_INT_MIN (1 << 31)
|
||||
|
||||
#define CONF_RET_OK 0
|
||||
#define CONF_RET_ERR -1
|
||||
#define CONF_RET_WARN -2
|
||||
#define CONF_RET_NOENT -3
|
||||
|
||||
struct config_item {
|
||||
const char *item;
|
||||
int (*item_func)(const char *item, void *data, int argc, char *argv[]);
|
||||
@@ -107,9 +112,9 @@ extern int conf_size(const char *item, void *data, int argc, char *argv[]);
|
||||
*
|
||||
*/
|
||||
|
||||
int load_conf(const char *file, struct config_item items[]);
|
||||
typedef int(conf_error_handler)(const char *file, int lineno, int ret);
|
||||
|
||||
int load_conf_get_line_count(void);
|
||||
int load_conf(const char *file, struct config_item items[], conf_error_handler handler);
|
||||
|
||||
void load_exit(void);
|
||||
|
||||
|
||||
@@ -1027,7 +1027,6 @@ void *art_substring(const art_tree *t, const unsigned char *str, int str_len, un
|
||||
// Check if the expanded path matches
|
||||
if (!str_prefix_matches((art_leaf*)n, str, str_len)) {
|
||||
found = (art_leaf*)n;
|
||||
art_copy_key(found, key, key_len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1040,7 +1039,6 @@ void *art_substring(const art_tree *t, const unsigned char *str, int str_len, un
|
||||
// Check if the expanded path matches
|
||||
if (!str_prefix_matches((art_leaf*)m, str, str_len)) {
|
||||
found = (art_leaf*)m;
|
||||
art_copy_key(found, key, key_len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1062,5 +1060,7 @@ void *art_substring(const art_tree *t, const unsigned char *str, int str_len, un
|
||||
return NULL;
|
||||
}
|
||||
|
||||
art_copy_key(found, key, key_len);
|
||||
|
||||
return found->value;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
__thread int line_no;
|
||||
|
||||
int conf_custom(const char *item, void *data, int argc, char *argv[])
|
||||
{
|
||||
struct config_item_custom *item_custom = data;
|
||||
@@ -182,12 +180,21 @@ void load_exit(void)
|
||||
return;
|
||||
}
|
||||
|
||||
int load_conf_get_line_count(void)
|
||||
int load_conf_printf(const char *file, int lineno, int ret)
|
||||
{
|
||||
return line_no;
|
||||
if (ret != CONF_RET_OK) {
|
||||
printf("process config file '%s' failed at line %d.", file, lineno);
|
||||
if (ret == CONF_RET_ERR || ret == CONF_RET_NOENT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_conf_file(const char *file, struct config_item *items)
|
||||
int load_conf_file(const char *file, struct config_item *items, conf_error_handler handler)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char line[MAX_LINE_LEN];
|
||||
@@ -197,6 +204,13 @@ int load_conf_file(const char *file, struct config_item *items)
|
||||
int i;
|
||||
int argc;
|
||||
char *argv[1024];
|
||||
int ret = 0;
|
||||
int call_ret = 0;
|
||||
int line_no = 0;
|
||||
|
||||
if (handler == NULL) {
|
||||
handler = load_conf_printf;
|
||||
}
|
||||
|
||||
fp = fopen(file, "r");
|
||||
if (fp == NULL) {
|
||||
@@ -223,6 +237,7 @@ int load_conf_file(const char *file, struct config_item *items)
|
||||
|
||||
for (i = 0;; i++) {
|
||||
if (items[i].item == NULL) {
|
||||
handler(file, line_no, CONF_RET_NOENT);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -236,7 +251,9 @@ int load_conf_file(const char *file, struct config_item *items)
|
||||
|
||||
conf_getopt_reset();
|
||||
/* call item function */
|
||||
if (items[i].item_func(items[i].item, items[i].data, argc, argv) != 0) {
|
||||
call_ret = items[i].item_func(items[i].item, items[i].data, argc, argv);
|
||||
ret = handler(file, line_no, call_ret);
|
||||
if (ret != 0) {
|
||||
conf_getopt_reset();
|
||||
goto errout;
|
||||
}
|
||||
@@ -257,7 +274,7 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int load_conf(const char *file, struct config_item items[])
|
||||
int load_conf(const char *file, struct config_item items[], conf_error_handler handler)
|
||||
{
|
||||
return load_conf_file(file, items);
|
||||
return load_conf_file(file, items, handler);
|
||||
}
|
||||
|
||||
@@ -221,6 +221,9 @@ Clear_Radix(radix_tree_t *radix, rdx_cb_t func, void *cbctx)
|
||||
void
|
||||
Destroy_Radix(radix_tree_t *radix, rdx_cb_t func, void *cbctx)
|
||||
{
|
||||
if (radix == NULL) {
|
||||
return;
|
||||
}
|
||||
Clear_Radix(radix, func, cbctx);
|
||||
free(radix);
|
||||
}
|
||||
|
||||
@@ -200,12 +200,14 @@ int smartdns_init_ssl(void)
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_CRYPTO_thread_setup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int smartdns_destroy_ssl(void)
|
||||
{
|
||||
SSL_CRYPTO_thread_cleanup();
|
||||
ERR_free_strings();
|
||||
EVP_cleanup();
|
||||
|
||||
@@ -384,6 +386,8 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (dns_server_load_conf(config_file) != 0) {
|
||||
fprintf(stderr, "load config failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (create_pid_file(pid_file) != 0) {
|
||||
|
||||
94
src/util.c
94
src/util.c
@@ -1,4 +1,5 @@
|
||||
#include "util.h"
|
||||
#include "dns_conf.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -7,6 +8,9 @@
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define NFNL_SUBSYS_IPSET 6
|
||||
|
||||
@@ -16,6 +20,7 @@
|
||||
#define IPSET_ATTR_IPADDR_IPV6 2
|
||||
#define IPSET_ATTR_PROTOCOL 1
|
||||
#define IPSET_ATTR_SETNAME 2
|
||||
#define IPSET_ATTR_TIMEOUT 6
|
||||
#define IPSET_ADD 9
|
||||
#define IPSET_DEL 10
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
@@ -243,11 +248,20 @@ static int _ipset_socket_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int addr_len, int operate)
|
||||
static int _ipset_support_timeout(const char *ipsetname)
|
||||
{
|
||||
if (dns_conf_ipset_timeout_enable) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout, int operate)
|
||||
{
|
||||
struct nlmsghdr *netlink_head;
|
||||
struct ipset_netlink_msg *netlink_msg;
|
||||
struct ipset_netlink_attr *nested[2];
|
||||
struct ipset_netlink_attr *nested[3];
|
||||
char buffer[BUFF_SZ];
|
||||
uint8_t proto;
|
||||
ssize_t rc;
|
||||
@@ -282,7 +296,7 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int
|
||||
netlink_head = (struct nlmsghdr *)buffer;
|
||||
netlink_head->nlmsg_len = NETLINK_ALIGN(sizeof(struct nlmsghdr));
|
||||
netlink_head->nlmsg_type = operate | (NFNL_SUBSYS_IPSET << 8);
|
||||
netlink_head->nlmsg_flags = NLM_F_REQUEST;
|
||||
netlink_head->nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE;
|
||||
|
||||
netlink_msg = (struct ipset_netlink_msg *)(buffer + netlink_head->nlmsg_len);
|
||||
netlink_head->nlmsg_len += NETLINK_ALIGN(sizeof(struct ipset_netlink_msg));
|
||||
@@ -300,9 +314,15 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int
|
||||
nested[1] = (struct ipset_netlink_attr *)(buffer + NETLINK_ALIGN(netlink_head->nlmsg_len));
|
||||
netlink_head->nlmsg_len += NETLINK_ALIGN(sizeof(struct ipset_netlink_attr));
|
||||
nested[1]->type = NLA_F_NESTED | IPSET_ATTR_IP;
|
||||
_ipset_add_attr(netlink_head, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, addr_len, addr);
|
||||
|
||||
_ipset_add_attr(netlink_head, (af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER, addr_len, addr);
|
||||
nested[1]->len = (void *)buffer + NETLINK_ALIGN(netlink_head->nlmsg_len) - (void *)nested[1];
|
||||
|
||||
if (timeout > 0 && _ipset_support_timeout(ipsetname) == 0) {
|
||||
timeout = htonl(timeout);
|
||||
_ipset_add_attr(netlink_head, IPSET_ATTR_TIMEOUT | NLA_F_NET_BYTEORDER, sizeof(timeout), &timeout);
|
||||
}
|
||||
|
||||
nested[0]->len = (void *)buffer + NETLINK_ALIGN(netlink_head->nlmsg_len) - (void *)nested[0];
|
||||
|
||||
for (;;) {
|
||||
@@ -323,12 +343,70 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int
|
||||
return rc;
|
||||
}
|
||||
|
||||
int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len)
|
||||
int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout)
|
||||
{
|
||||
return _ipset_operate(ipsetname, addr, addr_len, IPSET_ADD);
|
||||
return _ipset_operate(ipsetname, addr, addr_len, timeout, IPSET_ADD);
|
||||
}
|
||||
|
||||
int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len)
|
||||
{
|
||||
return _ipset_operate(ipsetname, addr, addr_len, IPSET_DEL);
|
||||
}
|
||||
return _ipset_operate(ipsetname, addr, addr_len, 0, IPSET_DEL);
|
||||
}
|
||||
|
||||
#define THREAD_STACK_SIZE (16*1024)
|
||||
static pthread_mutex_t *lock_cs;
|
||||
static long *lock_count;
|
||||
|
||||
void pthreads_locking_callback(int mode, int type, const char *file, int line)
|
||||
{
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
pthread_mutex_lock(&(lock_cs[type]));
|
||||
lock_count[type]++;
|
||||
} else {
|
||||
pthread_mutex_unlock(&(lock_cs[type]));
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long pthreads_thread_id(void)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
ret = (unsigned long)pthread_self();
|
||||
return (ret);
|
||||
}
|
||||
|
||||
void SSL_CRYPTO_thread_setup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
|
||||
lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
|
||||
if (!lock_cs || !lock_count) {
|
||||
/* Nothing we can do about this...void function! */
|
||||
if (lock_cs)
|
||||
OPENSSL_free(lock_cs);
|
||||
if (lock_count)
|
||||
OPENSSL_free(lock_count);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
lock_count[i] = 0;
|
||||
pthread_mutex_init(&(lock_cs[i]), NULL);
|
||||
}
|
||||
|
||||
CRYPTO_set_id_callback(pthreads_thread_id);
|
||||
CRYPTO_set_locking_callback(pthreads_locking_callback);
|
||||
}
|
||||
|
||||
void SSL_CRYPTO_thread_cleanup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
pthread_mutex_destroy(&(lock_cs[i]));
|
||||
}
|
||||
OPENSSL_free(lock_cs);
|
||||
OPENSSL_free(lock_count);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,12 @@ char *reverse_string(char *output, char *input, int len);
|
||||
|
||||
void print_stack(void);
|
||||
|
||||
int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len);
|
||||
int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout);
|
||||
|
||||
int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len);
|
||||
|
||||
void SSL_CRYPTO_thread_setup(void);
|
||||
|
||||
void SSL_CRYPTO_thread_cleanup(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user