Compare commits
105 Commits
Release35
...
Release37.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64e5b326cc | ||
|
|
f659cf3725 | ||
|
|
83c8105312 | ||
|
|
fecc313e03 | ||
|
|
145f7cfa42 | ||
|
|
464f2adaa7 | ||
|
|
7c9288f887 | ||
|
|
96d3deb595 | ||
|
|
584480dda1 | ||
|
|
2848aa0ac7 | ||
|
|
c156595f61 | ||
|
|
9dfe51c5ed | ||
|
|
5a2559f064 | ||
|
|
3605e6ed71 | ||
|
|
6588c9822f | ||
|
|
2f1d83cc2c | ||
|
|
ac042e8bee | ||
|
|
ab415f2ee9 | ||
|
|
d3bbd8edd7 | ||
|
|
9390a49a72 | ||
|
|
798226ddb3 | ||
|
|
d223194eff | ||
|
|
a83818c094 | ||
|
|
4e2161c6fc | ||
|
|
7d62226995 | ||
|
|
092b4ede88 | ||
|
|
301ab3ba10 | ||
|
|
362b7f978f | ||
|
|
435b2905cf | ||
|
|
e3436263d9 | ||
|
|
1f07a7ea97 | ||
|
|
9fdf53baa5 | ||
|
|
db328640c8 | ||
|
|
5006059074 | ||
|
|
883116708b | ||
|
|
cbc8c59125 | ||
|
|
b70feb112a | ||
|
|
ff0f42b87c | ||
|
|
1873a0c336 | ||
|
|
995bee4088 | ||
|
|
09dc2e9275 | ||
|
|
c0f4c72626 | ||
|
|
d185b78836 | ||
|
|
7e985e7d11 | ||
|
|
6cfaa639f6 | ||
|
|
c960f3f511 | ||
|
|
848c9e6cf2 | ||
|
|
c7db5b2667 | ||
|
|
0a04b91763 | ||
|
|
c27040099b | ||
|
|
b6740f5aab | ||
|
|
6a7ce39727 | ||
|
|
2365a1a2b0 | ||
|
|
b5a5311976 | ||
|
|
b125d142bd | ||
|
|
bc68d5979c | ||
|
|
b6f9d7e7bc | ||
|
|
e6fe6771bf | ||
|
|
94b84cd32c | ||
|
|
dae263444f | ||
|
|
dbfe9063e4 | ||
|
|
ae3beb5fba | ||
|
|
7a55471ce3 | ||
|
|
03478debe8 | ||
|
|
ee40591aed | ||
|
|
bdc3a87d6d | ||
|
|
68ce6b3f0f | ||
|
|
9dffec3fd3 | ||
|
|
e64007f558 | ||
|
|
87a400ebae | ||
|
|
9804c305d0 | ||
|
|
e1755dadc1 | ||
|
|
c7d54a2111 | ||
|
|
34691154fb | ||
|
|
29a5803860 | ||
|
|
ebd820bcbb | ||
|
|
1de5557430 | ||
|
|
c92615e6cd | ||
|
|
c561ae2fc5 | ||
|
|
d30264ed08 | ||
|
|
22e13b40db | ||
|
|
75dda9340d | ||
|
|
baf2be681d | ||
|
|
5bd521c36b | ||
|
|
d0305f60f6 | ||
|
|
6e1363dca4 | ||
|
|
23e9021d30 | ||
|
|
92af4c05c0 | ||
|
|
24661c2419 | ||
|
|
1efa1942cc | ||
|
|
1fd18601e7 | ||
|
|
d7d7ef48cd | ||
|
|
0652316e98 | ||
|
|
ee9059bb37 | ||
|
|
45180c0dd6 | ||
|
|
f29e292a41 | ||
|
|
cf34cbc045 | ||
|
|
8d7c54d382 | ||
|
|
75d91096ca | ||
|
|
e98cf5b711 | ||
|
|
a33d09f80b | ||
|
|
ba282c8c60 | ||
|
|
a588793221 | ||
|
|
cd88dd4854 | ||
|
|
8973acad44 |
9
.github/ISSUE_TEMPLATE/issue.md
vendored
9
.github/ISSUE_TEMPLATE/issue.md
vendored
@@ -15,6 +15,11 @@ assignees: ''
|
||||
|
||||
2. 运营商
|
||||
|
||||
3. smartdns来源以及版本
|
||||
|
||||
4. 涉及的配置(注意去除个人相关信息)
|
||||
|
||||
|
||||
**重现步骤**
|
||||
1. 上游DNS配置。
|
||||
|
||||
@@ -22,8 +27,8 @@ assignees: ''
|
||||
|
||||
|
||||
**信息收集**
|
||||
1. 将/var/log/smrtdns.log日志作为附件上传。
|
||||
2. 如进程异常,请将coredump功能开启,上传coredump信息文件。
|
||||
1. 将/var/log/smrtdns.log日志作为附件上传(注意去除个人相关信息)。
|
||||
2. 如进程异常,请将coredump功能开启,上传coredump信息文件,同时上传配套的smartdns进程文件。
|
||||
在自定义界面,开启设置->自定义设置->生成coredump配置,重现问题后提交coredump文件
|
||||
coredump文件在/tmp目录下
|
||||
|
||||
|
||||
57
Dockerfile
57
Dockerfile
@@ -1,18 +1,45 @@
|
||||
FROM debian:buster-slim
|
||||
FROM ubuntu:latest as smartdns-builder
|
||||
LABEL previous-stage=smartdns-builder
|
||||
|
||||
RUN apt update && \
|
||||
apt install -y git make gcc libssl-dev && \
|
||||
git clone https://github.com/pymumu/smartdns.git --depth 1 && \
|
||||
cd smartdns && \
|
||||
sh ./package/build-pkg.sh --platform debian --arch `dpkg --print-architecture` && \
|
||||
dpkg -i package/*.deb && \
|
||||
cd / && \
|
||||
rm -rf smartdns/ && \
|
||||
apt autoremove -y git make gcc libssl-dev && \
|
||||
apt clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
# prepare builder
|
||||
ARG OPENSSL_VER=1.1.1f
|
||||
RUN apt update && \
|
||||
apt install -y perl curl make musl-tools musl-dev && \
|
||||
ln -s /usr/include/linux /usr/include/$(uname -m)-linux-musl && \
|
||||
ln -s /usr/include/asm-generic /usr/include/$(uname -m)-linux-musl && \
|
||||
ln -s /usr/include/$(uname -m)-linux-gnu/asm /usr/include/$(uname -m)-linux-musl && \
|
||||
\
|
||||
mkdir -p /build/openssl && \
|
||||
cd /build/openssl && \
|
||||
curl -sSL http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/openssl_${OPENSSL_VER}.orig.tar.gz | tar --strip-components=1 -zxv && \
|
||||
\
|
||||
export CC=musl-gcc && \
|
||||
if [ "$(uname -m)" = "aarch64" ]; then \
|
||||
./config --prefix=/opt/build no-tests -mno-outline-atomics ; \
|
||||
else \
|
||||
./config --prefix=/opt/build no-tests ; \
|
||||
fi && \
|
||||
make all -j8 && make install_sw && \
|
||||
cd / && rm -rf /build
|
||||
|
||||
EXPOSE 53/udp
|
||||
VOLUME "/etc/smartdns/"
|
||||
# do make
|
||||
COPY . /build/smartdns/
|
||||
RUN cd /build/smartdns && \
|
||||
export CC=musl-gcc && \
|
||||
export CFLAGS="-I /opt/build/include" && \
|
||||
export LDFLAGS="-L /opt/build/lib" && \
|
||||
sh ./package/build-pkg.sh --platform linux --arch `dpkg --print-architecture` --static && \
|
||||
\
|
||||
( cd package && tar -xvf *.tar.gz && chmod a+x smartdns/etc/init.d/smartdns ) && \
|
||||
\
|
||||
mkdir -p /release/var/log /release/var/run && \
|
||||
cp package/smartdns/etc /release/ -a && \
|
||||
cp package/smartdns/usr /release/ -a && \
|
||||
cd / && rm -rf /build
|
||||
|
||||
CMD ["/usr/sbin/smartdns", "-f"]
|
||||
FROM busybox:latest
|
||||
COPY --from=smartdns-builder /release/ /
|
||||
EXPOSE 53/udp
|
||||
VOLUME "/etc/smartdns/"
|
||||
|
||||
CMD ["/usr/sbin/smartdns", "-f", "-x"]
|
||||
|
||||
64
ReadMe_en.md
64
ReadMe_en.md
@@ -281,7 +281,7 @@ https://github.com/pymumu/smartdns/releases
|
||||
|
||||
* **Check if the service is configured successfully**
|
||||
|
||||
* Method 1: Query domain name with `nslookup -querytype=ptr 0.0.0.1`
|
||||
* Query domain name with `nslookup -querytype=ptr 0.0.0.1`
|
||||
See if the `name` item in the command result is displayed as `smartdns` or `hostname`, such as `smartdns`
|
||||
|
||||
```shell
|
||||
@@ -293,18 +293,12 @@ https://github.com/pymumu/smartdns/releases
|
||||
smartdns name = smartdns.
|
||||
```
|
||||
|
||||
* Method 2: Use `nslookup` to query the `www.baidu.com` domain name to see if the IP address of Baidu in the result is `only one. If there are multiple IP addresses returned, it means that it is not valid. Please try to check several domain names.
|
||||
* or Query doman name `smartdns `with `nslookup smartdns`
|
||||
```shell
|
||||
$ nslookup smartdns
|
||||
```
|
||||
|
||||
```shell
|
||||
pi@raspberrypi:~ $ nslookup www.baidu.com 192.168.1.1
|
||||
Server: 192.168.1.1
|
||||
Address: 192.168.1.1#53
|
||||
|
||||
Non-authoritative answer:
|
||||
www.baidu.com canonical name = www.a.shifen.com.
|
||||
Name: www.a.shifen.com
|
||||
Address: 14.215.177.38
|
||||
```
|
||||
Check whether the command result resolves the IP address of the router, if so, it means it is working.
|
||||
|
||||
1. Start Service
|
||||
|
||||
@@ -503,13 +497,16 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|tcp-idle-time|TCP connection idle timeout|120|integer|tcp-idle-time 120
|
||||
|rr-ttl|Domain name TTL|Remote query result|number greater than 0|rr-ttl 600
|
||||
|rr-ttl-min|Domain name Minimum TTL|Remote query result|number greater than 0|rr-ttl-min 60
|
||||
|local-ttl|ttl for address and host|rr-ttl-min|number greater than 0|local-ttl 600
|
||||
|rr-ttl-reply-max|Domain name Minimum Reply TTL|Remote query result|number greater than 0|rr-ttl-reply-max 60
|
||||
|rr-ttl-max|Domain name Maximum TTL|Remote query result|number greater than 0|rr-ttl-max 600
|
||||
|max-reply-ip-num|Maximum number of IPs returned to the client|8|number of IPs, 1~16 |max-reply-ip-num 1
|
||||
|log-level|log level|error|fatal,error,warn,notice,info,debug|log-level error
|
||||
|log-file|log path|/var/log/smartdns.log|File Pah|log-file /var/log/smartdns.log
|
||||
|log-file|log path|/var/log/smartdns/smartdns.log|File Pah|log-file /var/log/smartdns/smartdns.log
|
||||
|log-size|log size|128K|number+K,M,G|log-size 128K
|
||||
|log-num|archived log number|2|Integer|log-num 2
|
||||
|audit-enable|audit log enable|no|[yes\|no]|audit-enable yes
|
||||
|audit-file|audit log file|/var/log/smartdns-audit.log|File Path|audit-file /var/log/smartdns-audit.log
|
||||
|audit-file|audit log file|/var/log/smartdns/smartdns-audit.log|File Path|audit-file /var/log/smartdns/smartdns-audit.log
|
||||
|audit-size|audit log size|128K|number+K,M,G|audit-size 128K
|
||||
|audit-num|archived audit log number|2|Integer|audit-num 2
|
||||
|conf-file|additional conf file|None|File path|conf-file /etc/smartdns/smartdns.more.conf
|
||||
@@ -517,7 +514,8 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|server-tcp|Upstream TCP DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-tcp 8.8.8.8:53
|
||||
|server-tls|Upstream TLS DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name. <br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-tls 8.8.8.8:853
|
||||
|server-https|Upstream HTTPS DNS server|None|Repeatable <br>`https://[host][:port]/path`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name<br>`[-http-host]`:http header host. <br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-https https://cloudflare-dns.com/dns-query
|
||||
|speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:443
|
||||
|speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:80,tcp:443
|
||||
|response-mode|First query response mode|first-ping|Mode: [fisrt-ping\|fastest-ip\|fastest-response]<br> [first-ping]: The fastest dns + ping response mode, DNS query delay + ping delay is the shortest;<br>[fastest-ip]: The fastest IP address mode, return the fastest ip address, may take some time to test speed. <br>[fastest-response]: The fastest response DNS result mode, the DNS query waiting time is the shortest. | response-mode first-ping |
|
||||
|address|Domain IP address|None|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-` for ignore, `#` for return SOA, `4` for IPV4, `6` for IPV6| address /www.example.com/1.2.3.4
|
||||
|nameserver|To query domain with specific server group|None|nameserver /domain/[group\|-], `group` is the group name, `-` means ignore this rule, use the `-group` parameter in the related server|nameserver /www.example.com/office
|
||||
|ipset|Domain IPSet|None|ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]], `-` for ignore|ipset /www.example.com/#4:dns4,#6:-
|
||||
@@ -528,12 +526,15 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|whitelist-ip|ip whitelist|None|[ip/subnet], Repeatable,When the filtering server responds IPs in the IP whitelist, only result in whitelist will be accepted| whitelist-ip 1.2.3.4/16
|
||||
|blacklist-ip|ip blacklist|None|[ip/subnet], Repeatable,When the filtering server responds IPs in the IP blacklist, The result will be discarded directly| blacklist-ip 1.2.3.4/16
|
||||
|force-AAAA-SOA|force AAAA query return SOA|no|[yes\|no]|force-AAAA-SOA yes
|
||||
|force-qtype-SOA|force specific qtype return SOA|qtype id|[qtypeid | ...]|force-qtype-SOA 65 28
|
||||
|prefetch-domain|domain prefetch feature|no|[yes\|no]|prefetch-domain yes
|
||||
|serve-expired|Cache serve expired feature|no|[yes\|no], Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish.|serve-expired yes
|
||||
|dnsmasq-lease-file|Support reading dnsmasq dhcp file to resolve local hostname|None|dnsmasq dhcp lease file| dnsmasq-lease-file /var/lib/misc/dnsmasq.leases
|
||||
|serve-expired|Cache serve expired feature|yes|[yes\|no], Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish.|serve-expired yes
|
||||
|serve-expired-ttl|Cache serve expired limite TTL|0|second,0:disable,> 0 seconds after expiration|serve-expired-ttl 0
|
||||
|serve-expired-reply-ttl|TTL value to use when replying with expired data|5|second,0:disable,> 0 seconds after expiration|serve-expired-reply-ttl 30
|
||||
|dualstack-ip-selection|Dualstack ip selection|no|[yes\|no]|dualstack-ip-selection yes
|
||||
|dualstack-ip-selection-threshold|Dualstack ip select threadhold|30ms|millisecond|dualstack-ip-selection-threshold [0-1000]
|
||||
|dualstack-ip-selection|Dualstack ip selection|yes|[yes\|no]|dualstack-ip-selection yes
|
||||
|dualstack-ip-selection-threshold|Dualstack ip select threadhold|15ms|millisecond|dualstack-ip-selection-threshold [0-1000]
|
||||
|user|run as user|root|user [username]|user nobody
|
||||
|ca-file|certificate file|/etc/ssl/certs/ca-certificates.crt|path|ca-file /etc/ssl/certs/ca-certificates.crt
|
||||
|ca-path|certificates path|/etc/ssl/certs|path|ca-path /etc/ssl/certs
|
||||
|
||||
@@ -638,7 +639,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
Enable cache serve expired feature with `serve-expired yes` to improve the cache hit rate and reduce the CPU consumption.
|
||||
This feature will return TTL = 0 to the client after the TTL timeout, and send a new query request again at the same time, and cache the new results for later query.
|
||||
|
||||
1. How does the second DNS customize more behavior?
|
||||
1. How does the second DNS customize more behavior?
|
||||
The second DNS can be used as the upstream of other DNS servers to provide more query behaviors. Bind configuration support can bind multiple ports. Different ports can be set with different flags to implement different functions, such as
|
||||
|
||||
```sh
|
||||
@@ -646,6 +647,31 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
bind [::]:6053 -no-speed-check -group office -no-rule-addr
|
||||
```
|
||||
|
||||
1. How to get SPKI of DOT
|
||||
The SPKI can be obtained from the page published by the DNS service provider. If it is not published, it can be obtained by the following command, replace IP with your own IP.
|
||||
|
||||
```sh
|
||||
echo | openssl s_client -connect '1.0.0.1:853' 2>/dev/null | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
|
||||
```
|
||||
|
||||
1. How to solve the problem of slow DNS resolution in iOS system?
|
||||
Since iOS14, Apple has supported the resolution of DNS HTTPS (TYPE65) records. This function is used for solving problems related to HTTPS connections, but it is still a draft, and it will cause some functions such as adblocking fail. It is recommended to disable it through the following configuration.
|
||||
|
||||
```sh
|
||||
force-qtype-SOA 65
|
||||
```
|
||||
|
||||
1. How to resolve localhost ip by hostname?
|
||||
smartdns can cooperate with the dhcp server of DNSMASQ to support the resolution of local host name to IP address. You can configure smartdns to read the lease file of dnsmasq and support the resolution. The specific configuration parameters are as follows, (note that the DNSMASQ lease file may be different for each system and needs to be configured according to the actual situation)
|
||||
|
||||
```sh
|
||||
dnsmasq-lease-file /var/lib/misc/dnsmasq.leases
|
||||
````\
|
||||
|
||||
After the configuration is complete, you can directly use the host name to connect to the local machine. But need to pay attention:
|
||||
|
||||
* Windows system uses mDNS to resolve addresses by default. If you need to use smartdns to resolve addresses under Windows, you need to add `.` after the host name, indicating that DNS resolution is used. Such as `ping smartdns.`
|
||||
|
||||
## Compile
|
||||
|
||||
smartdns contains scripts for compiling packages, supports compiling luci, debian, openwrt, opare installation packages, and can execute `package/build-pkg.sh` compilation.
|
||||
|
||||
@@ -68,11 +68,23 @@ case $1 in
|
||||
echo "Stop smartdns server failed."
|
||||
exit 1;
|
||||
fi
|
||||
rm -f "$PIDFILE"
|
||||
LOOP=1
|
||||
while true; do
|
||||
if [ ! -d "/proc/$PID" ]; then
|
||||
break;
|
||||
fi
|
||||
|
||||
if [ $LOOP -gt 12 ]; then
|
||||
kill -9 "$PID"
|
||||
break;
|
||||
fi
|
||||
LOOP=$((LOOP+1))
|
||||
sleep .5
|
||||
done
|
||||
echo "Stop smartdns server success."
|
||||
;;
|
||||
restart)
|
||||
"$0" stop && sleep 1 && "$0" start
|
||||
"$0" stop && "$0" start
|
||||
;;
|
||||
status)
|
||||
PID="$(cat "$PIDFILE" 2>/dev/null)"
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
# server-name smartdns
|
||||
#
|
||||
|
||||
# dns server run user
|
||||
# user [username]
|
||||
# example: run as nobody
|
||||
# user nobody
|
||||
#
|
||||
|
||||
# Include another configuration options
|
||||
# conf-file [file]
|
||||
# conf-file blacklist-ip.conf
|
||||
@@ -30,7 +36,9 @@
|
||||
# IPV6:
|
||||
# bind [::]:53
|
||||
# bind-tcp [::]:53
|
||||
bind [::]:53
|
||||
bind [::]:7053
|
||||
|
||||
force-AAAA-SOA yes
|
||||
|
||||
# tcp connection idle timeout
|
||||
# tcp-idle-time [second]
|
||||
@@ -38,7 +46,7 @@ bind [::]:53
|
||||
# dns cache size
|
||||
# cache-size [number]
|
||||
# 0: for no cache
|
||||
cache-size 4096
|
||||
cache-size 16384
|
||||
|
||||
# enable persist cache when restart
|
||||
# cache-persist yes
|
||||
@@ -77,31 +85,46 @@ cache-size 4096
|
||||
# speed check mode
|
||||
# speed-check-mode [ping|tcp:port|none|,]
|
||||
# example:
|
||||
# speed-check-mode ping,tcp:80
|
||||
# speed-check-mode ping,tcp:80,tcp:443
|
||||
# speed-check-mode tcp:443,ping
|
||||
# speed-check-mode none
|
||||
|
||||
# force AAAA query return SOA
|
||||
# force-AAAA-SOA [yes|no]
|
||||
|
||||
# force specific qtype return soa
|
||||
# force-qtype-SOA [qtypeid |...]
|
||||
# force-qtype-SOA 65 28
|
||||
|
||||
# Enable IPV4, IPV6 dual stack IP optimization selection strategy
|
||||
# dualstack-ip-selection-threshold [num] (0~1000)
|
||||
# dualstack-ip-allow-force-AAAA [yes|no]
|
||||
# dualstack-ip-selection [yes|no]
|
||||
# dualstack-ip-selection yes
|
||||
|
||||
# edns client subnet
|
||||
# edns-client-subnet [ip/subnet]
|
||||
# edns-client-subnet 192.168.1.1/24
|
||||
# edns-client-subnet [8::8]/56
|
||||
# edns-client-subnet 8::8/56
|
||||
|
||||
# ttl for all resource record
|
||||
# rr-ttl: ttl for all record
|
||||
# rr-ttl-min: minimum ttl for resource record
|
||||
# rr-ttl-max: maximum ttl for resource record
|
||||
# rr-ttl-reply-max: maximum reply ttl for resource record
|
||||
# example:
|
||||
# rr-ttl 300
|
||||
# rr-ttl-min 60
|
||||
# rr-ttl-max 86400
|
||||
# rr-ttl-reply-max 60
|
||||
|
||||
# Maximum number of IPs returned to the client|8|number of IPs, 1~16
|
||||
# example:
|
||||
# max-reply-ip-num 1
|
||||
|
||||
# response mode
|
||||
# Experimental feature
|
||||
# response-mode [first-ping|fastest-ip|fastest-response]
|
||||
|
||||
# set log level
|
||||
# log-level: [level], level=fatal, error, warn, notice, info, debug
|
||||
@@ -109,7 +132,7 @@ cache-size 4096
|
||||
# log-size: size of each log file, support k,m,g
|
||||
# log-num: number of logs
|
||||
log-level info
|
||||
# log-file /var/log/smartdns.log
|
||||
# log-file /var/log/smartdns/smartdns.log
|
||||
# log-size 128k
|
||||
# log-num 2
|
||||
|
||||
@@ -122,6 +145,9 @@ log-level info
|
||||
# audit-size 128k
|
||||
# audit-num 2
|
||||
|
||||
# Support reading dnsmasq dhcp file to resolve local hostname
|
||||
# dnsmasq-lease-file /var/lib/misc/dnsmasq.leases
|
||||
|
||||
# certificate file
|
||||
# ca-file [file]
|
||||
# ca-file /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
smartdns (1.2018.7.9) stable; urgency=low
|
||||
smartdns (1:1.2022.04.05) stable; urgency=low
|
||||
|
||||
* Initial build
|
||||
|
||||
|
||||
@@ -43,7 +43,9 @@ build()
|
||||
mkdir $ROOT/etc/default/ -p
|
||||
mkdir $ROOT/lib/systemd/system/ -p
|
||||
|
||||
sed -i "s/Version:.*/Version: $VER/" $ROOT/DEBIAN/control
|
||||
|
||||
pkgver=$(echo ${VER}| sed 's/^1\.//g')
|
||||
sed -i "s/Version:.*/Version: ${pkgver}/" $ROOT/DEBIAN/control
|
||||
sed -i "s/Architecture:.*/Architecture: $ARCH/" $ROOT/DEBIAN/control
|
||||
chmod 0755 $ROOT/DEBIAN/prerm
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ init_dir()
|
||||
which systemctl >/dev/null 2>&1
|
||||
ISSYSTEMD="$?"
|
||||
# Running under WSL (Windows Subsystem for Linux)?
|
||||
cat /proc/version | grep Microsoft >/dev/null 2>&1;
|
||||
cat /proc/version | grep -E '[Mm]icrosoft' >/dev/null 2>&1;
|
||||
if [ $? -eq 0 ]; then
|
||||
ISSYSTEMD=1
|
||||
ISWSL=0
|
||||
|
||||
@@ -124,6 +124,9 @@ msgstr "域名TTL最大值"
|
||||
msgid "Maximum TTL for all domain result."
|
||||
msgstr "设置所有域名的TTL最大值"
|
||||
|
||||
msgid "Maximum Reply TTL for all domain result."
|
||||
msgstr "设置返回给客户端的TTL最大值"
|
||||
|
||||
msgid "smartdns custom settings"
|
||||
msgstr "smartdns 自定义设置,具体配置参数参考指导"
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ end
|
||||
---- Support DualStack ip selection
|
||||
o = s:taboption("settings", Flag, "dualstack_ip_selection", translate("Dual-stack IP Selection"), translate("Enable IP selection between IPV4 and IPV6"))
|
||||
o.rmempty = false
|
||||
o.default = o.disabled
|
||||
o.default = o.enabled
|
||||
o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "0"
|
||||
end
|
||||
@@ -87,7 +87,7 @@ end
|
||||
o = s:taboption("settings", Flag, "serve_expired", translate("Serve expired"),
|
||||
translate("Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish."))
|
||||
o.rmempty = false
|
||||
o.default = o.disabled
|
||||
o.default = o.enabled
|
||||
o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "0"
|
||||
end
|
||||
@@ -112,15 +112,19 @@ o.rempty = true
|
||||
---- rr-ttl-min
|
||||
o = s:taboption("settings", Value, "rr_ttl_min", translate("Domain TTL Min"), translate("Minimum TTL for all domain result."))
|
||||
o.rempty = true
|
||||
o.placeholder = "300"
|
||||
o.default = 300
|
||||
o.placeholder = "600"
|
||||
o.default = 600
|
||||
o.optional = true
|
||||
|
||||
---- second dns server
|
||||
---- rr-ttl-max
|
||||
o = s:taboption("settings", Value, "rr_ttl_max", translate("Domain TTL Max"), translate("Maximum TTL for all domain result."))
|
||||
o.rempty = true
|
||||
|
||||
---- rr-ttl-reply-max
|
||||
o = s:taboption("settings", Value, "rr_ttl_reply_max", translate("Domain TTL Max"), translate("Maximum Reply TTL for all domain result."))
|
||||
o.rempty = true
|
||||
|
||||
---- second dns server
|
||||
---- Eanble
|
||||
o = s:taboption("seconddns", Flag, "seconddns_enabled", translate("Enable"), translate("Enable or disable second DNS server."))
|
||||
o.default = o.disabled
|
||||
|
||||
@@ -109,6 +109,12 @@ msgstr "重定向53端口到SmartDNS"
|
||||
msgid "Cache Size"
|
||||
msgstr "缓存大小"
|
||||
|
||||
msgid "Resolve Local Hostnames"
|
||||
msgstr "本地主机名解析"
|
||||
|
||||
msgid "Resolve local hostnames by reading Dnsmasq lease file"
|
||||
msgstr "读取Dnsmasq的DHCP Lease文件解析本地主机名"
|
||||
|
||||
msgid "DNS domain result cache size"
|
||||
msgstr "缓存DNS的结果,缓存大小,配置零则不缓存(单位:条)"
|
||||
|
||||
@@ -130,6 +136,9 @@ msgstr "域名TTL最大值"
|
||||
msgid "Maximum TTL for all domain result."
|
||||
msgstr "设置所有域名的TTL最大值"
|
||||
|
||||
msgid "Maximum Reply TTL for all domain result."
|
||||
msgstr "设置返回给客户端的TTL最大值"
|
||||
|
||||
msgid "smartdns custom settings"
|
||||
msgstr "smartdns 自定义设置,具体配置参数参考指导"
|
||||
|
||||
@@ -190,8 +199,8 @@ msgstr "跳过cache。"
|
||||
msgid "Force AAAA SOA"
|
||||
msgstr "停用IPV6地址解析"
|
||||
|
||||
msgid "Force AAAA SOA."
|
||||
msgstr "停用IPV6地址解析。"
|
||||
msgid "Force HTTPS SOA."
|
||||
msgstr "停用HTTPS解析。"
|
||||
|
||||
msgid "Upstream Servers"
|
||||
msgstr "上游服务器"
|
||||
|
||||
@@ -31,7 +31,7 @@ var callServiceList = rpc.declare({
|
||||
expect: { '': {} }
|
||||
});
|
||||
|
||||
function getPidOfSmartdns() {
|
||||
function getServiceStatus() {
|
||||
return L.resolveDefault(callServiceList(conf), {})
|
||||
.then(function (res) {
|
||||
var isrunning = false;
|
||||
@@ -49,6 +49,8 @@ function getIPTablesRedirect() {
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}).catch(function (err) {
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
@@ -59,12 +61,14 @@ function getIP6TablesRedirect() {
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
});
|
||||
}).catch(function (err) {
|
||||
return "";
|
||||
});;
|
||||
}
|
||||
|
||||
function smartdnsServiceStatus() {
|
||||
return Promise.all([
|
||||
getPidOfSmartdns(),
|
||||
getServiceStatus(),
|
||||
getIPTablesRedirect(),
|
||||
getIP6TablesRedirect()
|
||||
]);
|
||||
@@ -136,6 +140,10 @@ return L.view.extend({
|
||||
L.Poll.add(function () {
|
||||
return L.resolveDefault(smartdnsServiceStatus()).then(function (res) {
|
||||
var view = document.getElementById("service_status");
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.innerHTML = smartdnsRenderStatus(res);
|
||||
});
|
||||
});
|
||||
@@ -188,7 +196,7 @@ return L.view.extend({
|
||||
o = s.taboption("settings", form.Flag, "dualstack_ip_selection", _("Dual-stack IP Selection"),
|
||||
_("Enable IP selection between IPV4 and IPV6"));
|
||||
o.rmempty = false;
|
||||
o.default = o.disabled;
|
||||
o.default = o.enabled;
|
||||
|
||||
// Domain prefetch load ;
|
||||
o = s.taboption("settings", form.Flag, "prefetch_domain", _("Domain prefetch"),
|
||||
@@ -200,7 +208,7 @@ return L.view.extend({
|
||||
o = s.taboption("settings", form.Flag, "serve_expired", _("Serve expired"),
|
||||
_("Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish."));
|
||||
o.rmempty = false;
|
||||
o.default = o.disabled;
|
||||
o.default = o.enabled;
|
||||
|
||||
// Redirect;
|
||||
o = s.taboption("settings", form.ListValue, "redirect", _("Redirect"), _("SmartDNS redirect mode"));
|
||||
@@ -215,6 +223,21 @@ return L.view.extend({
|
||||
o = s.taboption("settings", form.Value, "cache_size", _("Cache Size"), _("DNS domain result cache size"));
|
||||
o.rempty = true;
|
||||
|
||||
// cache-size;
|
||||
o = s.taboption("settings", form.Flag, "resolve_local_hostnames", _("Resolve Local Hostnames"), _("Resolve local hostnames by reading Dnsmasq lease file"));
|
||||
o.rmempty = false;
|
||||
o.default = o.enabled;
|
||||
|
||||
// Force AAAA SOA
|
||||
o = s.taboption("settings", form.Flag, "force_aaaa_soa", _("Force AAAA SOA"), _("Force AAAA SOA."));
|
||||
o.rmempty = false;
|
||||
o.default = o.disabled;
|
||||
|
||||
// Force HTTPS SOA
|
||||
o = s.taboption("settings", form.Flag, "force_https_soa", _("Force HTTPS SOA"), _("Force HTTPS SOA."));
|
||||
o.rmempty = false;
|
||||
o.default = o.disabled;
|
||||
|
||||
// rr-ttl;
|
||||
o = s.taboption("settings", form.Value, "rr_ttl", _("Domain TTL"), _("TTL for all domain result."));
|
||||
o.rempty = true;
|
||||
@@ -223,16 +246,21 @@ return L.view.extend({
|
||||
o = s.taboption("settings", form.Value, "rr_ttl_min", _("Domain TTL Min"),
|
||||
_("Minimum TTL for all domain result."));
|
||||
o.rempty = true;
|
||||
o.placeholder = "300";
|
||||
o.default = 300;
|
||||
o.placeholder = "600";
|
||||
o.default = 600;
|
||||
o.optional = true;
|
||||
|
||||
// second dns server;
|
||||
// rr-ttl-max;
|
||||
o = s.taboption("settings", form.Value, "rr_ttl_max", _("Domain TTL Max"),
|
||||
_("Maximum TTL for all domain result."));
|
||||
_("Maximum TTL for all domain result."));
|
||||
o.rempty = true;
|
||||
|
||||
// rr-ttl-reply-max;
|
||||
o = s.taboption("settings", form.Value, "rr_ttl_reply_max", _("Domain Reply TTL Max"),
|
||||
_("Maximum Reply TTL for all domain result."));
|
||||
o.rempty = true;
|
||||
|
||||
// second dns server;
|
||||
// Eanble;
|
||||
o = s.taboption("seconddns", form.Flag, "seconddns_enabled", _("Enable"),
|
||||
_("Enable or disable second DNS server."));
|
||||
|
||||
@@ -260,6 +260,8 @@ load_service()
|
||||
{
|
||||
local section="$1"
|
||||
args=""
|
||||
dnsmase_lease_file="$(uci get dhcp.@dnsmasq[0].leasefile 2>/dev/null)"
|
||||
qtype_soa_list=""
|
||||
|
||||
mkdir -p $SMARTDNS_VAR_CONF_DIR
|
||||
rm -f $SMARTDNS_CONF_TMP
|
||||
@@ -289,7 +291,7 @@ load_service()
|
||||
fi
|
||||
}
|
||||
config_get dualstack_ip_selection "$section" "dualstack_ip_selection" "0"
|
||||
[ "$dualstack_ip_selection" = "1" ] && conf_append "dualstack-ip-selection" "yes"
|
||||
[ "$dualstack_ip_selection" = "0" ] && conf_append "dualstack-ip-selection" "no"
|
||||
|
||||
config_get prefetch_domain "$section" "prefetch_domain" "0"
|
||||
[ "$prefetch_domain" = "1" ] && conf_append "prefetch-domain" "yes"
|
||||
@@ -302,6 +304,15 @@ load_service()
|
||||
config_get cache_size "$section" "cache_size" ""
|
||||
[ -z "$cache_size" ] || conf_append "cache-size" "$cache_size"
|
||||
|
||||
config_get resolve_local_hostnames "$section" "resolve_local_hostnames" "1"
|
||||
[ -z "$resolve_local_hostnames" ] || conf_append "dnsmasq-lease-file" "$dnsmase_lease_file"
|
||||
|
||||
config_get force_aaaa_soa "$section" "force_aaaa_soa" "0"
|
||||
[ "$force_aaaa_soa" = "1" ] && qtype_soa_list="$qtype_soa_list 28"
|
||||
|
||||
config_get force_https_soa "$section" "force_https_soa" "0"
|
||||
[ "$force_https_soa" = "1" ] && qtype_soa_list="$qtype_soa_list 65"
|
||||
|
||||
config_get rr_ttl "$section" "rr_ttl" ""
|
||||
[ -z "$rr_ttl" ] || conf_append "rr-ttl" "$rr_ttl"
|
||||
|
||||
@@ -311,6 +322,9 @@ load_service()
|
||||
config_get rr_ttl_max "$section" "rr_ttl_max" ""
|
||||
[ -z "$rr_ttl_max" ] || conf_append "rr-ttl-max" "$rr_ttl_max"
|
||||
|
||||
config_get rr_ttl_reply_max "$section" "rr_ttl_reply_max" ""
|
||||
[ -z "$rr_ttl_reply_max" ] || conf_append "rr-ttl-reply-max" "$rr_ttl_reply_max"
|
||||
|
||||
config_get log_size "$section" "log_size" "64K"
|
||||
[ -z "$log_size" ] || conf_append "log-size" "$log_size"
|
||||
|
||||
@@ -328,6 +342,8 @@ load_service()
|
||||
config_get old_port "$section" "old_port" "0"
|
||||
config_get old_enabled "$section" "old_enabled" "0"
|
||||
|
||||
[ -z "$qtype_soa_list" ] || conf_append "force-qtype-SOA" "$qtype_soa_list"
|
||||
|
||||
if [ "$old_redirect" != "$redirect" ] || [ "$old_port" != "$SMARTDNS_PORT" ] || [ "$old_enabled" = "1" -a "$enabled" = "0" ]; then
|
||||
[ "$old_redirect" = "none" ] || {
|
||||
[ "$old_port" = "0" ] || clear_iptable "$old_port" "$ipv6_server"
|
||||
@@ -374,6 +390,7 @@ load_service()
|
||||
procd_set_param command /usr/sbin/smartdns -f -c $SMARTDNS_CONF $args
|
||||
[ "$RESPAWN" = "1" ] && procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
|
||||
procd_set_param file "$SMARTDNS_CONF"
|
||||
procd_set_param term_timeout 60
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ SMARTDNS_PID=/var/run/smartdns.pid
|
||||
SMARTDNS_PORT=535
|
||||
SMARTDNS_OPT=/opt/etc/smartdns/smartdns-opt.conf
|
||||
# workmode
|
||||
# DO NOT CHANGE THIS, CHANGE MODE IN smartdns-opt.conf
|
||||
# 0: run as port only
|
||||
# 1: redirect port
|
||||
# 2: replace
|
||||
@@ -232,11 +233,11 @@ 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
|
||||
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
|
||||
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
|
||||
@@ -339,7 +340,7 @@ case "$1" in
|
||||
SLEEP="sleep"
|
||||
SLEEPTIME=0.2
|
||||
fi
|
||||
N=30
|
||||
N=300
|
||||
while [ $N -gt 0 ]
|
||||
do
|
||||
pid="$(cat "$SMARTDNS_PID" | head -n 1 2>/dev/null)"
|
||||
@@ -348,7 +349,13 @@ case "$1" in
|
||||
fi
|
||||
|
||||
if [ ! -d "/proc/$pid" ]; then
|
||||
return 0;
|
||||
return 0
|
||||
fi
|
||||
|
||||
stat="$(cat /proc/${pid}/stat | awk '{print $3}' 2>/dev/null)"
|
||||
if [ "$stat" = "Z" ]; then
|
||||
$SLEEP $SLEEPTIME
|
||||
return 0
|
||||
fi
|
||||
|
||||
$SLEEP $SLEEPTIME 2>/dev/null
|
||||
|
||||
@@ -20,7 +20,7 @@ OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_co
|
||||
|
||||
# cflags
|
||||
ifndef CFLAGS
|
||||
CFLAGS =-O2 -g -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing -funwind-tables
|
||||
CFLAGS =-O2 -g -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing -funwind-tables -Wmissing-prototypes -Wshadow -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough
|
||||
endif
|
||||
override CFLAGS +=-Iinclude
|
||||
override CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
|
||||
|
||||
69
src/dns.h
69
src/dns.h
@@ -23,13 +23,18 @@
|
||||
#define DNS_RR_AAAA_LEN 16
|
||||
#define DNS_MAX_CNAME_LEN 256
|
||||
#define DNS_MAX_OPT_LEN 256
|
||||
#define DNS_IN_PACKSIZE (512 * 4)
|
||||
#define DNS_PACKSIZE (512 * 10)
|
||||
#define DNS_IN_PACKSIZE (512 * 8)
|
||||
#define DNS_PACKSIZE (512 * 12)
|
||||
#define DNS_DEFAULT_PACKET_SIZE 512
|
||||
|
||||
#define DNS_ADDR_FAMILY_IP 1
|
||||
#define DNS_ADDR_FAMILY_IPV6 2
|
||||
|
||||
/*
|
||||
DNS parameters:
|
||||
https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
|
||||
*/
|
||||
|
||||
typedef enum dns_qr {
|
||||
DNS_QR_QUERY = 0,
|
||||
DNS_QR_ANSWER = 1,
|
||||
@@ -61,6 +66,7 @@ typedef enum dns_type {
|
||||
DNS_T_SRV = 33,
|
||||
DNS_T_OPT = 41,
|
||||
DNS_T_SSHFP = 44,
|
||||
DNS_T_HTTPS = 65,
|
||||
DNS_T_SPF = 99,
|
||||
DNS_T_AXFR = 252,
|
||||
DNS_T_ALL = 255
|
||||
@@ -68,6 +74,7 @@ typedef enum dns_type {
|
||||
|
||||
typedef enum dns_opt_code {
|
||||
DNS_OPT_T_ECS = 8, // OPT ECS
|
||||
DNS_OPT_T_COOKIE = 10, //OPT Cookie
|
||||
DNS_OPT_T_TCP_KEEPALIVE = 11,
|
||||
DNS_OPT_T_ALL = 255
|
||||
} dns_opt_code_t;
|
||||
@@ -112,11 +119,15 @@ struct dns_head {
|
||||
unsigned short nrcount; /* number of addititional resource entries */
|
||||
} __attribute__((packed, aligned(2)));
|
||||
|
||||
struct dns_rrs {
|
||||
unsigned short next;
|
||||
unsigned short len;
|
||||
dns_type_t type;
|
||||
unsigned char data[0];
|
||||
#define DNS_PACKET_DICT_SIZE 16
|
||||
struct dns_packet_dict_item {
|
||||
unsigned short pos;
|
||||
unsigned int hash;
|
||||
};
|
||||
|
||||
struct dns_packet_dict {
|
||||
short dict_count;
|
||||
struct dns_packet_dict_item names[DNS_PACKET_DICT_SIZE];
|
||||
};
|
||||
|
||||
/* packet haed */
|
||||
@@ -129,23 +140,26 @@ struct dns_packet {
|
||||
unsigned short optcount;
|
||||
unsigned short optional;
|
||||
unsigned short payloadsize;
|
||||
struct dns_packet_dict namedict;
|
||||
int size;
|
||||
int len;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
/* RRS encode/decode context */
|
||||
struct dns_data_context {
|
||||
unsigned char *data;
|
||||
unsigned char *ptr;
|
||||
unsigned int maxsize;
|
||||
struct dns_rrs {
|
||||
struct dns_packet *packet;
|
||||
unsigned short next;
|
||||
unsigned short len;
|
||||
int type;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
/* packet encode/decode context */
|
||||
struct dns_context {
|
||||
struct dns_packet *packet;
|
||||
struct dns_packet_dict *namedict;
|
||||
unsigned char *data;
|
||||
unsigned int maxsize;
|
||||
int maxsize;
|
||||
unsigned char *ptr;
|
||||
};
|
||||
|
||||
@@ -169,6 +183,13 @@ struct dns_opt_ecs {
|
||||
unsigned char source_prefix;
|
||||
unsigned char scope_prefix;
|
||||
unsigned char addr[DNS_RR_AAAA_LEN];
|
||||
} __attribute__((packed));;
|
||||
|
||||
/* OPT COOLIE */
|
||||
struct dns_opt_cookie {
|
||||
char server_cookie_len;
|
||||
unsigned char client_cookie[8];
|
||||
unsigned char server_cookie[32];
|
||||
};
|
||||
|
||||
/* OPT */
|
||||
@@ -184,29 +205,29 @@ struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, i
|
||||
/*
|
||||
* Question
|
||||
*/
|
||||
int dns_add_domain(struct dns_packet *packet, char *domain, int qtype, int qclass);
|
||||
int dns_add_domain(struct dns_packet *packet, const char *domain, int qtype, int qclass);
|
||||
int dns_get_domain(struct dns_rrs *rrs, char *domain, int maxsize, int *qtype, int *qclass);
|
||||
|
||||
/*
|
||||
* Answers
|
||||
*/
|
||||
int dns_add_CNAME(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname);
|
||||
int dns_add_CNAME(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname);
|
||||
int dns_get_CNAME(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size);
|
||||
|
||||
int dns_add_A(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, unsigned char addr[DNS_RR_A_LEN]);
|
||||
int dns_add_A(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, unsigned char addr[DNS_RR_A_LEN]);
|
||||
int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[DNS_RR_A_LEN]);
|
||||
|
||||
int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname);
|
||||
int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, char *cname);
|
||||
int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size);
|
||||
|
||||
int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl,
|
||||
int dns_add_AAAA(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl,
|
||||
unsigned char addr[DNS_RR_AAAA_LEN]);
|
||||
int dns_get_AAAA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned char addr[DNS_RR_AAAA_LEN]);
|
||||
|
||||
int dns_add_SOA(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, struct dns_soa *soa);
|
||||
int dns_add_SOA(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, struct dns_soa *soa);
|
||||
int dns_get_SOA(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct dns_soa *soa);
|
||||
|
||||
int dns_add_NS(struct dns_packet *packet, dns_rr_type type, char *domain, int ttl, char *cname);
|
||||
int dns_add_NS(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname);
|
||||
int dns_get_NS(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size);
|
||||
|
||||
int dns_set_OPT_payload_size(struct dns_packet *packet, int payload_size);
|
||||
@@ -226,4 +247,12 @@ int dns_encode(unsigned char *data, int size, struct dns_packet *packet);
|
||||
|
||||
int dns_packet_init(struct dns_packet *packet, int size, struct dns_head *head);
|
||||
|
||||
struct dns_update_param {
|
||||
int id;
|
||||
int ip_ttl;
|
||||
int cname_ttl;
|
||||
};
|
||||
|
||||
int dns_packet_update(unsigned char *data, int size, struct dns_update_param *param);
|
||||
|
||||
#endif
|
||||
|
||||
239
src/dns_cache.c
239
src/dns_cache.c
@@ -128,9 +128,14 @@ enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data)
|
||||
return cache_data->head.cache_type;
|
||||
}
|
||||
|
||||
uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data)
|
||||
uint32_t dns_cache_get_query_flag(struct dns_cache_data *cache_data)
|
||||
{
|
||||
return cache_data->head.cache_flag;
|
||||
return cache_data->head.query_flag;
|
||||
}
|
||||
|
||||
const char *dns_cache_get_dns_group_name(struct dns_cache_data *cache_data)
|
||||
{
|
||||
return cache_data->head.dns_group_name;
|
||||
}
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data)
|
||||
@@ -156,12 +161,18 @@ struct dns_cache_data *dns_cache_new_data(void)
|
||||
return (struct dns_cache_data *)cache_addr;
|
||||
}
|
||||
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl)
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
dns_cache->head.is_soa = 1;
|
||||
if (dns_cache->head.cache_type == CACHE_TYPE_PACKET) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache;
|
||||
if (cache_addr == NULL) {
|
||||
goto errout;
|
||||
@@ -174,7 +185,13 @@ void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag
|
||||
cache_addr->addr_data.cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
cache_addr->head.cache_flag = cache_flag;
|
||||
if (query_option) {
|
||||
cache_addr->head.query_flag = query_option->query_flag;
|
||||
if (query_option->dns_group_name) {
|
||||
safe_strncpy(cache_addr->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
cache_addr->addr_data.soa = 1;
|
||||
cache_addr->head.cache_type = CACHE_TYPE_ADDR;
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
@@ -182,8 +199,8 @@ errout:
|
||||
return;
|
||||
}
|
||||
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl,
|
||||
unsigned char *addr, int addr_len)
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl, unsigned char *addr, int addr_len)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
goto errout;
|
||||
@@ -207,14 +224,21 @@ void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_fl
|
||||
cache_addr->addr_data.cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
cache_addr->head.cache_flag = cache_flag;
|
||||
if (query_option) {
|
||||
cache_addr->head.query_flag = query_option->query_flag;
|
||||
if (query_option->dns_group_name) {
|
||||
safe_strncpy(cache_addr->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
cache_addr->head.cache_type = CACHE_TYPE_ADDR;
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
errout:
|
||||
return;
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len)
|
||||
struct dns_cache_data *dns_cache_new_data_packet(struct dns_cache_query_option *query_option, void *packet,
|
||||
size_t packet_len)
|
||||
{
|
||||
struct dns_cache_packet *cache_packet = NULL;
|
||||
size_t data_size = 0;
|
||||
@@ -229,15 +253,22 @@ struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *pack
|
||||
}
|
||||
|
||||
memcpy(cache_packet->data, packet, packet_len);
|
||||
memset(&cache_packet->head, 0, sizeof(cache_packet->head));
|
||||
|
||||
cache_packet->head.cache_flag = cache_flag;
|
||||
if (query_option) {
|
||||
cache_packet->head.query_flag = query_option->query_flag;
|
||||
if (query_option->dns_group_name) {
|
||||
strncpy(cache_packet->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN - 1);
|
||||
}
|
||||
}
|
||||
cache_packet->head.cache_type = CACHE_TYPE_PACKET;
|
||||
cache_packet->head.size = packet_len;
|
||||
|
||||
return (struct dns_cache_data *)cache_packet;
|
||||
}
|
||||
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
static int _dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, int inactive,
|
||||
struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache_data *old_cache_data = NULL;
|
||||
@@ -263,11 +294,19 @@ int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
dns_cache->info.qtype = qtype;
|
||||
dns_cache->info.ttl = ttl;
|
||||
dns_cache->info.speed = speed;
|
||||
time(&dns_cache->info.insert_time);
|
||||
old_cache_data = dns_cache->cache_data;
|
||||
dns_cache->cache_data = cache_data;
|
||||
list_del_init(&dns_cache->list);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
|
||||
if (inactive == 0) {
|
||||
time(&dns_cache->info.insert_time);
|
||||
time(&dns_cache->info.replace_time);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
} else {
|
||||
time(&dns_cache->info.replace_time);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
dns_cache_data_free(old_cache_data);
|
||||
@@ -275,18 +314,48 @@ int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data *cache_data, struct list_head *head)
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
return _dns_cache_replace(domain, ttl, qtype, speed, 0, cache_data);
|
||||
}
|
||||
|
||||
int dns_cache_replace_inactive(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
return _dns_cache_replace(domain, ttl, qtype, speed, 1, cache_data);
|
||||
}
|
||||
|
||||
static void _dns_cache_remove_by_domain(const char *domain, dns_type_t qtype)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
key = hash_string(domain);
|
||||
key = jhash(&qtype, sizeof(qtype), key);
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_for_each_possible(dns_cache_head.cache_hash, dns_cache, node, key)
|
||||
{
|
||||
if (dns_cache->info.qtype != qtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(domain, dns_cache->info.domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
_dns_cache_remove(dns_cache);
|
||||
break;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
}
|
||||
|
||||
static int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data *cache_data, struct list_head *head)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
/* if cache already exists, free */
|
||||
dns_cache = dns_cache_lookup(info->domain, info->qtype);
|
||||
if (dns_cache) {
|
||||
dns_cache_delete(dns_cache);
|
||||
dns_cache_release(dns_cache);
|
||||
dns_cache = NULL;
|
||||
}
|
||||
_dns_cache_remove_by_domain(info->domain, info->qtype);
|
||||
|
||||
dns_cache = malloc(sizeof(*dns_cache));
|
||||
if (dns_cache == NULL) {
|
||||
@@ -307,7 +376,7 @@ int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data *cache_
|
||||
|
||||
/* Release extra cache, remove oldest cache record */
|
||||
if (atomic_inc_return(&dns_cache_head.num) > dns_cache_head.size) {
|
||||
struct dns_cache *del_cache;
|
||||
struct dns_cache *del_cache = NULL;
|
||||
del_cache = _dns_inactive_cache_first();
|
||||
if (del_cache) {
|
||||
_dns_cache_remove(del_cache);
|
||||
@@ -348,6 +417,7 @@ int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
info.hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
||||
info.speed = speed;
|
||||
time(&info.insert_time);
|
||||
time(&info.replace_time);
|
||||
|
||||
return _dns_cache_insert(&info, cache_data, &dns_cache_head.cache_list);
|
||||
}
|
||||
@@ -357,7 +427,7 @@ struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
uint32_t key = 0;
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *dns_cache_ret = NULL;
|
||||
time_t now;
|
||||
time_t now = 0;
|
||||
|
||||
if (dns_cache_head.size <= 0) {
|
||||
return NULL;
|
||||
@@ -400,7 +470,7 @@ struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
|
||||
int dns_cache_get_ttl(struct dns_cache *dns_cache)
|
||||
{
|
||||
time_t now;
|
||||
time_t now = 0;
|
||||
int ttl = 0;
|
||||
time(&now);
|
||||
|
||||
@@ -412,15 +482,45 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache)
|
||||
return ttl;
|
||||
}
|
||||
|
||||
int dns_cache_is_soa(struct dns_cache *dns_cache) {
|
||||
int dns_cache_get_cname_ttl(struct dns_cache *dns_cache)
|
||||
{
|
||||
time_t now = 0;
|
||||
int ttl = 0;
|
||||
time(&now);
|
||||
|
||||
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache_get_data(dns_cache);
|
||||
|
||||
if (cache_addr->head.cache_type != CACHE_TYPE_ADDR) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ttl = dns_cache->info.insert_time + cache_addr->addr_data.cname_ttl - now;
|
||||
if (ttl < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addr_ttl = dns_cache_get_ttl(dns_cache);
|
||||
if (ttl < addr_ttl && ttl < 0) {
|
||||
return addr_ttl;
|
||||
}
|
||||
|
||||
if (ttl < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ttl;
|
||||
}
|
||||
|
||||
int dns_cache_is_soa(struct dns_cache *dns_cache)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache_get_data(dns_cache);
|
||||
if (cache_addr->head.cache_type == CACHE_TYPE_ADDR && cache_addr->addr_data.soa) {
|
||||
if (dns_cache->cache_data->head.is_soa) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -466,12 +566,16 @@ void dns_cache_update(struct dns_cache *dns_cache)
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
}
|
||||
|
||||
void _dns_cache_remove_expired_ttl(time_t *now)
|
||||
static void _dns_cache_remove_expired_ttl(dns_cache_callback inactive_precallback, int ttl_inactive_pre,
|
||||
unsigned int max_callback_num, const time_t *now)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *tmp;
|
||||
struct dns_cache *tmp = NULL;
|
||||
unsigned int callback_num = 0;
|
||||
int ttl = 0;
|
||||
LIST_HEAD(checklist);
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.inactive_list, list)
|
||||
{
|
||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - *now;
|
||||
@@ -479,21 +583,55 @@ void _dns_cache_remove_expired_ttl(time_t *now)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dns_cache_head.inactive_list_expired + ttl > 0) {
|
||||
if (dns_cache_head.inactive_list_expired + ttl < 0) {
|
||||
_dns_cache_remove(dns_cache);
|
||||
continue;
|
||||
}
|
||||
|
||||
_dns_cache_remove(dns_cache);
|
||||
ttl = *now - dns_cache->info.replace_time;
|
||||
if (ttl < ttl_inactive_pre || inactive_precallback == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (callback_num >= max_callback_num) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dns_cache->del_pending == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the TTL time is in the pre-timeout range, call callback function */
|
||||
dns_cache_get(dns_cache);
|
||||
list_add_tail(&dns_cache->check_list, &checklist);
|
||||
dns_cache->del_pending = 1;
|
||||
callback_num++;
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
list_for_each_entry_safe(dns_cache, tmp, &checklist, check_list)
|
||||
{
|
||||
/* run inactive_precallback */
|
||||
if (inactive_precallback) {
|
||||
inactive_precallback(dns_cache);
|
||||
}
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
}
|
||||
|
||||
void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
void dns_cache_invalidate(dns_cache_callback precallback, int ttl_pre, unsigned int max_callback_num,
|
||||
dns_cache_callback inactive_precallback, int ttl_inactive_pre)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *tmp;
|
||||
time_t now;
|
||||
struct dns_cache *tmp = NULL;
|
||||
time_t now = 0;
|
||||
int ttl = 0;
|
||||
LIST_HEAD(checklist);
|
||||
unsigned int callback_num = 0;
|
||||
|
||||
if (max_callback_num <= 0) {
|
||||
max_callback_num = -1;
|
||||
}
|
||||
|
||||
if (dns_cache_head.size <= 0) {
|
||||
return;
|
||||
@@ -506,35 +644,36 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - now;
|
||||
if (ttl > 0 && ttl < ttl_pre) {
|
||||
/* If the TTL time is in the pre-timeout range, call callback function */
|
||||
if (callback && dns_cache->del_pending == 0) {
|
||||
if (precallback && dns_cache->del_pending == 0 && callback_num < max_callback_num) {
|
||||
list_add_tail(&dns_cache->check_list, &checklist);
|
||||
dns_cache_get(dns_cache);
|
||||
dns_cache->del_pending = 1;
|
||||
callback_num++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (ttl < 0) {
|
||||
if (dns_cache_head.enable_inactive && (dns_cache_is_soa(dns_cache) == 0)) {
|
||||
if (dns_cache_head.enable_inactive) {
|
||||
_dns_cache_move_inactive(dns_cache);
|
||||
} else {
|
||||
_dns_cache_remove(dns_cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
if (dns_cache_head.enable_inactive && dns_cache_head.inactive_list_expired != 0) {
|
||||
_dns_cache_remove_expired_ttl(&now);
|
||||
_dns_cache_remove_expired_ttl(inactive_precallback, ttl_inactive_pre, max_callback_num, &now);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
list_for_each_entry_safe(dns_cache, tmp, &checklist, check_list)
|
||||
{
|
||||
/* run callback */
|
||||
if (callback) {
|
||||
callback(dns_cache);
|
||||
if (precallback) {
|
||||
precallback(dns_cache);
|
||||
}
|
||||
list_del(&dns_cache->check_list);
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
}
|
||||
@@ -542,8 +681,8 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
static int _dns_cache_read_record(int fd, uint32_t cache_number)
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
unsigned int i = 0;
|
||||
ssize_t ret = 0;
|
||||
struct dns_cache_record cache_record;
|
||||
struct dns_cache_data_head data_head;
|
||||
struct dns_cache_data *cache_data = NULL;
|
||||
@@ -611,12 +750,18 @@ errout:
|
||||
int dns_cache_load(const char *file)
|
||||
{
|
||||
int fd = -1;
|
||||
int ret = 0;
|
||||
ssize_t ret = 0;
|
||||
off_t filesize = 0;
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
filesize = lseek(fd, 0, SEEK_END);
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
posix_fadvise(fd, 0, filesize, POSIX_FADV_WILLNEED | POSIX_FADV_SEQUENTIAL);
|
||||
|
||||
struct dns_cache_file cache_file;
|
||||
ret = read(fd, &cache_file, sizeof(cache_file));
|
||||
if (ret != sizeof(cache_file)) {
|
||||
@@ -629,11 +774,12 @@ int dns_cache_load(const char *file)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (strncmp(cache_file.version, __TIMESTAMP__, DNS_CACHE_VERSION_LEN) != 0) {
|
||||
if (strncmp(cache_file.version, __TIMESTAMP__, DNS_CACHE_VERSION_LEN - 1) != 0) {
|
||||
tlog(TLOG_WARN, "cache version is different, skip load cache.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_INFO, "load cache file %s, total %d records", file, cache_file.cache_number);
|
||||
if (_dns_cache_read_record(fd, cache_file.cache_number) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
@@ -660,7 +806,7 @@ static int _dns_cache_write_record(int fd, uint32_t *cache_number, enum CACHE_RE
|
||||
cache_record.magic = MAGIC_CACHE_DATA;
|
||||
cache_record.type = type;
|
||||
memcpy(&cache_record.info, &dns_cache->info, sizeof(struct dns_cache_info));
|
||||
int ret = write(fd, &cache_record, sizeof(cache_record));
|
||||
ssize_t ret = write(fd, &cache_record, sizeof(cache_record));
|
||||
if (ret != sizeof(cache_record)) {
|
||||
tlog(TLOG_ERROR, "write cache failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
@@ -668,7 +814,7 @@ static int _dns_cache_write_record(int fd, uint32_t *cache_number, enum CACHE_RE
|
||||
|
||||
struct dns_cache_data *cache_data = dns_cache->cache_data;
|
||||
ret = write(fd, cache_data, sizeof(*cache_data) + cache_data->head.size);
|
||||
if (ret != sizeof(*cache_data) + cache_data->head.size) {
|
||||
if (ret != (int)sizeof(*cache_data) + cache_data->head.size) {
|
||||
tlog(TLOG_ERROR, "write cache data failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
@@ -752,7 +898,8 @@ errout:
|
||||
void dns_cache_destroy(void)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *tmp;
|
||||
struct dns_cache *tmp = NULL;
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.inactive_list, list)
|
||||
{
|
||||
|
||||
@@ -31,8 +31,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DNS_CACHE_TTL_MIN 30
|
||||
#define DNS_CACHE_TTL_MIN 1
|
||||
#define DNS_CACHE_VERSION_LEN 32
|
||||
#define DNS_CACHE_GROUP_NAME_LEN 32
|
||||
#define MAGIC_NUMBER 0x6548634163536e44
|
||||
#define MAGIC_CACHE_DATA 0x44615461
|
||||
|
||||
@@ -47,10 +48,17 @@ enum CACHE_RECORD_TYPE {
|
||||
CACHE_RECORD_TYPE_INACTIVE,
|
||||
};
|
||||
|
||||
struct dns_cache_query_option {
|
||||
uint32_t query_flag;
|
||||
const char *dns_group_name;
|
||||
};
|
||||
|
||||
struct dns_cache_data_head {
|
||||
uint32_t cache_flag;
|
||||
enum CACHE_TYPE cache_type;
|
||||
size_t size;
|
||||
uint32_t query_flag;
|
||||
char dns_group_name[DNS_CACHE_GROUP_NAME_LEN];
|
||||
int is_soa;
|
||||
ssize_t size;
|
||||
};
|
||||
|
||||
struct dns_cache_data {
|
||||
@@ -84,6 +92,7 @@ struct dns_cache_info {
|
||||
int speed;
|
||||
int hitnum_update_add;
|
||||
time_t insert_time;
|
||||
time_t replace_time;
|
||||
dns_type_t qtype;
|
||||
};
|
||||
|
||||
@@ -113,16 +122,21 @@ struct dns_cache_file {
|
||||
|
||||
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data);
|
||||
|
||||
uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data);
|
||||
uint32_t dns_cache_get_query_flag(struct dns_cache_data *cache_data);
|
||||
|
||||
const char *dns_cache_get_dns_group_name(struct dns_cache_data *cache_data);
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data);
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len);
|
||||
struct dns_cache_data *dns_cache_new_data_packet(struct dns_cache_query_option *query_option, void *packet,
|
||||
size_t packet_len);
|
||||
|
||||
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
|
||||
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
int dns_cache_replace_inactive(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype);
|
||||
@@ -137,22 +151,26 @@ int dns_cache_hitnum_dec_get(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_update(struct dns_cache *dns_cache);
|
||||
|
||||
typedef void dns_cache_preinvalid_callback(struct dns_cache *dns_cache);
|
||||
typedef void dns_cache_callback(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre);
|
||||
void dns_cache_invalidate(dns_cache_callback precallback, int ttl_pre, unsigned int max_callback_num,
|
||||
dns_cache_callback inactive_precallback, int ttl_inactive_pre);
|
||||
|
||||
int dns_cache_get_ttl(struct dns_cache *dns_cache);
|
||||
|
||||
int dns_cache_get_cname_ttl(struct dns_cache *dns_cache);
|
||||
|
||||
int dns_cache_is_soa(struct dns_cache *dns_cache);
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data(void);
|
||||
|
||||
struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl,
|
||||
unsigned char *addr, int addr_len);
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl, unsigned char *addr, int addr_len);
|
||||
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl);
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl);
|
||||
|
||||
void dns_cache_destroy(void);
|
||||
|
||||
|
||||
587
src/dns_client.c
587
src/dns_client.c
File diff suppressed because it is too large
Load Diff
@@ -47,17 +47,41 @@ typedef enum dns_result_type {
|
||||
#define DNSSERVER_FLAG_CHECK_EDNS (0x1 << 2)
|
||||
#define DNSSERVER_FLAG_CHECK_TTL (0x1 << 3)
|
||||
|
||||
#define DNS_QUEY_OPTION_ECS_DNS (1 << 0)
|
||||
#define DNS_QUEY_OPTION_ECS_IP (1 << 1)
|
||||
|
||||
int dns_client_init(void);
|
||||
|
||||
int dns_client_set_ecs(char *ip, int subnet);
|
||||
|
||||
struct dns_server_info;
|
||||
/* query result notify function */
|
||||
typedef int (*dns_client_callback)(char *domain, dns_result_type rtype, unsigned int result_flag,
|
||||
typedef int (*dns_client_callback)(const char *domain, dns_result_type rtype, struct dns_server_info *server_info,
|
||||
struct dns_packet *packet, unsigned char *inpacket, int inpacket_len,
|
||||
void *user_ptr);
|
||||
|
||||
unsigned int dns_client_server_result_flag(struct dns_server_info *server_info);
|
||||
|
||||
const char *dns_client_get_server_ip(struct dns_server_info *server_info);
|
||||
|
||||
int dns_client_get_server_port(struct dns_server_info *server_info);
|
||||
|
||||
dns_server_type_t dns_client_get_server_type(struct dns_server_info *server_info);
|
||||
|
||||
struct dns_query_ecs_ip {
|
||||
char ip[DNS_MAX_CNAME_LEN];
|
||||
int subnet;
|
||||
};
|
||||
|
||||
struct dns_query_options {
|
||||
unsigned long long enable_flag;
|
||||
struct dns_opt_ecs ecs_dns;
|
||||
struct dns_query_ecs_ip ecs_ip;
|
||||
};
|
||||
|
||||
/* query domain */
|
||||
int dns_client_query(char *domain, int qtype, dns_client_callback callback, void *user_ptr, const char *group_name);
|
||||
int dns_client_query(const char *domain, int qtype, dns_client_callback callback, void *user_ptr, const char *group_name,
|
||||
struct dns_query_options *options);
|
||||
|
||||
void dns_client_exit(void);
|
||||
|
||||
@@ -104,13 +128,13 @@ int dns_client_add_server(char *server_ip, int port, dns_server_type_t server_ty
|
||||
/* remove remote dns server */
|
||||
int dns_client_remove_server(char *server_ip, int port, dns_server_type_t server_type);
|
||||
|
||||
int dns_client_add_group(char *group_name);
|
||||
int dns_client_add_group(const char *group_name);
|
||||
|
||||
int dns_client_add_to_group(char *group_name, char *server_ip, int port, dns_server_type_t server_type);
|
||||
int dns_client_add_to_group(const char *group_name, char *server_ip, int port, dns_server_type_t server_type);
|
||||
|
||||
int dns_client_remove_from_group(char *group_name, char *server_ip, int port, dns_server_type_t server_type);
|
||||
int dns_client_remove_from_group(const char *group_name, char *server_ip, int port, dns_server_type_t server_type);
|
||||
|
||||
int dns_client_remove_group(char *group_name);
|
||||
int dns_client_remove_group(const char *group_name);
|
||||
|
||||
int dns_server_num(void);
|
||||
|
||||
|
||||
650
src/dns_conf.c
650
src/dns_conf.c
@@ -21,6 +21,7 @@
|
||||
#include "rbtree.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
@@ -30,6 +31,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#define DEFAULT_DNS_CACHE_SIZE 512
|
||||
#define DNS_MAX_REPLY_IP_NUM 8
|
||||
|
||||
/* ipset */
|
||||
struct dns_ipset_table {
|
||||
@@ -37,31 +39,56 @@ struct dns_ipset_table {
|
||||
};
|
||||
static struct dns_ipset_table dns_ipset_table;
|
||||
|
||||
struct dns_qtype_soa_table dns_qtype_soa_table;
|
||||
|
||||
/* dns groups */
|
||||
struct dns_group_table dns_group_table;
|
||||
|
||||
struct dns_ptr_table dns_ptr_table;
|
||||
|
||||
static char dns_conf_dnsmasq_lease_file[DNS_MAX_PATH];
|
||||
static time_t dns_conf_dnsmasq_lease_file_time;
|
||||
|
||||
struct dns_hosts_table dns_hosts_table;
|
||||
int dns_hosts_record_num;
|
||||
|
||||
/* server ip/port */
|
||||
struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP];
|
||||
int dns_conf_bind_ip_num = 0;
|
||||
int dns_conf_tcp_idle_time = 120;
|
||||
|
||||
int dns_conf_max_reply_ip_num = DNS_MAX_REPLY_IP_NUM;
|
||||
|
||||
static struct config_enum_list dns_conf_response_mode_enum[] = {
|
||||
{"first-ping", DNS_RESPONSE_MODE_FIRST_PING_IP},
|
||||
{"fastest-ip", DNS_RESPONSE_MODE_FASTEST_IP},
|
||||
{"fastest-response", DNS_RESPONSE_MODE_FASTEST_RESPONSE},
|
||||
{0, 0}};
|
||||
|
||||
enum response_mode_type dns_conf_response_mode;
|
||||
|
||||
/* cache */
|
||||
int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
|
||||
int dns_conf_prefetch = 0;
|
||||
int dns_conf_serve_expired = 0;
|
||||
int dns_conf_serve_expired_ttl = 0;
|
||||
int dns_conf_serve_expired_reply_ttl = 5;
|
||||
int dns_conf_serve_expired = 1;
|
||||
int dns_conf_serve_expired_ttl = 24 * 3600; /* 1 day */
|
||||
int dns_conf_serve_expired_prefetch_time;
|
||||
int dns_conf_serve_expired_reply_ttl = 3;
|
||||
|
||||
/* upstream servers */
|
||||
struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
char dns_conf_server_name[DNS_MAX_SERVER_NAME_LEN];
|
||||
int dns_conf_server_num;
|
||||
|
||||
struct dns_domain_check_order dns_conf_check_order = {
|
||||
.order = {DOMAIN_CHECK_ICMP, DOMAIN_CHECK_TCP},
|
||||
.tcp_port = 80,
|
||||
struct dns_domain_check_orders dns_conf_check_orders = {
|
||||
.orders =
|
||||
{
|
||||
{.type = DOMAIN_CHECK_ICMP, .tcp_port = 0},
|
||||
{.type = DOMAIN_CHECK_TCP, .tcp_port = 80},
|
||||
{.type = DOMAIN_CHECK_TCP, .tcp_port = 443},
|
||||
},
|
||||
};
|
||||
int dns_has_cap_ping = 0;
|
||||
static int dns_has_cap_ping = 0;
|
||||
|
||||
/* logging */
|
||||
int dns_conf_log_level = TLOG_ERROR;
|
||||
@@ -88,17 +115,25 @@ art_tree dns_conf_domain_rule;
|
||||
struct dns_conf_address_rule dns_conf_address_rule;
|
||||
|
||||
/* dual-stack selection */
|
||||
int dns_conf_dualstack_ip_selection;
|
||||
int dns_conf_dualstack_ip_selection_threshold = 30;
|
||||
int dns_conf_dualstack_ip_selection = 1;
|
||||
int dns_conf_dualstack_ip_allow_force_AAAA;
|
||||
int dns_conf_dualstack_ip_selection_threshold = 15;
|
||||
|
||||
/* TTL */
|
||||
int dns_conf_rr_ttl;
|
||||
int dns_conf_rr_ttl_min;
|
||||
int dns_conf_rr_ttl_reply_max;
|
||||
int dns_conf_rr_ttl_min = 600;
|
||||
int dns_conf_rr_ttl_max;
|
||||
int dns_conf_local_ttl;
|
||||
int dns_conf_force_AAAA_SOA;
|
||||
|
||||
int dns_conf_force_no_cname;
|
||||
int dns_conf_ipset_timeout_enable;
|
||||
|
||||
char dns_conf_user[DNS_CONF_USRNAME_LEN];
|
||||
|
||||
int dns_save_fail_packet;
|
||||
char dns_save_fail_packet_dir[DNS_MAX_PATH];
|
||||
|
||||
/* ECS */
|
||||
struct dns_edns_client_subnet dns_conf_ipv4_ecs;
|
||||
struct dns_edns_client_subnet dns_conf_ipv6_ecs;
|
||||
@@ -226,7 +261,7 @@ static void _config_group_table_destroy(void)
|
||||
{
|
||||
struct dns_server_groups *group = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
int i;
|
||||
unsigned long i = 0;
|
||||
|
||||
hash_for_each_safe(dns_group_table.group, i, tmp, group, node)
|
||||
{
|
||||
@@ -238,7 +273,7 @@ static void _config_group_table_destroy(void)
|
||||
static int _config_server(int argc, char *argv[], dns_server_type_t type, int default_port)
|
||||
{
|
||||
int index = dns_conf_server_num;
|
||||
struct dns_servers *server;
|
||||
struct dns_servers *server = NULL;
|
||||
int port = -1;
|
||||
char *ip = NULL;
|
||||
int opt = 0;
|
||||
@@ -432,7 +467,7 @@ static int _config_domain_rule_add(char *domain, enum domain_rule type, void *ru
|
||||
|
||||
/* Reverse string, for suffix match */
|
||||
len = strlen(domain);
|
||||
if (len >= sizeof(domain_key)) {
|
||||
if (len >= (int)sizeof(domain_key)) {
|
||||
tlog(TLOG_ERROR, "domain name %s too long", domain);
|
||||
goto errout;
|
||||
}
|
||||
@@ -493,7 +528,7 @@ static int _config_domain_rule_flag_set(char *domain, unsigned int flag, unsigne
|
||||
int len = 0;
|
||||
|
||||
len = strlen(domain);
|
||||
if (len >= sizeof(domain_key)) {
|
||||
if (len >= (int)sizeof(domain_key)) {
|
||||
tlog(TLOG_ERROR, "domain %s too long", domain);
|
||||
return -1;
|
||||
}
|
||||
@@ -551,7 +586,7 @@ static void _config_ipset_table_destroy(void)
|
||||
{
|
||||
struct dns_ipset_name *ipset_name = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
int i;
|
||||
unsigned long i = 0;
|
||||
|
||||
hash_for_each_safe(dns_ipset_table.ipset, i, tmp, ipset_name, node)
|
||||
{
|
||||
@@ -596,8 +631,8 @@ static int _conf_domain_rule_ipset(char *domain, const char *ipsetname)
|
||||
struct dns_ipset_rule *ipset_rule = NULL;
|
||||
const char *ipset = NULL;
|
||||
char *copied_name = NULL;
|
||||
enum domain_rule type;
|
||||
int ignore_flag;
|
||||
enum domain_rule type = 0;
|
||||
int ignore_flag = 0;
|
||||
|
||||
copied_name = strdup(ipsetname);
|
||||
|
||||
@@ -607,10 +642,10 @@ static int _conf_domain_rule_ipset(char *domain, const char *ipsetname)
|
||||
|
||||
for (char *tok = strtok(copied_name, ","); tok; tok = strtok(NULL, ",")) {
|
||||
if (tok[0] == '#') {
|
||||
if (strncmp(tok, "#6:", 3u) == 0) {
|
||||
if (strncmp(tok, "#6:", 3U) == 0) {
|
||||
type = DOMAIN_RULE_IPSET_IPV6;
|
||||
ignore_flag = DOMAIN_FLAG_IPSET_IPV6_IGN;
|
||||
} else if (strncmp(tok, "#4:", 3u) == 0) {
|
||||
} else if (strncmp(tok, "#4:", 3U) == 0) {
|
||||
type = DOMAIN_RULE_IPSET_IPV4;
|
||||
ignore_flag = DOMAIN_FLAG_IPSET_IPV4_IGN;
|
||||
} else {
|
||||
@@ -687,7 +722,7 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
|
||||
struct dns_address_IPV6 *address_ipv6 = NULL;
|
||||
void *address = NULL;
|
||||
char ip[MAX_IP_LEN];
|
||||
int port;
|
||||
int port = 0;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
enum domain_rule type = 0;
|
||||
@@ -739,7 +774,7 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
|
||||
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr_in;
|
||||
struct sockaddr_in *addr_in = NULL;
|
||||
address_ipv4 = malloc(sizeof(*address_ipv4));
|
||||
if (address_ipv4 == NULL) {
|
||||
goto errout;
|
||||
@@ -751,7 +786,7 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
|
||||
address = address_ipv4;
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6;
|
||||
struct sockaddr_in6 *addr_in6 = NULL;
|
||||
addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
address_ipv4 = malloc(sizeof(*address_ipv4));
|
||||
@@ -810,17 +845,17 @@ errout:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _config_speed_check_mode_parser(struct dns_domain_check_order *check_order, const char *mode)
|
||||
static int _config_speed_check_mode_parser(struct dns_domain_check_orders *check_orders, const char *mode)
|
||||
{
|
||||
char tmpbuff[DNS_MAX_OPT_LEN];
|
||||
char *field;
|
||||
char *ptr;
|
||||
char *field = NULL;
|
||||
char *ptr = NULL;
|
||||
int order = 0;
|
||||
int port = 80;
|
||||
int i = 0;
|
||||
|
||||
safe_strncpy(tmpbuff, mode, DNS_MAX_OPT_LEN);
|
||||
memset(check_order, 0, sizeof(*check_order));
|
||||
memset(check_orders, 0, sizeof(*check_orders));
|
||||
|
||||
ptr = tmpbuff;
|
||||
do {
|
||||
@@ -841,7 +876,8 @@ static int _config_speed_check_mode_parser(struct dns_domain_check_order *check_
|
||||
}
|
||||
continue;
|
||||
}
|
||||
check_order->order[order] = DOMAIN_CHECK_ICMP;
|
||||
check_orders->orders[order].type = DOMAIN_CHECK_ICMP;
|
||||
check_orders->orders[order].tcp_port = 0;
|
||||
} else if (strstr(field, "tcp") == field) {
|
||||
char *port_str = strstr(field, ":");
|
||||
if (port_str) {
|
||||
@@ -851,12 +887,12 @@ static int _config_speed_check_mode_parser(struct dns_domain_check_order *check_
|
||||
}
|
||||
}
|
||||
|
||||
check_order->order[order] = DOMAIN_CHECK_TCP;
|
||||
check_order->tcp_port = port;
|
||||
check_orders->orders[order].type = DOMAIN_CHECK_TCP;
|
||||
check_orders->orders[order].tcp_port = port;
|
||||
} else if (strncmp(field, "none", sizeof("none")) == 0) {
|
||||
check_order->order[order] = DOMAIN_CHECK_NONE;
|
||||
for (i = order + 1; i < DOMAIN_CHECK_NUM; i++) {
|
||||
check_order->order[i] = DOMAIN_CHECK_NONE;
|
||||
for (i = order; i < DOMAIN_CHECK_NUM; i++) {
|
||||
check_orders->orders[i].type = DOMAIN_CHECK_NONE;
|
||||
check_orders->orders[i].tcp_port = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -880,18 +916,19 @@ static int _config_speed_check_mode(void *data, int argc, char *argv[])
|
||||
}
|
||||
|
||||
safe_strncpy(mode, argv[1], sizeof(mode));
|
||||
return _config_speed_check_mode_parser(&dns_conf_check_order, mode);
|
||||
return _config_speed_check_mode_parser(&dns_conf_check_orders, mode);
|
||||
}
|
||||
|
||||
static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
|
||||
{
|
||||
int index = dns_conf_bind_ip_num;
|
||||
struct dns_bind_ip *bind_ip;
|
||||
struct dns_bind_ip *bind_ip = NULL;
|
||||
char *ip = NULL;
|
||||
int opt = 0;
|
||||
char group_name[DNS_GROUP_NAME_LEN];
|
||||
const char *group = NULL;
|
||||
unsigned int server_flag = 0;
|
||||
int i = 0;
|
||||
|
||||
/* clang-format off */
|
||||
static struct option long_options[] = {
|
||||
@@ -919,6 +956,20 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < dns_conf_bind_ip_num; i++) {
|
||||
bind_ip = &dns_conf_bind_ip[i];
|
||||
if (bind_ip->type != type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(bind_ip->ip, ip, DNS_MAX_IPLEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tlog(TLOG_WARN, "Bind server %s, type %d, already configured, skip.", ip, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bind_ip = &dns_conf_bind_ip[index];
|
||||
bind_ip->type = type;
|
||||
bind_ip->flags = 0;
|
||||
@@ -983,7 +1034,7 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
|
||||
bind_ip->flags = server_flag;
|
||||
bind_ip->group = group;
|
||||
dns_conf_bind_ip_num++;
|
||||
tlog(TLOG_DEBUG, "bind ip %s, type:%d, flag: %X", ip, type, server_flag);
|
||||
tlog(TLOG_DEBUG, "bind ip %s, type: %d, flag: %X", ip, type, server_flag);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1105,8 +1156,8 @@ errout:
|
||||
|
||||
static radix_node_t *_create_addr_node(char *addr)
|
||||
{
|
||||
radix_node_t *node;
|
||||
void *p;
|
||||
radix_node_t *node = NULL;
|
||||
void *p = NULL;
|
||||
prefix_t prefix;
|
||||
const char *errmsg = NULL;
|
||||
radix_tree_t *tree = NULL;
|
||||
@@ -1171,6 +1222,47 @@ static int _config_iplist_rule(char *subnet, enum address_rule rule)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _config_qtype_soa(void *data, int argc, char *argv[])
|
||||
{
|
||||
struct dns_qtype_soa_list *soa_list = NULL;
|
||||
int i = 0;
|
||||
|
||||
if (argc <= 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
soa_list = malloc(sizeof(*soa_list));
|
||||
if (soa_list == NULL) {
|
||||
tlog(TLOG_ERROR, "cannot malloc memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(soa_list, 0, sizeof(*soa_list));
|
||||
soa_list->qtypeid = atol(argv[i]);
|
||||
if (soa_list->qtypeid == DNS_T_AAAA) {
|
||||
dns_conf_force_AAAA_SOA = 1;
|
||||
}
|
||||
uint32_t key = hash_32_generic(soa_list->qtypeid, 32);
|
||||
hash_add(dns_qtype_soa_table.qtype, &soa_list->node, key);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _config_qtype_soa_table_destroy(void)
|
||||
{
|
||||
struct dns_qtype_soa_list *soa_list = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
unsigned long i = 0;
|
||||
|
||||
hash_for_each_safe(dns_qtype_soa_table.qtype, i, tmp, soa_list, node)
|
||||
{
|
||||
hlist_del_init(&soa_list->node);
|
||||
free(soa_list);
|
||||
}
|
||||
}
|
||||
|
||||
static int _config_blacklist_ip(void *data, int argc, char *argv[])
|
||||
{
|
||||
if (argc <= 1) {
|
||||
@@ -1216,7 +1308,7 @@ static int _conf_edns_client_subnet(void *data, int argc, char *argv[])
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
|
||||
if (argc <= 1 || data == NULL) {
|
||||
if (argc <= 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1259,25 +1351,26 @@ errout:
|
||||
|
||||
static int _conf_domain_rule_speed_check(char *domain, const char *mode)
|
||||
{
|
||||
struct dns_domain_check_order *check_order;
|
||||
struct dns_domain_check_orders *check_orders = NULL;
|
||||
|
||||
check_order = malloc(sizeof(*check_order));
|
||||
if (check_order == NULL) {
|
||||
check_orders = malloc(sizeof(*check_orders) * DOMAIN_CHECK_NUM);
|
||||
if (check_orders == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
memset(check_orders, 0, sizeof(*check_orders));
|
||||
|
||||
if (_config_speed_check_mode_parser(check_orders, mode) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_config_speed_check_mode_parser(check_order, mode) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_config_domain_rule_add(domain, DOMAIN_RULE_CHECKSPEED, check_order) != 0) {
|
||||
if (_config_domain_rule_add(domain, DOMAIN_RULE_CHECKSPEED, check_orders) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (check_order) {
|
||||
free(check_order);
|
||||
if (check_orders) {
|
||||
free(check_orders);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1388,6 +1481,342 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct dns_ptr *_dns_conf_get_ptr(const char *ptr_domain)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_ptr *ptr = NULL;
|
||||
|
||||
key = hash_string(ptr_domain);
|
||||
hash_for_each_possible(dns_ptr_table.ptr, ptr, node, key)
|
||||
{
|
||||
if (strncmp(ptr->ptr_domain, ptr_domain, DNS_MAX_PTR_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ptr = malloc(sizeof(*ptr));
|
||||
if (ptr == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
safe_strncpy(ptr->ptr_domain, ptr_domain, DNS_MAX_PTR_LEN);
|
||||
hash_add(dns_ptr_table.ptr, &ptr->node, key);
|
||||
|
||||
return ptr;
|
||||
errout:
|
||||
if (ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _conf_ptr_add(const char *hostname, const char *ip)
|
||||
{
|
||||
struct dns_ptr *ptr = NULL;
|
||||
struct sockaddr_storage addr;
|
||||
unsigned char *paddr = NULL;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
char ptr_domain[DNS_MAX_PTR_LEN];
|
||||
|
||||
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 = NULL;
|
||||
addr_in = (struct sockaddr_in *)&addr;
|
||||
paddr = (unsigned char *)&(addr_in->sin_addr.s_addr);
|
||||
snprintf(ptr_domain, sizeof(ptr_domain), "%d.%d.%d.%d.in-addr.arpa", paddr[3], paddr[2], paddr[1], paddr[0]);
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6 = NULL;
|
||||
addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
paddr = addr_in6->sin6_addr.s6_addr + 12;
|
||||
snprintf(ptr_domain, sizeof(ptr_domain), "%d.%d.%d.%d.in-addr.arpa", paddr[3], paddr[2], paddr[1],
|
||||
paddr[0]);
|
||||
} else {
|
||||
paddr = addr_in6->sin6_addr.s6_addr;
|
||||
snprintf(ptr_domain, sizeof(ptr_domain),
|
||||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||||
"%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
|
||||
"%x.ip6.arpa",
|
||||
paddr[15] & 0xF, (paddr[15] >> 4) & 0xF, paddr[14] & 0xF, (paddr[14] >> 4) & 0xF, paddr[13] & 0xF,
|
||||
(paddr[13] >> 4) & 0xF, paddr[12] & 0xF, (paddr[12] >> 4) & 0xF, paddr[11] & 0xF,
|
||||
(paddr[11] >> 4) & 0xF, paddr[10] & 0xF, (paddr[10] >> 4) & 0xF, paddr[9] & 0xF,
|
||||
(paddr[9] >> 4) & 0xF, paddr[8] & 0xF, (paddr[8] >> 4) & 0xF, paddr[7] & 0xF,
|
||||
(paddr[7] >> 4) & 0xF, paddr[6] & 0xF, (paddr[6] >> 4) & 0xF, paddr[5] & 0xF,
|
||||
(paddr[5] >> 4) & 0xF, paddr[4] & 0xF, (paddr[4] >> 4) & 0xF, paddr[3] & 0xF,
|
||||
(paddr[3] >> 4) & 0xF, paddr[2] & 0xF, (paddr[2] >> 4) & 0xF, paddr[1] & 0xF,
|
||||
(paddr[1] >> 4) & 0xF, paddr[0] & 0xF, (paddr[0] >> 4) & 0xF);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
goto errout;
|
||||
break;
|
||||
}
|
||||
|
||||
ptr = _dns_conf_get_ptr(ptr_domain);
|
||||
if (ptr == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
safe_strncpy(ptr->hostname, hostname, DNS_MAX_CNAME_LEN);
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _config_ptr_table_destroy(void)
|
||||
{
|
||||
struct dns_ptr *ptr = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
unsigned long i = 0;
|
||||
|
||||
hash_for_each_safe(dns_ptr_table.ptr, i, tmp, ptr, node)
|
||||
{
|
||||
hlist_del_init(&ptr->node);
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static struct dns_hosts *_dns_conf_get_hosts(const char *hostname, int dns_type)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_hosts *host = NULL;
|
||||
char hostname_lower[DNS_MAX_CNAME_LEN];
|
||||
|
||||
key = hash_string(to_lower_case(hostname_lower, hostname, DNS_MAX_CNAME_LEN));
|
||||
key = jhash(&dns_type, sizeof(dns_type), key);
|
||||
hash_for_each_possible(dns_hosts_table.hosts, host, node, key)
|
||||
{
|
||||
if (host->dns_type != dns_type) {
|
||||
continue;
|
||||
}
|
||||
if (strncmp(host->domain, hostname_lower, DNS_MAX_CNAME_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
host = malloc(sizeof(*host));
|
||||
if (host == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
safe_strncpy(host->domain, hostname_lower, DNS_MAX_CNAME_LEN);
|
||||
host->dns_type = dns_type;
|
||||
host->is_soa = 1;
|
||||
hash_add(dns_hosts_table.hosts, &host->node, key);
|
||||
|
||||
return host;
|
||||
errout:
|
||||
if (host) {
|
||||
free(host);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _conf_host_add(const char *hostname, const char *ip, dns_hosts_type host_type)
|
||||
{
|
||||
struct dns_hosts *host = NULL;
|
||||
struct dns_hosts *host_other __attribute__((unused));
|
||||
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addr_len = sizeof(addr);
|
||||
int dns_type = 0;
|
||||
int dns_type_other = 0;
|
||||
|
||||
if (getaddr_by_host(ip, (struct sockaddr *)&addr, &addr_len) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET:
|
||||
dns_type = DNS_T_A;
|
||||
dns_type_other = DNS_T_AAAA;
|
||||
break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6 = NULL;
|
||||
addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
dns_type = DNS_T_A;
|
||||
dns_type_other = DNS_T_AAAA;
|
||||
} else {
|
||||
dns_type = DNS_T_AAAA;
|
||||
dns_type_other = DNS_T_A;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
goto errout;
|
||||
break;
|
||||
}
|
||||
|
||||
host = _dns_conf_get_hosts(hostname, dns_type);
|
||||
if (host == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* add this to return SOA when addr is not exist */
|
||||
host_other = _dns_conf_get_hosts(hostname, dns_type_other);
|
||||
|
||||
host->host_type = host_type;
|
||||
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr_in = NULL;
|
||||
addr_in = (struct sockaddr_in *)&addr;
|
||||
memcpy(host->ipv4_addr, &addr_in->sin_addr.s_addr, 4);
|
||||
host->is_soa = 0;
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6 = NULL;
|
||||
addr_in6 = (struct sockaddr_in6 *)&addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
memcpy(host->ipv4_addr, addr_in6->sin6_addr.s6_addr + 12, 4);
|
||||
} else {
|
||||
memcpy(host->ipv6_addr, addr_in6->sin6_addr.s6_addr, 16);
|
||||
}
|
||||
host->is_soa = 0;
|
||||
} break;
|
||||
default:
|
||||
goto errout;
|
||||
}
|
||||
|
||||
dns_hosts_record_num++;
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _conf_dhcp_lease_dnsmasq_add(const char *file)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char line[MAX_LINE_LEN];
|
||||
char ip[DNS_MAX_IPLEN];
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
int ret = 0;
|
||||
int line_no = 0;
|
||||
int filed_num = 0;
|
||||
|
||||
fp = fopen(file, "r");
|
||||
if (fp == NULL) {
|
||||
tlog(TLOG_WARN, "open file %s error, %s", file, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
line_no = 0;
|
||||
while (fgets(line, MAX_LINE_LEN, fp)) {
|
||||
line_no++;
|
||||
filed_num = sscanf(line, "%*s %*s %64s %256s %*s", ip, hostname);
|
||||
if (filed_num <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(hostname, "*", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = _conf_host_add(hostname, ip, DNS_HOST_TYPE_DNSMASQ);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_WARN, "add host %s/%s at %d failed", hostname, ip, line_no);
|
||||
}
|
||||
|
||||
ret = _conf_ptr_add(hostname, ip);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_WARN, "add ptr %s/%s at %d failed.", hostname, ip, line_no);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _conf_dhcp_lease_dnsmasq_file(void *data, int argc, char *argv[])
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (argc < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
conf_get_conf_fullpath(argv[1], dns_conf_dnsmasq_lease_file, sizeof(dns_conf_dnsmasq_lease_file));
|
||||
if (_conf_dhcp_lease_dnsmasq_add(dns_conf_dnsmasq_lease_file) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stat(dns_conf_dnsmasq_lease_file, &statbuf) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
dns_conf_dnsmasq_lease_file_time = statbuf.st_mtime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _conf_hosts_file(void *data, int argc, char *argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _config_host_table_destroy(void)
|
||||
{
|
||||
struct dns_hosts *host = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
unsigned long i = 0;
|
||||
|
||||
hash_for_each_safe(dns_hosts_table.hosts, i, tmp, host, node)
|
||||
{
|
||||
hlist_del_init(&host->node);
|
||||
free(host);
|
||||
}
|
||||
|
||||
dns_hosts_record_num = 0;
|
||||
}
|
||||
|
||||
int dns_server_check_update_hosts(void)
|
||||
{
|
||||
struct stat statbuf;
|
||||
time_t now = 0;
|
||||
|
||||
if (dns_conf_dnsmasq_lease_file[0] == '\0') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stat(dns_conf_dnsmasq_lease_file, &statbuf) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dns_conf_dnsmasq_lease_file_time == statbuf.st_mtime) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
time(&now);
|
||||
|
||||
if (now - statbuf.st_mtime < 30) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_config_ptr_table_destroy();
|
||||
_config_host_table_destroy();
|
||||
|
||||
if (_conf_dhcp_lease_dnsmasq_add(dns_conf_dnsmasq_lease_file) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_conf_dnsmasq_lease_file_time = statbuf.st_mtime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _config_log_level(void *data, int argc, char *argv[])
|
||||
{
|
||||
/* read log level and set */
|
||||
@@ -1412,6 +1841,35 @@ static int _config_log_level(void *data, int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _config_setup_smartdns_domain(void)
|
||||
{
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
/* get local host name */
|
||||
if (getdomainname(hostname, DNS_MAX_CNAME_LEN) != 0) {
|
||||
gethostname(hostname, DNS_MAX_CNAME_LEN);
|
||||
}
|
||||
|
||||
/* get host name again */
|
||||
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
gethostname(hostname, DNS_MAX_CNAME_LEN);
|
||||
}
|
||||
|
||||
/* if hostname is (none), return smartdns */
|
||||
if (strncmp(hostname, "(none)", DNS_MAX_CNAME_LEN - 1) == 0) {
|
||||
safe_strncpy(hostname, "smartdns", DNS_MAX_CNAME_LEN);
|
||||
}
|
||||
|
||||
if (hostname[0] != '\0') {
|
||||
_config_domain_rule_flag_set(hostname, DOMAIN_FLAG_SMARTDNS_DOMAIN, 0);
|
||||
}
|
||||
|
||||
if (dns_conf_server_name[0] != '\0') {
|
||||
_config_domain_rule_flag_set(dns_conf_server_name, DOMAIN_FLAG_SMARTDNS_DOMAIN, 0);
|
||||
}
|
||||
|
||||
_config_domain_rule_flag_set("smartdns", DOMAIN_FLAG_SMARTDNS_DOMAIN, 0);
|
||||
}
|
||||
|
||||
static struct config_item _config_item[] = {
|
||||
CONF_STRING("server-name", (char *)dns_conf_server_name, DNS_MAX_SERVER_NAME_LEN),
|
||||
CONF_CUSTOM("bind", _config_bind_ip_udp, NULL),
|
||||
@@ -1433,7 +1891,9 @@ static struct config_item _config_item[] = {
|
||||
CONF_YESNO("serve-expired", &dns_conf_serve_expired),
|
||||
CONF_INT("serve-expired-ttl", &dns_conf_serve_expired_ttl, 0, CONF_INT_MAX),
|
||||
CONF_INT("serve-expired-reply-ttl", &dns_conf_serve_expired_reply_ttl, 0, CONF_INT_MAX),
|
||||
CONF_INT("serve-expired-prefetch-time", &dns_conf_serve_expired_prefetch_time, 0, CONF_INT_MAX),
|
||||
CONF_YESNO("dualstack-ip-selection", &dns_conf_dualstack_ip_selection),
|
||||
CONF_YESNO("dualstack-ip-allow-force-AAAA", &dns_conf_dualstack_ip_allow_force_AAAA),
|
||||
CONF_INT("dualstack-ip-selection-threshold", &dns_conf_dualstack_ip_selection_threshold, 0, 1000),
|
||||
CONF_CUSTOM("log-level", _config_log_level, NULL),
|
||||
CONF_STRING("log-file", (char *)dns_conf_log_file, DNS_MAX_PATH),
|
||||
@@ -1447,29 +1907,42 @@ static struct config_item _config_item[] = {
|
||||
CONF_INT("rr-ttl", &dns_conf_rr_ttl, 0, CONF_INT_MAX),
|
||||
CONF_INT("rr-ttl-min", &dns_conf_rr_ttl_min, 0, CONF_INT_MAX),
|
||||
CONF_INT("rr-ttl-max", &dns_conf_rr_ttl_max, 0, CONF_INT_MAX),
|
||||
CONF_INT("rr-ttl-reply-max", &dns_conf_rr_ttl_reply_max, 0, CONF_INT_MAX),
|
||||
CONF_INT("local-ttl", &dns_conf_local_ttl, 0, CONF_INT_MAX),
|
||||
CONF_INT("max-reply-ip-num", &dns_conf_max_reply_ip_num, 1, CONF_INT_MAX),
|
||||
CONF_ENUM("response-mode", &dns_conf_response_mode, &dns_conf_response_mode_enum),
|
||||
CONF_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA),
|
||||
CONF_YESNO("force-no-CNAME", &dns_conf_force_no_cname),
|
||||
CONF_CUSTOM("force-qtype-SOA", _config_qtype_soa, NULL),
|
||||
CONF_CUSTOM("blacklist-ip", _config_blacklist_ip, NULL),
|
||||
CONF_CUSTOM("whitelist-ip", _conf_whitelist_ip, NULL),
|
||||
CONF_CUSTOM("bogus-nxdomain", _conf_bogus_nxdomain, NULL),
|
||||
CONF_CUSTOM("ignore-ip", _conf_ip_ignore, NULL),
|
||||
CONF_CUSTOM("edns-client-subnet", _conf_edns_client_subnet, NULL),
|
||||
CONF_CUSTOM("domain-rules", _conf_domain_rules, NULL),
|
||||
CONF_CUSTOM("dnsmasq-lease-file", _conf_dhcp_lease_dnsmasq_file, NULL),
|
||||
CONF_CUSTOM("hosts-file", _conf_hosts_file, NULL),
|
||||
CONF_STRING("ca-file", (char *)&dns_conf_ca_file, DNS_MAX_PATH),
|
||||
CONF_STRING("ca-path", (char *)&dns_conf_ca_path, DNS_MAX_PATH),
|
||||
CONF_STRING("user", (char *)&dns_conf_user, sizeof(dns_conf_user)),
|
||||
CONF_YESNO("debug-save-fail-packet", &dns_save_fail_packet),
|
||||
CONF_STRING("debug-save-fail-packet-dir", (char *)&dns_save_fail_packet_dir, sizeof(dns_save_fail_packet_dir)),
|
||||
CONF_CUSTOM("conf-file", config_addtional_file, NULL),
|
||||
CONF_END(),
|
||||
};
|
||||
|
||||
static 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) {
|
||||
switch (ret) {
|
||||
case CONF_RET_ERR:
|
||||
case CONF_RET_WARN:
|
||||
case CONF_RET_BADCONF:
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1477,10 +1950,15 @@ static int _conf_printf(const char *file, int lineno, int ret)
|
||||
|
||||
int config_addtional_file(void *data, int argc, char *argv[])
|
||||
{
|
||||
char *conf_file = argv[1];
|
||||
char *conf_file = NULL;
|
||||
char file_path[DNS_MAX_PATH];
|
||||
char file_path_dir[DNS_MAX_PATH];
|
||||
|
||||
if (argc < 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
conf_file = argv[1];
|
||||
if (conf_file[0] != '/') {
|
||||
safe_strncpy(file_path_dir, conf_get_conf_file(), DNS_MAX_PATH);
|
||||
dirname(file_path_dir);
|
||||
@@ -1518,7 +1996,12 @@ static int _dns_server_load_conf_init(void)
|
||||
art_tree_init(&dns_conf_domain_rule);
|
||||
|
||||
hash_init(dns_ipset_table.ipset);
|
||||
hash_init(dns_qtype_soa_table.qtype);
|
||||
hash_init(dns_group_table.group);
|
||||
hash_init(dns_hosts_table.hosts);
|
||||
hash_init(dns_ptr_table.ptr);
|
||||
|
||||
_config_setup_smartdns_domain();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1530,11 +2013,15 @@ void dns_server_load_exit(void)
|
||||
Destroy_Radix(dns_conf_address_rule.ipv6, _config_address_destroy, NULL);
|
||||
_config_ipset_table_destroy();
|
||||
_config_group_table_destroy();
|
||||
_config_ptr_table_destroy();
|
||||
_config_host_table_destroy();
|
||||
_config_qtype_soa_table_destroy();
|
||||
}
|
||||
|
||||
static int _dns_conf_speed_check_mode_verify(void)
|
||||
{
|
||||
int i, j;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int print_log = 0;
|
||||
|
||||
if (dns_has_cap_ping == 1) {
|
||||
@@ -1542,11 +2029,13 @@ static int _dns_conf_speed_check_mode_verify(void)
|
||||
}
|
||||
|
||||
for (i = 0; i < DOMAIN_CHECK_NUM; i++) {
|
||||
if (dns_conf_check_order.order[i] == DOMAIN_CHECK_ICMP) {
|
||||
if (dns_conf_check_orders.orders[i].type == DOMAIN_CHECK_ICMP) {
|
||||
for (j = i + 1; j < DOMAIN_CHECK_NUM; j++) {
|
||||
dns_conf_check_order.order[j - 1] = dns_conf_check_order.order[j];
|
||||
dns_conf_check_orders.orders[j - 1].type = dns_conf_check_orders.orders[j].type;
|
||||
dns_conf_check_orders.orders[j - 1].tcp_port = dns_conf_check_orders.orders[j].tcp_port;
|
||||
}
|
||||
dns_conf_check_order.order[j - 1] = DOMAIN_CHECK_NONE;
|
||||
dns_conf_check_orders.orders[j - 1].type = DOMAIN_CHECK_NONE;
|
||||
dns_conf_check_orders.orders[j - 1].tcp_port = 0;
|
||||
print_log = 1;
|
||||
}
|
||||
}
|
||||
@@ -1558,13 +2047,35 @@ static int _dns_conf_speed_check_mode_verify(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_ping_cap_check(void)
|
||||
{
|
||||
int has_ping = 0;
|
||||
int has_raw_cap = 0;
|
||||
|
||||
has_raw_cap = has_network_raw_cap();
|
||||
has_ping = has_unprivileged_ping();
|
||||
if (has_ping == 0) {
|
||||
if (errno == EACCES && has_raw_cap == 0) {
|
||||
tlog(TLOG_WARN, "unpriviledged ping is disabled, please enable by setting net.ipv4.ping_group_range");
|
||||
}
|
||||
}
|
||||
|
||||
if (has_ping == 1 || has_raw_cap == 1) {
|
||||
dns_has_cap_ping = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_conf_load_pre(void)
|
||||
{
|
||||
if (_dns_server_load_conf_init() != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
dns_has_cap_ping = has_network_raw_cap();
|
||||
_dns_ping_cap_check();
|
||||
|
||||
safe_strncpy(dns_save_fail_packet_dir, SMARTDNS_DEBUG_DIR, sizeof(dns_save_fail_packet_dir));
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1576,6 +2087,25 @@ static int _dns_conf_load_post(void)
|
||||
{
|
||||
_dns_conf_speed_check_mode_verify();
|
||||
|
||||
if (dns_conf_cachesize == 0 && dns_conf_response_mode == DNS_RESPONSE_MODE_FASTEST_RESPONSE) {
|
||||
dns_conf_response_mode = DNS_RESPONSE_MODE_FASTEST_IP;
|
||||
tlog(TLOG_WARN, "force set response to %s as cache size is 0",
|
||||
dns_conf_response_mode_enum[dns_conf_response_mode].name);
|
||||
}
|
||||
|
||||
|
||||
if ((dns_conf_rr_ttl_min > dns_conf_rr_ttl_max) && dns_conf_rr_ttl_max > 0) {
|
||||
dns_conf_rr_ttl_min = dns_conf_rr_ttl_max;
|
||||
}
|
||||
|
||||
if ((dns_conf_rr_ttl_max < dns_conf_rr_ttl_min) && dns_conf_rr_ttl_max > 0) {
|
||||
dns_conf_rr_ttl_max = dns_conf_rr_ttl_min;
|
||||
}
|
||||
|
||||
if (dns_conf_local_ttl == 0) {
|
||||
dns_conf_local_ttl = dns_conf_rr_ttl_min;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,10 +35,12 @@ extern "C" {
|
||||
#define DNS_MAX_BIND_IP 16
|
||||
#define DNS_MAX_SERVERS 64
|
||||
#define DNS_MAX_SERVER_NAME_LEN 128
|
||||
#define DNS_MAX_PTR_LEN 128
|
||||
#define DNS_MAX_IPSET_NAMELEN 32
|
||||
#define DNS_GROUP_NAME_LEN 32
|
||||
#define DNS_NAX_GROUP_NUMBER 16
|
||||
#define DNS_MAX_IPLEN 64
|
||||
#define DNS_CONF_USRNAME_LEN 32
|
||||
#define DNS_MAX_SPKI_LEN 64
|
||||
#define DNS_MAX_URL_LEN 256
|
||||
#define DNS_MAX_PATH 1024
|
||||
@@ -47,9 +49,10 @@ extern "C" {
|
||||
#define DEFAULT_DNS_HTTPS_PORT 443
|
||||
#define DNS_MAX_CONF_CNAME_LEN 256
|
||||
#define SMARTDNS_CONF_FILE "/etc/smartdns/smartdns.conf"
|
||||
#define SMARTDNS_LOG_FILE "/var/log/smartdns.log"
|
||||
#define SMARTDNS_AUDIT_FILE "/var/log/smartdns-audit.log"
|
||||
#define SMARTDNS_LOG_FILE "/var/log/smartdns/smartdns.log"
|
||||
#define SMARTDNS_AUDIT_FILE "/var/log/smartdns/smartdns-audit.log"
|
||||
#define SMARTDNS_CACHE_FILE "/tmp/smartdns.cache"
|
||||
#define SMARTDNS_DEBUG_DIR "/tmp/smartdns"
|
||||
|
||||
enum domain_rule {
|
||||
DOMAIN_RULE_FLAGS = 0,
|
||||
@@ -72,7 +75,7 @@ typedef enum {
|
||||
#define DOMAIN_CHECK_NONE 0
|
||||
#define DOMAIN_CHECK_ICMP 1
|
||||
#define DOMAIN_CHECK_TCP 2
|
||||
#define DOMAIN_CHECK_NUM 2
|
||||
#define DOMAIN_CHECK_NUM 3
|
||||
|
||||
#define DOMAIN_FLAG_ADDR_SOA (1 << 0)
|
||||
#define DOMAIN_FLAG_ADDR_IPV4_SOA (1 << 1)
|
||||
@@ -85,6 +88,7 @@ typedef enum {
|
||||
#define DOMAIN_FLAG_IPSET_IPV6_IGN (1 << 8)
|
||||
#define DOMAIN_FLAG_NAMESERVER_IGNORE (1 << 9)
|
||||
#define DOMAIN_FLAG_DUALSTACK_SELECT (1 << 10)
|
||||
#define DOMAIN_FLAG_SMARTDNS_DOMAIN (1 << 11)
|
||||
|
||||
#define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0)
|
||||
|
||||
@@ -136,15 +140,53 @@ struct dns_server_groups {
|
||||
};
|
||||
|
||||
struct dns_domain_check_order {
|
||||
char order[DOMAIN_CHECK_NUM];
|
||||
char type;
|
||||
unsigned short tcp_port;
|
||||
};
|
||||
|
||||
struct dns_domain_check_orders {
|
||||
struct dns_domain_check_order orders[DOMAIN_CHECK_NUM];
|
||||
};
|
||||
|
||||
struct dns_group_table {
|
||||
DECLARE_HASHTABLE(group, 8);
|
||||
};
|
||||
extern struct dns_group_table dns_group_table;
|
||||
|
||||
struct dns_ptr {
|
||||
struct hlist_node node;
|
||||
char ptr_domain[DNS_MAX_PTR_LEN];
|
||||
char hostname[DNS_MAX_CNAME_LEN];
|
||||
};
|
||||
|
||||
struct dns_ptr_table {
|
||||
DECLARE_HASHTABLE(ptr, 16);
|
||||
};
|
||||
extern struct dns_ptr_table dns_ptr_table;
|
||||
|
||||
typedef enum dns_hosts_type {
|
||||
DNS_HOST_TYPE_HOST = 0,
|
||||
DNS_HOST_TYPE_DNSMASQ = 1,
|
||||
} dns_hosts_type;
|
||||
|
||||
struct dns_hosts {
|
||||
struct hlist_node node;
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
dns_hosts_type host_type;
|
||||
int dns_type;
|
||||
int is_soa;
|
||||
union {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
||||
};
|
||||
};
|
||||
|
||||
struct dns_hosts_table {
|
||||
DECLARE_HASHTABLE(hosts, 16);
|
||||
};
|
||||
extern struct dns_hosts_table dns_hosts_table;
|
||||
extern int dns_hosts_record_num;
|
||||
|
||||
struct dns_servers {
|
||||
char server[DNS_MAX_IPLEN];
|
||||
unsigned short port;
|
||||
@@ -203,6 +245,16 @@ struct dns_bind_ip {
|
||||
const char *group;
|
||||
};
|
||||
|
||||
struct dns_qtype_soa_list {
|
||||
struct hlist_node node;
|
||||
uint32_t qtypeid;
|
||||
};
|
||||
|
||||
struct dns_qtype_soa_table {
|
||||
DECLARE_HASHTABLE(qtype, 8);
|
||||
};
|
||||
extern struct dns_qtype_soa_table dns_qtype_soa_table;
|
||||
|
||||
extern struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP];
|
||||
extern int dns_conf_bind_ip_num;
|
||||
|
||||
@@ -211,6 +263,7 @@ extern int dns_conf_cachesize;
|
||||
extern int dns_conf_prefetch;
|
||||
extern int dns_conf_serve_expired;
|
||||
extern int dns_conf_serve_expired_ttl;
|
||||
extern int dns_conf_serve_expired_prefetch_time;
|
||||
extern int dns_conf_serve_expired_reply_ttl;
|
||||
extern struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
extern int dns_conf_server_num;
|
||||
@@ -226,7 +279,7 @@ extern char dns_conf_ca_path[DNS_MAX_PATH];
|
||||
extern char dns_conf_cache_file[DNS_MAX_PATH];
|
||||
extern int dns_conf_cache_persist;
|
||||
|
||||
extern struct dns_domain_check_order dns_conf_check_order;
|
||||
extern struct dns_domain_check_orders dns_conf_check_orders;
|
||||
|
||||
extern struct dns_server_groups dns_conf_server_groups[DNS_NAX_GROUP_NUMBER];
|
||||
extern int dns_conf_server_group_num;
|
||||
@@ -242,23 +295,43 @@ extern art_tree dns_conf_domain_rule;
|
||||
extern struct dns_conf_address_rule dns_conf_address_rule;
|
||||
|
||||
extern int dns_conf_dualstack_ip_selection;
|
||||
extern int dns_conf_dualstack_ip_allow_force_AAAA;
|
||||
extern int dns_conf_dualstack_ip_selection_threshold;
|
||||
|
||||
extern int dns_conf_max_reply_ip_num;
|
||||
enum response_mode_type {
|
||||
DNS_RESPONSE_MODE_FIRST_PING_IP = 0,
|
||||
DNS_RESPONSE_MODE_FASTEST_IP,
|
||||
DNS_RESPONSE_MODE_FASTEST_RESPONSE,
|
||||
};
|
||||
extern enum response_mode_type dns_conf_response_mode;
|
||||
|
||||
extern int dns_conf_rr_ttl;
|
||||
extern int dns_conf_rr_ttl_reply_max;
|
||||
extern int dns_conf_rr_ttl_min;
|
||||
extern int dns_conf_rr_ttl_max;
|
||||
extern int dns_conf_force_AAAA_SOA;
|
||||
extern int dns_conf_ipset_timeout_enable;
|
||||
extern int dns_conf_local_ttl;
|
||||
|
||||
extern int dns_conf_force_no_cname;
|
||||
|
||||
extern char dns_conf_user[DNS_CONF_USRNAME_LEN];
|
||||
|
||||
extern struct dns_edns_client_subnet dns_conf_ipv4_ecs;
|
||||
extern struct dns_edns_client_subnet dns_conf_ipv6_ecs;
|
||||
|
||||
extern char dns_conf_sni_proxy_ip[DNS_MAX_IPLEN];
|
||||
|
||||
extern int dns_save_fail_packet;
|
||||
extern char dns_save_fail_packet_dir[DNS_MAX_PATH];
|
||||
|
||||
void dns_server_load_exit(void);
|
||||
|
||||
int dns_server_load_conf(const char *file);
|
||||
|
||||
int dns_server_check_update_hosts(void);
|
||||
|
||||
extern int config_addtional_file(void *data, int argc, char *argv[]);
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
|
||||
3494
src/dns_server.c
3494
src/dns_server.c
File diff suppressed because it is too large
Load Diff
@@ -21,11 +21,20 @@
|
||||
|
||||
#include "dns.h"
|
||||
#include <stdint.h>
|
||||
#include "dns_client.h"
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct dns_server_query_option {
|
||||
uint32_t server_flags;
|
||||
const char *dns_group_name;
|
||||
unsigned long ecs_enable_flag;
|
||||
struct dns_opt_ecs ecs_dns;
|
||||
struct dns_query_ecs_ip ecs_ip;
|
||||
};
|
||||
|
||||
int dns_server_init(void);
|
||||
|
||||
int dns_server_run(void);
|
||||
@@ -37,11 +46,12 @@ void dns_server_stop(void);
|
||||
void dns_server_exit(void);
|
||||
|
||||
/* query result notify function */
|
||||
typedef int (*dns_result_callback)(char *domain, dns_rtcode_t rtcode, dns_type_t addr_type, char *ip,
|
||||
typedef int (*dns_result_callback)(const char *domain, dns_rtcode_t rtcode, dns_type_t addr_type, char *ip,
|
||||
unsigned int ping_time, void *user_ptr);
|
||||
|
||||
/* query domain */
|
||||
int dns_server_query(char *domain, int qtype, uint32_t server_flags, dns_result_callback callback, void *user_ptr);
|
||||
int dns_server_query(const char *domain, int qtype, struct dns_server_query_option *server_query_option,
|
||||
dns_result_callback callback, void *user_ptr);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
|
||||
216
src/fast_ping.c
216
src/fast_ping.c
@@ -97,6 +97,7 @@ struct ping_host_struct {
|
||||
FAST_PING_TYPE type;
|
||||
|
||||
void *userptr;
|
||||
int error;
|
||||
fast_ping_result ping_callback;
|
||||
char host[PING_MAX_HOSTLEN];
|
||||
|
||||
@@ -123,12 +124,13 @@ struct ping_host_struct {
|
||||
};
|
||||
|
||||
struct fast_ping_struct {
|
||||
int run;
|
||||
atomic_t run;
|
||||
pthread_t tid;
|
||||
pthread_mutex_t lock;
|
||||
unsigned short ident;
|
||||
|
||||
int epoll_fd;
|
||||
int no_unprivileged_ping;
|
||||
int fd_icmp;
|
||||
struct ping_host_struct icmp_host;
|
||||
int fd_icmp6;
|
||||
@@ -149,7 +151,7 @@ static int bool_print_log = 1;
|
||||
static uint16_t _fast_ping_checksum(uint16_t *header, size_t len)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
int i;
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i = 0; i < len / sizeof(uint16_t); i++) {
|
||||
sum += ntohs(header[i]);
|
||||
@@ -260,13 +262,13 @@ static uint32_t _fast_ping_hash_key(unsigned int sid, struct sockaddr *addr)
|
||||
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr_in;
|
||||
struct sockaddr_in *addr_in = NULL;
|
||||
addr_in = (struct sockaddr_in *)addr;
|
||||
sin_addr = &addr_in->sin_addr.s_addr;
|
||||
sin_addr_len = IPV4_ADDR_LEN;
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6;
|
||||
struct sockaddr_in6 *addr_in6 = NULL;
|
||||
addr_in6 = (struct sockaddr_in6 *)addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
sin_addr = addr_in6->sin6_addr.s6_addr + 12;
|
||||
@@ -356,7 +358,7 @@ static void _fast_ping_close_host_sock(struct ping_host_struct *ping_host)
|
||||
if (ping_host->fd < 0) {
|
||||
return;
|
||||
}
|
||||
struct epoll_event *event;
|
||||
struct epoll_event *event = NULL;
|
||||
event = (struct epoll_event *)1;
|
||||
epoll_ctl(ping.epoll_fd, EPOLL_CTL_DEL, ping_host->fd, event);
|
||||
close(ping_host->fd);
|
||||
@@ -386,11 +388,10 @@ static void _fast_ping_host_put(struct ping_host_struct *ping_host)
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len,
|
||||
ping_host->seq, ping_host->ttl, &tv, ping_host->userptr);
|
||||
ping_host->seq, ping_host->ttl, &tv, ping_host->error, ping_host->userptr);
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "ping end, id %d", ping_host->sid);
|
||||
// memset(ping_host, 0, sizeof(*ping_host));
|
||||
tlog(TLOG_DEBUG, "ping %s end, id %d", ping_host->host, ping_host->sid);
|
||||
ping_host->type = FAST_PING_END;
|
||||
free(ping_host);
|
||||
}
|
||||
@@ -414,7 +415,7 @@ static void _fast_ping_host_remove(struct ping_host_struct *ping_host)
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len,
|
||||
ping_host->seq, ping_host->ttl, &tv, ping_host->userptr);
|
||||
ping_host->seq, ping_host->ttl, &tv, ping_host->error, ping_host->userptr);
|
||||
}
|
||||
|
||||
_fast_ping_host_put(ping_host);
|
||||
@@ -441,11 +442,11 @@ static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
|
||||
packet->msg.seq = ping_host->seq;
|
||||
icmp6->icmp6_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
|
||||
|
||||
len = sendto(ping.fd_icmp6, &ping_host->packet, sizeof(struct fast_ping_packet), 0,
|
||||
(struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
||||
len = sendto(ping.fd_icmp6, &ping_host->packet, sizeof(struct fast_ping_packet), 0, &ping_host->addr,
|
||||
ping_host->addr_len);
|
||||
if (len < 0 || len != sizeof(struct fast_ping_packet)) {
|
||||
int err = errno;
|
||||
if (errno == ENETUNREACH || errno == EINVAL) {
|
||||
if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -473,7 +474,7 @@ static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
|
||||
{
|
||||
struct fast_ping_packet *packet = &ping_host->packet;
|
||||
struct icmp *icmp = &packet->icmp;
|
||||
int len;
|
||||
int len = 0;
|
||||
|
||||
ping_host->seq++;
|
||||
memset(icmp, 0, sizeof(*icmp));
|
||||
@@ -490,11 +491,10 @@ static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
|
||||
packet->msg.cookie = ping_host->cookie;
|
||||
icmp->icmp_cksum = _fast_ping_checksum((void *)packet, sizeof(struct fast_ping_packet));
|
||||
|
||||
len = sendto(ping.fd_icmp, packet, sizeof(struct fast_ping_packet), 0, (struct sockaddr *)&ping_host->addr,
|
||||
ping_host->addr_len);
|
||||
len = sendto(ping.fd_icmp, packet, sizeof(struct fast_ping_packet), 0, &ping_host->addr, ping_host->addr_len);
|
||||
if (len < 0 || len != sizeof(struct fast_ping_packet)) {
|
||||
int err = errno;
|
||||
if (errno == ENETUNREACH || errno == EINVAL) {
|
||||
if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL) {
|
||||
goto errout;
|
||||
}
|
||||
char ping_host_name[PING_MAX_HOSTLEN];
|
||||
@@ -513,7 +513,7 @@ errout:
|
||||
static int _fast_ping_sendping_udp(struct ping_host_struct *ping_host)
|
||||
{
|
||||
struct ping_dns_head dns_head;
|
||||
int len;
|
||||
int len = 0;
|
||||
int flag = 0;
|
||||
int fd = 0;
|
||||
|
||||
@@ -538,10 +538,10 @@ static int _fast_ping_sendping_udp(struct ping_host_struct *ping_host)
|
||||
dns_head.id = htons(ping_host->sid);
|
||||
dns_head.flag = flag;
|
||||
gettimeofday(&ping_host->last, NULL);
|
||||
len = sendto(fd, &dns_head, sizeof(dns_head), 0, (struct sockaddr *)&ping_host->addr, ping_host->addr_len);
|
||||
len = sendto(fd, &dns_head, sizeof(dns_head), 0, &ping_host->addr, ping_host->addr_len);
|
||||
if (len < 0 || len != sizeof(dns_head)) {
|
||||
int err = errno;
|
||||
if (errno == ENETUNREACH || errno == EINVAL) {
|
||||
if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL) {
|
||||
goto errout;
|
||||
}
|
||||
char ping_host_name[PING_MAX_HOSTLEN];
|
||||
@@ -560,7 +560,7 @@ errout:
|
||||
static int _fast_ping_sendping_tcp(struct ping_host_struct *ping_host)
|
||||
{
|
||||
struct epoll_event event;
|
||||
int flags;
|
||||
int flags = 0;
|
||||
int fd = -1;
|
||||
int yes = 1;
|
||||
const int priority = SOCKET_PRIORITY;
|
||||
@@ -585,10 +585,10 @@ static int _fast_ping_sendping_tcp(struct ping_host_struct *ping_host)
|
||||
set_sock_lingertime(fd, 0);
|
||||
|
||||
ping_host->seq++;
|
||||
if (connect(fd, (struct sockaddr *)&ping_host->addr, ping_host->addr_len) != 0) {
|
||||
if (connect(fd, &ping_host->addr, ping_host->addr_len) != 0) {
|
||||
if (errno != EINPROGRESS) {
|
||||
char ping_host_name[PING_MAX_HOSTLEN];
|
||||
if (errno == ENETUNREACH || errno == EINVAL) {
|
||||
if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -644,6 +644,7 @@ static int _fast_ping_sendping(struct ping_host_struct *ping_host)
|
||||
ping_host->send = 1;
|
||||
|
||||
if (ret != 0) {
|
||||
ping_host->error = errno;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -663,21 +664,46 @@ static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type)
|
||||
|
||||
switch (type) {
|
||||
case FAST_PING_ICMP:
|
||||
fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||
if (ping.no_unprivileged_ping == 0) {
|
||||
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
|
||||
} else {
|
||||
fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||
if (fd > 0) {
|
||||
_fast_ping_install_filter_v4(fd);
|
||||
}
|
||||
}
|
||||
if (fd < 0) {
|
||||
if (errno == EACCES || errno == EAFNOSUPPORT) {
|
||||
if (bool_print_log == 0) {
|
||||
goto errout;
|
||||
}
|
||||
bool_print_log = 0;
|
||||
}
|
||||
tlog(TLOG_ERROR, "create icmp socket failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
_fast_ping_install_filter_v4(fd);
|
||||
icmp_host = &ping.icmp_host;
|
||||
break;
|
||||
case FAST_PING_ICMP6:
|
||||
fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
||||
if (ping.no_unprivileged_ping == 0) {
|
||||
fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
|
||||
} else {
|
||||
fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
||||
if (fd > 0) {
|
||||
_fast_ping_install_filter_v6(fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
if (errno == EACCES || errno == EAFNOSUPPORT) {
|
||||
if (bool_print_log == 0) {
|
||||
goto errout;
|
||||
}
|
||||
bool_print_log = 0;
|
||||
}
|
||||
tlog(TLOG_ERROR, "create icmp socket failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
_fast_ping_install_filter_v6(fd);
|
||||
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));
|
||||
@@ -696,6 +722,9 @@ static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type)
|
||||
setsockopt(fd, SOL_IP, IP_TTL, &val, sizeof(val));
|
||||
setsockopt(fd, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos));
|
||||
|
||||
icmp_host->fd = fd;
|
||||
icmp_host->type = type;
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN;
|
||||
event.data.ptr = icmp_host;
|
||||
@@ -703,12 +732,14 @@ static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
icmp_host->fd = fd;
|
||||
icmp_host->type = type;
|
||||
return fd;
|
||||
|
||||
errout:
|
||||
close(fd);
|
||||
if (icmp_host) {
|
||||
icmp_host->fd = -1;
|
||||
icmp_host->type = 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -848,13 +879,15 @@ errout:
|
||||
|
||||
static void _fast_ping_print_result(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result,
|
||||
struct sockaddr *addr, socklen_t addr_len, int seqno, int ttl, struct timeval *tv,
|
||||
void *userptr)
|
||||
int error, void *userptr)
|
||||
{
|
||||
if (result == PING_RESULT_RESPONSE) {
|
||||
double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0;
|
||||
tlog(TLOG_INFO, "from %15s: seq=%d ttl=%d time=%.3f\n", host, seqno, ttl, rtt);
|
||||
} else if (result == PING_RESULT_TIMEOUT) {
|
||||
tlog(TLOG_INFO, "from %15s: seq=%d timeout\n", host, seqno);
|
||||
} else if (result == PING_RESULT_ERROR) {
|
||||
tlog(TLOG_DEBUG, "from %15s: error is %s\n", host, strerror(error));
|
||||
} else if (result == PING_RESULT_END) {
|
||||
fast_ping_stop(ping_host);
|
||||
}
|
||||
@@ -866,7 +899,7 @@ static int _fast_ping_get_addr_by_icmp(const char *ip_str, int port, struct addr
|
||||
struct addrinfo *gai = NULL;
|
||||
int socktype = 0;
|
||||
int domain = -1;
|
||||
FAST_PING_TYPE ping_type;
|
||||
FAST_PING_TYPE ping_type = 0;
|
||||
int sockproto = 0;
|
||||
char *service = NULL;
|
||||
|
||||
@@ -915,7 +948,7 @@ static int _fast_ping_get_addr_by_tcp(const char *ip_str, int port, struct addri
|
||||
{
|
||||
struct addrinfo *gai = NULL;
|
||||
int socktype = 0;
|
||||
FAST_PING_TYPE ping_type;
|
||||
FAST_PING_TYPE ping_type = 0;
|
||||
int sockproto = 0;
|
||||
char *service = NULL;
|
||||
char port_str[MAX_IP_LEN];
|
||||
@@ -951,7 +984,7 @@ static int _fast_ping_get_addr_by_dns(const char *ip_str, int port, struct addri
|
||||
{
|
||||
struct addrinfo *gai = NULL;
|
||||
int socktype = 0;
|
||||
FAST_PING_TYPE ping_type;
|
||||
FAST_PING_TYPE ping_type = 0;
|
||||
int sockproto = 0;
|
||||
char port_str[MAX_IP_LEN];
|
||||
int domain = -1;
|
||||
@@ -1028,11 +1061,11 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c
|
||||
{
|
||||
struct ping_host_struct *ping_host = NULL;
|
||||
struct addrinfo *gai = NULL;
|
||||
uint32_t addrkey;
|
||||
uint32_t addrkey = 0;
|
||||
char ip_str[PING_MAX_HOSTLEN];
|
||||
int port = -1;
|
||||
FAST_PING_TYPE ping_type = FAST_PING_END;
|
||||
unsigned int seed;
|
||||
unsigned int seed = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (parse_ip(host, ip_str, &port) != 0) {
|
||||
@@ -1041,7 +1074,6 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c
|
||||
|
||||
ret = _fast_ping_get_addr_by_type(type, ip_str, port, &gai, &ping_type);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "get addr by type failed, host: %s", host);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -1080,10 +1112,6 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c
|
||||
tlog(TLOG_DEBUG, "ping %s, id = %d", host, ping_host->sid);
|
||||
|
||||
addrkey = _fast_ping_hash_key(ping_host->sid, &ping_host->addr);
|
||||
pthread_mutex_lock(&ping.map_lock);
|
||||
_fast_ping_host_get(ping_host);
|
||||
hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
|
||||
pthread_mutex_unlock(&ping.map_lock);
|
||||
|
||||
_fast_ping_host_get(ping_host);
|
||||
_fast_ping_host_get(ping_host);
|
||||
@@ -1092,11 +1120,17 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c
|
||||
goto errout_remove;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&ping.map_lock);
|
||||
_fast_ping_host_get(ping_host);
|
||||
hash_add(ping.addrmap, &ping_host->addr_node, addrkey);
|
||||
ping_host->run = 1;
|
||||
pthread_mutex_unlock(&ping.map_lock);
|
||||
freeaddrinfo(gai);
|
||||
_fast_ping_host_put(ping_host);
|
||||
return ping_host;
|
||||
errout_remove:
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_ERROR, &ping_host->addr, ping_host->addr_len,
|
||||
ping_host->seq, ping_host->ttl, NULL, ping_host->error, ping_host->userptr);
|
||||
fast_ping_stop(ping_host);
|
||||
_fast_ping_host_put(ping_host);
|
||||
ping_host = NULL;
|
||||
@@ -1136,22 +1170,24 @@ static void tv_sub(struct timeval *out, struct timeval *in)
|
||||
static struct fast_ping_packet *_fast_ping_icmp6_packet(struct ping_host_struct *ping_host, struct msghdr *msg,
|
||||
u_char *packet_data, int data_len)
|
||||
{
|
||||
int icmp_len;
|
||||
int icmp_len = 0;
|
||||
struct fast_ping_packet *packet = (struct fast_ping_packet *)packet_data;
|
||||
struct icmp6_hdr *icmp6 = &packet->icmp6;
|
||||
struct cmsghdr *c;
|
||||
struct cmsghdr *c = NULL;
|
||||
int hops = 0;
|
||||
|
||||
for (c = CMSG_FIRSTHDR(msg); c; c = CMSG_NXTHDR(msg, c)) {
|
||||
if (c->cmsg_level != IPPROTO_IPV6)
|
||||
if (c->cmsg_level != IPPROTO_IPV6) {
|
||||
continue;
|
||||
}
|
||||
switch (c->cmsg_type) {
|
||||
case IPV6_HOPLIMIT:
|
||||
#ifdef IPV6_2292HOPLIMIT
|
||||
case IPV6_2292HOPLIMIT:
|
||||
#endif
|
||||
if (c->cmsg_len < CMSG_LEN(sizeof(int)))
|
||||
if (c->cmsg_len < CMSG_LEN(sizeof(int))) {
|
||||
continue;
|
||||
}
|
||||
memcpy(&hops, CMSG_DATA(c), sizeof(hops));
|
||||
}
|
||||
}
|
||||
@@ -1168,9 +1204,11 @@ static struct fast_ping_packet *_fast_ping_icmp6_packet(struct ping_host_struct
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (icmp6->icmp6_id != ping.ident) {
|
||||
tlog(TLOG_ERROR, "ident failed, %d:%d", icmp6->icmp6_id, ping.ident);
|
||||
return NULL;
|
||||
if (ping.no_unprivileged_ping) {
|
||||
if (icmp6->icmp6_id != ping.ident) {
|
||||
tlog(TLOG_ERROR, "ident failed, %d:%d", icmp6->icmp6_id, ping.ident);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return packet;
|
||||
@@ -1180,15 +1218,10 @@ static struct fast_ping_packet *_fast_ping_icmp_packet(struct ping_host_struct *
|
||||
u_char *packet_data, int data_len)
|
||||
{
|
||||
struct ip *ip = (struct ip *)packet_data;
|
||||
struct fast_ping_packet *packet;
|
||||
struct icmp *icmp;
|
||||
int hlen;
|
||||
int icmp_len;
|
||||
|
||||
if (ip->ip_p != IPPROTO_ICMP) {
|
||||
tlog(TLOG_ERROR, "ip type faild, %d:%d", ip->ip_p, IPPROTO_ICMP);
|
||||
return NULL;
|
||||
}
|
||||
struct fast_ping_packet *packet = NULL;
|
||||
struct icmp *icmp = NULL;
|
||||
int hlen = 0;
|
||||
int icmp_len = 0;
|
||||
|
||||
hlen = ip->ip_hl << 2;
|
||||
packet = (struct fast_ping_packet *)(packet_data + hlen);
|
||||
@@ -1206,9 +1239,16 @@ static struct fast_ping_packet *_fast_ping_icmp_packet(struct ping_host_struct *
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (icmp->icmp_id != ping.ident) {
|
||||
tlog(TLOG_ERROR, "ident failed, %d:%d", icmp->icmp_id, ping.ident);
|
||||
return NULL;
|
||||
if (ping.no_unprivileged_ping) {
|
||||
if (ip->ip_p != IPPROTO_ICMP) {
|
||||
tlog(TLOG_ERROR, "ip type faild, %d:%d", ip->ip_p, IPPROTO_ICMP);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (icmp->icmp_id != ping.ident) {
|
||||
tlog(TLOG_ERROR, "ident failed, %d:%d", icmp->icmp_id, ping.ident);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return packet;
|
||||
@@ -1241,18 +1281,18 @@ errout:
|
||||
|
||||
static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct timeval *now)
|
||||
{
|
||||
int len;
|
||||
int len = 0;
|
||||
u_char inpacket[ICMP_INPACKET_SIZE];
|
||||
struct sockaddr_storage from;
|
||||
struct ping_host_struct *recv_ping_host;
|
||||
struct ping_host_struct *recv_ping_host = NULL;
|
||||
struct fast_ping_packet *packet = NULL;
|
||||
socklen_t from_len = sizeof(from);
|
||||
uint32_t addrkey;
|
||||
uint32_t addrkey = 0;
|
||||
struct timeval tvresult = *now;
|
||||
struct timeval *tvsend = NULL;
|
||||
unsigned int sid;
|
||||
unsigned int seq;
|
||||
unsigned int cookie;
|
||||
unsigned int sid = 0;
|
||||
unsigned int seq = 0;
|
||||
unsigned int cookie = 0;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
char ans_data[4096];
|
||||
@@ -1315,7 +1355,7 @@ static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct ti
|
||||
if (recv_ping_host->ping_callback) {
|
||||
recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr,
|
||||
recv_ping_host->addr_len, recv_ping_host->seq, recv_ping_host->ttl, &tvresult,
|
||||
recv_ping_host->userptr);
|
||||
ping_host->error, recv_ping_host->userptr);
|
||||
}
|
||||
|
||||
recv_ping_host->send = 0;
|
||||
@@ -1349,7 +1389,8 @@ static int _fast_ping_process_tcp(struct ping_host_struct *ping_host, struct epo
|
||||
tv_sub(&tvresult, tvsend);
|
||||
if (ping_host->ping_callback) {
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr,
|
||||
ping_host->addr_len, ping_host->seq, ping_host->ttl, &tvresult, ping_host->userptr);
|
||||
ping_host->addr_len, ping_host->seq, ping_host->ttl, &tvresult, ping_host->error,
|
||||
ping_host->userptr);
|
||||
}
|
||||
|
||||
ping_host->send = 0;
|
||||
@@ -1368,20 +1409,20 @@ errout:
|
||||
|
||||
static int _fast_ping_process_udp(struct ping_host_struct *ping_host, struct timeval *now)
|
||||
{
|
||||
int len;
|
||||
ssize_t len = 0;
|
||||
u_char inpacket[ICMP_INPACKET_SIZE];
|
||||
struct sockaddr_storage from;
|
||||
struct ping_host_struct *recv_ping_host;
|
||||
struct ping_host_struct *recv_ping_host = NULL;
|
||||
struct ping_dns_head *dns_head = NULL;
|
||||
socklen_t from_len = sizeof(from);
|
||||
uint32_t addrkey;
|
||||
uint32_t addrkey = 0;
|
||||
struct timeval tvresult = *now;
|
||||
struct timeval *tvsend = NULL;
|
||||
unsigned int sid;
|
||||
unsigned int sid = 0;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
char ans_data[4096];
|
||||
struct cmsghdr *cmsg;
|
||||
struct cmsghdr *cmsg = NULL;
|
||||
int ttl = 0;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
@@ -1416,7 +1457,7 @@ static int _fast_ping_process_udp(struct ping_host_struct *ping_host, struct tim
|
||||
|
||||
from_len = msg.msg_namelen;
|
||||
dns_head = (struct ping_dns_head *)inpacket;
|
||||
if (len < sizeof(*dns_head)) {
|
||||
if (len < (ssize_t)sizeof(*dns_head)) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -1445,7 +1486,7 @@ static int _fast_ping_process_udp(struct ping_host_struct *ping_host, struct tim
|
||||
if (recv_ping_host->ping_callback) {
|
||||
recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr,
|
||||
recv_ping_host->addr_len, recv_ping_host->seq, recv_ping_host->ttl, &tvresult,
|
||||
recv_ping_host->userptr);
|
||||
ping_host->error, recv_ping_host->userptr);
|
||||
}
|
||||
|
||||
recv_ping_host->send = 0;
|
||||
@@ -1491,7 +1532,7 @@ static void _fast_ping_remove_all(void)
|
||||
struct ping_host_struct *ping_host = NULL;
|
||||
struct ping_host_struct *ping_host_tmp = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
int i;
|
||||
unsigned long i = 0;
|
||||
|
||||
LIST_HEAD(remove_list);
|
||||
|
||||
@@ -1513,11 +1554,11 @@ static void _fast_ping_period_run(void)
|
||||
struct ping_host_struct *ping_host = NULL;
|
||||
struct ping_host_struct *ping_host_tmp = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
int i = 0;
|
||||
unsigned long i = 0;
|
||||
struct timeval now;
|
||||
struct timezone tz;
|
||||
struct timeval interval;
|
||||
int64_t millisecond;
|
||||
int64_t millisecond = 0;
|
||||
gettimeofday(&now, &tz);
|
||||
LIST_HEAD(action);
|
||||
|
||||
@@ -1553,7 +1594,7 @@ static void _fast_ping_period_run(void)
|
||||
millisecond = interval.tv_sec * 1000 + interval.tv_usec / 1000;
|
||||
if (millisecond >= ping_host->timeout && ping_host->send == 1) {
|
||||
ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr,
|
||||
ping_host->addr_len, ping_host->seq, ping_host->ttl, &interval,
|
||||
ping_host->addr_len, ping_host->seq, ping_host->ttl, &interval, ping_host->error,
|
||||
ping_host->userptr);
|
||||
ping_host->send = 0;
|
||||
}
|
||||
@@ -1583,8 +1624,8 @@ static void _fast_ping_period_run(void)
|
||||
static void *_fast_ping_work(void *arg)
|
||||
{
|
||||
struct epoll_event events[PING_MAX_EVENTS + 1];
|
||||
int num;
|
||||
int i;
|
||||
int num = 0;
|
||||
int i = 0;
|
||||
unsigned long now = {0};
|
||||
struct timeval tvnow = {0};
|
||||
int sleep = 100;
|
||||
@@ -1594,7 +1635,7 @@ static void *_fast_ping_work(void *arg)
|
||||
sleep_time = sleep;
|
||||
now = get_tick_count() - sleep;
|
||||
expect_time = now + sleep;
|
||||
while (ping.run) {
|
||||
while (atomic_read(&ping.run)) {
|
||||
now = get_tick_count();
|
||||
if (now >= expect_time) {
|
||||
_fast_ping_period_run();
|
||||
@@ -1634,7 +1675,7 @@ int fast_ping_init(void)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
int epollfd = -1;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
bool_print_log = 1;
|
||||
|
||||
if (ping.epoll_fd > 0) {
|
||||
@@ -1654,8 +1695,9 @@ int fast_ping_init(void)
|
||||
pthread_mutex_init(&ping.lock, NULL);
|
||||
hash_init(ping.addrmap);
|
||||
ping.epoll_fd = epollfd;
|
||||
ping.no_unprivileged_ping = !has_unprivileged_ping();
|
||||
ping.ident = (getpid() & 0XFFFF);
|
||||
ping.run = 1;
|
||||
atomic_set(&ping.run, 1);
|
||||
ret = pthread_create(&ping.tid, &attr, _fast_ping_work, NULL);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "create ping work thread failed, %s\n", strerror(errno));
|
||||
@@ -1664,10 +1706,11 @@ int fast_ping_init(void)
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (ping.tid > 0) {
|
||||
if (ping.tid) {
|
||||
void *retval = NULL;
|
||||
ping.run = 0;
|
||||
atomic_set(&ping.run, 0);
|
||||
pthread_join(ping.tid, &retval);
|
||||
ping.tid = 0;
|
||||
}
|
||||
|
||||
if (epollfd) {
|
||||
@@ -1705,10 +1748,11 @@ static void _fast_ping_close_fds(void)
|
||||
|
||||
void fast_ping_exit(void)
|
||||
{
|
||||
if (ping.tid > 0) {
|
||||
if (ping.tid) {
|
||||
void *ret = NULL;
|
||||
ping.run = 0;
|
||||
atomic_set(&ping.run, 0);
|
||||
pthread_join(ping.tid, &ret);
|
||||
ping.tid = 0;
|
||||
}
|
||||
|
||||
_fast_ping_close_fds();
|
||||
|
||||
@@ -34,13 +34,14 @@ typedef enum {
|
||||
typedef enum {
|
||||
PING_RESULT_RESPONSE = 1,
|
||||
PING_RESULT_TIMEOUT = 2,
|
||||
PING_RESULT_END = 3,
|
||||
PING_RESULT_ERROR = 3,
|
||||
PING_RESULT_END = 4,
|
||||
} FAST_PING_RESULT;
|
||||
|
||||
struct ping_host_struct;
|
||||
typedef void (*fast_ping_result)(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result,
|
||||
struct sockaddr *addr, socklen_t addr_len, int seqno, int ttl, struct timeval *tv,
|
||||
void *userptr);
|
||||
int error, void *userptr);
|
||||
|
||||
/* start ping */
|
||||
struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int count, int interval, int timeout,
|
||||
|
||||
@@ -108,7 +108,7 @@ struct http_head_fields *http_head_first_fields(struct http_head *http_head)
|
||||
|
||||
const char *http_head_get_fields_value(struct http_head *http_head, const char *name)
|
||||
{
|
||||
unsigned long key;
|
||||
uint32_t key;
|
||||
struct http_head_fields *filed;
|
||||
|
||||
key = hash_string(name);
|
||||
@@ -193,7 +193,7 @@ int http_head_get_data_len(struct http_head *http_head)
|
||||
|
||||
static int _http_head_add_fields(struct http_head *http_head, char *name, char *value)
|
||||
{
|
||||
unsigned long key = 0;
|
||||
uint32_t key = 0;
|
||||
struct http_head_fields *fields = NULL;
|
||||
fields = malloc(sizeof(*fields));
|
||||
if (fields == NULL) {
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
#ifndef _GENERIC_ATOMIC_H
|
||||
#define _GENERIC_ATOMIC_H
|
||||
|
||||
#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
|
||||
|
||||
#define READ_ONCE(x) \
|
||||
({ typeof(x) ___x = ACCESS_ONCE(x); ___x; })
|
||||
|
||||
/**
|
||||
* Atomic type.
|
||||
*/
|
||||
@@ -35,14 +40,20 @@ typedef struct {
|
||||
*
|
||||
* Atomically reads the value of @v.
|
||||
*/
|
||||
#define atomic_read(v) ((v)->counter)
|
||||
static inline int atomic_read(const atomic_t *v)
|
||||
{
|
||||
return READ_ONCE((v)->counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set atomic variable
|
||||
* @param v pointer of type atomic_t
|
||||
* @param i required value
|
||||
*/
|
||||
#define atomic_set(v,i) (((v)->counter) = (i))
|
||||
static inline void atomic_set(atomic_t *v, int i)
|
||||
{
|
||||
v->counter = i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to the atomic variable
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#define CONF_RET_ERR -1
|
||||
#define CONF_RET_WARN -2
|
||||
#define CONF_RET_NOENT -3
|
||||
#define CONF_RET_BADCONF -4
|
||||
|
||||
struct config_item {
|
||||
const char *item;
|
||||
@@ -63,6 +64,16 @@ struct config_item_size {
|
||||
size_t max;
|
||||
};
|
||||
|
||||
struct config_enum_list {
|
||||
char *name;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct config_enum {
|
||||
int *data;
|
||||
struct config_enum_list *list;
|
||||
};
|
||||
|
||||
#define CONF_INT(key, value, min_value, max_value) \
|
||||
{ \
|
||||
key, conf_int, &(struct config_item_int) \
|
||||
@@ -91,6 +102,15 @@ struct config_item_size {
|
||||
.data = value, .min = min_value, .max = max_value \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CONF_ENUM(key, value, enum) \
|
||||
{ \
|
||||
key, conf_enum, &(struct config_enum) \
|
||||
{ \
|
||||
.data = (int *)value, .list = (struct config_enum_list *)enum \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
* func: int (*func)(void *data, int argc, char *argv[]);
|
||||
*/
|
||||
@@ -117,6 +137,8 @@ extern int conf_yesno(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
extern int conf_size(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
extern int conf_enum(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
/*
|
||||
* Example:
|
||||
* int num = 0;
|
||||
@@ -138,4 +160,6 @@ void load_exit(void);
|
||||
|
||||
const char *conf_get_conf_file(void);
|
||||
|
||||
const char *conf_get_conf_fullpath(const char *path, char *fullpath, size_t path_len);
|
||||
|
||||
#endif // !_GENERIC_CONF_H
|
||||
|
||||
@@ -219,14 +219,16 @@ static inline uint32_t hash32_ptr(const void *ptr)
|
||||
return (uint32_t)val;
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
hash_string(const char *str)
|
||||
static inline uint32_t hash_string(const char *s)
|
||||
{
|
||||
unsigned long v = 0;
|
||||
const char *c;
|
||||
for (c = str; *c; )
|
||||
v = (((v << 1) + (v >> 14)) ^ (*c++)) & 0x3fff;
|
||||
return(v);
|
||||
uint32_t h = 0;
|
||||
|
||||
while (*s) {
|
||||
h = h * 31 + *s;
|
||||
s++;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
#endif /* _GENERIC_HASH_H */
|
||||
|
||||
@@ -24,6 +24,15 @@
|
||||
|
||||
static inline char *safe_strncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
if (src == NULL) {
|
||||
dest[0] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if __GNUC__ > 7
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstringop-truncation"
|
||||
|
||||
@@ -1016,7 +1016,7 @@ static void art_copy_key(art_leaf *leaf, unsigned char *key, int *key_len)
|
||||
return;
|
||||
}
|
||||
|
||||
len = leaf->key_len > *key_len ? *key_len : leaf->key_len;
|
||||
len = (int)leaf->key_len > *key_len ? *key_len : (int)leaf->key_len;
|
||||
memcpy(key, leaf->key, len);
|
||||
*key_len = len;
|
||||
}
|
||||
|
||||
@@ -18,16 +18,46 @@
|
||||
|
||||
#include "conf.h"
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <linux/limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char *currrent_conf_file = NULL;
|
||||
static const char *current_conf_file = NULL;
|
||||
|
||||
const char *conf_get_conf_file(void)
|
||||
{
|
||||
return currrent_conf_file;
|
||||
return current_conf_file;
|
||||
}
|
||||
|
||||
const char *conf_get_conf_fullpath(const char *path, char *fullpath, size_t path_len)
|
||||
{
|
||||
char file_path_dir[PATH_MAX];
|
||||
|
||||
if (path_len < 1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (path[0] == '/') {
|
||||
strncpy(fullpath, path, path_len);
|
||||
return fullpath;
|
||||
}
|
||||
|
||||
strncpy(file_path_dir, conf_get_conf_file(), PATH_MAX - 1);
|
||||
file_path_dir[PATH_MAX - 1] = 0;
|
||||
dirname(file_path_dir);
|
||||
if (file_path_dir[0] == '\0') {
|
||||
strncpy(fullpath, path, path_len);
|
||||
return fullpath;
|
||||
}
|
||||
|
||||
if (snprintf(fullpath, PATH_MAX, "%s/%s", file_path_dir, path) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fullpath;
|
||||
}
|
||||
|
||||
int conf_custom(const char *item, void *data, int argc, char *argv[])
|
||||
@@ -97,7 +127,6 @@ int conf_yesno(const char *item, void *data, int argc, char *argv[])
|
||||
|
||||
int conf_size(const char *item, void *data, int argc, char *argv[])
|
||||
{
|
||||
/* read dns cache size */
|
||||
int base = 1;
|
||||
size_t size = 0;
|
||||
int num = 0;
|
||||
@@ -129,7 +158,32 @@ int conf_size(const char *item, void *data, int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
void conf_getopt_reset(void)
|
||||
int conf_enum(const char *item, void *data, int argc, char *argv[])
|
||||
{
|
||||
struct config_enum *item_enum = data;
|
||||
char *enum_name = argv[1];
|
||||
int i = 0;
|
||||
|
||||
if (argc <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; item_enum->list[i].name != NULL; i++) {
|
||||
if (strcmp(enum_name, item_enum->list[i].name) == 0) {
|
||||
*(item_enum->data) = item_enum->list[i].id;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Not found config value '%s', valid value is:\n", enum_name);
|
||||
for (i = 0; item_enum->list[i].name != NULL; i++) {
|
||||
printf(" %s\n", item_enum->list[i].name);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void conf_getopt_reset(void)
|
||||
{
|
||||
static struct option long_options[] = {{"-", 0, 0, 0}, {0, 0, 0, 0}};
|
||||
int argc = 2;
|
||||
@@ -144,7 +198,7 @@ void conf_getopt_reset(void)
|
||||
optopt = 0;
|
||||
}
|
||||
|
||||
int conf_parse_args(char *key, char *value, int *argc, char **argv)
|
||||
static int conf_parse_args(char *key, char *value, int *argc, char **argv)
|
||||
{
|
||||
char *start = NULL;
|
||||
char *ptr = value;
|
||||
@@ -205,12 +259,9 @@ int conf_parse_args(char *key, char *value, int *argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void load_exit(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
void load_exit(void) {}
|
||||
|
||||
int load_conf_printf(const char *file, int lineno, int ret)
|
||||
static int load_conf_printf(const char *file, int lineno, int ret)
|
||||
{
|
||||
if (ret != CONF_RET_OK) {
|
||||
printf("process config file '%s' failed at line %d.", file, lineno);
|
||||
@@ -224,15 +275,15 @@ int load_conf_printf(const char *file, int lineno, int ret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_conf_file(const char *file, struct config_item *items, conf_error_handler handler)
|
||||
static int load_conf_file(const char *file, struct config_item *items, conf_error_handler handler)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char line[MAX_LINE_LEN];
|
||||
char key[MAX_KEY_LEN];
|
||||
char value[MAX_LINE_LEN];
|
||||
int filed_num = 0;
|
||||
int i;
|
||||
int argc;
|
||||
int i = 0;
|
||||
int argc = 0;
|
||||
char *argv[1024];
|
||||
int ret = 0;
|
||||
int call_ret = 0;
|
||||
@@ -262,6 +313,7 @@ int load_conf_file(const char *file, struct config_item *items, conf_error_handl
|
||||
|
||||
/* if field format is not key = value, error */
|
||||
if (filed_num != 2) {
|
||||
handler(file, line_no, CONF_RET_BADCONF);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -281,7 +333,7 @@ int load_conf_file(const char *file, struct config_item *items, conf_error_handl
|
||||
|
||||
conf_getopt_reset();
|
||||
/* call item function */
|
||||
currrent_conf_file = file;
|
||||
current_conf_file = file;
|
||||
call_ret = items[i].item_func(items[i].item, items[i].data, argc, argv);
|
||||
ret = handler(file, line_no, call_ret);
|
||||
if (ret != 0) {
|
||||
|
||||
@@ -87,7 +87,7 @@ comp_with_mask(unsigned char *addr, unsigned char *dest, unsigned int mask)
|
||||
{
|
||||
if (memcmp(addr, dest, mask / 8) == 0) {
|
||||
unsigned int n = mask / 8;
|
||||
unsigned int m = ((~0) << (8 - (mask % 8)));
|
||||
unsigned int m = ((unsigned int)(~0) << (8 - (mask % 8)));
|
||||
|
||||
if (mask % 8 == 0 || (addr[n] & m) == (dest[n] & m))
|
||||
return (1);
|
||||
@@ -549,7 +549,7 @@ sanitise_mask(unsigned char *addr, unsigned int masklen, unsigned int maskbits)
|
||||
unsigned int j = masklen % 8;
|
||||
|
||||
if (j != 0) {
|
||||
addr[i] &= (~0) << (8 - j);
|
||||
addr[i] &= (unsigned int)(~0) << (8 - j);
|
||||
i++;
|
||||
}
|
||||
for (; i < maskbits / 8; i++)
|
||||
|
||||
175
src/smartdns.c
175
src/smartdns.c
@@ -31,12 +31,15 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libgen.h>
|
||||
#include <linux/capability.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <pwd.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <ucontext.h>
|
||||
@@ -49,6 +52,78 @@
|
||||
|
||||
static int verbose_screen;
|
||||
|
||||
int capget(struct __user_cap_header_struct *header, struct __user_cap_data_struct *cap);
|
||||
int capset(struct __user_cap_header_struct *header, struct __user_cap_data_struct *cap);
|
||||
|
||||
static int get_uid_gid(int *uid, int *gid)
|
||||
{
|
||||
struct passwd *result = NULL;
|
||||
struct passwd pwd;
|
||||
char *buf = NULL;
|
||||
ssize_t bufsize = 0;
|
||||
int ret = -1;
|
||||
|
||||
if (dns_conf_user[0] == '\0') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
if (bufsize == -1) {
|
||||
bufsize = 1024 * 16;
|
||||
}
|
||||
|
||||
buf = malloc(bufsize);
|
||||
if (buf == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = getpwnam_r(dns_conf_user, &pwd, buf, bufsize, &result);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
*uid = result->pw_uid;
|
||||
*gid = result->pw_gid;
|
||||
|
||||
out:
|
||||
if (buf) {
|
||||
free(buf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int drop_root_privilege(void)
|
||||
{
|
||||
struct __user_cap_data_struct cap;
|
||||
struct __user_cap_header_struct header;
|
||||
header.version = _LINUX_CAPABILITY_VERSION;
|
||||
header.pid = 0;
|
||||
int uid = 0;
|
||||
int gid = 0;
|
||||
int unused __attribute__((unused)) = 0;
|
||||
|
||||
if (get_uid_gid(&uid, &gid) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (capget(&header, &cap) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
|
||||
cap.effective |= (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN);
|
||||
cap.permitted |= (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN);
|
||||
unused = setgid(gid);
|
||||
unused = setuid(uid);
|
||||
if (capset(&header, &cap) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _help(void)
|
||||
{
|
||||
/* clang-format off */
|
||||
@@ -57,7 +132,7 @@ static void _help(void)
|
||||
"Start smartdns server.\n"
|
||||
" -f run forground.\n"
|
||||
" -c [conf] config file.\n"
|
||||
" -p [pid] pid file path\n"
|
||||
" -p [pid] pid file path, '-' means don't create pid file.\n"
|
||||
" -S ignore segment fault signal.\n"
|
||||
" -x verbose screen.\n"
|
||||
" -v dispaly version.\n"
|
||||
@@ -112,7 +187,7 @@ static int _smartdns_load_from_resolv(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(key, "nameserver", MAX_KEY_LEN) != 0) {
|
||||
if (strncmp(key, "nameserver", MAX_KEY_LEN - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -138,14 +213,14 @@ static int _smartdns_load_from_resolv(void)
|
||||
|
||||
static int _smartdns_add_servers(void)
|
||||
{
|
||||
int i = 0;
|
||||
unsigned long i = 0;
|
||||
int j = 0;
|
||||
int ret = 0;
|
||||
struct dns_server_groups *group = NULL;
|
||||
struct dns_servers *server = NULL;
|
||||
struct client_dns_server_flags flags;
|
||||
|
||||
for (i = 0; i < dns_conf_server_num; i++) {
|
||||
for (i = 0; i < (unsigned int)dns_conf_server_num; i++) {
|
||||
memset(&flags, 0, sizeof(flags));
|
||||
switch (dns_conf_servers[i].type) {
|
||||
case DNS_SERVER_UDP: {
|
||||
@@ -248,15 +323,22 @@ static int _smartdns_destroy_ssl(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _smartdns_init(void)
|
||||
static const char *_smartdns_log_path(void)
|
||||
{
|
||||
int ret;
|
||||
char *logfile = SMARTDNS_LOG_FILE;
|
||||
|
||||
if (dns_conf_log_file[0] != 0) {
|
||||
logfile = dns_conf_log_file;
|
||||
}
|
||||
|
||||
return logfile;
|
||||
}
|
||||
|
||||
static int _smartdns_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
const char *logfile = _smartdns_log_path();
|
||||
|
||||
ret = tlog_init(logfile, dns_conf_log_size, dns_conf_log_num, 0, 0);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "start tlog failed.\n");
|
||||
@@ -266,7 +348,7 @@ static int _smartdns_init(void)
|
||||
tlog_setlogscreen(verbose_screen);
|
||||
tlog_setlevel(dns_conf_log_level);
|
||||
|
||||
tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <pymumu@gmail.com>, build:%s %s)", __DATE__,
|
||||
tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <pymumu@gmail.com>, build: %s %s)", __DATE__,
|
||||
__TIME__);
|
||||
|
||||
if (_smartdns_init_ssl() != 0) {
|
||||
@@ -322,9 +404,10 @@ static int _smartdns_run(void)
|
||||
|
||||
static void _smartdns_exit(void)
|
||||
{
|
||||
dns_server_exit();
|
||||
tlog(TLOG_INFO, "smartdns exit...");
|
||||
dns_client_exit();
|
||||
fast_ping_exit();
|
||||
dns_server_exit();
|
||||
_smartdns_destroy_ssl();
|
||||
tlog_exit();
|
||||
dns_server_load_exit();
|
||||
@@ -332,6 +415,7 @@ static void _smartdns_exit(void)
|
||||
|
||||
static void _sig_exit(int signo)
|
||||
{
|
||||
tlog(TLOG_INFO, "stop smartdns by signal %d", signo);
|
||||
dns_server_stop();
|
||||
}
|
||||
|
||||
@@ -374,7 +458,8 @@ static int sig_num = sizeof(sig_list) / sizeof(int);
|
||||
|
||||
static void _reg_signal(void)
|
||||
{
|
||||
struct sigaction act, old;
|
||||
struct sigaction act;
|
||||
struct sigaction old;
|
||||
int i = 0;
|
||||
act.sa_sigaction = _sig_error_exit;
|
||||
sigemptyset(&act.sa_mask);
|
||||
@@ -385,19 +470,61 @@ static void _reg_signal(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int _smartdns_create_logdir(void)
|
||||
{
|
||||
int uid = 0;
|
||||
int gid = 0;
|
||||
char logdir[PATH_MAX] = {0};
|
||||
safe_strncpy(logdir, _smartdns_log_path(), PATH_MAX);
|
||||
dirname(logdir);
|
||||
|
||||
if (access(logdir, F_OK) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mkdir(logdir, 0750) != 0) {
|
||||
if (errno == EEXIST) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unused __attribute__((unused)) = 0;
|
||||
|
||||
if (get_uid_gid(&uid, &gid) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
chown(logdir, uid, gid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _smartdns_init_pre(void)
|
||||
{
|
||||
_smartdns_create_logdir();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int is_forground = 0;
|
||||
int opt;
|
||||
int opt = 0;
|
||||
char config_file[MAX_LINE_LEN];
|
||||
char pid_file[MAX_LINE_LEN];
|
||||
int signal_ignore = 0;
|
||||
sigset_t empty_sigblock;
|
||||
|
||||
safe_strncpy(config_file, SMARTDNS_CONF_FILE, MAX_LINE_LEN);
|
||||
safe_strncpy(pid_file, SMARTDNS_PID_FILE, MAX_LINE_LEN);
|
||||
|
||||
while ((opt = getopt(argc, argv, "fhc:p:Svx")) != -1) {
|
||||
/* patch for Asus router: unblock all signal*/
|
||||
sigemptyset(&empty_sigblock);
|
||||
sigprocmask(SIG_SETMASK, &empty_sigblock, NULL);
|
||||
|
||||
while ((opt = getopt(argc, argv, "fhc:p:SvxN:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
is_forground = 1;
|
||||
@@ -418,12 +545,21 @@ int main(int argc, char *argv[])
|
||||
_show_version();
|
||||
return 0;
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
case 'N':
|
||||
return dns_packet_debug(optarg);
|
||||
#endif
|
||||
case 'h':
|
||||
_help();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dns_server_load_conf(config_file) != 0) {
|
||||
fprintf(stderr, "load config failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (is_forground == 0) {
|
||||
if (daemon(0, 0) < 0) {
|
||||
fprintf(stderr, "run daemon process failed, %s\n", strerror(errno));
|
||||
@@ -435,24 +571,27 @@ int main(int argc, char *argv[])
|
||||
_reg_signal();
|
||||
}
|
||||
|
||||
if (create_pid_file(pid_file) != 0) {
|
||||
if (strncmp(pid_file, "-", 2) != 0 && create_pid_file(pid_file) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
if (dns_server_load_conf(config_file) != 0) {
|
||||
fprintf(stderr, "load config failed.\n");
|
||||
goto errout;
|
||||
signal(SIGINT, _sig_exit);
|
||||
signal(SIGTERM, _sig_exit);
|
||||
|
||||
if (_smartdns_init_pre() != 0) {
|
||||
fprintf(stderr, "init failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
drop_root_privilege();
|
||||
|
||||
ret = _smartdns_init();
|
||||
if (ret != 0) {
|
||||
usleep(100000);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
signal(SIGINT, _sig_exit);
|
||||
signal(SIGTERM, _sig_exit);
|
||||
atexit(_smartdns_exit);
|
||||
|
||||
return _smartdns_run();
|
||||
|
||||
196
src/tlog.c
196
src/tlog.c
@@ -19,6 +19,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
@@ -45,6 +46,14 @@
|
||||
|
||||
#define TLOG_SEGMENT_MAGIC 0xFF446154
|
||||
|
||||
struct linux_dirent64 {
|
||||
unsigned long long d_ino;
|
||||
long long d_off;
|
||||
unsigned short d_reclen;
|
||||
unsigned char d_type;
|
||||
char d_name[256];
|
||||
};
|
||||
|
||||
struct tlog_log {
|
||||
char *buff;
|
||||
int buffsize;
|
||||
@@ -70,8 +79,9 @@ struct tlog_log {
|
||||
int zip_pid;
|
||||
int multi_log;
|
||||
int logscreen;
|
||||
int no_write_log;
|
||||
int segment_log;
|
||||
unsigned int max_line_size;
|
||||
int max_line_size;
|
||||
|
||||
tlog_output_func output_func;
|
||||
void *private_data;
|
||||
@@ -207,7 +217,6 @@ static int _tlog_mkdir(const char *path)
|
||||
}
|
||||
|
||||
if (mkdir(path_c, 0750) != 0) {
|
||||
fprintf(stderr, "create directory %s failed, %s\n", path_c, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -317,7 +326,7 @@ int tlog_localtime(struct tlog_time *tm)
|
||||
return _tlog_gettime(tm);
|
||||
}
|
||||
|
||||
tlog_log *tlog_get_root()
|
||||
tlog_log *tlog_get_root(void)
|
||||
{
|
||||
return tlog.root;
|
||||
}
|
||||
@@ -504,9 +513,12 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
|
||||
if (len <= 0) {
|
||||
return -1;
|
||||
} else if (len >= log->max_line_size) {
|
||||
strncpy(buff, "[LOG TOO LONG, DISCARD]\n", sizeof(buff));
|
||||
buff[sizeof(buff) - 1] = '\0';
|
||||
len = strnlen(buff, sizeof(buff));
|
||||
len = log->max_line_size;
|
||||
buff[len - 1] = '\0';
|
||||
buff[len - 2] = '\n';
|
||||
buff[len - 3] = '.';
|
||||
buff[len - 4] = '.';
|
||||
buff[len - 5] = '.';
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&tlog.lock);
|
||||
@@ -919,47 +931,67 @@ static void _tlog_close_all_fd_by_res(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int _tlog_str_to_int(const char *str)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
while (*str >= '0' && *str <= '9') {
|
||||
num = num * 10 + (*str - '0');
|
||||
++str;
|
||||
}
|
||||
|
||||
if (*str) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static void _tlog_close_all_fd(void)
|
||||
{
|
||||
char path_name[PATH_MAX];
|
||||
DIR *dir = NULL;
|
||||
struct dirent *ent;
|
||||
#if defined(__linux__)
|
||||
int dir_fd = -1;
|
||||
|
||||
snprintf(path_name, sizeof(path_name), "/proc/self/fd/");
|
||||
dir = opendir(path_name);
|
||||
if (dir == NULL) {
|
||||
dir_fd = open("/proc/self/fd/", O_RDONLY | O_DIRECTORY);
|
||||
if (dir_fd < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
dir_fd = dirfd(dir);
|
||||
char buffer[sizeof(struct linux_dirent64)];
|
||||
int bytes;
|
||||
while ((bytes = syscall(SYS_getdents64, dir_fd,
|
||||
(struct linux_dirent64 *)buffer,
|
||||
sizeof(buffer)))
|
||||
> 0) {
|
||||
struct linux_dirent64 *entry;
|
||||
int offset;
|
||||
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
int fd = atoi(ent->d_name);
|
||||
if (fd < 0 || dir_fd == fd) {
|
||||
continue;
|
||||
}
|
||||
switch (fd) {
|
||||
case STDIN_FILENO:
|
||||
case STDOUT_FILENO:
|
||||
case STDERR_FILENO:
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (offset = 0; offset < bytes; offset += entry->d_reclen) {
|
||||
int fd;
|
||||
entry = (struct linux_dirent64 *)(buffer + offset);
|
||||
if ((fd = _tlog_str_to_int(entry->d_name)) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
if (fd == dir_fd || fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) {
|
||||
continue;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
close(dir_fd);
|
||||
|
||||
if (bytes < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return;
|
||||
errout:
|
||||
if (dir) {
|
||||
closedir(dir);
|
||||
if (dir_fd > 0) {
|
||||
close(dir_fd);
|
||||
}
|
||||
|
||||
#endif
|
||||
_tlog_close_all_fd_by_res();
|
||||
return;
|
||||
}
|
||||
@@ -1059,7 +1091,7 @@ static int _tlog_archive_log(struct tlog_log *log)
|
||||
}
|
||||
}
|
||||
|
||||
void _tlog_get_log_name_dir(struct tlog_log *log)
|
||||
static void _tlog_get_log_name_dir(struct tlog_log *log)
|
||||
{
|
||||
char log_file[PATH_MAX];
|
||||
if (log->fd > 0) {
|
||||
@@ -1098,6 +1130,10 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
unused = write(STDOUT_FILENO, buff, bufflen);
|
||||
}
|
||||
|
||||
if (log->no_write_log) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if log file size exceeds threshold, start to compress */
|
||||
if (log->multi_log && log->fd > 0) {
|
||||
log->filesize = lseek(log->fd, 0, SEEK_END);
|
||||
@@ -1128,7 +1164,15 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
|
||||
char logfile[PATH_MAX * 2];
|
||||
if (_tlog_mkdir(log->logdir) != 0) {
|
||||
fprintf(stderr, "create log dir %s failed.\n", log->logdir);
|
||||
if (print_errmsg == 0) {
|
||||
return -1;
|
||||
}
|
||||
print_errmsg = 0;
|
||||
fprintf(stderr, "create log dir %s failed, %s\n", log->logdir, strerror(errno));
|
||||
if (errno == EACCES && log->logscreen == 0) {
|
||||
fprintf(stderr, "no permission to write log file, output log to console\n");
|
||||
tlog_logscreen_only(log, 1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
snprintf(logfile, sizeof(logfile), "%s/%s", log->logdir, log->logname);
|
||||
@@ -1395,6 +1439,35 @@ static int _tlog_root_write_log(struct tlog_log *log, const char *buff, int buff
|
||||
return tlog.output_func(&empty_info.info, buff, bufflen, tlog_get_private(log));
|
||||
}
|
||||
|
||||
static void tlog_wait_zip_fini(void)
|
||||
{
|
||||
tlog_log *next;
|
||||
if (tlog.root == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
int wait_zip = 1;
|
||||
int time_out = 0;
|
||||
while (wait_zip) {
|
||||
wait_zip = 0;
|
||||
time_out++;
|
||||
next = tlog.log;
|
||||
while (next) {
|
||||
if (next->zip_pid > 0 && wait_zip == 0) {
|
||||
wait_zip = 1;
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
if (kill(next->zip_pid, 0) != 0 || time_out >= 5000) {
|
||||
next->zip_pid = -1;
|
||||
}
|
||||
next = next->next;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void *_tlog_work(void *arg)
|
||||
{
|
||||
int log_len = 0;
|
||||
@@ -1408,6 +1481,9 @@ static void *_tlog_work(void *arg)
|
||||
|
||||
unused = arg;
|
||||
|
||||
// for child process
|
||||
tlog_wait_zip_fini();
|
||||
|
||||
while (1) {
|
||||
log_len = 0;
|
||||
log_extlen = 0;
|
||||
@@ -1510,11 +1586,26 @@ static void _tlog_log_setlogscreen(struct tlog_log *log, int enable)
|
||||
log->logscreen = (enable != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void _tlog_log_setlogscreen_only(struct tlog_log *log, int enable)
|
||||
{
|
||||
if (log == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
log->logscreen = (enable != 0) ? 1 : 0;
|
||||
log->no_write_log = (enable != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
void tlog_setlogscreen(int enable)
|
||||
{
|
||||
_tlog_log_setlogscreen(tlog.root, enable);
|
||||
}
|
||||
|
||||
void tlog_setlogscreen_only(int enable)
|
||||
{
|
||||
_tlog_log_setlogscreen_only(tlog.root, enable);
|
||||
}
|
||||
|
||||
int tlog_write_log(char *buff, int bufflen)
|
||||
{
|
||||
if (unlikely(tlog.root == NULL)) {
|
||||
@@ -1533,6 +1624,15 @@ void tlog_logscreen(tlog_log *log, int enable)
|
||||
_tlog_log_setlogscreen(log, enable);
|
||||
}
|
||||
|
||||
void tlog_logscreen_only(tlog_log *log, int enable)
|
||||
{
|
||||
if (log == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
_tlog_log_setlogscreen_only(log, enable);
|
||||
}
|
||||
|
||||
int tlog_reg_output_func(tlog_log *log, tlog_output_func output)
|
||||
{
|
||||
if (log == NULL) {
|
||||
@@ -1680,6 +1780,12 @@ static void tlog_fork_prepare(void)
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&tlog.lock);
|
||||
tlog_log *next;
|
||||
next = tlog.log;
|
||||
while (next) {
|
||||
next->multi_log = 1;
|
||||
next = next->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void tlog_fork_parent(void)
|
||||
@@ -1699,6 +1805,16 @@ static void tlog_fork_child(void)
|
||||
return;
|
||||
}
|
||||
|
||||
next = tlog.log;
|
||||
while (next) {
|
||||
next->start = 0;
|
||||
next->end = 0;
|
||||
next->ext_end = 0;
|
||||
next->dropped = 0;
|
||||
next->filesize = 0;
|
||||
next = next->next;
|
||||
}
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
int ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL);
|
||||
if (ret != 0) {
|
||||
@@ -1750,27 +1866,29 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
|
||||
}
|
||||
tlog_reg_output_func(log, _tlog_root_write_log);
|
||||
|
||||
tlog.root = log;
|
||||
ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "create tlog work thread failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog.root = log;
|
||||
if (flag & TLOG_SUPPORT_FORK) {
|
||||
pthread_atfork(&tlog_fork_prepare, &tlog_fork_parent, &tlog_fork_child);
|
||||
}
|
||||
return 0;
|
||||
errout:
|
||||
if (tlog.tid > 0) {
|
||||
if (tlog.tid) {
|
||||
void *retval = NULL;
|
||||
tlog.run = 0;
|
||||
pthread_join(tlog.tid, &retval);
|
||||
tlog.tid = 0;
|
||||
}
|
||||
|
||||
pthread_cond_destroy(&tlog.cond);
|
||||
pthread_mutex_destroy(&tlog.lock);
|
||||
tlog.run = 0;
|
||||
tlog.root = NULL;
|
||||
|
||||
_tlog_close(log, 1);
|
||||
|
||||
@@ -1779,13 +1897,14 @@ errout:
|
||||
|
||||
void tlog_exit(void)
|
||||
{
|
||||
if (tlog.tid > 0) {
|
||||
if (tlog.tid) {
|
||||
void *ret = NULL;
|
||||
tlog.run = 0;
|
||||
pthread_mutex_lock(&tlog.lock);
|
||||
pthread_cond_signal(&tlog.cond);
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
pthread_join(tlog.tid, &ret);
|
||||
tlog.tid = 0;
|
||||
}
|
||||
|
||||
tlog.root = NULL;
|
||||
@@ -1795,4 +1914,7 @@ void tlog_exit(void)
|
||||
|
||||
pthread_cond_destroy(&tlog.cond);
|
||||
pthread_mutex_destroy(&tlog.lock);
|
||||
|
||||
tlog_format = NULL;
|
||||
tlog.is_wait = 0;
|
||||
}
|
||||
|
||||
11
src/tlog.h
11
src/tlog.h
@@ -8,6 +8,7 @@
|
||||
#define TLOG_H
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <functional>
|
||||
@@ -78,7 +79,9 @@ level: Current log Levels
|
||||
format: Log formats
|
||||
*/
|
||||
#ifndef BASE_FILE_NAME
|
||||
#define BASE_FILE_NAME __FILE__
|
||||
#define BASE_FILE_NAME \
|
||||
(__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \
|
||||
: __FILE__)
|
||||
#endif
|
||||
#define tlog(level, format, ...) tlog_ext(level, BASE_FILE_NAME, __LINE__, __func__, NULL, format, ##__VA_ARGS__)
|
||||
|
||||
@@ -101,6 +104,9 @@ extern void tlog_set_logfile(const char *logfile);
|
||||
/* enalbe log to screen */
|
||||
extern void tlog_setlogscreen(int enable);
|
||||
|
||||
/* output log to screen only */
|
||||
extern void tlog_setlogscreen_only(int enable);
|
||||
|
||||
/* enalbe early log to screen */
|
||||
extern void tlog_set_early_printf(int enable);
|
||||
|
||||
@@ -181,6 +187,9 @@ extern int tlog_vprintf(tlog_log *log, const char *format, va_list ap);
|
||||
/* enalbe log to screen */
|
||||
extern void tlog_logscreen(tlog_log *log, int enable);
|
||||
|
||||
/* enalbe log to screen only*/
|
||||
extern void tlog_logscreen_only(tlog_log *log, int enable);
|
||||
|
||||
/* register output callback */
|
||||
typedef int (*tlog_output_func)(struct tlog_log *log, const char *buff, int bufflen);
|
||||
extern int tlog_reg_output_func(tlog_log *log, tlog_output_func output);
|
||||
|
||||
510
src/util.c
510
src/util.c
@@ -28,16 +28,19 @@
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
@@ -76,7 +79,9 @@
|
||||
|
||||
#define NETLINK_ALIGN(len) (((len) + 3) & ~(3))
|
||||
|
||||
#define BUFF_SZ 256
|
||||
#define BUFF_SZ 1024
|
||||
#define PACKET_BUF_SIZE 8192
|
||||
#define PACKET_MAGIC 0X11040918
|
||||
|
||||
struct ipset_netlink_attr {
|
||||
unsigned short len;
|
||||
@@ -107,12 +112,12 @@ char *gethost_by_addr(char *host, int maxsize, struct sockaddr *addr)
|
||||
host[0] = 0;
|
||||
switch (addr_store->ss_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr_in;
|
||||
struct sockaddr_in *addr_in = NULL;
|
||||
addr_in = (struct sockaddr_in *)addr;
|
||||
inet_ntop(AF_INET, &addr_in->sin_addr, host, maxsize);
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6;
|
||||
struct sockaddr_in6 *addr_in6 = NULL;
|
||||
addr_in6 = (struct sockaddr_in6 *)addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
struct sockaddr_in addr_in4;
|
||||
@@ -132,7 +137,7 @@ errout:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int getaddr_by_host(char *host, struct sockaddr *addr, socklen_t *addr_len)
|
||||
int getaddr_by_host(const char *host, struct sockaddr *addr, socklen_t *addr_len)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result = NULL;
|
||||
@@ -175,14 +180,14 @@ int getsocknet_inet(int fd, struct sockaddr *addr, socklen_t *addr_len)
|
||||
|
||||
switch (addr_store.ss_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr_in;
|
||||
struct sockaddr_in *addr_in = NULL;
|
||||
addr_in = (struct sockaddr_in *)addr;
|
||||
addr_in->sin_family = AF_INET;
|
||||
*addr_len = sizeof(struct sockaddr_in);
|
||||
memcpy(addr, addr_in, sizeof(struct sockaddr_in));
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6;
|
||||
struct sockaddr_in6 *addr_in6 = NULL;
|
||||
addr_in6 = (struct sockaddr_in6 *)addr;
|
||||
if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) {
|
||||
struct sockaddr_in addr_in4;
|
||||
@@ -410,7 +415,7 @@ int parse_uri(char *value, char *scheme, char *host, int *port, char *path)
|
||||
};
|
||||
|
||||
field_len = host_end - process_ptr;
|
||||
if (field_len >= sizeof(host_name)) {
|
||||
if (field_len >= (int)sizeof(host_name)) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(host_name, process_ptr, field_len);
|
||||
@@ -430,7 +435,7 @@ int parse_uri(char *value, char *scheme, char *host, int *port, char *path)
|
||||
|
||||
int set_fd_nonblock(int fd, int nonblock)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
|
||||
if (flags == -1) {
|
||||
@@ -472,6 +477,31 @@ char *reverse_string(char *output, const char *input, int len, int to_lower_case
|
||||
return begin;
|
||||
}
|
||||
|
||||
char *to_lower_case(char *output, const char *input, int len)
|
||||
{
|
||||
char *begin = output;
|
||||
int i = 0;
|
||||
if (len <= 0) {
|
||||
*output = 0;
|
||||
return output;
|
||||
}
|
||||
|
||||
len--;
|
||||
while (i < len && *(input + i) != '\0') {
|
||||
*output = *(input + i);
|
||||
if (*output >= 'A' && *output <= 'Z') {
|
||||
/* To lower case */
|
||||
*output = *output + 32;
|
||||
}
|
||||
output++;
|
||||
i++;
|
||||
}
|
||||
|
||||
*output = 0;
|
||||
|
||||
return begin;
|
||||
}
|
||||
|
||||
static inline void _ipset_add_attr(struct nlmsghdr *netlink_head, uint16_t type, size_t len, const void *data)
|
||||
{
|
||||
struct ipset_netlink_attr *attr = (void *)netlink_head + NETLINK_ALIGN(netlink_head->nlmsg_len);
|
||||
@@ -497,7 +527,7 @@ static int _ipset_socket_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _ipset_support_timeout(const char *ipsetname)
|
||||
static int _ipset_support_timeout(void)
|
||||
{
|
||||
if (dns_conf_ipset_timeout_enable) {
|
||||
return 0;
|
||||
@@ -509,14 +539,15 @@ static int _ipset_support_timeout(const char *ipsetname)
|
||||
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 nlmsghdr *netlink_head = NULL;
|
||||
struct ipset_netlink_msg *netlink_msg = NULL;
|
||||
struct ipset_netlink_attr *nested[3];
|
||||
char buffer[BUFF_SZ];
|
||||
uint8_t proto;
|
||||
ssize_t rc;
|
||||
uint8_t proto = 0;
|
||||
ssize_t rc = 0;
|
||||
int af = 0;
|
||||
static const struct sockaddr_nl snl = {.nl_family = AF_NETLINK};
|
||||
uint32_t expire = 0;
|
||||
|
||||
if (addr_len != IPV4_ADDR_LEN && addr_len != IPV6_ADDR_LEN) {
|
||||
errno = EINVAL;
|
||||
@@ -570,9 +601,9 @@ static int _ipset_operate(const char *ipsetname, const unsigned char addr[], int
|
||||
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);
|
||||
if (timeout > 0 && _ipset_support_timeout() == 0) {
|
||||
expire = htonl(timeout);
|
||||
_ipset_add_attr(netlink_head, IPSET_ATTR_TIMEOUT | NLA_F_NET_BYTEORDER, sizeof(expire), &expire);
|
||||
}
|
||||
|
||||
nested[0]->len = (void *)buffer + NETLINK_ALIGN(netlink_head->nlmsg_len) - (void *)nested[0];
|
||||
@@ -607,22 +638,30 @@ int ipset_del(const char *ipsetname, const unsigned char addr[], int addr_len)
|
||||
|
||||
unsigned char *SSL_SHA256(const unsigned char *d, size_t n, unsigned char *md)
|
||||
{
|
||||
SHA256_CTX c;
|
||||
static unsigned char m[SHA256_DIGEST_LENGTH];
|
||||
|
||||
if (md == NULL)
|
||||
if (md == NULL) {
|
||||
md = m;
|
||||
SHA256_Init(&c);
|
||||
SHA256_Update(&c, d, n);
|
||||
SHA256_Final(md, &c);
|
||||
OPENSSL_cleanse(&c, sizeof(c));
|
||||
}
|
||||
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_MD_CTX_init(ctx);
|
||||
EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
|
||||
EVP_DigestUpdate(ctx, d, n);
|
||||
EVP_DigestFinal_ex(ctx, m, NULL);
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
|
||||
return (md);
|
||||
}
|
||||
|
||||
int SSL_base64_decode(const char *in, unsigned char *out)
|
||||
{
|
||||
size_t inlen = strlen(in);
|
||||
int outlen;
|
||||
int outlen = 0;
|
||||
|
||||
if (inlen == 0) {
|
||||
return 0;
|
||||
@@ -645,8 +684,8 @@ errout:
|
||||
|
||||
int create_pid_file(const char *pid_file)
|
||||
{
|
||||
int fd;
|
||||
int flags;
|
||||
int fd = 0;
|
||||
int flags = 0;
|
||||
char buff[TMP_BUFF_LEN_32];
|
||||
|
||||
/* create pid file, and lock this file */
|
||||
@@ -711,7 +750,7 @@ static __attribute__((unused)) void _pthreads_locking_callback(int mode, int typ
|
||||
|
||||
static __attribute__((unused)) unsigned long _pthreads_thread_id(void)
|
||||
{
|
||||
unsigned long ret;
|
||||
unsigned long ret = 0;
|
||||
|
||||
ret = (unsigned long)pthread_self();
|
||||
return (ret);
|
||||
@@ -719,16 +758,18 @@ static __attribute__((unused)) unsigned long _pthreads_thread_id(void)
|
||||
|
||||
void SSL_CRYPTO_thread_setup(void)
|
||||
{
|
||||
int i;
|
||||
int i = 0;
|
||||
|
||||
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)
|
||||
if (lock_cs) {
|
||||
OPENSSL_free(lock_cs);
|
||||
if (lock_count)
|
||||
}
|
||||
if (lock_count) {
|
||||
OPENSSL_free(lock_count);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
@@ -736,13 +777,17 @@ void SSL_CRYPTO_thread_setup(void)
|
||||
pthread_mutex_init(&(lock_cs[i]), NULL);
|
||||
}
|
||||
|
||||
#if OPENSSL_API_COMPAT < 0x10000000
|
||||
CRYPTO_set_id_callback(_pthreads_thread_id);
|
||||
#else
|
||||
CRYPTO_THREADID_set_callback(_pthreads_thread_id);
|
||||
#endif
|
||||
CRYPTO_set_locking_callback(_pthreads_locking_callback);
|
||||
}
|
||||
|
||||
void SSL_CRYPTO_thread_cleanup(void)
|
||||
{
|
||||
int i;
|
||||
int i = 0;
|
||||
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
@@ -779,18 +824,20 @@ static int parse_server_name_extension(const char *, size_t, char *, const char
|
||||
*/
|
||||
int parse_tls_header(const char *data, size_t data_len, char *hostname, const char **hostname_ptr)
|
||||
{
|
||||
char tls_content_type;
|
||||
char tls_version_major;
|
||||
char tls_version_minor;
|
||||
char tls_content_type = 0;
|
||||
char tls_version_major = 0;
|
||||
char tls_version_minor = 0;
|
||||
size_t pos = TLS_HEADER_LEN;
|
||||
size_t len;
|
||||
size_t len = 0;
|
||||
|
||||
if (hostname == NULL)
|
||||
if (hostname == NULL) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* Check that our TCP payload is at least large enough for a TLS header */
|
||||
if (data_len < TLS_HEADER_LEN)
|
||||
if (data_len < TLS_HEADER_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* SSL 2.0 compatible Client Hello
|
||||
*
|
||||
@@ -818,8 +865,9 @@ int parse_tls_header(const char *data, size_t data_len, char *hostname, const ch
|
||||
data_len = MIN(data_len, len);
|
||||
|
||||
/* Check we received entire TLS record length */
|
||||
if (data_len < len)
|
||||
if (data_len < len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handshake
|
||||
@@ -841,20 +889,23 @@ int parse_tls_header(const char *data, size_t data_len, char *hostname, const ch
|
||||
pos += 38;
|
||||
|
||||
/* Session ID */
|
||||
if (pos + 1 > data_len)
|
||||
if (pos + 1 > data_len) {
|
||||
return -5;
|
||||
}
|
||||
len = (unsigned char)data[pos];
|
||||
pos += 1 + len;
|
||||
|
||||
/* Cipher Suites */
|
||||
if (pos + 2 > data_len)
|
||||
if (pos + 2 > data_len) {
|
||||
return -5;
|
||||
}
|
||||
len = ((unsigned char)data[pos] << 8) + (unsigned char)data[pos + 1];
|
||||
pos += 2 + len;
|
||||
|
||||
/* Compression Methods */
|
||||
if (pos + 1 > data_len)
|
||||
if (pos + 1 > data_len) {
|
||||
return -5;
|
||||
}
|
||||
len = (unsigned char)data[pos];
|
||||
pos += 1 + len;
|
||||
|
||||
@@ -863,20 +914,22 @@ int parse_tls_header(const char *data, size_t data_len, char *hostname, const ch
|
||||
}
|
||||
|
||||
/* Extensions */
|
||||
if (pos + 2 > data_len)
|
||||
if (pos + 2 > data_len) {
|
||||
return -5;
|
||||
}
|
||||
len = ((unsigned char)data[pos] << 8) + (unsigned char)data[pos + 1];
|
||||
pos += 2;
|
||||
|
||||
if (pos + len > data_len)
|
||||
if (pos + len > data_len) {
|
||||
return -5;
|
||||
}
|
||||
return parse_extensions(data + pos, len, hostname, hostname_ptr);
|
||||
}
|
||||
|
||||
static int parse_extensions(const char *data, size_t data_len, char *hostname, const char **hostname_ptr)
|
||||
{
|
||||
size_t pos = 0;
|
||||
size_t len;
|
||||
size_t len = 0;
|
||||
|
||||
/* Parse each 4 bytes for the extension header */
|
||||
while (pos + 4 <= data_len) {
|
||||
@@ -887,15 +940,17 @@ static int parse_extensions(const char *data, size_t data_len, char *hostname, c
|
||||
if (data[pos] == 0x00 && data[pos + 1] == 0x00) {
|
||||
/* There can be only one extension of each type, so we break
|
||||
* our state and move p to beinnging of the extension here */
|
||||
if (pos + 4 + len > data_len)
|
||||
if (pos + 4 + len > data_len) {
|
||||
return -5;
|
||||
}
|
||||
return parse_server_name_extension(data + pos + 4, len, hostname, hostname_ptr);
|
||||
}
|
||||
pos += 4 + len; /* Advance to the next extension header */
|
||||
}
|
||||
/* Check we ended where we expected to */
|
||||
if (pos != data_len)
|
||||
if (pos != data_len) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
return -2;
|
||||
}
|
||||
@@ -903,13 +958,14 @@ static int parse_extensions(const char *data, size_t data_len, char *hostname, c
|
||||
static int parse_server_name_extension(const char *data, size_t data_len, char *hostname, const char **hostname_ptr)
|
||||
{
|
||||
size_t pos = 2; /* skip server name list length */
|
||||
size_t len;
|
||||
size_t len = 0;
|
||||
|
||||
while (pos + 3 < data_len) {
|
||||
len = ((unsigned char)data[pos + 1] << 8) + (unsigned char)data[pos + 2];
|
||||
|
||||
if (pos + 3 + len > data_len)
|
||||
if (pos + 3 + len > data_len) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
switch (data[pos]) { /* name type */
|
||||
case 0x00: /* host_name */
|
||||
@@ -926,8 +982,9 @@ static int parse_server_name_extension(const char *data, size_t data_len, char *
|
||||
pos += 3 + len;
|
||||
}
|
||||
/* Check we ended where we expected to */
|
||||
if (pos != data_len)
|
||||
if (pos != data_len) {
|
||||
return -5;
|
||||
}
|
||||
|
||||
return -2;
|
||||
}
|
||||
@@ -935,8 +992,12 @@ static int parse_server_name_extension(const char *data, size_t data_len, char *
|
||||
void get_compiled_time(struct tm *tm)
|
||||
{
|
||||
char s_month[5];
|
||||
int month, day, year;
|
||||
int hour, min, sec;
|
||||
int month = 0;
|
||||
int day = 0;
|
||||
int year = 0;
|
||||
int hour = 0;
|
||||
int min = 0;
|
||||
int sec = 0;
|
||||
static const char *month_names = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||
|
||||
sscanf(__DATE__, "%4s %d %d", s_month, &day, &year);
|
||||
@@ -954,8 +1015,9 @@ void get_compiled_time(struct tm *tm)
|
||||
int is_numeric(const char *str)
|
||||
{
|
||||
while (*str != '\0') {
|
||||
if (*str < '0' || *str > '9')
|
||||
if (*str < '0' || *str > '9') {
|
||||
return -1;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
return 0;
|
||||
@@ -972,6 +1034,25 @@ int has_network_raw_cap(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int has_unprivileged_ping(void)
|
||||
{
|
||||
int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
|
||||
if (fd < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6);
|
||||
if (fd < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt)
|
||||
{
|
||||
const int yes = 1;
|
||||
@@ -1025,9 +1106,9 @@ static _Unwind_Reason_Code unwind_callback(struct _Unwind_Context *context, void
|
||||
if (pc) {
|
||||
if (state->current == state->end) {
|
||||
return _URC_END_OF_STACK;
|
||||
} else {
|
||||
*state->current++ = (void *)(pc);
|
||||
}
|
||||
|
||||
*state->current++ = (void *)(pc);
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
@@ -1036,6 +1117,7 @@ void print_stack(void)
|
||||
{
|
||||
const size_t max_buffer = 30;
|
||||
void *buffer[max_buffer];
|
||||
int idx = 0;
|
||||
|
||||
struct backtrace_state state = {buffer, buffer + max_buffer};
|
||||
_Unwind_Backtrace(unwind_callback, &state);
|
||||
@@ -1043,9 +1125,9 @@ void print_stack(void)
|
||||
if (frame_num == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
tlog(TLOG_FATAL, "Stack:");
|
||||
for (int idx = 0; idx < frame_num; ++idx) {
|
||||
for (idx = 0; idx < frame_num; ++idx) {
|
||||
const void *addr = buffer[idx];
|
||||
const char *symbol = "";
|
||||
|
||||
@@ -1056,6 +1138,320 @@ void print_stack(void)
|
||||
}
|
||||
|
||||
void *offset = (void *)((char *)(addr) - (char *)(info.dli_fbase));
|
||||
tlog(TLOG_FATAL, "#%.2d: %p %s from %s+%p", idx + 1, addr, symbol, info.dli_fname, offset);
|
||||
tlog(TLOG_FATAL, "#%.2d: %p %s() from %s+%p", idx + 1, addr, symbol, info.dli_fname, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bug_ext(const char *file, int line, const char *func, const char *errfmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, errfmt);
|
||||
tlog_vext(TLOG_FATAL, file, line, func, NULL, errfmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
print_stack();
|
||||
/* trigger BUG */
|
||||
sleep(1);
|
||||
raise(SIGSEGV);
|
||||
|
||||
while (true) {
|
||||
sleep(1);
|
||||
};
|
||||
}
|
||||
|
||||
int write_file(const char *filename, void *data, int data_len)
|
||||
{
|
||||
int fd = open(filename, O_WRONLY | O_CREAT, 0644);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int len = write(fd, data, data_len);
|
||||
if (len < 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
errout:
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_packet_save(const char *dir, const char *type, const char *from, const void *packet, int packet_len)
|
||||
{
|
||||
char *data = NULL;
|
||||
int data_len = 0;
|
||||
char filename[BUFF_SZ];
|
||||
char time_s[BUFF_SZ];
|
||||
int ret = -1;
|
||||
|
||||
struct tm *ptm;
|
||||
struct tm tm;
|
||||
struct timeval tmval;
|
||||
struct stat sb;
|
||||
|
||||
if (stat(dir, &sb) != 0) {
|
||||
mkdir(dir, 0750);
|
||||
}
|
||||
|
||||
if (gettimeofday(&tmval, NULL) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptm = localtime_r(&tmval.tv_sec, &tm);
|
||||
if (ptm == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = snprintf(time_s, sizeof(time_s) - 1, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d.%.3d", ptm->tm_year + 1900,
|
||||
ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)(tmval.tv_usec / 1000));
|
||||
ret = snprintf(filename, sizeof(filename) - 1, "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d%.1d.packet", dir, type,
|
||||
ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec,
|
||||
(int)(tmval.tv_usec / 100000));
|
||||
|
||||
data = malloc(PACKET_BUF_SIZE);
|
||||
if (data == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data_len = snprintf(data, PACKET_BUF_SIZE,
|
||||
"type: %s\n"
|
||||
"from: %s\n"
|
||||
"time: %s\n"
|
||||
"packet-len: %d\n",
|
||||
type, from, time_s, packet_len);
|
||||
if (data_len <= 0 || data_len >= PACKET_BUF_SIZE) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
data[data_len] = 0;
|
||||
data_len++;
|
||||
uint32_t magic = htonl(PACKET_MAGIC);
|
||||
memcpy(data + data_len, &magic, sizeof(magic));
|
||||
data_len += sizeof(magic);
|
||||
int len_in_h = htonl(packet_len);
|
||||
memcpy(data + data_len, &len_in_h, sizeof(len_in_h));
|
||||
data_len += 4;
|
||||
memcpy(data + data_len, packet, packet_len);
|
||||
data_len += packet_len;
|
||||
|
||||
ret = write_file(filename, data, data_len);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (data) {
|
||||
free(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
struct _dns_read_packet_info {
|
||||
int data_len;
|
||||
int message_len;
|
||||
char *message;
|
||||
int packet_len;
|
||||
uint8_t *packet;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
static struct _dns_read_packet_info *_dns_read_packet_file(const char *packet_file)
|
||||
{
|
||||
struct _dns_read_packet_info *info = NULL;
|
||||
int fd = 0;
|
||||
int len = 0;
|
||||
int message_len = 0;
|
||||
uint8_t *ptr = NULL;
|
||||
|
||||
info = malloc(sizeof(struct _dns_read_packet_info) + PACKET_BUF_SIZE);
|
||||
fd = open(packet_file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
printf("open file %s failed, %s\n", packet_file, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
len = read(fd, info->data, PACKET_BUF_SIZE);
|
||||
if (len < 0) {
|
||||
printf("read file %s failed, %s\n", packet_file, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
message_len = strnlen((char *)info->data, PACKET_BUF_SIZE);
|
||||
if (message_len >= 512 || message_len >= len) {
|
||||
printf("invalid packet file, bad message len\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
info->message_len = message_len;
|
||||
info->message = (char *)info->data;
|
||||
|
||||
ptr = info->data + message_len + 1;
|
||||
uint32_t magic = 0;
|
||||
if (ptr - (uint8_t *)info + sizeof(magic) >= (size_t)len) {
|
||||
printf("invalid packet file, magic length is invalid.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memcpy(&magic, ptr, sizeof(magic));
|
||||
if (magic != htonl(PACKET_MAGIC)) {
|
||||
printf("invalid packet file, bad magic\n");
|
||||
goto errout;
|
||||
}
|
||||
ptr += sizeof(magic);
|
||||
|
||||
uint32_t packet_len = 0;
|
||||
if (ptr - info->data + sizeof(packet_len) >= (size_t)len) {
|
||||
printf("invalid packet file, packet length is invalid.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memcpy(&packet_len, ptr, sizeof(packet_len));
|
||||
packet_len = ntohl(packet_len);
|
||||
ptr += sizeof(packet_len);
|
||||
if (packet_len != (size_t)len - (ptr - info->data)) {
|
||||
printf("invalid packet file, packet length is invalid\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
info->packet_len = packet_len;
|
||||
info->packet = ptr;
|
||||
|
||||
close(fd);
|
||||
return info;
|
||||
errout:
|
||||
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (info) {
|
||||
free(info);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _dns_debug_display(struct dns_packet *packet)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int ttl = 0;
|
||||
struct dns_rrs *rrs = NULL;
|
||||
int rr_count = 0;
|
||||
char req_host[MAX_IP_LEN];
|
||||
|
||||
for (j = 1; j < DNS_RRS_END; j++) {
|
||||
rrs = dns_get_rrs_start(packet, j, &rr_count);
|
||||
printf("section: %d\n", j);
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
|
||||
switch (rrs->type) {
|
||||
case DNS_T_A: {
|
||||
unsigned char addr[4];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
/* get A result */
|
||||
dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
req_host[0] = '\0';
|
||||
inet_ntop(AF_INET, addr, req_host, sizeof(req_host));
|
||||
printf("domain: %s A: %s TTL: %d\n", name, req_host, ttl);
|
||||
} break;
|
||||
case DNS_T_AAAA: {
|
||||
unsigned char addr[16];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
req_host[0] = '\0';
|
||||
inet_ntop(AF_INET6, addr, req_host, sizeof(req_host));
|
||||
printf("domain: %s AAAA: %s TTL:%d\n", name, req_host, ttl);
|
||||
} break;
|
||||
case DNS_T_NS: {
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
|
||||
printf("domain: %s TTL: %d NS: %s\n", name, ttl, cname);
|
||||
} break;
|
||||
case DNS_T_CNAME: {
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
if (dns_conf_force_no_cname) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
|
||||
printf("domain: %s TTL: %d CNAME: %s\n", name, ttl, cname);
|
||||
} break;
|
||||
case DNS_T_SOA: {
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
struct dns_soa soa;
|
||||
dns_get_SOA(rrs, name, 128, &ttl, &soa);
|
||||
printf("domain: %s SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, expire: "
|
||||
"%d, minimum: %d",
|
||||
name, soa.mname, soa.rname, soa.serial, soa.refresh, soa.retry, soa.expire, soa.minimum);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_packet_debug(const char *packet_file)
|
||||
{
|
||||
struct _dns_read_packet_info *info = NULL;
|
||||
char buff[DNS_PACKSIZE];
|
||||
|
||||
tlog_setlogscreen_only(1);
|
||||
tlog_setlevel(TLOG_DEBUG);
|
||||
|
||||
info = _dns_read_packet_file(packet_file);
|
||||
if (info == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
const char *send_env = getenv("SMARTDNS_DEBUG_SEND");
|
||||
if (send_env != NULL) {
|
||||
char ip[32];
|
||||
int port = 53;
|
||||
if (parse_ip(send_env, ip, &port) == 0) {
|
||||
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd > 0) {
|
||||
struct sockaddr_in server;
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons(port);
|
||||
server.sin_addr.s_addr = inet_addr(ip);
|
||||
sendto(sockfd, info->packet, info->packet_len, 0, (struct sockaddr *)&server, sizeof(server));
|
||||
close(sockfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct dns_packet *packet = (struct dns_packet *)buff;
|
||||
if (dns_decode(packet, DNS_PACKSIZE, info->packet, info->packet_len) != 0) {
|
||||
printf("decode failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
_dns_debug_display(packet);
|
||||
|
||||
free(info);
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (info) {
|
||||
free(info);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
22
src/util.h
22
src/util.h
@@ -45,11 +45,21 @@ extern "C" {
|
||||
#define PORT_NOT_DEFINED -1
|
||||
#define MAX_IP_LEN 64
|
||||
|
||||
#ifndef BASE_FILE_NAME
|
||||
#define BASE_FILE_NAME \
|
||||
(__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \
|
||||
: __FILE__)
|
||||
#endif
|
||||
#define BUG(format, ...) bug_ext(BASE_FILE_NAME, __LINE__, __func__, format, ##__VA_ARGS__)
|
||||
|
||||
void bug_ext(const char *file, int line, const char *func, const char *errfmt, ...)
|
||||
__attribute__((format(printf, 4, 5))) __attribute__((nonnull(4)));
|
||||
|
||||
unsigned long get_tick_count(void);
|
||||
|
||||
char *gethost_by_addr(char *host, int maxsize, struct sockaddr *addr);
|
||||
|
||||
int getaddr_by_host(char *host, struct sockaddr *addr, socklen_t *addr_len);
|
||||
int getaddr_by_host(const char *host, struct sockaddr *addr, socklen_t *addr_len);
|
||||
|
||||
int getsocknet_inet(int fd, struct sockaddr *addr, socklen_t *addr_len);
|
||||
|
||||
@@ -65,6 +75,8 @@ int set_fd_nonblock(int fd, int nonblock);
|
||||
|
||||
char *reverse_string(char *output, const char *input, int len, int to_lower_case);
|
||||
|
||||
char *to_lower_case(char *output, const char *input, int len);
|
||||
|
||||
void print_stack(void);
|
||||
|
||||
int ipset_add(const char *ipsetname, const unsigned char addr[], int addr_len, unsigned long timeout);
|
||||
@@ -102,6 +114,8 @@ int is_numeric(const char *str);
|
||||
|
||||
int has_network_raw_cap(void);
|
||||
|
||||
int has_unprivileged_ping(void);
|
||||
|
||||
int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt);
|
||||
|
||||
int set_sock_lingertime(int fd, int time);
|
||||
@@ -110,6 +124,12 @@ uint64_t get_free_space(const char *path);
|
||||
|
||||
void print_stack(void);
|
||||
|
||||
int write_file(const char *filename, void *data, int data_len);
|
||||
|
||||
int dns_packet_save(const char *dir, const char *type, const char *from, const void *packet, int packet_len);
|
||||
|
||||
int dns_packet_debug(const char *packet_file);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus */
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
[Unit]
|
||||
Description=SmartDNS Server
|
||||
After=network.target
|
||||
StartLimitBurst=0
|
||||
StartLimitIntervalSec=60
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
PIDFile=/var/run/smartdns.pid
|
||||
EnvironmentFile=/etc/default/smartdns
|
||||
ExecStart=/usr/sbin/smartdns -p /var/run/smartdns.pid $SMART_DNS_OPTS
|
||||
KillMode=process
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
TimeoutStopSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Alias=smartdns.service
|
||||
@@ -9,10 +9,9 @@ Type=forking
|
||||
PIDFile=@RUNSTATEDIR@/smartdns.pid
|
||||
EnvironmentFile=@SYSCONFDIR@/default/smartdns
|
||||
ExecStart=@SBINDIR@/smartdns -p @RUNSTATEDIR@/smartdns.pid $SMART_DNS_OPTS
|
||||
KillMode=process
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
TimeoutStopSec=5
|
||||
TimeoutStopSec=15
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
Reference in New Issue
Block a user