Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63415ef868 | ||
|
|
c4bffbb1dd | ||
|
|
7b1ea2c43d | ||
|
|
5df4364809 | ||
|
|
61a6e676bc | ||
|
|
9f32e01971 | ||
|
|
c17f5df6cd | ||
|
|
9554b3debe | ||
|
|
11d92a67a1 | ||
|
|
cde9fe5d5c | ||
|
|
52a35a5f88 | ||
|
|
ce18317a08 | ||
|
|
fd2eb6980f | ||
|
|
407aba08c5 | ||
|
|
7997300781 | ||
|
|
d094a70078 | ||
|
|
066c472467 | ||
|
|
fb5b089740 | ||
|
|
62e0416d91 | ||
|
|
d2e3ae6289 | ||
|
|
fa349b1864 | ||
|
|
fc82c56947 | ||
|
|
26798f8f1a | ||
|
|
48ef6f2547 | ||
|
|
f65c8a1280 | ||
|
|
a10b21c822 | ||
|
|
9a83df46e0 | ||
|
|
a482ceeb5a | ||
|
|
4853a964c1 | ||
|
|
b3e16c3c60 | ||
|
|
eb0d0336de | ||
|
|
d54d7cf80a | ||
|
|
eb9fc6c13d | ||
|
|
c9524065a5 | ||
|
|
568f95dbdf | ||
|
|
79a49c6bd6 | ||
|
|
8c06923438 | ||
|
|
ef806ecc9c | ||
|
|
d02bceabf1 | ||
|
|
f1debd0878 | ||
|
|
73c96cf932 | ||
|
|
7bfb4e070a | ||
|
|
14330dd5da | ||
|
|
2a8d3aff61 | ||
|
|
3d7db2dacf | ||
|
|
aca8cf92cb | ||
|
|
f39bdb64b2 | ||
|
|
95c79ce1f6 | ||
|
|
62171f2a4d | ||
|
|
37a87e864e | ||
|
|
a1d067f9eb | ||
|
|
96d37332e4 | ||
|
|
3916ea570a | ||
|
|
51c81513ab | ||
|
|
1dd01ff4bd | ||
|
|
bfacad33ae | ||
|
|
b7fb501be9 | ||
|
|
28139d2020 | ||
|
|
f7ede1b7d0 | ||
|
|
875100f5c1 | ||
|
|
1a492f7dc0 | ||
|
|
1ff7829b49 | ||
|
|
8befd9d5d2 | ||
|
|
5658d72b3b | ||
|
|
1b12709451 | ||
|
|
c39a7b9b41 | ||
|
|
901baf80c0 | ||
|
|
45e3455932 | ||
|
|
887ef7b20e | ||
|
|
9307855f7c | ||
|
|
fb7b747f9f | ||
|
|
7eb9d5d42f | ||
|
|
1054229efb | ||
|
|
c19a39a447 | ||
|
|
1ba6ee7cb9 | ||
|
|
601ebd590e | ||
|
|
b133ce408a | ||
|
|
8d3a62c568 | ||
|
|
93a8b87c17 | ||
|
|
ffc331af21 | ||
|
|
89e958abfa | ||
|
|
2576fdb02f | ||
|
|
7ff6ae3ea0 | ||
|
|
c2b072b523 | ||
|
|
1df9d624b4 | ||
|
|
6b021946aa | ||
|
|
087c9f5df2 | ||
|
|
e66928f27f | ||
|
|
8a9a11d6d9 | ||
|
|
a6e5ceb675 | ||
|
|
08567c458b | ||
|
|
234c721011 | ||
|
|
45346705d8 | ||
|
|
9b7b2ad12d | ||
|
|
f072ff3412 | ||
|
|
ad43c796cf | ||
|
|
f5c8d3ce57 | ||
|
|
f621b424e2 | ||
|
|
d59c148a28 | ||
|
|
8ea34ab176 | ||
|
|
0340d272c3 |
45
.clang-tidy
Normal file
45
.clang-tidy
Normal file
@@ -0,0 +1,45 @@
|
||||
Checks: >
|
||||
-*,
|
||||
modernize-*,
|
||||
bugprone-*,
|
||||
concurrency-*,
|
||||
misc-*,
|
||||
readability-*,
|
||||
performance-*,
|
||||
portability-*,
|
||||
google-*,
|
||||
linuxkernel-*,
|
||||
-bugprone-narrowing-conversions,
|
||||
-bugprone-branch-clone,
|
||||
-bugprone-reserved-identifier,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-sizeof-expression,
|
||||
-bugprone-implicit-widening-of-multiplication-result,
|
||||
-bugprone-suspicious-memory-comparison,
|
||||
-bugprone-not-null-terminated-result,
|
||||
-bugprone-signal-handler,
|
||||
-bugprone-assignment-in-if-condition,
|
||||
-concurrency-mt-unsafe,
|
||||
-modernize-macro-to-enum,
|
||||
-misc-unused-parameters,
|
||||
-misc-misplaced-widening-cast,
|
||||
-misc-no-recursion,
|
||||
-readability-magic-numbers,
|
||||
-readability-use-anyofallof,
|
||||
-readability-identifier-length,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-named-parameter,
|
||||
-readability-isolate-declaration,
|
||||
-readability-else-after-return,
|
||||
-readability-redundant-control-flow,
|
||||
-readability-suspicious-call-argument,
|
||||
-google-readability-casting,
|
||||
-google-readability-todo,
|
||||
-performance-no-int-to-ptr,
|
||||
# clang-analyzer-*,
|
||||
# clang-analyzer-deadcode.DeadStores,
|
||||
# clang-analyzer-optin.performance.Padding,
|
||||
# -clang-analyzer-security.insecureAPI.*
|
||||
|
||||
# Turn all the warnings from the checks above into errors.
|
||||
FormatStyle: file
|
||||
35
.github/workflows/docker.yml
vendored
Normal file
35
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Publish Docker Image
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'new image tag(e.g. v1.1.0)'
|
||||
required: true
|
||||
default: 'latest'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v3
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
tags: ${{vars.DOCKERHUB_REPO}}:${{ github.event.inputs.version }}
|
||||
@@ -2,7 +2,7 @@ FROM ubuntu:latest as smartdns-builder
|
||||
LABEL previous-stage=smartdns-builder
|
||||
|
||||
# prepare builder
|
||||
ARG OPENSSL_VER=1.1.1f
|
||||
ARG OPENSSL_VER=3.0.10
|
||||
RUN apt update && \
|
||||
apt install -y perl curl make musl-tools musl-dev && \
|
||||
ln -s /usr/include/linux /usr/include/$(uname -m)-linux-musl && \
|
||||
@@ -27,7 +27,7 @@ COPY . /build/smartdns/
|
||||
RUN cd /build/smartdns && \
|
||||
export CC=musl-gcc && \
|
||||
export CFLAGS="-I /opt/build/include" && \
|
||||
export LDFLAGS="-L /opt/build/lib" && \
|
||||
export LDFLAGS="-L /opt/build/lib -L /opt/build/lib64" && \
|
||||
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 ) && \
|
||||
@@ -37,9 +37,9 @@ RUN cd /build/smartdns && \
|
||||
cp package/smartdns/usr /release/ -a && \
|
||||
cd / && rm -rf /build
|
||||
|
||||
FROM busybox:latest
|
||||
FROM busybox:stable-musl
|
||||
COPY --from=smartdns-builder /release/ /
|
||||
EXPOSE 53/udp
|
||||
VOLUME "/etc/smartdns/"
|
||||
VOLUME ["/etc/smartdns/"]
|
||||
|
||||
CMD ["/usr/sbin/smartdns", "-f", "-x"]
|
||||
|
||||
@@ -37,7 +37,7 @@ test -x $SMARTDNS || exit 5
|
||||
|
||||
case $1 in
|
||||
start)
|
||||
$SMARTDNS "$SMART_DNS_OPTS"
|
||||
$SMARTDNS "$SMART_DNS_OPTS" -R
|
||||
while true; do
|
||||
if [ -e "$PIDFILE" ]; then
|
||||
break;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
# Include another configuration options
|
||||
# conf-file [file]
|
||||
# conf-file blacklist-ip.conf
|
||||
# conf-file *.conf
|
||||
|
||||
# dns server bind ip and port, default dns server port is 53, support binding multi ip and port
|
||||
# bind udp server
|
||||
@@ -30,6 +31,8 @@
|
||||
# tls cert file
|
||||
# bind-cert-key-pass [password]
|
||||
# tls private key password
|
||||
# bind-https server
|
||||
# bind-https [IP]:[port][@device] [-group [group]] [-no-rule-addr] [-no-rule-nameserver] [-no-rule-ipset] [-no-speed-check] [-no-cache] [-no-rule-soa] [-no-dualstack-selection]
|
||||
# option:
|
||||
# -group: set domain request to use the appropriate server group.
|
||||
# -no-rule-addr: skip address rule.
|
||||
@@ -39,6 +42,7 @@
|
||||
# -no-cache: skip cache.
|
||||
# -no-rule-soa: Skip address SOA(#) rules.
|
||||
# -no-dualstack-selection: Disable dualstack ip selection.
|
||||
# -no-ip-alias: ignore ip alias.
|
||||
# -force-aaaa-soa: force AAAA query return SOA.
|
||||
# -ipset ipsetname: use ipset rule.
|
||||
# -nftset nftsetname: use nftset rule.
|
||||
@@ -100,6 +104,10 @@ bind [::]:53
|
||||
# List of IPs that will be ignored
|
||||
# ignore-ip [ip/subnet]
|
||||
|
||||
# alias of IPs
|
||||
# ip-alias [ip/subnet] [ip1[,ip2]...]
|
||||
# ip-alias 192.168.0.1/24 10.9.0.1,10.9.0.2
|
||||
|
||||
# speed check mode
|
||||
# speed-check-mode [ping|tcp:port|none|,]
|
||||
# example:
|
||||
@@ -112,7 +120,7 @@ bind [::]:53
|
||||
|
||||
# force specific qtype return soa
|
||||
# force-qtype-SOA [qtypeid |...]
|
||||
# force-qtype-SOA [qtypeid,...]
|
||||
# force-qtype-SOA [qtypeid|start_id-end_id|,...]
|
||||
# force-qtype-SOA 65 28
|
||||
# force-qtype-SOA 65,28
|
||||
force-qtype-SOA 65
|
||||
@@ -188,14 +196,16 @@ log-level info
|
||||
# -blacklist-ip: filter result with blacklist ip
|
||||
# -whitelist-ip: filter result with whitelist ip, result in whitelist-ip will be accepted.
|
||||
# -check-edns: result must exist edns RR, or discard result.
|
||||
# -group [group]: set server to group, use with nameserver /domain/group.
|
||||
# -exclude-default-group: exclude this server from default group.
|
||||
# -proxy [proxy-name]: use proxy to connect to server.
|
||||
# g|-group [group]: set server to group, use with nameserver /domain/group.
|
||||
# e|-exclude-default-group: exclude this server from default group.
|
||||
# p|-proxy [proxy-name]: use proxy to connect to server.
|
||||
# -bootstrap-dns: set as bootstrap dns server.
|
||||
# -set-mark: set mark on packets.
|
||||
# -subnet [ip/subnet]: set edns client subnet.
|
||||
# -host-ip [ip]: set dns server host ip.
|
||||
# server 8.8.8.8 -blacklist-ip -check-edns -group g1 -group g2
|
||||
# server tls://dns.google:853
|
||||
# server quic://dns.gooel.com:443
|
||||
# server https://dns.google/dns-query
|
||||
|
||||
# remote tcp dns server list
|
||||
@@ -208,8 +218,8 @@ log-level info
|
||||
# -spki-pin: TLS spki pin to verify.
|
||||
# -tls-host-verify: cert hostname to verify.
|
||||
# -host-name: TLS sni hostname.
|
||||
# -no-check-certificate: no check certificate.
|
||||
# -proxy [proxy-name]: use proxy to connect to server.
|
||||
# k|-no-check-certificate: no check certificate.
|
||||
# p|-proxy [proxy-name]: use proxy to connect to server.
|
||||
# -bootstrap-dns: set as bootstrap dns server.
|
||||
# Get SPKI with this command:
|
||||
# echo | openssl s_client -connect '[ip]:853' | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
|
||||
@@ -217,14 +227,28 @@ log-level info
|
||||
# server-tls 8.8.8.8
|
||||
# server-tls 1.0.0.1
|
||||
|
||||
# remote quic dns server list
|
||||
# server-quic [IP]:[PORT] [-blacklist-ip] [-whitelist-ip] [-spki-pin [sha256-pin]] [-group [group] ...] [-exclude-default-group]
|
||||
# -spki-pin: TLS spki pin to verify.
|
||||
# -tls-host-verify: cert hostname to verify.
|
||||
# -host-name: TLS sni hostname.
|
||||
# k|-no-check-certificate: no check certificate.
|
||||
# p|-proxy [proxy-name]: use proxy to connect to server.
|
||||
# -bootstrap-dns: set as bootstrap dns server.
|
||||
# Get SPKI with this command:
|
||||
# echo | openssl s_client -connect '[ip]:443' | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
|
||||
# default port is 443
|
||||
# server-quic 8.8.8.8
|
||||
# server-quic 1.0.0.1
|
||||
|
||||
# remote https dns server list
|
||||
# server-https https://[host]:[port]/path [-blacklist-ip] [-whitelist-ip] [-spki-pin [sha256-pin]] [-group [group] ...] [-exclude-default-group]
|
||||
# -spki-pin: TLS spki pin to verify.
|
||||
# -tls-host-verify: cert hostname to verify.
|
||||
# -host-name: TLS sni hostname.
|
||||
# -http-host: http host.
|
||||
# -no-check-certificate: no check certificate.
|
||||
# -proxy [proxy-name]: use proxy to connect to server.
|
||||
# k|-no-check-certificate: no check certificate.
|
||||
# p|-proxy [proxy-name]: use proxy to connect to server.
|
||||
# -bootstrap-dns: set as bootstrap dns server.
|
||||
# default port is 443
|
||||
# server-https https://cloudflare-dns.com/dns-query
|
||||
@@ -247,14 +271,20 @@ log-level info
|
||||
# expand-ptr-from-address yes
|
||||
|
||||
# specific address to domain
|
||||
# address /domain/[ip|-|-4|-6|#|#4|#6]
|
||||
# address /domain/[ip1,ip2|-|-4|-6|#|#4|#6]
|
||||
# address /www.example.com/1.2.3.4, return ip 1.2.3.4 to client
|
||||
# address /www.example.com/1.2.3.4,5.6.7.8, return multiple ip addresses
|
||||
# address /www.example.com/-, ignore address, query from upstream, suffix 4, for ipv4, 6 for ipv6, none for all
|
||||
# address /www.example.com/#, return SOA to client, suffix 4, for ipv4, 6 for ipv6, none for all
|
||||
|
||||
# specific cname to domain
|
||||
# cname /domain/target
|
||||
|
||||
# add srv record, support multiple srv record.
|
||||
# srv-record /domain/[target][,port][,priority][,weight]
|
||||
# srv-record /_ldap._tcp.example.com/ldapserver.example.com,389
|
||||
# srv-record /_ldap._tcp.example.com/
|
||||
|
||||
# enalbe DNS64 feature
|
||||
# dns64 [ip/subnet]
|
||||
# dns64 64:ff9b::/96
|
||||
@@ -289,6 +319,9 @@ log-level info
|
||||
# nftset /www.example.com/-, ignore this domain
|
||||
# nftset /www.example.com/#6:-, ignore ipv6
|
||||
|
||||
# set ddns domain
|
||||
# ddns-domain domain
|
||||
|
||||
# set domain rules
|
||||
# domain-rules /domain/ [-speed-check-mode [...]]
|
||||
# rules:
|
||||
@@ -301,6 +334,8 @@ log-level info
|
||||
# [-d] -dualstack-ip-selection [yes|no]: same as dualstack-ip-selection option
|
||||
# -no-serve-expired: ignore expired domain
|
||||
# -delete: delete domain rule
|
||||
# -no-ip-alias: ignore ip alias
|
||||
# -no-cache: ignore cache
|
||||
|
||||
# collection of domains
|
||||
# the domain-set can be used with /domain/ for address, nameserver, ipset, etc.
|
||||
@@ -315,3 +350,25 @@ log-level info
|
||||
# nameserver /domain-set:domain-list/server-group
|
||||
# ipset /domain-set:domain-list/ipset
|
||||
# domain-rules /domain-set:domain-list/ -speed-check-mode ping
|
||||
|
||||
# set ip rules
|
||||
# ip-rules ip-cidrs [-ip-alias [...]]
|
||||
# rules:
|
||||
# [-c] -ip-alias [ip1,ip2]: same as ip-alias option
|
||||
# [-a] -whitelist-ip: same as whitelist-ip option
|
||||
# [-n] -blacklist-ip: same as blacklist-ip option
|
||||
# [-p] -bogus-nxdomain: same as bogus-nxdomain option
|
||||
# [-t] -ignore-ip: same as ignore-ip option
|
||||
|
||||
# collection of IPs
|
||||
# the ip-set can be used with /ip-cidr/ for ip-alias, ignore-ip, etc.
|
||||
# ip-set -name [set-name] -type list -file [/path/to/file]
|
||||
# [-n] -name [set name]: ip set name
|
||||
# [-t] -type [list]: ip set type, list only now
|
||||
# [-f] -file [path/to/set]: file path of ip set
|
||||
#
|
||||
# example:
|
||||
# ip-set -name ip-list -file /etc/smartdns/ip-list.conf
|
||||
# bogus-nxdomain ip-set:ip-list
|
||||
# ip-alias ip-set:ip-list 1.2.3.4
|
||||
# ip-alias ip-set:ip-list ip-set:ip-map-list
|
||||
|
||||
@@ -67,6 +67,18 @@ msgstr "配置分流域名列表"
|
||||
msgid "Custom Settings"
|
||||
msgstr "自定义设置"
|
||||
|
||||
msgid "DOH Server"
|
||||
msgstr "DOH服务器"
|
||||
|
||||
msgid "DOH Server Port"
|
||||
msgstr "DOH服务器端口"
|
||||
|
||||
msgid "DOT Server"
|
||||
msgstr "DOT服务器"
|
||||
|
||||
msgid "DOT Server Port"
|
||||
msgstr "DOT服务器端口"
|
||||
|
||||
msgid "DNS Block Setting"
|
||||
msgstr "域名屏蔽设置"
|
||||
|
||||
@@ -184,8 +196,44 @@ msgstr "启用IPV6服务器。"
|
||||
msgid "Enable TCP DNS Server"
|
||||
msgstr "启用TCP服务器。"
|
||||
|
||||
msgid "Enable daily auto update."
|
||||
msgstr "启用每日自动更新"
|
||||
msgid "Enable daily(week) auto update."
|
||||
msgstr "启用每天(每周)自动更新。"
|
||||
|
||||
msgid "Enable DOH DNS Server"
|
||||
msgstr "启用DOH服务器。"
|
||||
|
||||
msgid "Enable DOT DNS Server"
|
||||
msgstr "启用DOT服务器。"
|
||||
|
||||
msgid "Update Time (Every Week)"
|
||||
msgstr "更新时间(每周)"
|
||||
|
||||
msgid "Every Day"
|
||||
msgstr "每天"
|
||||
|
||||
msgid "Every Monday"
|
||||
msgstr "每周一"
|
||||
|
||||
msgid "Every Tuesday"
|
||||
msgstr "每周二"
|
||||
|
||||
msgid "Every Wednesday"
|
||||
msgstr "每周三"
|
||||
|
||||
msgid "Every Thursday"
|
||||
msgstr "每周四"
|
||||
|
||||
msgid "Every Friday"
|
||||
msgstr "每周五"
|
||||
|
||||
msgid "Every Saturday"
|
||||
msgstr "每周六"
|
||||
|
||||
msgid "Every Sunday"
|
||||
msgstr "每周日"
|
||||
|
||||
msgid "Update Time (Every Day)"
|
||||
msgstr "更新时间(每天)"
|
||||
|
||||
msgid "Enable domain prefetch, accelerate domain response speed."
|
||||
msgstr "启用域名预加载,加速域名响应速度。"
|
||||
@@ -398,6 +446,15 @@ msgstr "重启服务"
|
||||
msgid "Second Server Settings"
|
||||
msgstr "第二DNS服务器"
|
||||
|
||||
msgid "Server certificate file path."
|
||||
msgstr "服务器证书文件路径。"
|
||||
|
||||
msgid "Server certificate key file path."
|
||||
msgstr "服务器证书私钥文件路径。"
|
||||
|
||||
msgid "Server certificate key file password."
|
||||
msgstr "服务器证书私钥文件密码。"
|
||||
|
||||
msgid "Serve expired"
|
||||
msgstr "缓存过期服务"
|
||||
|
||||
@@ -410,6 +467,15 @@ msgstr "服务器组%s不存在"
|
||||
msgid "Server Name"
|
||||
msgstr "服务器名称"
|
||||
|
||||
msgid "Server Cert"
|
||||
msgstr "服务器证书"
|
||||
|
||||
msgid "Server Cert Key"
|
||||
msgstr "服务器证书私钥"
|
||||
|
||||
msgid "Server Cert Key Pass"
|
||||
msgstr "服务器证书私钥密码"
|
||||
|
||||
msgid "Set Specific domain ip address."
|
||||
msgstr "设置指定域名的IP地址。"
|
||||
|
||||
@@ -478,6 +544,12 @@ msgstr "跳过Nameserver规则。"
|
||||
msgid "SmartDNS"
|
||||
msgstr "SmartDNS"
|
||||
|
||||
msgid "Smartdns DOH server port."
|
||||
msgstr "Smartdns DOH服务器端口号。
|
||||
|
||||
msgid "Smartdns DOT server port."
|
||||
msgstr "Smartdns DOT服务器端口号。"
|
||||
|
||||
msgid "SmartDNS Server"
|
||||
msgstr "SmartDNS 服务器"
|
||||
|
||||
@@ -648,4 +720,4 @@ msgid "type"
|
||||
msgstr "类型"
|
||||
|
||||
msgid "udp"
|
||||
msgstr "udp"
|
||||
msgstr "udp"
|
||||
@@ -130,6 +130,56 @@ o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "1"
|
||||
end
|
||||
|
||||
---- Enable DOT server;
|
||||
o = s:taboption("advanced", Flag, "tls_server", translate("DOT Server"), translate("Enable DOT DNS Server"))
|
||||
o.rmempty = false
|
||||
o.default = o.disabled
|
||||
o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "0"
|
||||
end
|
||||
|
||||
o = s:taboption("advanced", Value, "tls_server_port", translate("DOT Server Port"), translate("Smartdns DOT server port."))
|
||||
o.placeholder = 853
|
||||
o.default = 853
|
||||
o.datatype = "port"
|
||||
o.rempty = false
|
||||
o:depends('tls_server', '1')
|
||||
|
||||
---- Enable DOH server;
|
||||
o = s:taboption("advanced", Flag, "doh_server", translate("DOH Server"), translate("Enable DOH DNS Server"))
|
||||
o.rmempty = false
|
||||
o.default = o.disabled
|
||||
o.cfgvalue = function(...)
|
||||
return Flag.cfgvalue(...) or "0"
|
||||
end
|
||||
|
||||
o = s:taboption("advanced", Value, "doh_server_port", translate("DOH Server Port"), translate("Smartdns DOH server port."))
|
||||
o.placeholder = 843
|
||||
o.default = 843
|
||||
o.datatype = "port"
|
||||
o.rempty = false
|
||||
o:depends('doh_server', '1')
|
||||
|
||||
o = s:taboption("advanced", Value, "bind_cert", translate("Server Cert"), translate("Server certificate file path."))
|
||||
o.datatype = "string"
|
||||
o.placeholder = "/var/etc/smartdns/smartdns/smartdns-cert.pem"
|
||||
o.rempty = true
|
||||
o:depends('tls_server', '1')
|
||||
o:depends('doh_server', '1')
|
||||
|
||||
o = s:taboption("advanced", Value, "bind_cert_key", translate("Server Cert Key"), translate("Server certificate key file path."))
|
||||
o.datatype = "string"
|
||||
o.placeholder = "/var/etc/smartdns/smartdns/smartdns-key.pem"
|
||||
o.rempty = false
|
||||
o:depends('tls_server', '1')
|
||||
o:depends('doh_server', '1')
|
||||
|
||||
o = s:taboption("advanced", Value, "bind_cert_key_pass", translate("Server Cert Key Pass"), translate("Server certificate key file password."))
|
||||
o.datatype = "string"
|
||||
o.rempty = false
|
||||
o:depends('tls_server', '1')
|
||||
o:depends('doh_server', '1')
|
||||
|
||||
---- Support IPV6
|
||||
o = s:taboption("advanced", Flag, "ipv6_server", translate("IPV6 Server"), translate("Enable IPV6 DNS Server"))
|
||||
o.rmempty = false
|
||||
@@ -671,11 +721,26 @@ s = m:section(TypedSection, "smartdns", translate("Download Files Setting"), tra
|
||||
s.anonymous = true
|
||||
|
||||
---- download Files Settings
|
||||
o = s:option(Flag, "enable_auto_update", translate("Enable Auto Update"), translate("Enable daily auto update."))
|
||||
o = s:option(Flag, "enable_auto_update", translate("Enable Auto Update"), translate("Enable daily(week) auto update."))
|
||||
o.rmempty = true
|
||||
o.default = o.disabled
|
||||
o.rempty = true
|
||||
|
||||
o = s:option(ListValue, "auto_update_week_time", translate("Update Time (Every Week)"))
|
||||
o:value("*", translate("Every Day"))
|
||||
o:value("1", translate("Every Monday"))
|
||||
o:value("2", translate("Every Tuesday"))
|
||||
o:value("3", translate("Every Wednesday"))
|
||||
o:value("4", translate("Every Thursday"))
|
||||
o:value("5", translate("Every Friday"))
|
||||
o:value("6", translate("Every Saturday"))
|
||||
o:value("0", translate("Every Sunday"))
|
||||
o.default = "*"
|
||||
|
||||
o = s:option(ListValue, "auto_update_day_time", translate("Update Time (Every Day)"))
|
||||
for i = 0, 23 do o:value(i, i .. ":00") end
|
||||
o.default = 5
|
||||
|
||||
o = s:option(FileUpload, "upload_conf_file", translate("Upload Config File"),
|
||||
translate("Upload smartdns config file to /etc/smartdns/conf.d"))
|
||||
o.rmempty = true
|
||||
@@ -780,4 +845,3 @@ o.write = function()
|
||||
end
|
||||
|
||||
return m
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@ msgid ""
|
||||
"Additional Flags for rules, read help on domain-rule for more information."
|
||||
msgstr "额外的规则标识,具体参考domain-rule的帮助说明。"
|
||||
|
||||
msgid ""
|
||||
"Additional Flags for rules, read help on ip-rule for more information."
|
||||
msgstr "额外的规则标识,具体参考ip-rule的帮助说明。"
|
||||
|
||||
msgid "Additional Rule Flag"
|
||||
msgstr "额外规则标识"
|
||||
|
||||
@@ -29,12 +33,21 @@ msgstr "自动设置Dnsmasq"
|
||||
msgid "Automatically set as upstream of dnsmasq when port changes."
|
||||
msgstr "端口更改时自动设为 dnsmasq 的上游。"
|
||||
|
||||
msgid "Blacklist IP"
|
||||
msgstr "黑名单"
|
||||
|
||||
msgid "Blacklist IP Rule, Decline IP addresses within the range."
|
||||
msgstr "黑名单规则,拒绝指定范围的IP地址。"
|
||||
|
||||
msgid "Bind Device"
|
||||
msgstr "绑定到设备"
|
||||
|
||||
msgid "Bind Device Name"
|
||||
msgstr "绑定的设备名称"
|
||||
|
||||
msgid "Bogus nxdomain"
|
||||
msgstr "假冒IP"
|
||||
|
||||
msgid "Block domain"
|
||||
msgstr "屏蔽域名"
|
||||
|
||||
@@ -64,9 +77,27 @@ msgstr "配置域名规则列表"
|
||||
msgid "Configure forwarding domain name list."
|
||||
msgstr "配置分流域名列表"
|
||||
|
||||
msgid "Configure ip rule list."
|
||||
msgstr "配置IP规则列表"
|
||||
|
||||
msgid "Custom Settings"
|
||||
msgstr "自定义设置"
|
||||
|
||||
msgid "Do not use these IP addresses."
|
||||
msgstr "忽略这些IP地址"
|
||||
|
||||
msgid "DOH Server"
|
||||
msgstr "DOH服务器"
|
||||
|
||||
msgid "DOH Server Port"
|
||||
msgstr "DOH服务器端口"
|
||||
|
||||
msgid "DOT Server"
|
||||
msgstr "DOT服务器"
|
||||
|
||||
msgid "DOT Server Port"
|
||||
msgstr "DOT服务器端口"
|
||||
|
||||
msgid "DNS Block Setting"
|
||||
msgstr "域名屏蔽设置"
|
||||
|
||||
@@ -184,8 +215,44 @@ msgstr "启用IPV6服务器。"
|
||||
msgid "Enable TCP DNS Server"
|
||||
msgstr "启用TCP服务器。"
|
||||
|
||||
msgid "Enable daily auto update."
|
||||
msgstr "启用每日自动更新"
|
||||
msgid "Enable daily (weekly) auto update."
|
||||
msgstr "启用每日(每周)自动更新"
|
||||
|
||||
msgid "Enable DOH DNS Server"
|
||||
msgstr "启用DOH服务器"
|
||||
|
||||
msgid "Enable DOT DNS Server"
|
||||
msgstr "启用DOT服务器"
|
||||
|
||||
msgid "Update time (every day)"
|
||||
msgstr "更新时间(每天)"
|
||||
|
||||
msgid "Update Time (Every Week)"
|
||||
msgstr "更新时间(每周)"
|
||||
|
||||
msgid "Every Day"
|
||||
msgstr "每天"
|
||||
|
||||
msgid "Every Monday"
|
||||
msgstr "每周一"
|
||||
|
||||
msgid "Every Tuesday"
|
||||
msgstr "每周二"
|
||||
|
||||
msgid "Every Wednesday"
|
||||
msgstr "每周三"
|
||||
|
||||
msgid "Every Thursday"
|
||||
msgstr "每周四"
|
||||
|
||||
msgid "Every Friday"
|
||||
msgstr "每周五"
|
||||
|
||||
msgid "Every Saturday"
|
||||
msgstr "每周六"
|
||||
|
||||
msgid "Every Sunday"
|
||||
msgstr "每周日"
|
||||
|
||||
msgid "Enable domain prefetch, accelerate domain response speed."
|
||||
msgstr "启用域名预加载,加速域名响应速度。"
|
||||
@@ -259,6 +326,30 @@ msgstr "IP黑名单过滤"
|
||||
msgid "IPV6 Server"
|
||||
msgstr "IPV6服务器"
|
||||
|
||||
msgid "IP alias"
|
||||
msgstr "IP别名"
|
||||
|
||||
msgid "IP Addresses"
|
||||
msgstr "IP地址"
|
||||
|
||||
msgid "IP Address Mapping, Can be used for CDN acceleration with Anycast IP, such as Cloudflare's CDN."
|
||||
msgstr "IP地址映射,可用于支持AnyCast IP的CDN加速,比如Cloudflare的CDN。"
|
||||
|
||||
msgid "Ignore IP"
|
||||
msgstr "忽略IP"
|
||||
|
||||
msgid "IP Rule List"
|
||||
msgstr "IP规则列表"
|
||||
|
||||
msgid "IP Rule Name"
|
||||
msgstr "IP规则名称"
|
||||
|
||||
msgid "IP Set File"
|
||||
msgstr "IP集合列表文件"
|
||||
|
||||
msgid "IP addresses, CIDR format."
|
||||
msgstr "IP地址,CIDR格式。"
|
||||
|
||||
msgid "IPset Name"
|
||||
msgstr "IPset名称"
|
||||
|
||||
@@ -349,6 +440,9 @@ msgstr "无"
|
||||
msgid "Only socks5 proxy support udp server."
|
||||
msgstr "仅SOCKS5代理支持UDP服务器。"
|
||||
|
||||
msgid "Please check the system logs and check if the configuration is valid."
|
||||
msgstr "请检查系统日志,并检查配置是否合法。"
|
||||
|
||||
msgid "Please set proxy server first."
|
||||
msgstr "请先设置代理服务器。"
|
||||
|
||||
@@ -380,6 +474,9 @@ msgstr "设置返回给客户端的域名TTL最大值。"
|
||||
msgid "Report bugs"
|
||||
msgstr "报告BUG"
|
||||
|
||||
msgid "Return SOA when the requested result contains a specified IP address."
|
||||
msgstr "当结果包含对应范围的IP时,返回SOA。"
|
||||
|
||||
msgid "Resolve Local Hostnames"
|
||||
msgstr "解析本地主机名"
|
||||
|
||||
@@ -398,6 +495,15 @@ msgstr "重启服务"
|
||||
msgid "Second Server Settings"
|
||||
msgstr "第二DNS服务器"
|
||||
|
||||
msgid "Server certificate file path."
|
||||
msgstr "服务器证书文件路径。"
|
||||
|
||||
msgid "Server certificate key file path."
|
||||
msgstr "服务器证书私钥文件路径。"
|
||||
|
||||
msgid "Server certificate key file password."
|
||||
msgstr "服务器证书私钥文件密码。"
|
||||
|
||||
msgid "Serve expired"
|
||||
msgstr "缓存过期服务"
|
||||
|
||||
@@ -410,6 +516,15 @@ msgstr "服务器组%s不存在"
|
||||
msgid "Server Name"
|
||||
msgstr "服务器名称"
|
||||
|
||||
msgid "Server Cert"
|
||||
msgstr "服务器证书"
|
||||
|
||||
msgid "Server Cert Key"
|
||||
msgstr "服务器证书私钥"
|
||||
|
||||
msgid "Server Cert Key Pass"
|
||||
msgstr "服务器证书私钥密码"
|
||||
|
||||
msgid "Set Specific domain ip address."
|
||||
msgstr "设置指定域名的IP地址。"
|
||||
|
||||
@@ -419,6 +534,9 @@ msgstr "设置指定域名的规则列表。"
|
||||
msgid "Set Specific ip blacklist."
|
||||
msgstr "设置指定的 IP 黑名单列表。"
|
||||
|
||||
msgid "Set Specific ip rule list."
|
||||
msgstr "设置对应IP的规则。"
|
||||
|
||||
msgid "Set TLS hostname to verify."
|
||||
msgstr "设置校验TLS主机名。"
|
||||
|
||||
@@ -478,6 +596,12 @@ msgstr "跳过Nameserver规则。"
|
||||
msgid "SmartDNS"
|
||||
msgstr "SmartDNS"
|
||||
|
||||
msgid "Smartdns DOH server port."
|
||||
msgstr "Smartdns DOH服务器端口号。
|
||||
|
||||
msgid "Smartdns DOT server port."
|
||||
msgstr "Smartdns DOT服务器端口号。"
|
||||
|
||||
msgid "SmartDNS Server"
|
||||
msgstr "SmartDNS 服务器"
|
||||
|
||||
@@ -575,6 +699,9 @@ msgstr "上传域名列表文件,或在下载文件设置页面设置自动下
|
||||
msgid "Upload domain list file."
|
||||
msgstr "上传域名列表文件"
|
||||
|
||||
msgid "Upload IP set file."
|
||||
msgstr "上传IP集合列表文件。"
|
||||
|
||||
msgid "Upload smartdns config file to /etc/smartdns/conf.d"
|
||||
msgstr "上传配置文件到/etc/smartdns/conf.d"
|
||||
|
||||
@@ -602,6 +729,12 @@ msgstr ""
|
||||
"用于校验 TLS 服务器的有效性,数值为 Base64 编码的 SPKI 指纹,留空表示不验证 "
|
||||
"TLS 的合法性。"
|
||||
|
||||
msgid "Whitelist IP"
|
||||
msgstr "白名单"
|
||||
|
||||
msgid "Whitelist IP Rule, Accept IP addresses within the range."
|
||||
msgstr "白名单规则,接受指定范围的IP地址。"
|
||||
|
||||
msgid "Write cache to disk on exit and load on startup."
|
||||
msgstr "退出时保存cache到磁盘,启动时加载。"
|
||||
|
||||
|
||||
@@ -58,12 +58,17 @@ function smartdnsRenderStatus(res) {
|
||||
|
||||
var autoSetDnsmasq = uci.get_first('smartdns', 'smartdns', 'auto_set_dnsmasq');
|
||||
var smartdnsPort = uci.get_first('smartdns', 'smartdns', 'port');
|
||||
var smartdnsEnable = uci.get_first('smartdns', 'smartdns', 'enabled');
|
||||
var dnsmasqServer = uci.get_first('dhcp', 'dnsmasq', 'server');
|
||||
|
||||
if (isRunning) {
|
||||
renderHTML += "<span style=\"color:green;font-weight:bold\">SmartDNS - " + _("RUNNING") + "</span>";
|
||||
} else {
|
||||
renderHTML += "<span style=\"color:red;font-weight:bold\">SmartDNS - " + _("NOT RUNNING") + "</span>";
|
||||
if (smartdnsEnable === '1') {
|
||||
renderHTML += "<br /><span style=\"color:red;font-weight:bold\">" + _("Please check the system logs and check if the configuration is valid.");
|
||||
renderHTML += "</span>";
|
||||
}
|
||||
return renderHTML;
|
||||
}
|
||||
|
||||
@@ -79,7 +84,6 @@ function smartdnsRenderStatus(res) {
|
||||
|
||||
return renderHTML;
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
load: function () {
|
||||
return Promise.all([
|
||||
@@ -156,7 +160,7 @@ return view.extend({
|
||||
o.default = 53;
|
||||
o.datatype = "port";
|
||||
o.rempty = false;
|
||||
|
||||
|
||||
// auto-conf-dnsmasq;
|
||||
o = s.taboption("settings", form.Flag, "auto_set_dnsmasq", _("Automatically Set Dnsmasq"), _("Automatically set as upstream of dnsmasq when port changes."));
|
||||
o.rmempty = false;
|
||||
@@ -220,6 +224,50 @@ return view.extend({
|
||||
o.rmempty = false;
|
||||
o.default = o.enabled;
|
||||
|
||||
// Enable DOT server;
|
||||
o = s.taboption("advanced", form.Flag, "tls_server", _("DOT Server"), _("Enable DOT DNS Server"));
|
||||
o.rmempty = false;
|
||||
o.default = o.disabled;
|
||||
|
||||
o = s.taboption("advanced", form.Value, "tls_server_port", _("DOT Server Port"), _("Smartdns DOT server port."));
|
||||
o.placeholder = 853;
|
||||
o.default = 853;
|
||||
o.datatype = "port";
|
||||
o.rempty = false;
|
||||
o.depends('tls_server', '1');
|
||||
|
||||
// Enable DOH server;
|
||||
o = s.taboption("advanced", form.Flag, "doh_server", _("DOH Server"), _("Enable DOH DNS Server"));
|
||||
o.rmempty = false;
|
||||
o.default = o.disabled;
|
||||
|
||||
o = s.taboption("advanced", form.Value, "doh_server_port", _("DOH Server Port"), _("Smartdns DOH server port."));
|
||||
o.placeholder = 843;
|
||||
o.default = 843;
|
||||
o.datatype = "port";
|
||||
o.rempty = false;
|
||||
o.depends('doh_server', '1');
|
||||
|
||||
o = s.taboption("advanced", form.Value, "bind_cert", _("Server Cert"), _("Server certificate file path."));
|
||||
o.datatype = "string";
|
||||
o.placeholder = "/var/etc/smartdns/smartdns/smartdns-cert.pem"
|
||||
o.rempty = true;
|
||||
o.depends('tls_server', '1');
|
||||
o.depends('doh_server', '1');
|
||||
|
||||
o = s.taboption("advanced", form.Value, "bind_cert_key", _("Server Cert Key"), _("Server certificate key file path."));
|
||||
o.datatype = "string";
|
||||
o.placeholder = "/var/etc/smartdns/smartdns/smartdns-key.pem"
|
||||
o.rempty = false;
|
||||
o.depends('tls_server', '1');
|
||||
o.depends('doh_server', '1');
|
||||
|
||||
o = s.taboption("advanced", form.Value, "bind_cert_key_pass", _("Server Cert Key Pass"), _("Server certificate key file password."));
|
||||
o.datatype = "string";
|
||||
o.rempty = false;
|
||||
o.depends('tls_server', '1');
|
||||
o.depends('doh_server', '1');
|
||||
|
||||
// Support IPV6;
|
||||
o = s.taboption("advanced", form.Flag, "ipv6_server", _("IPV6 Server"), _("Enable IPV6 DNS Server"));
|
||||
o.rmempty = false;
|
||||
@@ -279,7 +327,7 @@ return view.extend({
|
||||
o.default = o.enabled;
|
||||
|
||||
// Ipset no speed.
|
||||
o = s.taboption("advanced", form.Value, "ipset_no_speed", _("No Speed IPset Name"),
|
||||
o = s.taboption("advanced", form.Value, "ipset_no_speed", _("No Speed IPset Name"),
|
||||
_("Ipset name, Add domain result to ipset when speed check fails."));
|
||||
o.rmempty = true;
|
||||
o.datatype = "string";
|
||||
@@ -300,7 +348,7 @@ return view.extend({
|
||||
}
|
||||
|
||||
// NFTset no speed.
|
||||
o = s.taboption("advanced", form.Value, "nftset_no_speed", _("No Speed NFTset Name"),
|
||||
o = s.taboption("advanced", form.Value, "nftset_no_speed", _("No Speed NFTset Name"),
|
||||
_("Nftset name, Add domain result to nftset when speed check fails, format: [#[4|6]:[family#table#set]]"));
|
||||
o.rmempty = true;
|
||||
o.datatype = "string";
|
||||
@@ -343,7 +391,7 @@ return view.extend({
|
||||
o.rempty = true;
|
||||
|
||||
// other args
|
||||
o = s.taboption("advanced", form.Value, "server_flags", _("Additional Server Args"),
|
||||
o = s.taboption("advanced", form.Value, "server_flags", _("Additional Server Args"),
|
||||
_("Additional server args, refer to the help description of the bind option."))
|
||||
o.default = ""
|
||||
o.rempty = true
|
||||
@@ -476,7 +524,7 @@ return view.extend({
|
||||
}
|
||||
|
||||
// other args
|
||||
o = s.taboption("seconddns", form.Value, "seconddns_server_flags", _("Additional Server Args"),
|
||||
o = s.taboption("seconddns", form.Value, "seconddns_server_flags", _("Additional Server Args"),
|
||||
_("Additional server args, refer to the help description of the bind option."))
|
||||
o.default = ""
|
||||
o.rempty = true
|
||||
@@ -492,11 +540,29 @@ return view.extend({
|
||||
///////////////////////////////////////
|
||||
// download Files Settings
|
||||
///////////////////////////////////////
|
||||
o = s.taboption("files", form.Flag, "enable_auto_update", _("Enable Auto Update"), _("Enable daily auto update."));
|
||||
o = s.taboption("files", form.Flag, "enable_auto_update", _("Enable Auto Update"), _("Enable daily (weekly) auto update."));
|
||||
o.rmempty = true;
|
||||
o.default = o.disabled;
|
||||
o.rempty = true;
|
||||
|
||||
o = s.taboption("files", form.ListValue, "auto_update_week_time", _("Update Time (Every Week)"));
|
||||
o.value('*', _('Every Day'));
|
||||
o.value('1', _('Every Monday'));
|
||||
o.value('2', _('Every Tuesday'));
|
||||
o.value('3', _('Every Wednesday'));
|
||||
o.value('4', _('Every Thursday'));
|
||||
o.value('5', _('Every Friday'));
|
||||
o.value('6', _('Every Saturday'));
|
||||
o.value('0', _('Every Sunday'));
|
||||
o.default = "*";
|
||||
o.depends('enable_auto_update', '1');
|
||||
|
||||
o = s.taboption('files', form.ListValue, 'auto_update_day_time', _("Update time (every day)"));
|
||||
for (var i = 0; i < 24; i++)
|
||||
o.value(i, i + ':00');
|
||||
o.default = '5';
|
||||
o.depends('enable_auto_update', '1');
|
||||
|
||||
o = s.taboption("files", form.FileUpload, "upload_conf_file", _("Upload Config File"),
|
||||
_("Upload smartdns config file to /etc/smartdns/conf.d"));
|
||||
o.rmempty = true
|
||||
@@ -804,6 +870,7 @@ return view.extend({
|
||||
s.tab("forwarding", _('DNS Forwarding Setting'));
|
||||
s.tab("block", _("DNS Block Setting"));
|
||||
s.tab("domain-rule-list", _("Domain Rule List"), _("Set Specific domain rule list."));
|
||||
s.tab("ip-rule-list", _("IP Rule List"), _("Set Specific ip rule list."));
|
||||
s.tab("domain-address", _("Domain Address"), _("Set Specific domain ip address."));
|
||||
s.tab("blackip-list", _("IP Blacklist"), _("Set Specific ip blacklist."));
|
||||
|
||||
@@ -1131,6 +1198,72 @@ return view.extend({
|
||||
});
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
// ip rule list;
|
||||
///////////////////////////////////////
|
||||
o = s.taboption('ip-rule-list', form.SectionValue, '__ip-rule-list__', form.GridSection, 'ip-rule-list', _('IP Rule List'),
|
||||
_('Configure ip rule list.'));
|
||||
|
||||
ss = o.subsection;
|
||||
|
||||
ss.addremove = true;
|
||||
ss.anonymous = true;
|
||||
ss.sortable = true;
|
||||
|
||||
// enable flag;
|
||||
so = ss.option(form.Flag, "enabled", _("Enable"), _("Enable"));
|
||||
so.rmempty = false;
|
||||
so.default = so.enabled;
|
||||
so.editable = true;
|
||||
|
||||
// name;
|
||||
so = ss.option(form.Value, "name", _("IP Rule Name"), _("IP Rule Name"));
|
||||
so.rmempty = true;
|
||||
so.datatype = "string";
|
||||
|
||||
so = ss.option(form.FileUpload, "ip_set_file", _("IP Set File"), _("Upload IP set file."));
|
||||
so.rmempty = true
|
||||
so.datatype = "file"
|
||||
so.modalonly = true;
|
||||
so.root_directory = "/etc/smartdns/ip-set"
|
||||
|
||||
so = ss.option(form.DynamicList, "ip_addr", _("IP Addresses"), _("IP addresses, CIDR format."));
|
||||
so.rmempty = true;
|
||||
so.datatype = "ipaddr"
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.option(form.Flag, "whitelist_ip", _("Whitelist IP"), _("Whitelist IP Rule, Accept IP addresses within the range."));
|
||||
so.rmempty = true;
|
||||
so.default = so.disabled;
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.option(form.Flag, "blacklist_ip", _("Blacklist IP"), _("Blacklist IP Rule, Decline IP addresses within the range."));
|
||||
so.rmempty = true;
|
||||
so.default = so.disabled;
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.option(form.Flag, "ignore_ip", _("Ignore IP"), _("Do not use these IP addresses."));
|
||||
so.rmempty = true;
|
||||
so.default = so.disabled;
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.option(form.Flag, "bogus_nxdomain", _("Bogus nxdomain"), _("Return SOA when the requested result contains a specified IP address."));
|
||||
so.rmempty = true;
|
||||
so.default = so.disabled;
|
||||
so.modalonly = true;
|
||||
|
||||
so = ss.option(form.DynamicList, "ip_alias", _("IP alias"), _("IP Address Mapping, Can be used for CDN acceleration with Anycast IP, such as Cloudflare's CDN."));
|
||||
so.rmempty = true;
|
||||
so.datatype = 'ipaddr("nomask")';
|
||||
so.modalonly = true;
|
||||
|
||||
// other args
|
||||
so = ss.option(form.Value, "addition_flag", _("Additional Rule Flag"),
|
||||
_("Additional Flags for rules, read help on ip-rule for more information."))
|
||||
so.default = ""
|
||||
so.rempty = true
|
||||
so.modalonly = true;
|
||||
|
||||
////////////////
|
||||
// Support
|
||||
////////////////
|
||||
|
||||
@@ -50,12 +50,14 @@ endef
|
||||
|
||||
define Package/smartdns/install
|
||||
$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/config $(1)/etc/init.d
|
||||
$(INSTALL_DIR) $(1)/etc/smartdns $(1)/etc/smartdns/domain-set $(1)/etc/smartdns/conf.d/
|
||||
$(INSTALL_DIR) $(1)/etc/smartdns $(1)/etc/smartdns/domain-set $(1)/etc/smartdns/conf.d/ $(1)/etc/smartdns/ip-set
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/smartdns $(1)/usr/sbin/smartdns
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/package/openwrt/files/etc/init.d/smartdns $(1)/etc/init.d/smartdns
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/address.conf $(1)/etc/smartdns/address.conf
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/blacklist-ip.conf $(1)/etc/smartdns/blacklist-ip.conf
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/custom.conf $(1)/etc/smartdns/custom.conf
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/domain-block.list $(1)/etc/smartdns/domain-block.list
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/domain-forwarding.list $(1)/etc/smartdns/domain-forwarding.list
|
||||
$(INSTALL_CONF) $(PKG_BUILD_DIR)/package/openwrt/files/etc/config/smartdns $(1)/etc/config/smartdns
|
||||
endef
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# Add custom settings here.
|
||||
# please read https://pymumu.github.io/smartdns/config/basic-config/
|
||||
# please read https://pymumu.github.io/smartdns/config/basic-config/
|
||||
|
||||
@@ -27,6 +27,8 @@ if [ ! -d "/run" ]; then
|
||||
SERVICE_PID_FILE="/var/run/smartdns.pid"
|
||||
fi
|
||||
|
||||
SMARTDNS_DEFAULT_FORWARDING_FILE="/etc/smartdns/domain-forwarding.list"
|
||||
SMARTDNS_DEFAULT_DOMAIN_BLOCK_FILE="/etc/smartdns/domain-block.list"
|
||||
SMARTDNS_CONF_DIR="/etc/smartdns"
|
||||
SMARTDNS_CONF_DOWNLOAD_DIR="$SMARTDNS_CONF_DIR/conf.d"
|
||||
SMARTDNS_DOMAIN_LIST_DOWNLOAD_DIR="$SMARTDNS_CONF_DIR/domain-set"
|
||||
@@ -124,6 +126,10 @@ clear_iptable()
|
||||
{
|
||||
local OLD_PORT="$1"
|
||||
local ipv6_server=$2
|
||||
|
||||
which iptables >/dev/null 2>&1
|
||||
[ $? -ne 0 ] && return
|
||||
|
||||
IPS="$(ifconfig | grep "inet addr" | grep -v ":127" | grep "Bcast" | awk '{print $2}' | awk -F : '{print $2}')"
|
||||
for IP in $IPS
|
||||
do
|
||||
@@ -260,13 +266,13 @@ disable_auto_update()
|
||||
|
||||
enable_auto_update()
|
||||
{
|
||||
grep "0 5 * * * /etc/init.d/smartdns updatefiles" /etc/crontabs/root 2>/dev/null
|
||||
grep "0 $auto_update_day_time * * $auto_update_week_time /etc/init.d/smartdns updatefiles" /etc/crontabs/root 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
disable_auto_update 1
|
||||
echo "0 5 * * * /etc/init.d/smartdns updatefiles" >> /etc/crontabs/root
|
||||
echo "0 $auto_update_day_time * * $auto_update_week_time /etc/init.d/smartdns updatefiles" >> /etc/crontabs/root
|
||||
restart_crond
|
||||
}
|
||||
|
||||
@@ -296,23 +302,27 @@ load_domain_rules()
|
||||
|
||||
config_get forwarding_domain_set_file "$section" "forwarding_domain_set_file" ""
|
||||
[ ! -z "$forwarding_domain_set_file" ] && {
|
||||
[ ! -e "$forwarding_domain_set_file" ] && touch $forwarding_domain_set_file
|
||||
conf_append "domain-set" "-name ${domain_set_name}-forwarding-file -file '$forwarding_domain_set_file'"
|
||||
conf_append "domain-rules" "/domain-set:${domain_set_name}-forwarding-file/ $domain_set_args"
|
||||
}
|
||||
|
||||
[ ! -z "$domain_set_args" ] && {
|
||||
conf_append "domain-set" "-name ${domain_set_name}-forwarding-list -file /etc/smartdns/domain-forwarding.list"
|
||||
[ ! -e "$SMARTDNS_DEFAULT_FORWARDING_FILE" ] && touch $SMARTDNS_DEFAULT_FORWARDING_FILE
|
||||
conf_append "domain-set" "-name ${domain_set_name}-forwarding-list -file $SMARTDNS_DEFAULT_FORWARDING_FILE"
|
||||
conf_append "domain-rules" "/domain-set:${domain_set_name}-forwarding-list/ $domain_set_args"
|
||||
}
|
||||
|
||||
config_get block_domain_set_file "$section" "block_domain_set_file"
|
||||
[ ! -z "$block_domain_set_file" ] && {
|
||||
[ ! -e "$block_domain_set_file" ] && touch $block_domain_set_file
|
||||
conf_append "domain-set" "-name ${domain_set_name}-block-file -file '$block_domain_set_file'"
|
||||
conf_append "domain-rules" "/domain-set:${domain_set_name}-block-file/ -group block"
|
||||
conf_append "domain-rules" "/domain-set:${domain_set_name}-block-file/ -address #"
|
||||
}
|
||||
|
||||
conf_append "domain-set" "-name ${domain_set_name}-block-list -file /etc/smartdns/domain-block.list"
|
||||
conf_append "domain-rules" "/domain-set:${domain_set_name}-block-list/ --address #"
|
||||
[ ! -e "$SMARTDNS_DEFAULT_DOMAIN_BLOCK_FILE" ] && touch $SMARTDNS_DEFAULT_DOMAIN_BLOCK_FILE
|
||||
conf_append "domain-set" "-name ${domain_set_name}-block-list -file $SMARTDNS_DEFAULT_DOMAIN_BLOCK_FILE"
|
||||
conf_append "domain-rules" "/domain-set:${domain_set_name}-block-list/ -address #"
|
||||
}
|
||||
|
||||
load_domain_rule_list()
|
||||
@@ -355,16 +365,64 @@ load_domain_rule_list()
|
||||
[ ! -z "$addition_flag" ] && domain_set_args="$domain_set_args $addition_flag"
|
||||
[ -z "$domain_set_args" ] && return
|
||||
|
||||
[ ! -e "$domain_list_file" ] && touch $domain_list_file
|
||||
conf_append "domain-set" "-name domain-rule-list-${domain_set_name} -file '$domain_list_file'"
|
||||
conf_append "domain-rules" "/domain-set:domain-rule-list-${domain_set_name}/ $domain_set_args"
|
||||
}
|
||||
|
||||
ip_rule_addr_append()
|
||||
{
|
||||
conf_append "ip-rules" "$1 $IP_set_args"
|
||||
}
|
||||
|
||||
load_IP_rule_list()
|
||||
{
|
||||
local section="$1"
|
||||
local IP_set_args=""
|
||||
local IP_set_name="$section"
|
||||
|
||||
config_get_bool enabled "$section" "enabled" "0"
|
||||
[ "$enabled" != "1" ] && return
|
||||
|
||||
config_get ip_set_file "$section" "ip_set_file" ""
|
||||
|
||||
config_get_bool whitelist_ip "$section" "whitelist_ip" "0"
|
||||
[ "$whitelist_ip" = "1" ] && IP_set_args="$IP_set_args -whitelist-ip"
|
||||
|
||||
config_get_bool blacklist_ip "$section" "blacklist_ip" "0"
|
||||
[ "$blacklist_ip" = "1" ] && IP_set_args="$IP_set_args -blacklist-ip"
|
||||
|
||||
config_get_bool ignore_ip "$section" "ignore_ip" "0"
|
||||
[ "$ignore_ip" = "1" ] && IP_set_args="$IP_set_args -ignore-ip"
|
||||
|
||||
config_get_bool bogus_nxdomain "$section" "bogus_nxdomain" "0"
|
||||
[ "$bogus_nxdomain" = "1" ] && IP_set_args="$IP_set_args -bogus-nxdomain"
|
||||
|
||||
config_get ip_alias "$section" "ip_alias" ""
|
||||
[ ! -z "$ip_alias" ] && {
|
||||
ip_alias="$(echo "$ip_alias" | sed 's/ /,/g')"
|
||||
IP_set_args="$IP_set_args -ip-alias $ip_alias"
|
||||
}
|
||||
|
||||
config_get addition_flag "$section" "addition_flag" ""
|
||||
[ ! -z "$addition_flag" ] && IP_set_args="$IP_set_args $addition_flag"
|
||||
[ -z "$IP_set_args" ] && return
|
||||
|
||||
[ ! -z "$ip_set_file" ] && [ -e "$ip_set_file" ] && {
|
||||
conf_append "ip-set" "-name ip-rule-list-file-${section} -file '$ip_set_file'"
|
||||
conf_append "ip-rules" "ip-set:ip-rule-list-file-${section} $IP_set_args"
|
||||
}
|
||||
|
||||
config_list_foreach "$section" "ip_addr" ip_rule_addr_append
|
||||
}
|
||||
|
||||
conf_append_bind()
|
||||
{
|
||||
local ADDR=""
|
||||
local port="$1"
|
||||
local devices="$2"
|
||||
local tcp_server="$3"
|
||||
local bind_type="$1"
|
||||
local port="$2"
|
||||
local devices="$3"
|
||||
local device=""
|
||||
local ipv6_server="$4"
|
||||
local ARGS="$5"
|
||||
|
||||
@@ -381,16 +439,8 @@ conf_append_bind()
|
||||
for device in $devices; do
|
||||
device="@$device"
|
||||
[ "$device" = "@-" ] && device=""
|
||||
conf_append "bind" "$ADDR:$port$device $ARGS"
|
||||
conf_append "$bind_type" "$ADDR:$port$device $ARGS"
|
||||
done
|
||||
|
||||
[ "$tcp_server" = "1" ] && {
|
||||
for device in $devices; do
|
||||
device="@$device"
|
||||
[ "$device" = "@-" ] && device=""
|
||||
conf_append "bind-tcp" "$ADDR:$port$device $ARGS"
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
load_second_server()
|
||||
@@ -448,7 +498,8 @@ load_second_server()
|
||||
config_get seconddns_server_flags "$section" "seconddns_server_flags" ""
|
||||
[ -z "$seconddns_server_flags" ] || ARGS="$ARGS $seconddns_server_flags"
|
||||
|
||||
conf_append_bind "$seconddns_port" "$device" "$seconddns_tcp_server" "$ipv6_server" "$ARGS"
|
||||
conf_append_bind "bind" "$seconddns_port" "$device" "$ipv6_server" "$ARGS"
|
||||
[ "$seconddns_tcp_server" = "1" ] && conf_append_bind "bind-tcp" "$seconddns_port" "$device" "$ipv6_server" "$ARGS"
|
||||
}
|
||||
|
||||
conf_append_conf_files()
|
||||
@@ -496,8 +547,18 @@ load_service()
|
||||
config_get port "$section" "port" "53"
|
||||
config_get ipv6_server "$section" "ipv6_server" "1"
|
||||
config_get tcp_server "$section" "tcp_server" "1"
|
||||
config_get tls_server "$section" "tls_server" "0"
|
||||
config_get tls_server_port "$section" "tls_server_port" "853"
|
||||
config_get doh_server "$section" "doh_server" "0"
|
||||
config_get doh_server_port "$section" "doh_server_port" "843"
|
||||
config_get bind_cert "$section" "bind_cert" ""
|
||||
config_get bind_cert_key "$section" "bind_cert_key" ""
|
||||
config_get bind_cert_key_pass "$section" "bind_cert_key_pass" ""
|
||||
config_get server_flags "$section" "server_flags" ""
|
||||
|
||||
config_get auto_update_week_time "$section" "auto_update_week_time" "*"
|
||||
config_get auto_update_day_time "$section" "auto_update_day_time" "5"
|
||||
|
||||
config_get speed_check_mode "$section" "speed_check_mode" ""
|
||||
[ ! -z "$speed_check_mode" ] && conf_append "speed-check-mode" "$speed_check_mode"
|
||||
|
||||
@@ -649,7 +710,14 @@ load_service()
|
||||
[ "$auto_set_dnsmasq" = "0" ] && [ "$old_auto_set_dnsmasq" = "1" ] && stop_forward_dnsmasq "$old_port" "0"
|
||||
}
|
||||
|
||||
conf_append_bind "$port" "$device" "$tcp_server" "$ipv6_server" "$server_flags"
|
||||
conf_append_bind "bind" "$port" "$device" "$ipv6_server" "$server_flags"
|
||||
[ "$tcp_server" = "1" ] && conf_append_bind "bind-tcp" "$port" "$device" "$ipv6_server" "$server_flags"
|
||||
[ "$tls_server" = "1" ] && conf_append_bind "bind-tls" "$tls_server_port" "$device" "$ipv6_server" "$server_flags"
|
||||
[ "$doh_server" = "1" ] && conf_append_bind "bind-https" "$doh_server_port" "$device" "$ipv6_server" "$server_flags"
|
||||
|
||||
[ ! -z "$bind_cert" ] && conf_append "bind-cert-file" "$bind_cert"
|
||||
[ ! -z "$bind_cert_key" ] && conf_append "bind-cert-key-file" "$bind_cert_key"
|
||||
[ ! -z "$bind_cert_key_pass" ] && conf_append "bind-cert-key-pass" "$bind_cert_key_pass"
|
||||
|
||||
load_second_server "$section"
|
||||
|
||||
@@ -661,6 +729,8 @@ load_service()
|
||||
|
||||
config_foreach load_domain_rule_list "domain-rule-list"
|
||||
|
||||
config_foreach load_IP_rule_list "ip-rule-list"
|
||||
|
||||
{
|
||||
echo "conf-file $ADDRESS_CONF"
|
||||
echo "conf-file $BLACKLIST_IP_CONF"
|
||||
|
||||
@@ -48,6 +48,7 @@ build()
|
||||
mkdir $ROOT/root/etc/init.d -p
|
||||
mkdir $ROOT/root/etc/smartdns/ -p
|
||||
mkdir $ROOT/root/etc/smartdns/domain-set/ -p
|
||||
mkdir $ROOT/root/etc/smartdns/ip-set/ -p
|
||||
mkdir $ROOT/root/etc/smartdns/conf.d/ -p
|
||||
|
||||
cp $SMARTDNS_CONF $ROOT/root/etc/smartdns/
|
||||
|
||||
@@ -121,8 +121,7 @@ restart_dnsmasq()
|
||||
PID2="$(echo "$CMD" | awk 'NR==2{print $1}')"
|
||||
PID2_PPID="$(grep 'PPid:' /proc/$PID2/status | awk '{print $2}' 2>/dev/null)"
|
||||
if [ "$PID2_PPID" != "$PID1" ]; then
|
||||
echo "find multiple dnsmasq, but not started by the same process"
|
||||
return 1
|
||||
kill -9 "$PID2"
|
||||
fi
|
||||
PID=$PID1
|
||||
else
|
||||
@@ -341,9 +340,12 @@ case "$1" in
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SMARTDNS_OPTION=""
|
||||
[ "$SMARTDNS_CRASH_RESTART" = "1" ] && SMARTDNS_OPTION="$SMARTDNS_OPTION -R"
|
||||
|
||||
set_smartdns_port
|
||||
get_tz
|
||||
$SMARTDNS_BIN -c "$SMARTDNS_CONF" -p $SMARTDNS_PID
|
||||
$SMARTDNS_BIN -c "$SMARTDNS_CONF" -p $SMARTDNS_PID $SMARTDNS_OPTION
|
||||
if [ $? -ne 0 ]; then
|
||||
clear_rule
|
||||
exit 1
|
||||
|
||||
@@ -5,4 +5,7 @@
|
||||
SMARTDNS_WORKMODE="1"
|
||||
|
||||
# smartdns port
|
||||
SMARTDNS_PORT="535"
|
||||
SMARTDNS_PORT="535"
|
||||
|
||||
# restart when crash
|
||||
SMARTDNS_CRASH_RESTART="1"
|
||||
12
src/Makefile
12
src/Makefile
@@ -15,8 +15,9 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
BIN=smartdns
|
||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o lib/nftset.o
|
||||
OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o $(OBJS_LIB)
|
||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/timer_wheel.o lib/idna.o lib/conf.o lib/nftset.o
|
||||
OBJS_MAIN=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o timer.o
|
||||
OBJS=$(OBJS_MAIN) $(OBJS_LIB)
|
||||
|
||||
# cflags
|
||||
ifndef CFLAGS
|
||||
@@ -27,7 +28,7 @@ ifndef CFLAGS
|
||||
endif
|
||||
CFLAGS +=-Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing -funwind-tables -Wmissing-prototypes -Wshadow -Wextra -Wno-unused-parameter -Wno-implicit-fallthrough
|
||||
endif
|
||||
override CFLAGS +=-Iinclude
|
||||
override CFLAGS +=-Iinclude -I/home/rock/code/build/openssl/openssl-3.2.0/include
|
||||
override CFLAGS += -DBASE_FILE_NAME='"$(notdir $<)"'
|
||||
override CFLAGS += $(EXTRA_CFLAGS)
|
||||
ifdef VER
|
||||
@@ -39,7 +40,7 @@ override CXXFLAGS +=-Iinclude
|
||||
|
||||
# ldflags
|
||||
ifeq ($(STATIC), yes)
|
||||
override LDFLAGS += -lssl -lcrypto -Wl,--whole-archive -lpthread -Wl,--no-whole-archive -ldl -static
|
||||
override LDFLAGS += -lssl -lcrypto -Wl,--whole-archive -lpthread -Wl,--no-whole-archive -ldl -static -L/home/rock/code/build/openssl/openssl-3.2.0
|
||||
else
|
||||
override LDFLAGS += -lssl -lcrypto -lpthread -ldl
|
||||
endif
|
||||
@@ -51,5 +52,8 @@ all: $(BIN)
|
||||
$(BIN) : $(OBJS)
|
||||
$(CC) $(OBJS) -o $@ $(LDFLAGS)
|
||||
|
||||
clang-tidy:
|
||||
clang-tidy -p=. $(OBJS_MAIN:.o=.c) -- $(CFLAGS)
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS) $(BIN)
|
||||
|
||||
219
src/dns.c
219
src/dns.c
@@ -738,14 +738,14 @@ static int _dns_add_opt_RAW(struct dns_packet *packet, dns_opt_code_t opt_rrtype
|
||||
struct dns_opt *opt = (struct dns_opt *)opt_data;
|
||||
int len = 0;
|
||||
|
||||
opt->code = DNS_OPT_T_TCP_KEEPALIVE;
|
||||
opt->code = opt_rrtype;
|
||||
opt->length = sizeof(unsigned short);
|
||||
|
||||
memcpy(opt->data, raw, raw_len);
|
||||
len += raw_len;
|
||||
len += sizeof(*opt);
|
||||
|
||||
return _dns_add_RAW(packet, DNS_RRS_OPT, (dns_type_t)DNS_OPT_T_TCP_KEEPALIVE, "", 0, opt_data, len);
|
||||
return _dns_add_RAW(packet, DNS_RRS_OPT, (dns_type_t)opt_rrtype, "", 0, opt_data, len);
|
||||
}
|
||||
|
||||
static int _dns_get_opt_RAW(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, struct dns_opt *dns_opt,
|
||||
@@ -759,8 +759,6 @@ static int _dns_get_opt_RAW(struct dns_rrs *rrs, char *domain, int maxsize, int
|
||||
static int __attribute__((unused)) _dns_add_OPT(struct dns_packet *packet, dns_rr_type type, unsigned short opt_code,
|
||||
unsigned short opt_len, struct dns_opt *opt)
|
||||
{
|
||||
// TODO
|
||||
|
||||
int ret = 0;
|
||||
int len = 0;
|
||||
struct dns_context context;
|
||||
@@ -806,8 +804,6 @@ static int __attribute__((unused)) _dns_add_OPT(struct dns_packet *packet, dns_r
|
||||
static int __attribute__((unused)) _dns_get_OPT(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len,
|
||||
struct dns_opt *opt, int *opt_maxlen)
|
||||
{
|
||||
// TODO
|
||||
|
||||
int qtype = 0;
|
||||
int qclass = 0;
|
||||
int rr_len = 0;
|
||||
@@ -875,6 +871,27 @@ int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *
|
||||
return _dns_get_RAW(rrs, domain, maxsize, ttl, cname, &len);
|
||||
}
|
||||
|
||||
int dns_add_TXT(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *text)
|
||||
{
|
||||
int rr_len = strnlen(text, DNS_MAX_CNAME_LEN);
|
||||
char data[DNS_MAX_CNAME_LEN];
|
||||
|
||||
if (rr_len > DNS_MAX_CNAME_LEN - 2) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data[0] = rr_len;
|
||||
rr_len++;
|
||||
memcpy(data + 1, text, rr_len);
|
||||
data[rr_len] = 0;
|
||||
return _dns_add_RAW(packet, type, DNS_T_TXT, domain, ttl, data, rr_len);
|
||||
}
|
||||
|
||||
int dns_get_TXT(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *text, int txt_size)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_add_NS(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname)
|
||||
{
|
||||
int rr_len = strnlen(cname, DNS_MAX_CNAME_LEN) + 1;
|
||||
@@ -1013,7 +1030,7 @@ int dns_add_OPT_ECS(struct dns_packet *packet, struct dns_opt_ecs *ecs)
|
||||
return _dns_add_RAW(packet, DNS_RRS_OPT, (dns_type_t)DNS_OPT_T_ECS, "", 0, opt_data, len);
|
||||
}
|
||||
|
||||
int dns_get_OPT_ECS(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, struct dns_opt_ecs *ecs)
|
||||
int dns_get_OPT_ECS(struct dns_rrs *rrs, struct dns_opt_ecs *ecs)
|
||||
{
|
||||
unsigned char opt_data[DNS_MAX_OPT_LEN];
|
||||
char domain[DNS_MAX_CNAME_LEN] = {0};
|
||||
@@ -1050,16 +1067,16 @@ int dns_add_OPT_TCP_KEEPALIVE(struct dns_packet *packet, unsigned short timeout)
|
||||
return _dns_add_opt_RAW(packet, DNS_OPT_T_TCP_KEEPALIVE, &timeout_net, data_len);
|
||||
}
|
||||
|
||||
int dns_get_OPT_TCP_KEEPALIVE(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len,
|
||||
unsigned short *timeout)
|
||||
int dns_get_OPT_TCP_KEEPALIVE(struct dns_rrs *rrs, unsigned short *timeout)
|
||||
{
|
||||
unsigned char opt_data[DNS_MAX_OPT_LEN];
|
||||
char domain[DNS_MAX_CNAME_LEN] = {0};
|
||||
struct dns_opt *opt = (struct dns_opt *)opt_data;
|
||||
int len = DNS_MAX_OPT_LEN;
|
||||
int ttl = 0;
|
||||
unsigned char *data = NULL;
|
||||
|
||||
if (_dns_get_opt_RAW(rrs, NULL, 0, &ttl, opt, &len) != 0) {
|
||||
if (_dns_get_opt_RAW(rrs, domain, DNS_MAX_CNAME_LEN, &ttl, opt, &len) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1087,6 +1104,60 @@ int dns_get_OPT_TCP_KEEPALIVE(struct dns_rrs *rrs, unsigned short *opt_code, uns
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_add_SRV(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, int priority, int weight,
|
||||
int port, const char *target)
|
||||
{
|
||||
unsigned char data[DNS_MAX_CNAME_LEN];
|
||||
unsigned char *data_ptr = data;
|
||||
|
||||
int target_len = 0;
|
||||
if (target == NULL) {
|
||||
target = "";
|
||||
}
|
||||
|
||||
target_len = strnlen(target, DNS_MAX_CNAME_LEN) + 1;
|
||||
memcpy(data_ptr, &priority, sizeof(unsigned short));
|
||||
data_ptr += sizeof(unsigned short);
|
||||
memcpy(data_ptr, &weight, sizeof(unsigned short));
|
||||
data_ptr += sizeof(unsigned short);
|
||||
memcpy(data_ptr, &port, sizeof(unsigned short));
|
||||
data_ptr += sizeof(unsigned short);
|
||||
if (data_ptr - data + target_len >= DNS_MAX_CNAME_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
safe_strncpy((char *)data_ptr, target, target_len);
|
||||
data_ptr += target_len;
|
||||
|
||||
return _dns_add_RAW(packet, type, DNS_T_SRV, domain, ttl, data, data_ptr - data);
|
||||
}
|
||||
|
||||
int dns_get_SRV(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned short *priority,
|
||||
unsigned short *weight, unsigned short *port, char *target, int target_size)
|
||||
{
|
||||
unsigned char data[DNS_MAX_CNAME_LEN];
|
||||
unsigned char *ptr = data;
|
||||
int len = sizeof(data);
|
||||
|
||||
if (_dns_get_RAW(rrs, domain, maxsize, ttl, data, &len) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len < 6) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(priority, ptr, sizeof(unsigned short));
|
||||
ptr += sizeof(unsigned short);
|
||||
memcpy(weight, ptr, sizeof(unsigned short));
|
||||
ptr += sizeof(unsigned short);
|
||||
memcpy(port, ptr, sizeof(unsigned short));
|
||||
ptr += sizeof(unsigned short);
|
||||
safe_strncpy(target, (char *)ptr, target_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_add_HTTPS_start(struct dns_rr_nested *svcparam_buffer, struct dns_packet *packet, dns_rr_type type,
|
||||
const char *domain, int ttl, int priority, const char *target)
|
||||
{
|
||||
@@ -1596,6 +1667,26 @@ static int _dns_encode_CNAME(struct dns_context *context, struct dns_rrs *rrs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_decode_SRV(struct dns_context *context, unsigned short *priority, unsigned short *weight,
|
||||
unsigned short *port, char *target, int target_size)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (_dns_left_len(context) < 6) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*priority = _dns_read_short(&context->ptr);
|
||||
*weight = _dns_read_short(&context->ptr);
|
||||
*port = _dns_read_short(&context->ptr);
|
||||
|
||||
ret = _dns_decode_domain(context, target, target_size);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_decode_SOA(struct dns_context *context, struct dns_soa *soa)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -1685,10 +1776,56 @@ static int _dns_encode_SOA(struct dns_context *context, struct dns_rrs *rrs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_encode_SRV(struct dns_context *context, struct dns_rrs *rrs)
|
||||
{
|
||||
int ret = 0;
|
||||
int qtype = 0;
|
||||
int qclass = 0;
|
||||
int ttl = 0;
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
int rr_len = 0;
|
||||
unsigned char *rr_len_ptr = NULL;
|
||||
struct dns_context data_context;
|
||||
|
||||
_dns_init_context_by_rrs(rrs, &data_context);
|
||||
ret = _dns_get_rr_head(&data_context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = _dns_encode_rr_head(context, domain, qtype, qclass, ttl, rr_len, &rr_len_ptr);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rr_len = 0;
|
||||
|
||||
if (_dns_left_len(context) < 6) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_dns_write_short(&context->ptr, *(unsigned short *)data_context.ptr);
|
||||
data_context.ptr += 2;
|
||||
_dns_write_short(&context->ptr, *(unsigned short *)data_context.ptr);
|
||||
data_context.ptr += 2;
|
||||
_dns_write_short(&context->ptr, *(unsigned short *)data_context.ptr);
|
||||
data_context.ptr += 2;
|
||||
rr_len += 6;
|
||||
|
||||
ret = _dns_encode_domain(context, (char *)data_context.ptr);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
rr_len += ret;
|
||||
data_context.ptr += strnlen((char *)(data_context.ptr), DNS_MAX_CNAME_LEN) + 1;
|
||||
|
||||
_dns_write_short(&rr_len_ptr, rr_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *ecs, int opt_len)
|
||||
{
|
||||
// TODO
|
||||
|
||||
int len = 0;
|
||||
if (opt_len < 4) {
|
||||
return -1;
|
||||
@@ -1716,7 +1853,6 @@ static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *
|
||||
|
||||
static int _dns_decode_opt_cookie(struct dns_context *context, struct dns_opt_cookie *cookie, int opt_len)
|
||||
{
|
||||
// TODO
|
||||
if (opt_len < (int)member_size(struct dns_opt_cookie, client_cookie)) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1743,6 +1879,23 @@ static int _dns_decode_opt_cookie(struct dns_context *context, struct dns_opt_co
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_decode_opt_tcp_keepalive(struct dns_context *context, unsigned short *timeout, int opt_len)
|
||||
{
|
||||
if (opt_len == 0) {
|
||||
*timeout = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (opt_len < (int)sizeof(unsigned short)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*timeout = _dns_read_short(&context->ptr);
|
||||
|
||||
tlog(TLOG_DEBUG, "OPT TCP KEEPALIVE %u", *timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_encode_OPT(struct dns_context *context, struct dns_rrs *rrs)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -1861,7 +2014,7 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
unsigned short opt_code = 0;
|
||||
unsigned short opt_len = 0;
|
||||
unsigned short errcode = (ttl >> 16) & 0xFFFF;
|
||||
unsigned short ever = (ttl)&0xFFFF;
|
||||
unsigned short ever = (ttl) & 0xFFFF;
|
||||
unsigned char *start = context->ptr;
|
||||
struct dns_packet *packet = context->packet;
|
||||
int ret = 0;
|
||||
@@ -1946,6 +2099,20 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
return -1;
|
||||
}
|
||||
} break;
|
||||
case DNS_OPT_T_TCP_KEEPALIVE: {
|
||||
unsigned short timeout = 0;
|
||||
ret = _dns_decode_opt_tcp_keepalive(context, &timeout, opt_len);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "decode tcp keepalive failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = dns_add_OPT_TCP_KEEPALIVE(packet, timeout);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "add tcp keepalive failed.");
|
||||
return -1;
|
||||
}
|
||||
} break;
|
||||
case DNS_OPT_T_PADDING:
|
||||
context->ptr += opt_len;
|
||||
break;
|
||||
@@ -2232,6 +2399,24 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
return -1;
|
||||
}
|
||||
} break;
|
||||
case DNS_T_SRV: {
|
||||
unsigned short priority = 0;
|
||||
unsigned short weight = 0;
|
||||
unsigned short port = 0;
|
||||
char target[DNS_MAX_CNAME_LEN];
|
||||
|
||||
ret = _dns_decode_SRV(context, &priority, &weight, &port, target, DNS_MAX_CNAME_LEN);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_DEBUG, "decode SRV failed, %s", domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = dns_add_SRV(packet, type, domain, ttl, priority, weight, port, target);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_DEBUG, "add SRV failed, %s", domain);
|
||||
return -1;
|
||||
}
|
||||
} break;
|
||||
case DNS_T_OPT: {
|
||||
unsigned char *opt_start = context->ptr;
|
||||
ret = _dns_decode_opt(context, type, ttl, rr_len);
|
||||
@@ -2348,6 +2533,12 @@ static int _dns_encode_an(struct dns_context *context, struct dns_rrs *rrs)
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DNS_T_SRV:
|
||||
ret = _dns_encode_SRV(context, rrs);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case DNS_T_HTTPS:
|
||||
ret = _dns_encode_HTTPS(context, rrs);
|
||||
if (ret < 0) {
|
||||
|
||||
16
src/dns.h
16
src/dns.h
@@ -72,6 +72,7 @@ typedef enum dns_type {
|
||||
DNS_T_SRV = 33,
|
||||
DNS_T_OPT = 41,
|
||||
DNS_T_SSHFP = 44,
|
||||
DNS_T_SVCB = 64,
|
||||
DNS_T_HTTPS = 65,
|
||||
DNS_T_SPF = 99,
|
||||
DNS_T_AXFR = 252,
|
||||
@@ -262,6 +263,9 @@ int dns_get_A(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned
|
||||
int dns_add_PTR(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *cname);
|
||||
int dns_get_PTR(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *cname, int cname_size);
|
||||
|
||||
int dns_add_TXT(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, const char *text);
|
||||
int dns_get_TXT(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char *text, int txt_size);
|
||||
|
||||
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]);
|
||||
@@ -276,11 +280,15 @@ int dns_set_OPT_payload_size(struct dns_packet *packet, int payload_size);
|
||||
int dns_get_OPT_payload_size(struct dns_packet *packet);
|
||||
|
||||
int dns_add_OPT_ECS(struct dns_packet *packet, struct dns_opt_ecs *ecs);
|
||||
int dns_get_OPT_ECS(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len, struct dns_opt_ecs *ecs);
|
||||
int dns_get_OPT_ECS(struct dns_rrs *rrs, struct dns_opt_ecs *ecs);
|
||||
|
||||
int dns_add_OPT_TCP_KEEPALIVE(struct dns_packet *packet, unsigned short timeout);
|
||||
int dns_get_OPT_TCP_KEEPALIVE(struct dns_rrs *rrs, unsigned short *opt_code, unsigned short *opt_len,
|
||||
unsigned short *timeout);
|
||||
int dns_get_OPT_TCP_KEEPALIVE(struct dns_rrs *rrs, unsigned short *timeout);
|
||||
|
||||
int dns_add_SRV(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, int priority, int weight,
|
||||
int port, const char *target);
|
||||
int dns_get_SRV(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, unsigned short *priority,
|
||||
unsigned short *weight, unsigned short *port, char *target, int target_size);
|
||||
|
||||
/* the key must be added in orders, or dig will report FORMERR */
|
||||
int dns_add_HTTPS_start(struct dns_rr_nested *svcparam_buffer, struct dns_packet *packet, dns_rr_type type,
|
||||
@@ -302,7 +310,7 @@ int dns_add_HTTPS_end(struct dns_rr_nested *svcparam);
|
||||
|
||||
int dns_get_HTTPS_svcparm_start(struct dns_rrs *rrs, struct dns_https_param **https_param, char *domain, int maxsize,
|
||||
int *ttl, int *priority, char *target, int target_size);
|
||||
struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *parm);
|
||||
struct dns_https_param *dns_get_HTTPS_svcparm_next(struct dns_rrs *rrs, struct dns_https_param *param);
|
||||
|
||||
/*
|
||||
* Packet operation
|
||||
|
||||
605
src/dns_cache.c
605
src/dns_cache.c
@@ -18,66 +18,65 @@
|
||||
|
||||
#include "dns_cache.h"
|
||||
#include "stringutil.h"
|
||||
#include "timer.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define DNS_CACHE_MAX_HITNUM 5000
|
||||
#define DNS_CACHE_HITNUM_STEP 2
|
||||
#define DNS_CACHE_MAX_HITNUM 6000
|
||||
#define DNS_CACHE_HITNUM_STEP 3
|
||||
#define DNS_CACHE_HITNUM_STEP_MAX 6
|
||||
#define DNS_CACHE_READ_TIMEOUT 60
|
||||
#define DNS_CACHE_FAIL_TIMEOUT (60 * 5)
|
||||
#define EXPIRED_DOMAIN_PREFETCH_TIME (3600 * 8)
|
||||
|
||||
struct dns_cache_head {
|
||||
DECLARE_HASHTABLE(cache_hash, 16);
|
||||
struct hash_table cache_hash;
|
||||
struct list_head cache_list;
|
||||
struct list_head inactive_list;
|
||||
atomic_t num;
|
||||
int size;
|
||||
int enable_inactive;
|
||||
int inactive_list_expired;
|
||||
pthread_mutex_t lock;
|
||||
dns_cache_callback timeout_callback;
|
||||
};
|
||||
|
||||
typedef int (*dns_cache_read_callback)(struct dns_cache_record *cache_record, struct dns_cache_data *cache_data);
|
||||
|
||||
static int is_cache_init;
|
||||
static struct dns_cache_head dns_cache_head;
|
||||
|
||||
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired)
|
||||
int dns_cache_init(int size, dns_cache_callback timeout_callback)
|
||||
{
|
||||
int bits = 0;
|
||||
if (is_cache_init == 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&dns_cache_head.cache_list);
|
||||
INIT_LIST_HEAD(&dns_cache_head.inactive_list);
|
||||
hash_init(dns_cache_head.cache_hash);
|
||||
|
||||
bits = ilog2(size) - 1;
|
||||
if (bits >= 20) {
|
||||
bits = 20;
|
||||
} else if (bits < 12) {
|
||||
bits = 12;
|
||||
}
|
||||
|
||||
hash_table_init(dns_cache_head.cache_hash, bits, malloc);
|
||||
atomic_set(&dns_cache_head.num, 0);
|
||||
dns_cache_head.size = size;
|
||||
dns_cache_head.enable_inactive = enable_inactive;
|
||||
dns_cache_head.inactive_list_expired = inactive_list_expired;
|
||||
|
||||
dns_cache_head.timeout_callback = timeout_callback;
|
||||
pthread_mutex_init(&dns_cache_head.lock, NULL);
|
||||
|
||||
is_cache_init = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __attribute__((unused)) struct dns_cache *_dns_cache_last(void)
|
||||
static struct dns_cache *_dns_cache_first(void)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
dns_cache = list_last_entry(&dns_cache_head.inactive_list, struct dns_cache, list);
|
||||
if (dns_cache) {
|
||||
return dns_cache;
|
||||
}
|
||||
|
||||
return list_last_entry(&dns_cache_head.cache_list, struct dns_cache, list);
|
||||
}
|
||||
|
||||
static struct dns_cache *_dns_inactive_cache_first(void)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
dns_cache = list_first_entry_or_null(&dns_cache_head.inactive_list, struct dns_cache, list);
|
||||
if (dns_cache) {
|
||||
return dns_cache;
|
||||
}
|
||||
|
||||
return list_first_entry_or_null(&dns_cache_head.cache_list, struct dns_cache, list);
|
||||
}
|
||||
|
||||
@@ -86,7 +85,8 @@ static void _dns_cache_delete(struct dns_cache *dns_cache)
|
||||
hash_del(&dns_cache->node);
|
||||
list_del_init(&dns_cache->list);
|
||||
atomic_dec(&dns_cache_head.num);
|
||||
dns_cache_data_free(dns_cache->cache_data);
|
||||
dns_cache_data_put(dns_cache->cache_data);
|
||||
dns_cache->cache_data = NULL;
|
||||
free(dns_cache);
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ void dns_cache_release(struct dns_cache *dns_cache)
|
||||
if (dns_cache == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!atomic_dec_and_test(&dns_cache->ref)) {
|
||||
return;
|
||||
}
|
||||
@@ -114,20 +115,10 @@ static void _dns_cache_remove(struct dns_cache *dns_cache)
|
||||
{
|
||||
hash_del(&dns_cache->node);
|
||||
list_del_init(&dns_cache->list);
|
||||
dns_timer_del(&dns_cache->timer);
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
|
||||
static void _dns_cache_move_inactive(struct dns_cache *dns_cache)
|
||||
{
|
||||
list_del_init(&dns_cache->list);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list);
|
||||
}
|
||||
|
||||
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data)
|
||||
{
|
||||
return cache_data->head.cache_type;
|
||||
}
|
||||
|
||||
uint32_t dns_cache_get_query_flag(struct dns_cache *dns_cache)
|
||||
{
|
||||
return dns_cache->info.query_flag;
|
||||
@@ -138,91 +129,6 @@ const char *dns_cache_get_dns_group_name(struct dns_cache *dns_cache)
|
||||
return dns_cache->info.dns_group_name;
|
||||
}
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data)
|
||||
{
|
||||
if (data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_addr(void)
|
||||
{
|
||||
struct dns_cache_addr *cache_addr = malloc(sizeof(struct dns_cache_addr));
|
||||
memset(cache_addr, 0, sizeof(struct dns_cache_addr));
|
||||
if (cache_addr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cache_addr->head.cache_type = CACHE_TYPE_NONE;
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
cache_addr->head.magic = MAGIC_CACHE_DATA;
|
||||
|
||||
return (struct dns_cache_data *)cache_addr;
|
||||
}
|
||||
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, 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;
|
||||
}
|
||||
|
||||
memset(cache_addr->addr_data.addr, 0, sizeof(cache_addr->addr_data.addr));
|
||||
|
||||
if (cname) {
|
||||
safe_strncpy(cache_addr->addr_data.cname, cname, DNS_MAX_CNAME_LEN);
|
||||
cache_addr->addr_data.cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
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);
|
||||
errout:
|
||||
return;
|
||||
}
|
||||
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, char *cname, int cname_ttl, unsigned char *addr,
|
||||
int addr_len)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache;
|
||||
if (cache_addr == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (addr_len == DNS_RR_A_LEN) {
|
||||
memcpy(cache_addr->addr_data.addr, addr, DNS_RR_A_LEN);
|
||||
} else if (addr_len != DNS_RR_AAAA_LEN) {
|
||||
memcpy(cache_addr->addr_data.addr, addr, DNS_RR_AAAA_LEN);
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cname) {
|
||||
safe_strncpy(cache_addr->addr_data.cname, cname, DNS_MAX_CNAME_LEN);
|
||||
cache_addr->addr_data.cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
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(void *packet, size_t packet_len)
|
||||
{
|
||||
struct dns_cache_packet *cache_packet = NULL;
|
||||
@@ -240,15 +146,50 @@ struct dns_cache_data *dns_cache_new_data_packet(void *packet, size_t packet_len
|
||||
memcpy(cache_packet->data, packet, packet_len);
|
||||
memset(&cache_packet->head, 0, sizeof(cache_packet->head));
|
||||
|
||||
cache_packet->head.cache_type = CACHE_TYPE_PACKET;
|
||||
cache_packet->head.size = packet_len;
|
||||
cache_packet->head.magic = MAGIC_CACHE_DATA;
|
||||
atomic_set(&cache_packet->head.ref, 1);
|
||||
|
||||
return (struct dns_cache_data *)cache_packet;
|
||||
}
|
||||
|
||||
static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int speed, int no_inactive, int inactive,
|
||||
struct dns_cache_data *cache_data)
|
||||
static void dns_cache_timer_release(struct tw_base *base, struct tw_timer_list *timer, void *data)
|
||||
{
|
||||
struct dns_cache *dns_cache = data;
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
|
||||
static void dns_cache_expired(struct tw_base *base, struct tw_timer_list *timer, void *data, unsigned long timestamp)
|
||||
{
|
||||
struct dns_cache *dns_cache = data;
|
||||
|
||||
if (dns_cache->del_pending == 1) {
|
||||
dns_cache_release(dns_cache);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dns_cache_head.timeout_callback) {
|
||||
dns_cache_tmout_action_t tmout_act = dns_cache_head.timeout_callback(dns_cache);
|
||||
switch (tmout_act) {
|
||||
case DNS_CACHE_TMOUT_ACTION_OK:
|
||||
break;
|
||||
case DNS_CACHE_TMOUT_ACTION_DEL:
|
||||
dns_cache_release(dns_cache);
|
||||
return;
|
||||
case DNS_CACHE_TMOUT_ACTION_RETRY:
|
||||
dns_timer_mod(&dns_cache->timer, DNS_CACHE_FAIL_TIMEOUT);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dns_cache->del_pending = 1;
|
||||
dns_timer_mod(&dns_cache->timer, 5);
|
||||
}
|
||||
|
||||
static int _dns_cache_replace(struct dns_cache_key *cache_key, int rcode, int ttl, int speed, int timeout,
|
||||
int update_time, struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache_data *old_cache_data = NULL;
|
||||
@@ -260,7 +201,7 @@ static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int spee
|
||||
/* lookup existing cache */
|
||||
dns_cache = dns_cache_lookup(cache_key);
|
||||
if (dns_cache == NULL) {
|
||||
return dns_cache_insert(cache_key, ttl, speed, no_inactive, cache_data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||
@@ -270,43 +211,37 @@ static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int spee
|
||||
/* update cache data */
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
dns_cache->del_pending = 0;
|
||||
dns_cache->info.ttl = ttl;
|
||||
dns_cache->info.rcode = rcode;
|
||||
dns_cache->info.qtype = cache_key->qtype;
|
||||
dns_cache->info.query_flag = cache_key->query_flag;
|
||||
dns_cache->info.ttl = ttl;
|
||||
dns_cache->info.speed = speed;
|
||||
dns_cache->info.no_inactive = no_inactive;
|
||||
dns_cache->info.timeout = timeout;
|
||||
dns_cache->info.is_visited = 1;
|
||||
old_cache_data = dns_cache->cache_data;
|
||||
dns_cache->cache_data = cache_data;
|
||||
list_del_init(&dns_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);
|
||||
if (cache_data) {
|
||||
old_cache_data = dns_cache->cache_data;
|
||||
dns_cache->cache_data = cache_data;
|
||||
}
|
||||
|
||||
if (update_time) {
|
||||
time(&dns_cache->info.insert_time);
|
||||
}
|
||||
time(&dns_cache->info.replace_time);
|
||||
list_del(&dns_cache->list);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
dns_timer_mod(&dns_cache->timer, timeout);
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
dns_cache_data_free(old_cache_data);
|
||||
if (old_cache_data) {
|
||||
dns_cache_data_put(old_cache_data);
|
||||
}
|
||||
dns_cache_release(dns_cache);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int speed, int no_inactive,
|
||||
int dns_cache_replace(struct dns_cache_key *cache_key, int rcode, int ttl, int speed, int timeout, int update_time,
|
||||
struct dns_cache_data *cache_data)
|
||||
{
|
||||
return _dns_cache_replace(cache_key, ttl, speed, no_inactive, 0, cache_data);
|
||||
}
|
||||
|
||||
int dns_cache_replace_inactive(struct dns_cache_key *cache_key, int ttl, int speed, int no_inactive,
|
||||
struct dns_cache_data *cache_data)
|
||||
{
|
||||
return _dns_cache_replace(cache_key, ttl, speed, no_inactive, 1, cache_data);
|
||||
return _dns_cache_replace(cache_key, rcode, ttl, speed, timeout, update_time, cache_data);
|
||||
}
|
||||
|
||||
static void _dns_cache_remove_by_domain(struct dns_cache_key *cache_key)
|
||||
@@ -320,7 +255,7 @@ static void _dns_cache_remove_by_domain(struct dns_cache_key *cache_key)
|
||||
key = jhash(&cache_key->query_flag, sizeof(cache_key->query_flag), key);
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_for_each_possible(dns_cache_head.cache_hash, dns_cache, node, key)
|
||||
hash_table_for_each_possible(dns_cache_head.cache_hash, dns_cache, node, key)
|
||||
{
|
||||
if (dns_cache->info.qtype != cache_key->qtype) {
|
||||
continue;
|
||||
@@ -345,7 +280,8 @@ static void _dns_cache_remove_by_domain(struct dns_cache_key *cache_key)
|
||||
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)
|
||||
static int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data *cache_data, struct list_head *head,
|
||||
int timeout)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
@@ -372,31 +308,38 @@ static int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data
|
||||
memcpy(&dns_cache->info, info, sizeof(*info));
|
||||
dns_cache->del_pending = 0;
|
||||
dns_cache->cache_data = cache_data;
|
||||
dns_cache->timer.function = dns_cache_expired;
|
||||
dns_cache->timer.del_function = dns_cache_timer_release;
|
||||
dns_cache->timer.expires = timeout;
|
||||
dns_cache->timer.data = dns_cache;
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_add(dns_cache_head.cache_hash, &dns_cache->node, key);
|
||||
hash_table_add(dns_cache_head.cache_hash, &dns_cache->node, key);
|
||||
list_add_tail(&dns_cache->list, head);
|
||||
INIT_LIST_HEAD(&dns_cache->check_list);
|
||||
|
||||
/* Release extra cache, remove oldest cache record */
|
||||
if (atomic_inc_return(&dns_cache_head.num) > dns_cache_head.size) {
|
||||
struct dns_cache *del_cache = NULL;
|
||||
del_cache = _dns_inactive_cache_first();
|
||||
del_cache = _dns_cache_first();
|
||||
if (del_cache) {
|
||||
_dns_cache_remove(del_cache);
|
||||
}
|
||||
}
|
||||
|
||||
dns_cache_get(dns_cache);
|
||||
dns_timer_add(&dns_cache->timer);
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (dns_cache) {
|
||||
free(dns_cache);
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_cache_insert(struct dns_cache_key *cache_key, int ttl, int speed, int no_inactive,
|
||||
int dns_cache_insert(struct dns_cache_key *cache_key, int rcode, int ttl, int speed, int timeout,
|
||||
struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache_info info;
|
||||
@@ -406,7 +349,7 @@ int dns_cache_insert(struct dns_cache_key *cache_key, int ttl, int speed, int no
|
||||
}
|
||||
|
||||
if (dns_cache_head.size <= 0) {
|
||||
dns_cache_data_free(cache_data);
|
||||
dns_cache_data_put(cache_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -423,12 +366,30 @@ int dns_cache_insert(struct dns_cache_key *cache_key, int ttl, int speed, int no
|
||||
info.ttl = ttl;
|
||||
info.hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
||||
info.speed = speed;
|
||||
info.no_inactive = no_inactive;
|
||||
info.timeout = timeout;
|
||||
info.is_visited = 1;
|
||||
info.rcode = rcode;
|
||||
time(&info.insert_time);
|
||||
time(&info.replace_time);
|
||||
|
||||
return _dns_cache_insert(&info, cache_data, &dns_cache_head.cache_list);
|
||||
return _dns_cache_insert(&info, cache_data, &dns_cache_head.cache_list, timeout);
|
||||
}
|
||||
|
||||
int dns_cache_update_timer(struct dns_cache_key *key, int timeout)
|
||||
{
|
||||
struct dns_cache *dns_cache = dns_cache_lookup(key);
|
||||
if (dns_cache == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
dns_timer_mod(&dns_cache->timer, timeout);
|
||||
dns_cache->del_pending = 0;
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
dns_cache_release(dns_cache);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_cache *dns_cache_lookup(struct dns_cache_key *cache_key)
|
||||
@@ -450,7 +411,7 @@ struct dns_cache *dns_cache_lookup(struct dns_cache_key *cache_key)
|
||||
time(&now);
|
||||
/* find cache */
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_for_each_possible(dns_cache_head.cache_hash, dns_cache, node, key)
|
||||
hash_table_for_each_possible(dns_cache_head.cache_hash, dns_cache, node, key)
|
||||
{
|
||||
if (dns_cache->info.qtype != cache_key->qtype) {
|
||||
continue;
|
||||
@@ -473,13 +434,7 @@ struct dns_cache *dns_cache_lookup(struct dns_cache_key *cache_key)
|
||||
}
|
||||
|
||||
if (dns_cache_ret) {
|
||||
/* Return NULL if the cache times out */
|
||||
if (dns_cache_head.enable_inactive == 0 && (now - dns_cache_ret->info.insert_time > dns_cache_ret->info.ttl)) {
|
||||
_dns_cache_remove(dns_cache_ret);
|
||||
dns_cache_ret = NULL;
|
||||
} else {
|
||||
dns_cache_get(dns_cache_ret);
|
||||
}
|
||||
dns_cache_get(dns_cache_ret);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
@@ -501,51 +456,37 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache)
|
||||
return ttl;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (dns_cache->cache_data->head.is_soa) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache)
|
||||
{
|
||||
return dns_cache->cache_data;
|
||||
struct dns_cache_data *cache_data;
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
dns_cache_data_get(dns_cache->cache_data);
|
||||
cache_data = dns_cache->cache_data;
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
return cache_data;
|
||||
}
|
||||
|
||||
void dns_cache_data_get(struct dns_cache_data *cache_data)
|
||||
{
|
||||
if (atomic_inc_return(&cache_data->head.ref) == 1) {
|
||||
tlog(TLOG_ERROR, "BUG: dns_cache data is invalid.");
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void dns_cache_data_put(struct dns_cache_data *cache_data)
|
||||
{
|
||||
if (cache_data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!atomic_dec_and_test(&cache_data->head.ref)) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(cache_data);
|
||||
}
|
||||
|
||||
int dns_cache_is_visited(struct dns_cache *dns_cache)
|
||||
@@ -553,6 +494,11 @@ int dns_cache_is_visited(struct dns_cache *dns_cache)
|
||||
return dns_cache->info.is_visited;
|
||||
}
|
||||
|
||||
int dns_cache_total_num(void)
|
||||
{
|
||||
return atomic_read(&dns_cache_head.num);
|
||||
}
|
||||
|
||||
void dns_cache_delete(struct dns_cache *dns_cache)
|
||||
{
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
@@ -591,127 +537,58 @@ void dns_cache_update(struct dns_cache *dns_cache)
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
}
|
||||
|
||||
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)
|
||||
static int _dns_cache_read_to_cache(struct dns_cache_record *cache_record, struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *tmp = NULL;
|
||||
unsigned int callback_num = 0;
|
||||
int ttl = 0;
|
||||
LIST_HEAD(checklist);
|
||||
struct list_head *head = NULL;
|
||||
head = &dns_cache_head.cache_list;
|
||||
struct dns_cache_info *info = &cache_record->info;
|
||||
int expired_time = 0;
|
||||
|
||||
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;
|
||||
if (ttl > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dns_cache_head.inactive_list_expired + ttl < 0) {
|
||||
_dns_cache_remove(dns_cache);
|
||||
continue;
|
||||
}
|
||||
|
||||
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++;
|
||||
time_t now = time(NULL);
|
||||
if (now < info->replace_time) {
|
||||
info->replace_time = now;
|
||||
}
|
||||
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);
|
||||
expired_time = dns_conf_serve_expired_prefetch_time;
|
||||
if (expired_time == 0) {
|
||||
expired_time = dns_conf_serve_expired_ttl / 2;
|
||||
if (expired_time == 0 || expired_time > EXPIRED_DOMAIN_PREFETCH_TIME) {
|
||||
expired_time = EXPIRED_DOMAIN_PREFETCH_TIME;
|
||||
}
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
|
||||
int passed_time = now - info->replace_time;
|
||||
int timeout = info->timeout - passed_time;
|
||||
if ((timeout > expired_time + info->ttl) && expired_time >= 0) {
|
||||
timeout = expired_time + info->ttl;
|
||||
}
|
||||
|
||||
if (timeout < DNS_CACHE_READ_TIMEOUT * 2) {
|
||||
timeout = DNS_CACHE_READ_TIMEOUT + (rand() % DNS_CACHE_READ_TIMEOUT);
|
||||
}
|
||||
|
||||
if (_dns_cache_insert(&cache_record->info, cache_data, head, timeout) != 0) {
|
||||
tlog(TLOG_ERROR, "insert cache data failed.");
|
||||
cache_data = NULL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
dns_cache_data_get(cache_data);
|
||||
|
||||
daemon_keepalive();
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
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)
|
||||
static int _dns_cache_read_record(int fd, uint32_t cache_number, dns_cache_read_callback callback)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
time(&now);
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list)
|
||||
{
|
||||
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 (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->info.no_inactive == 0) {
|
||||
_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(inactive_precallback, ttl_inactive_pre, max_callback_num, &now);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(dns_cache, tmp, &checklist, check_list)
|
||||
{
|
||||
/* run callback */
|
||||
if (precallback) {
|
||||
precallback(dns_cache);
|
||||
}
|
||||
list_del(&dns_cache->check_list);
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
}
|
||||
|
||||
static int _dns_cache_read_record(int fd, uint32_t cache_number)
|
||||
{
|
||||
|
||||
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;
|
||||
struct list_head *head = NULL;
|
||||
|
||||
for (i = 0; i < cache_number; i++) {
|
||||
ret = read(fd, &cache_record, sizeof(cache_record));
|
||||
@@ -725,15 +602,6 @@ static int _dns_cache_read_record(int fd, uint32_t cache_number)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cache_record.type == CACHE_RECORD_TYPE_ACTIVE) {
|
||||
head = &dns_cache_head.cache_list;
|
||||
} else if (cache_record.type == CACHE_RECORD_TYPE_INACTIVE) {
|
||||
head = &dns_cache_head.inactive_list;
|
||||
} else {
|
||||
tlog(TLOG_ERROR, "read cache record type is invalid.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = read(fd, &data_head, sizeof(data_head));
|
||||
if (ret != sizeof(data_head)) {
|
||||
tlog(TLOG_ERROR, "read data head failed, %s", strerror(errno));
|
||||
@@ -757,6 +625,7 @@ static int _dns_cache_read_record(int fd, uint32_t cache_number)
|
||||
}
|
||||
|
||||
memcpy(&cache_data->head, &data_head, sizeof(data_head));
|
||||
atomic_set(&cache_data->head.ref, 1);
|
||||
ret = read(fd, cache_data->data, data_head.size);
|
||||
if (ret != data_head.size) {
|
||||
tlog(TLOG_ERROR, "read cache data failed, %s", strerror(errno));
|
||||
@@ -767,29 +636,23 @@ static int _dns_cache_read_record(int fd, uint32_t cache_number)
|
||||
cache_record.info.is_visited = 0;
|
||||
cache_record.info.domain[DNS_MAX_CNAME_LEN - 1] = '\0';
|
||||
cache_record.info.dns_group_name[DNS_GROUP_NAME_LEN - 1] = '\0';
|
||||
if (cache_record.type >= CACHE_RECORD_TYPE_END) {
|
||||
tlog(TLOG_ERROR, "read cache record type is invalid.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_cache_insert(&cache_record.info, cache_data, head) != 0) {
|
||||
tlog(TLOG_ERROR, "insert cache data failed.");
|
||||
cache_data = NULL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = callback(&cache_record, cache_data);
|
||||
dns_cache_data_put(cache_data);
|
||||
cache_data = NULL;
|
||||
if (ret != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (cache_data) {
|
||||
free(cache_data);
|
||||
dns_cache_data_put(cache_data);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_cache_load(const char *file)
|
||||
static int _dns_cache_file_read(const char *file, dns_cache_read_callback callback)
|
||||
{
|
||||
int fd = -1;
|
||||
ssize_t ret = 0;
|
||||
@@ -822,7 +685,7 @@ int dns_cache_load(const char *file)
|
||||
}
|
||||
|
||||
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) {
|
||||
if (_dns_cache_read_record(fd, cache_file.cache_number, callback) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -836,17 +699,23 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_cache_write_record(int fd, uint32_t *cache_number, enum CACHE_RECORD_TYPE type, struct list_head *head)
|
||||
int dns_cache_load(const char *file)
|
||||
{
|
||||
return _dns_cache_file_read(file, _dns_cache_read_to_cache);
|
||||
}
|
||||
|
||||
static int _dns_cache_write_record(int fd, uint32_t *cache_number, struct list_head *head)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *tmp = NULL;
|
||||
struct dns_cache_record cache_record;
|
||||
|
||||
memset(&cache_record, 0, sizeof(cache_record));
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
list_for_each_entry_safe_reverse(dns_cache, tmp, head, list)
|
||||
list_for_each_entry_safe(dns_cache, tmp, head, list)
|
||||
{
|
||||
cache_record.magic = MAGIC_RECORD;
|
||||
cache_record.type = type;
|
||||
memcpy(&cache_record.info, &dns_cache->info, sizeof(struct dns_cache_info));
|
||||
ssize_t ret = write(fd, &cache_record, sizeof(cache_record));
|
||||
if (ret != sizeof(cache_record)) {
|
||||
@@ -874,12 +743,7 @@ errout:
|
||||
|
||||
static int _dns_cache_write_records(int fd, uint32_t *cache_number)
|
||||
{
|
||||
|
||||
if (_dns_cache_write_record(fd, cache_number, CACHE_RECORD_TYPE_ACTIVE, &dns_cache_head.cache_list) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_dns_cache_write_record(fd, cache_number, CACHE_RECORD_TYPE_INACTIVE, &dns_cache_head.inactive_list) != 0) {
|
||||
if (_dns_cache_write_record(fd, cache_number, &dns_cache_head.cache_list) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -945,28 +809,47 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_cache_print(struct dns_cache_record *cache_record, struct dns_cache_data *cache_data)
|
||||
{
|
||||
printf("domain: %s, qtype: %d, ttl: %d, speed: %.1fms\n", cache_record->info.domain, cache_record->info.qtype,
|
||||
cache_record->info.ttl, (float)cache_record->info.speed / 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_cache_print(const char *file)
|
||||
{
|
||||
if (access(file, F_OK) != 0) {
|
||||
tlog(TLOG_ERROR, "cache file %s not exist.", file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _dns_cache_file_read(file, _dns_cache_print);
|
||||
}
|
||||
|
||||
void dns_cache_destroy(void)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
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)
|
||||
{
|
||||
_dns_cache_delete(dns_cache);
|
||||
if (is_cache_init == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list)
|
||||
{
|
||||
_dns_cache_delete(dns_cache);
|
||||
_dns_cache_remove(dns_cache);
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
pthread_mutex_destroy(&dns_cache_head.lock);
|
||||
hash_table_free(dns_cache_head.cache_hash, free);
|
||||
|
||||
is_cache_init = 0;
|
||||
}
|
||||
|
||||
const char *dns_cache_file_version(void)
|
||||
{
|
||||
const char *version = "cache ver 1.0";
|
||||
const char *version = "cache ver 1.3";
|
||||
return version;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "hash.h"
|
||||
#include "hashtable.h"
|
||||
#include "list.h"
|
||||
#include "timer.h"
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
@@ -39,21 +40,8 @@ extern "C" {
|
||||
#define MAGIC_CACHE_DATA 0x61546144
|
||||
#define MAGIC_RECORD 0x64526352
|
||||
|
||||
enum CACHE_TYPE {
|
||||
CACHE_TYPE_NONE,
|
||||
CACHE_TYPE_ADDR,
|
||||
CACHE_TYPE_PACKET,
|
||||
};
|
||||
|
||||
enum CACHE_RECORD_TYPE {
|
||||
CACHE_RECORD_TYPE_ACTIVE,
|
||||
CACHE_RECORD_TYPE_INACTIVE,
|
||||
CACHE_RECORD_TYPE_END,
|
||||
};
|
||||
|
||||
struct dns_cache_data_head {
|
||||
enum CACHE_TYPE cache_type;
|
||||
int is_soa;
|
||||
atomic_t ref;
|
||||
ssize_t size;
|
||||
uint32_t magic;
|
||||
};
|
||||
@@ -88,9 +76,10 @@ struct dns_cache_info {
|
||||
char dns_group_name[DNS_GROUP_NAME_LEN];
|
||||
uint32_t query_flag;
|
||||
int ttl;
|
||||
int rcode;
|
||||
int hitnum;
|
||||
int speed;
|
||||
int no_inactive;
|
||||
int timeout;
|
||||
int hitnum_update_add;
|
||||
int is_visited;
|
||||
time_t insert_time;
|
||||
@@ -99,7 +88,6 @@ struct dns_cache_info {
|
||||
|
||||
struct dns_cache_record {
|
||||
uint32_t magic;
|
||||
enum CACHE_RECORD_TYPE type;
|
||||
struct dns_cache_info info;
|
||||
};
|
||||
|
||||
@@ -113,6 +101,8 @@ struct dns_cache {
|
||||
|
||||
struct dns_cache_info info;
|
||||
struct dns_cache_data *cache_data;
|
||||
|
||||
struct tw_timer_list timer;
|
||||
};
|
||||
|
||||
struct dns_cache_file {
|
||||
@@ -128,28 +118,34 @@ struct dns_cache_key {
|
||||
uint32_t query_flag;
|
||||
};
|
||||
|
||||
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data);
|
||||
|
||||
uint32_t dns_cache_get_query_flag(struct dns_cache *dns_cache);
|
||||
|
||||
const char *dns_cache_get_dns_group_name(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data);
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(void *packet, size_t packet_len);
|
||||
|
||||
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
|
||||
typedef enum DNS_CACHE_TMOUT_ACTION {
|
||||
DNS_CACHE_TMOUT_ACTION_OK = 0,
|
||||
DNS_CACHE_TMOUT_ACTION_DEL = 1,
|
||||
DNS_CACHE_TMOUT_ACTION_RETRY = 2,
|
||||
} dns_cache_tmout_action_t;
|
||||
|
||||
int dns_cache_replace(struct dns_cache_key *key, int ttl, int speed, int no_inactive,
|
||||
typedef dns_cache_tmout_action_t (*dns_cache_callback)(struct dns_cache *dns_cache);
|
||||
|
||||
int dns_cache_init(int size, dns_cache_callback timeout_callback);
|
||||
|
||||
int dns_cache_replace(struct dns_cache_key *key, int rcode, int ttl, int speed, int timeout, int update_time,
|
||||
struct dns_cache_data *cache_data);
|
||||
|
||||
int dns_cache_replace_inactive(struct dns_cache_key *key, int ttl, int speed, int no_inactive,
|
||||
struct dns_cache_data *cache_data);
|
||||
|
||||
int dns_cache_insert(struct dns_cache_key *key, int ttl, int speed, int no_inactive, struct dns_cache_data *cache_data);
|
||||
int dns_cache_insert(struct dns_cache_key *key, int rcode, int ttl, int speed, int timeout,
|
||||
struct dns_cache_data *cache_data);
|
||||
|
||||
struct dns_cache *dns_cache_lookup(struct dns_cache_key *key);
|
||||
|
||||
int dns_cache_total_num(void);
|
||||
|
||||
int dns_cache_update_timer(struct dns_cache_key *key, int timeout);
|
||||
|
||||
void dns_cache_delete(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_get(struct dns_cache *dns_cache);
|
||||
@@ -162,25 +158,13 @@ int dns_cache_is_visited(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_update(struct dns_cache *dns_cache);
|
||||
|
||||
typedef void dns_cache_callback(struct dns_cache *dns_cache);
|
||||
|
||||
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_addr(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, char *cname, int cname_ttl, unsigned char *addr,
|
||||
int addr_len);
|
||||
void dns_cache_data_get(struct dns_cache_data *cache_data);
|
||||
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, char *cname, int cname_ttl);
|
||||
void dns_cache_data_put(struct dns_cache_data *cache_data);
|
||||
|
||||
void dns_cache_destroy(void);
|
||||
|
||||
@@ -188,6 +172,8 @@ int dns_cache_load(const char *file);
|
||||
|
||||
int dns_cache_save(const char *file, int check_lock);
|
||||
|
||||
int dns_cache_print(const char *file);
|
||||
|
||||
const char *dns_cache_file_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
539
src/dns_client.c
539
src/dns_client.c
@@ -61,9 +61,9 @@
|
||||
#define DNS_TCP_BUFFER (32 * 1024)
|
||||
#define DNS_TCP_IDLE_TIMEOUT (60 * 10)
|
||||
#define DNS_TCP_CONNECT_TIMEOUT (5)
|
||||
#define DNS_QUERY_TIMEOUT (500)
|
||||
#define DNS_QUERY_TIMEOUT (3000)
|
||||
#define DNS_QUERY_RETRY (4)
|
||||
#define DNS_PENDING_SERVER_RETRY 40
|
||||
#define DNS_PENDING_SERVER_RETRY 60
|
||||
#define SOCKET_PRIORITY (6)
|
||||
#define SOCKET_IP_TOS (IPTOS_LOWDELAY | IPTOS_RELIABILITY)
|
||||
|
||||
@@ -93,7 +93,7 @@ struct dns_server_info {
|
||||
/* server ping handle */
|
||||
struct ping_host_struct *ping_host;
|
||||
|
||||
char ip[DNS_HOSTNAME_LEN];
|
||||
char ip[DNS_MAX_HOSTNAME];
|
||||
int port;
|
||||
char proxy_name[DNS_HOSTNAME_LEN];
|
||||
/* server type */
|
||||
@@ -107,6 +107,7 @@ struct dns_server_info {
|
||||
int ttl_range;
|
||||
SSL *ssl;
|
||||
int ssl_write_len;
|
||||
int ssl_want_write;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL_SESSION *ssl_session;
|
||||
|
||||
@@ -161,7 +162,8 @@ struct dns_server_pending {
|
||||
unsigned int has_v6;
|
||||
unsigned int query_v4;
|
||||
unsigned int query_v6;
|
||||
unsigned int has_soa;
|
||||
unsigned int has_soa_v4;
|
||||
unsigned int has_soa_v6;
|
||||
|
||||
/* server type */
|
||||
dns_server_type_t type;
|
||||
@@ -266,7 +268,7 @@ struct dns_query_struct {
|
||||
/* replied hash table */
|
||||
DECLARE_HASHTABLE(replied_map, 4);
|
||||
};
|
||||
|
||||
static int is_client_init;
|
||||
static struct dns_client client;
|
||||
static LIST_HEAD(pending_servers);
|
||||
static pthread_mutex_t pending_server_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
@@ -421,6 +423,9 @@ static const char *_dns_server_get_type_string(dns_server_type_t type)
|
||||
case DNS_SERVER_HTTPS:
|
||||
type_str = "https";
|
||||
break;
|
||||
case DNS_SERVER_QUIC:
|
||||
type_str = "quic";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -442,8 +447,8 @@ static struct addrinfo *_dns_client_getaddr(const char *host, char *port, int ty
|
||||
|
||||
ret = getaddrinfo(host, port, &hints, &result);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "get addr info failed. %s\n", gai_strerror(ret));
|
||||
tlog(TLOG_ERROR, "host = %s, port = %s, type = %d, protocol = %d", host, port, type, protocol);
|
||||
tlog(TLOG_WARN, "get addr info failed. %s\n", gai_strerror(ret));
|
||||
tlog(TLOG_WARN, "host = %s, port = %s, type = %d, protocol = %d", host, port, type, protocol);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -861,6 +866,7 @@ static char *_dns_client_server_get_tls_host_verify(struct dns_server_info *serv
|
||||
struct client_dns_server_flag_https *flag_https = &server_info->flags.https;
|
||||
tls_host_verify = flag_https->tls_host_verify;
|
||||
} break;
|
||||
case DNS_SERVER_QUIC:
|
||||
case DNS_SERVER_TLS: {
|
||||
struct client_dns_server_flag_tls *flag_tls = &server_info->flags.tls;
|
||||
tls_host_verify = flag_tls->tls_host_verify;
|
||||
@@ -893,6 +899,7 @@ static char *_dns_client_server_get_spki(struct dns_server_info *server_info, in
|
||||
spki = flag_https->spki;
|
||||
*spki_len = flag_https->spi_len;
|
||||
} break;
|
||||
case DNS_SERVER_QUIC:
|
||||
case DNS_SERVER_TLS: {
|
||||
struct client_dns_server_flag_tls *flag_tls = &server_info->flags.tls;
|
||||
spki = flag_tls->spki;
|
||||
@@ -953,7 +960,7 @@ static int _dns_client_set_trusted_cert(SSL_CTX *ssl_ctx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SSL_CTX *_ssl_ctx_get(void)
|
||||
static SSL_CTX *_ssl_ctx_get(int is_quic)
|
||||
{
|
||||
pthread_mutex_lock(&client.server_list_lock);
|
||||
SSL_CTX *ssl_ctx = client.ssl_ctx;
|
||||
@@ -963,7 +970,18 @@ static SSL_CTX *_ssl_ctx_get(void)
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
|
||||
if (is_quic) {
|
||||
ssl_ctx = SSL_CTX_new(OSSL_QUIC_client_method());
|
||||
} else {
|
||||
ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||
}
|
||||
#else
|
||||
if (is_quic) {
|
||||
return NULL;
|
||||
}
|
||||
ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||||
#endif
|
||||
#else
|
||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
#endif
|
||||
@@ -1050,6 +1068,12 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
|
||||
sock_type = SOCK_STREAM;
|
||||
skip_check_cert = flag_https->skip_check_cert;
|
||||
} break;
|
||||
case DNS_SERVER_QUIC: {
|
||||
struct client_dns_server_flag_tls *flag_tls = &flags->tls;
|
||||
spki_data_len = flag_tls->spi_len;
|
||||
sock_type = SOCK_DGRAM;
|
||||
skip_check_cert = flag_tls->skip_check_cert;
|
||||
} break;
|
||||
case DNS_SERVER_TLS: {
|
||||
struct client_dns_server_flag_tls *flag_tls = &flags->tls;
|
||||
spki_data_len = flag_tls->spi_len;
|
||||
@@ -1074,7 +1098,7 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(port_s, 8, "%d", port);
|
||||
snprintf(port_s, sizeof(port_s), "%d", port);
|
||||
gai = _dns_client_getaddr(server_ip, port_s, sock_type, 0);
|
||||
if (gai == NULL) {
|
||||
tlog(TLOG_DEBUG, "get address failed, %s:%d", server_ip, port);
|
||||
@@ -1122,8 +1146,12 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
|
||||
}
|
||||
|
||||
/* if server type is TLS, create ssl context */
|
||||
if (server_type == DNS_SERVER_TLS || server_type == DNS_SERVER_HTTPS) {
|
||||
server_info->ssl_ctx = _ssl_ctx_get();
|
||||
if (server_type == DNS_SERVER_TLS || server_type == DNS_SERVER_HTTPS || server_type == DNS_SERVER_QUIC) {
|
||||
if (server_type == DNS_SERVER_QUIC) {
|
||||
server_info->ssl_ctx = _ssl_ctx_get(1);
|
||||
} else {
|
||||
server_info->ssl_ctx = _ssl_ctx_get(0);
|
||||
}
|
||||
if (server_info->ssl_ctx == NULL) {
|
||||
tlog(TLOG_ERROR, "init ssl failed.");
|
||||
goto errout;
|
||||
@@ -1235,6 +1263,7 @@ static void _dns_client_shutdown_socket(struct dns_server_info *server_info)
|
||||
shutdown(server_info->fd, SHUT_RDWR);
|
||||
}
|
||||
break;
|
||||
case DNS_SERVER_QUIC:
|
||||
case DNS_SERVER_TLS:
|
||||
case DNS_SERVER_HTTPS:
|
||||
if (server_info->ssl) {
|
||||
@@ -1402,6 +1431,8 @@ static int _dns_client_add_server_pending(char *server_ip, char *server_host, in
|
||||
struct client_dns_server_flags *flags, int is_pending)
|
||||
{
|
||||
int ret = 0;
|
||||
struct addrinfo *gai = NULL;
|
||||
char server_ip_tmp[DNS_HOSTNAME_LEN] = {0};
|
||||
|
||||
if (server_type >= DNS_SERVER_TYPE_END) {
|
||||
tlog(TLOG_ERROR, "server type is invalid.");
|
||||
@@ -1414,6 +1445,22 @@ static int _dns_client_add_server_pending(char *server_ip, char *server_host, in
|
||||
tlog(TLOG_INFO, "add pending server %s", server_ip);
|
||||
return 0;
|
||||
}
|
||||
} else if (check_is_ipaddr(server_ip) && is_pending == 0) {
|
||||
gai = _dns_client_getaddr(server_ip, NULL, SOCK_STREAM, 0);
|
||||
if (gai == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_host_by_addr(server_ip_tmp, sizeof(server_ip_tmp), gai->ai_addr) != NULL) {
|
||||
tlog(TLOG_INFO, "resolve %s to %s.", server_ip, server_ip_tmp);
|
||||
server_ip = server_ip_tmp;
|
||||
} else {
|
||||
tlog(TLOG_INFO, "resolve %s failed.", server_ip);
|
||||
freeaddrinfo(gai);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeaddrinfo(gai);
|
||||
}
|
||||
|
||||
/* add server */
|
||||
@@ -1779,17 +1826,12 @@ static int _dns_client_create_socket_udp_proxy(struct dns_server_info *server_in
|
||||
}
|
||||
|
||||
set_fd_nonblock(fd, 1);
|
||||
set_sock_keepalive(fd, 15, 3, 4);
|
||||
set_sock_keepalive(fd, 30, 3, 5);
|
||||
|
||||
ret = proxy_conn_connect(proxy);
|
||||
if (ret != 0) {
|
||||
if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == EPERM || errno == EACCES) {
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (errno != EINPROGRESS) {
|
||||
tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
@@ -1843,14 +1885,8 @@ static int _dns_client_create_socket_udp(struct dns_server_info *server_info)
|
||||
server_info->status = DNS_SERVER_STATUS_CONNECTIONLESS;
|
||||
|
||||
if (connect(fd, &server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == ECONNREFUSED || errno == EPERM ||
|
||||
errno == EACCES) {
|
||||
tlog(TLOG_INFO, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (errno != EINPROGRESS) {
|
||||
tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
@@ -1941,7 +1977,7 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
|
||||
setsockopt(fd, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof(yes));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof(yes));
|
||||
set_sock_keepalive(fd, 15, 3, 4);
|
||||
set_sock_keepalive(fd, 30, 3, 5);
|
||||
|
||||
if (proxy) {
|
||||
ret = proxy_conn_connect(proxy);
|
||||
@@ -1950,13 +1986,8 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == ECONNREFUSED) {
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (errno != EINPROGRESS) {
|
||||
tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
@@ -1994,6 +2025,138 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _DNS_client_create_socket_quic(struct dns_server_info *server_info, char *hostname)
|
||||
{
|
||||
#ifdef OSSL_QUIC1_VERSION
|
||||
int fd = 0;
|
||||
struct epoll_event event;
|
||||
SSL *ssl = NULL;
|
||||
struct proxy_conn *proxy = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (server_info->ssl_ctx == NULL) {
|
||||
tlog(TLOG_ERROR, "create ssl ctx failed, %s", server_info->ip);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (server_info->proxy_name[0] != '\0') {
|
||||
proxy = proxy_conn_new(server_info->proxy_name, server_info->ip, server_info->port, 1);
|
||||
if (proxy == NULL) {
|
||||
tlog(TLOG_ERROR, "create proxy failed, %s, proxy: %s", server_info->ip, server_info->proxy_name);
|
||||
goto errout;
|
||||
}
|
||||
fd = proxy_conn_get_fd(proxy);
|
||||
} else {
|
||||
fd = socket(server_info->ai_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
}
|
||||
|
||||
ssl = SSL_new(server_info->ssl_ctx);
|
||||
if (ssl == NULL) {
|
||||
tlog(TLOG_ERROR, "new ssl failed, %s", server_info->ip);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
tlog(TLOG_ERROR, "create socket failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (set_fd_nonblock(fd, 1) != 0) {
|
||||
tlog(TLOG_ERROR, "set socket non block failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (server_info->so_mark >= 0) {
|
||||
unsigned int so_mark = server_info->so_mark;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_MARK, &so_mark, sizeof(so_mark)) != 0) {
|
||||
tlog(TLOG_DEBUG, "set socket mark failed, %s", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (proxy) {
|
||||
ret = proxy_conn_connect(proxy);
|
||||
} else {
|
||||
ret = connect(fd, &server_info->addr, server_info->ai_addrlen);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (errno != EINPROGRESS) {
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
SSL_set_connect_state(ssl);
|
||||
SSL_set_blocking_mode(ssl, 0);
|
||||
if (SSL_set_fd(ssl, fd) == 0) {
|
||||
tlog(TLOG_ERROR, "ssl set fd failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* reuse ssl session */
|
||||
if (server_info->ssl_session) {
|
||||
SSL_set_session(ssl, server_info->ssl_session);
|
||||
}
|
||||
|
||||
SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
if (hostname[0] != 0) {
|
||||
SSL_set_tlsext_host_name(ssl, hostname);
|
||||
}
|
||||
|
||||
SSL_set1_host(ssl, hostname);
|
||||
|
||||
static const unsigned char alpn[] = {3, 'd', 'o', 'q'};
|
||||
if (SSL_set_alpn_protos(ssl, alpn, sizeof(alpn))) {
|
||||
tlog(TLOG_INFO, "SSL_set_alpn_protos failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
server_info->fd = fd;
|
||||
server_info->ssl = ssl;
|
||||
server_info->ssl_write_len = -1;
|
||||
server_info->status = DNS_SERVER_STATUS_CONNECTING;
|
||||
server_info->proxy = proxy;
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN | EPOLLOUT;
|
||||
event.data.ptr = server_info;
|
||||
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
|
||||
tlog(TLOG_ERROR, "epoll ctl failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "tls server %s connecting.\n", server_info->ip);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (server_info->fd > 0) {
|
||||
server_info->fd = -1;
|
||||
}
|
||||
|
||||
if (server_info->ssl) {
|
||||
server_info->ssl = NULL;
|
||||
}
|
||||
|
||||
server_info->status = DNS_SERVER_STATUS_INIT;
|
||||
|
||||
if (fd > 0 && proxy == NULL) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (ssl) {
|
||||
SSL_free(ssl);
|
||||
}
|
||||
|
||||
if (proxy) {
|
||||
proxy_conn_free(proxy);
|
||||
}
|
||||
|
||||
return -1;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, char *hostname)
|
||||
{
|
||||
int fd = 0;
|
||||
@@ -2053,7 +2216,7 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof(yes));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof(yes));
|
||||
set_sock_keepalive(fd, 15, 3, 4);
|
||||
set_sock_keepalive(fd, 30, 3, 5);
|
||||
setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority));
|
||||
setsockopt(fd, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos));
|
||||
|
||||
@@ -2064,13 +2227,8 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (errno == ENETUNREACH || errno == EHOSTUNREACH || errno == ECONNREFUSED) {
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (errno != EINPROGRESS) {
|
||||
tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
@@ -2151,6 +2309,10 @@ static int _dns_client_create_socket(struct dns_server_info *server_info)
|
||||
struct client_dns_server_flag_tls *flag_tls = NULL;
|
||||
flag_tls = &server_info->flags.tls;
|
||||
return _DNS_client_create_socket_tls(server_info, flag_tls->hostname);
|
||||
} else if (server_info->type == DNS_SERVER_QUIC) {
|
||||
struct client_dns_server_flag_tls *flag_tls = NULL;
|
||||
flag_tls = &server_info->flags.tls;
|
||||
return _DNS_client_create_socket_quic(server_info, flag_tls->hostname);
|
||||
} else if (server_info->type == DNS_SERVER_HTTPS) {
|
||||
struct client_dns_server_flag_https *flag_https = NULL;
|
||||
flag_https = &server_info->flags.https;
|
||||
@@ -2239,13 +2401,14 @@ static int _dns_client_process_udp_proxy(struct dns_server_info *server_info, st
|
||||
}
|
||||
|
||||
int latency = get_tick_count() - server_info->send_tick;
|
||||
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d, latency: %d",
|
||||
get_host_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len, latency);
|
||||
|
||||
if (latency < server_info->drop_packet_latency_ms) {
|
||||
tlog(TLOG_DEBUG, "drop packet from %s, latency: %d", from_host, latency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d",
|
||||
get_host_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len);
|
||||
|
||||
/* update recv time */
|
||||
time(&server_info->last_recv);
|
||||
|
||||
@@ -2322,14 +2485,15 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e
|
||||
}
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d, ttl: %d",
|
||||
get_host_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len, ttl);
|
||||
int latency = get_tick_count() - server_info->send_tick;
|
||||
tlog(TLOG_DEBUG, "recv udp packet from %s, len: %d, ttl: %d, latency: %d",
|
||||
get_host_by_addr(from_host, sizeof(from_host), (struct sockaddr *)&from), len, ttl, latency);
|
||||
|
||||
/* update recv time */
|
||||
time(&server_info->last_recv);
|
||||
|
||||
int latency = get_tick_count() - server_info->send_tick;
|
||||
if (latency < server_info->drop_packet_latency_ms) {
|
||||
tlog(TLOG_DEBUG, "drop packet from %s, latency: %d", from_host, latency);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2374,16 +2538,16 @@ static int _dns_client_socket_ssl_send(struct dns_server_info *server, const voi
|
||||
ssl_ret = _ssl_get_error(server, ret);
|
||||
switch (ssl_ret) {
|
||||
case SSL_ERROR_NONE:
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return 0;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
case SSL_ERROR_WANT_READ:
|
||||
errno = EAGAIN;
|
||||
ret = -1;
|
||||
ret = -SSL_ERROR_WANT_READ;
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
errno = EAGAIN;
|
||||
ret = -1;
|
||||
ret = -SSL_ERROR_WANT_WRITE;
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
ssl_err = ERR_get_error();
|
||||
@@ -2423,7 +2587,7 @@ static int _dns_client_socket_ssl_recv(struct dns_server_info *server, void *buf
|
||||
}
|
||||
|
||||
ret = _ssl_read(server, buf, num);
|
||||
if (ret >= 0) {
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2435,11 +2599,11 @@ static int _dns_client_socket_ssl_recv(struct dns_server_info *server, void *buf
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
errno = EAGAIN;
|
||||
ret = -1;
|
||||
ret = -SSL_ERROR_WANT_READ;
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
errno = EAGAIN;
|
||||
ret = -1;
|
||||
ret = -SSL_ERROR_WANT_WRITE;
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
ssl_err = ERR_get_error();
|
||||
@@ -2453,7 +2617,13 @@ static int _dns_client_socket_ssl_recv(struct dns_server_info *server, void *buf
|
||||
return 0;
|
||||
}
|
||||
|
||||
tlog(TLOG_INFO, "SSL read fail error no: %s(%lx), len: %d\n", ERR_reason_error_string(ssl_err), ssl_err, num);
|
||||
#ifdef SSL_R_UNEXPECTED_EOF_WHILE_READING
|
||||
if (ssl_reason == SSL_R_UNEXPECTED_EOF_WHILE_READING) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
tlog(TLOG_WARN, "SSL read fail error no: %s(%lx), reason: %d\n", ERR_reason_error_string(ssl_err), ssl_err, ssl_reason);
|
||||
errno = EFAULT;
|
||||
ret = -1;
|
||||
break;
|
||||
@@ -2462,9 +2632,6 @@ static int _dns_client_socket_ssl_recv(struct dns_server_info *server, void *buf
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (errno != ECONNRESET) {
|
||||
tlog(TLOG_INFO, "SSL syscall failed, %s ", strerror(errno));
|
||||
}
|
||||
ret = -1;
|
||||
return ret;
|
||||
default:
|
||||
@@ -2476,22 +2643,52 @@ static int _dns_client_socket_ssl_recv(struct dns_server_info *server, void *buf
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_client_ssl_poll_event(struct dns_server_info *server_info, int ssl_ret)
|
||||
{
|
||||
struct epoll_event fd_event;
|
||||
|
||||
memset(&fd_event, 0, sizeof(fd_event));
|
||||
|
||||
if (ssl_ret == SSL_ERROR_WANT_READ) {
|
||||
fd_event.events = EPOLLIN;
|
||||
} else if (ssl_ret == SSL_ERROR_WANT_WRITE) {
|
||||
fd_event.events = EPOLLOUT | EPOLLIN;
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
fd_event.data.ptr = server_info;
|
||||
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_MOD, server_info->fd, &fd_event) != 0) {
|
||||
tlog(TLOG_ERROR, "epoll ctl failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_client_socket_send(struct dns_server_info *server_info)
|
||||
{
|
||||
if (server_info->type == DNS_SERVER_UDP) {
|
||||
return -1;
|
||||
} else if (server_info->type == DNS_SERVER_TCP) {
|
||||
return send(server_info->fd, server_info->send_buff.data, server_info->send_buff.len, MSG_NOSIGNAL);
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS) {
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS ||
|
||||
server_info->type == DNS_SERVER_QUIC) {
|
||||
int write_len = server_info->send_buff.len;
|
||||
if (server_info->ssl_write_len > 0) {
|
||||
write_len = server_info->ssl_write_len;
|
||||
server_info->ssl_write_len = -1;
|
||||
}
|
||||
server_info->ssl_want_write = 0;
|
||||
|
||||
int ret = _dns_client_socket_ssl_send(server_info, server_info->send_buff.data, write_len);
|
||||
if (ret != 0) {
|
||||
if (errno == EAGAIN) {
|
||||
server_info->ssl_write_len = write_len;
|
||||
if (ret < 0 && errno == EAGAIN) {
|
||||
server_info->ssl_write_len = write_len;
|
||||
if (_dns_client_ssl_poll_event(server_info, SSL_ERROR_WANT_WRITE) == 0) {
|
||||
errno = EAGAIN;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@@ -2507,9 +2704,18 @@ static int _dns_client_socket_recv(struct dns_server_info *server_info)
|
||||
} else if (server_info->type == DNS_SERVER_TCP) {
|
||||
return recv(server_info->fd, server_info->recv_buff.data + server_info->recv_buff.len,
|
||||
DNS_TCP_BUFFER - server_info->recv_buff.len, 0);
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS) {
|
||||
return _dns_client_socket_ssl_recv(server_info, server_info->recv_buff.data + server_info->recv_buff.len,
|
||||
DNS_TCP_BUFFER - server_info->recv_buff.len);
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS ||
|
||||
server_info->type == DNS_SERVER_QUIC) {
|
||||
int ret = _dns_client_socket_ssl_recv(server_info, server_info->recv_buff.data + server_info->recv_buff.len,
|
||||
DNS_TCP_BUFFER - server_info->recv_buff.len);
|
||||
if (ret == -SSL_ERROR_WANT_WRITE && errno == EAGAIN) {
|
||||
if (_dns_client_ssl_poll_event(server_info, SSL_ERROR_WANT_WRITE) == 0) {
|
||||
errno = EAGAIN;
|
||||
server_info->ssl_want_write = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
@@ -2632,7 +2838,7 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "recv failed, server %s:%d, %s\n", server_info->ip, server_info->port, strerror(errno));
|
||||
tlog(TLOG_WARN, "recv failed, server %s:%d, %s\n", server_info->ip, server_info->port, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -2674,7 +2880,7 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
|
||||
server_info->status = DNS_SERVER_STATUS_DISCONNECTED;
|
||||
}
|
||||
|
||||
if (server_info->send_buff.len > 0) {
|
||||
if (server_info->send_buff.len > 0 || server_info->ssl_want_write == 1) {
|
||||
/* send existing send_buffer data */
|
||||
len = _dns_client_socket_send(server_info);
|
||||
if (len < 0) {
|
||||
@@ -2818,7 +3024,7 @@ static int _dns_client_verify_common_name(struct dns_server_info *server_info, X
|
||||
|
||||
tlog(TLOG_DEBUG, "peer SAN: %s", dns->data);
|
||||
if (_dns_client_tls_matchName(tls_host_verify, (char *)dns->data, dns->length) == 0) {
|
||||
tlog(TLOG_INFO, "peer SAN match: %s", dns->data);
|
||||
tlog(TLOG_DEBUG, "peer SAN match: %s", dns->data);
|
||||
return 0;
|
||||
}
|
||||
} break;
|
||||
@@ -2969,21 +3175,14 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
if (server_info->status == DNS_SERVER_STATUS_CONNECTING) {
|
||||
/* do SSL hand shake */
|
||||
ret = _ssl_do_handshake(server_info);
|
||||
if (ret == 0) {
|
||||
goto errout;
|
||||
} else if (ret < 0) {
|
||||
if (ret <= 0) {
|
||||
memset(&fd_event, 0, sizeof(fd_event));
|
||||
ssl_ret = _ssl_get_error(server_info, ret);
|
||||
if (ssl_ret == SSL_ERROR_WANT_READ) {
|
||||
fd_event.events = EPOLLIN;
|
||||
} else if (ssl_ret == SSL_ERROR_WANT_WRITE) {
|
||||
fd_event.events = EPOLLOUT | EPOLLIN;
|
||||
} else if (ssl_ret == SSL_ERROR_SYSCALL) {
|
||||
if (errno != ENETUNREACH) {
|
||||
tlog(TLOG_WARN, "Handshake with %s failed, %s", server_info->ip, strerror(errno));
|
||||
}
|
||||
goto errout;
|
||||
} else {
|
||||
if (_dns_client_ssl_poll_event(server_info, ssl_ret) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ssl_ret != SSL_ERROR_SYSCALL) {
|
||||
unsigned long ssl_err = ERR_get_error();
|
||||
int ssl_reason = ERR_GET_REASON(ssl_err);
|
||||
tlog(TLOG_WARN, "Handshake with %s failed, error no: %s(%d, %d, %d)\n", server_info->ip,
|
||||
@@ -2991,13 +3190,10 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
goto errout;
|
||||
}
|
||||
|
||||
fd_event.data.ptr = server_info;
|
||||
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_MOD, server_info->fd, &fd_event) != 0) {
|
||||
tlog(TLOG_ERROR, "epoll ctl failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
if (errno != ENETUNREACH) {
|
||||
tlog(TLOG_WARN, "Handshake with %s failed, %s", server_info->ip, strerror(errno));
|
||||
}
|
||||
|
||||
return 0;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "tls server %s connected.\n", server_info->ip);
|
||||
@@ -3127,7 +3323,8 @@ static int _dns_client_process(struct dns_server_info *server_info, struct epoll
|
||||
} else if (server_info->type == DNS_SERVER_TCP) {
|
||||
/* receive from tcp */
|
||||
return _dns_client_process_tcp(server_info, event, now);
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS) {
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS ||
|
||||
server_info->type == DNS_SERVER_QUIC) {
|
||||
/* receive from tls */
|
||||
return _dns_client_process_tls(server_info, event, now);
|
||||
} else {
|
||||
@@ -3329,7 +3526,8 @@ static int _dns_client_send_https(struct dns_server_info *server_info, void *pac
|
||||
http_len = snprintf((char *)inpacket, DNS_IN_PACKSIZE,
|
||||
"POST %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"content-type: application/dns-message\r\n"
|
||||
"User-Agent: smartdns\r\n"
|
||||
"Content-Type: application/dns-message\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"\r\n",
|
||||
https_flag->path, https_flag->httphost, len);
|
||||
@@ -3362,6 +3560,11 @@ static int _dns_client_send_https(struct dns_server_info *server_info, void *pac
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_client_send_quic(struct dns_server_info *server_info, void *packet, unsigned short len)
|
||||
{
|
||||
return _dns_client_send_tls(server_info, packet, len);
|
||||
}
|
||||
|
||||
static int _dns_client_setup_server_packet(struct dns_server_info *server_info, struct dns_query_struct *query,
|
||||
void *default_packet, int default_packet_len,
|
||||
unsigned char *packet_data_buffer, void **packet_data, int *packet_data_len)
|
||||
@@ -3370,21 +3573,22 @@ static int _dns_client_setup_server_packet(struct dns_server_info *server_info,
|
||||
struct dns_packet *packet = (struct dns_packet *)packet_buff;
|
||||
struct dns_head head;
|
||||
int encode_len = 0;
|
||||
int repack = 0;
|
||||
int hitchhiking = 0;
|
||||
|
||||
*packet_data = default_packet;
|
||||
*packet_data_len = default_packet_len;
|
||||
|
||||
if (query->qtype != DNS_T_AAAA && query->qtype != DNS_T_A) {
|
||||
/* no need to encode packet */
|
||||
return 0;
|
||||
if (server_info->ecs_ipv4.enable == true || server_info->ecs_ipv6.enable == true) {
|
||||
repack = 1;
|
||||
}
|
||||
|
||||
if (server_info->ecs_ipv4.enable == false && query->qtype == DNS_T_A) {
|
||||
/* no need to encode packet */
|
||||
return 0;
|
||||
if ((server_info->flags.server_flag & SERVER_FLAG_HITCHHIKING) != 0) {
|
||||
hitchhiking = 1;
|
||||
repack = 1;
|
||||
}
|
||||
|
||||
if (server_info->ecs_ipv6.enable == false && query->qtype == DNS_T_AAAA) {
|
||||
if (repack == 0) {
|
||||
/* no need to encode packet */
|
||||
return 0;
|
||||
}
|
||||
@@ -3404,6 +3608,11 @@ static int _dns_client_setup_server_packet(struct dns_server_info *server_info,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hitchhiking != 0 && dns_add_domain(packet, "-", query->qtype, DNS_C_IN) != 0) {
|
||||
tlog(TLOG_ERROR, "add domain to packet failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* add question */
|
||||
if (dns_add_domain(packet, query->domain, query->qtype, DNS_C_IN) != 0) {
|
||||
tlog(TLOG_ERROR, "add domain to packet failed.");
|
||||
@@ -3411,11 +3620,21 @@ static int _dns_client_setup_server_packet(struct dns_server_info *server_info,
|
||||
}
|
||||
|
||||
dns_set_OPT_payload_size(packet, DNS_IN_PACKSIZE);
|
||||
/* dns_add_OPT_TCP_KEEPALIVE(packet, 600); */
|
||||
if (query->qtype == DNS_T_A && server_info->ecs_ipv4.enable) {
|
||||
|
||||
if (server_info->type != DNS_SERVER_UDP) {
|
||||
dns_add_OPT_TCP_KEEPALIVE(packet, 6000);
|
||||
}
|
||||
|
||||
if ((query->qtype == DNS_T_A && server_info->ecs_ipv4.enable)) {
|
||||
dns_add_OPT_ECS(packet, &server_info->ecs_ipv4.ecs);
|
||||
} else if (query->qtype == DNS_T_AAAA && server_info->ecs_ipv6.enable) {
|
||||
} else if ((query->qtype == DNS_T_AAAA && server_info->ecs_ipv6.enable)) {
|
||||
dns_add_OPT_ECS(packet, &server_info->ecs_ipv6.ecs);
|
||||
} else {
|
||||
if (server_info->ecs_ipv6.enable) {
|
||||
dns_add_OPT_ECS(packet, &server_info->ecs_ipv6.ecs);
|
||||
} else if (server_info->ecs_ipv4.enable) {
|
||||
dns_add_OPT_ECS(packet, &server_info->ecs_ipv4.ecs);
|
||||
}
|
||||
}
|
||||
|
||||
/* encode packet */
|
||||
@@ -3479,7 +3698,7 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
}
|
||||
}
|
||||
total_server++;
|
||||
tlog(TLOG_DEBUG, "send query to server %s", server_info->ip);
|
||||
tlog(TLOG_DEBUG, "send query to server %s:%d", server_info->ip, server_info->port);
|
||||
if (server_info->fd <= 0) {
|
||||
ret = _dns_client_create_socket(server_info);
|
||||
if (ret != 0) {
|
||||
@@ -3496,6 +3715,8 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
atomic_inc(&query->dns_request_sent);
|
||||
send_count++;
|
||||
errno = 0;
|
||||
server_info->send_tick = get_tick_count();
|
||||
|
||||
switch (server_info->type) {
|
||||
case DNS_SERVER_UDP:
|
||||
/* udp query */
|
||||
@@ -3517,6 +3738,11 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
ret = _dns_client_send_https(server_info, packet_data, packet_data_len);
|
||||
send_err = errno;
|
||||
break;
|
||||
case DNS_SERVER_QUIC:
|
||||
/* quic query */
|
||||
ret = _dns_client_send_quic(server_info, packet_data, packet_data_len);
|
||||
send_err = errno;
|
||||
break;
|
||||
default:
|
||||
/* unsupported query type */
|
||||
ret = -1;
|
||||
@@ -3548,7 +3774,6 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
continue;
|
||||
}
|
||||
time(&server_info->last_send);
|
||||
server_info->send_tick = get_tick_count();
|
||||
}
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
|
||||
@@ -3616,7 +3841,7 @@ static int _dns_client_send_query(struct dns_query_struct *query)
|
||||
}
|
||||
|
||||
dns_set_OPT_payload_size(packet, DNS_IN_PACKSIZE);
|
||||
/* dns_add_OPT_TCP_KEEPALIVE(packet, 600); */
|
||||
/* dns_add_OPT_TCP_KEEPALIVE(packet, 1200); */
|
||||
if (_dns_client_dns_add_ecs(query, packet) != 0) {
|
||||
tlog(TLOG_ERROR, "add ecs failed.");
|
||||
return -1;
|
||||
@@ -3651,20 +3876,20 @@ static int _dns_client_query_setup_default_ecs(struct dns_query_struct *query)
|
||||
if (client.ecs_ipv4.enable) {
|
||||
add_ipv4_ecs = 1;
|
||||
} else if (client.ecs_ipv6.enable) {
|
||||
add_ipv4_ecs = 1;
|
||||
add_ipv6_ecs = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (add_ipv4_ecs) {
|
||||
memcpy(&query->ecs, &client.ecs_ipv4, sizeof(query->ecs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (add_ipv6_ecs) {
|
||||
memcpy(&query->ecs, &client.ecs_ipv6, sizeof(query->ecs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (add_ipv4_ecs) {
|
||||
memcpy(&query->ecs, &client.ecs_ipv4, sizeof(query->ecs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3889,31 +4114,40 @@ static void _dns_client_check_servers(void)
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
}
|
||||
|
||||
static int _dns_client_pending_server_resolve(const char *domain, dns_rtcode_t rtcode, dns_type_t addr_type, char *ip,
|
||||
unsigned int ping_time, void *user_ptr)
|
||||
static int _dns_client_pending_server_resolve(const struct dns_result *result, void *user_ptr)
|
||||
{
|
||||
struct dns_server_pending *pending = user_ptr;
|
||||
int ret = 0;
|
||||
int has_soa = 0;
|
||||
|
||||
if (rtcode == DNS_RC_NXDOMAIN) {
|
||||
pending->has_soa = 1;
|
||||
if (result->rtcode == DNS_RC_NXDOMAIN || result->has_soa == 1 || result->rtcode == DNS_RC_REFUSED ||
|
||||
(result->rtcode == DNS_RC_NOERROR && result->ip_num == 0)) {
|
||||
has_soa = 1;
|
||||
}
|
||||
|
||||
if (addr_type == DNS_T_A) {
|
||||
if (result->addr_type == DNS_T_A) {
|
||||
pending->ping_time_v4 = -1;
|
||||
if (rtcode == DNS_RC_NOERROR) {
|
||||
if (result->rtcode == DNS_RC_NOERROR && result->ip_num > 0) {
|
||||
pending->has_v4 = 1;
|
||||
pending->ping_time_v4 = ping_time;
|
||||
pending->has_soa = 0;
|
||||
safe_strncpy(pending->ipv4, ip, DNS_HOSTNAME_LEN);
|
||||
pending->ping_time_v4 = result->ping_time;
|
||||
pending->has_soa_v4 = 0;
|
||||
safe_strncpy(pending->ipv4, result->ip, DNS_HOSTNAME_LEN);
|
||||
} else if (has_soa) {
|
||||
pending->has_v4 = 0;
|
||||
pending->ping_time_v4 = -1;
|
||||
pending->has_soa_v4 = 1;
|
||||
}
|
||||
} else if (addr_type == DNS_T_AAAA) {
|
||||
} else if (result->addr_type == DNS_T_AAAA) {
|
||||
pending->ping_time_v6 = -1;
|
||||
if (rtcode == DNS_RC_NOERROR) {
|
||||
if (result->rtcode == DNS_RC_NOERROR && result->ip_num > 0) {
|
||||
pending->has_v6 = 1;
|
||||
pending->ping_time_v6 = ping_time;
|
||||
pending->has_soa = 0;
|
||||
safe_strncpy(pending->ipv6, ip, DNS_HOSTNAME_LEN);
|
||||
pending->ping_time_v6 = result->ping_time;
|
||||
pending->has_soa_v6 = 0;
|
||||
safe_strncpy(pending->ipv6, result->ip, DNS_HOSTNAME_LEN);
|
||||
} else if (has_soa) {
|
||||
pending->has_v6 = 0;
|
||||
pending->ping_time_v6 = -1;
|
||||
pending->has_soa_v6 = 1;
|
||||
}
|
||||
} else {
|
||||
ret = -1;
|
||||
@@ -4007,10 +4241,29 @@ static void _dns_client_add_pending_servers(void)
|
||||
int add_success = 0;
|
||||
char *dnsserver_ip = NULL;
|
||||
|
||||
/* if has no bootstrap DNS, just call getaddrinfo to get address */
|
||||
if (dns_client_has_bootstrap_dns == 0) {
|
||||
list_del_init(&pending->retry_list);
|
||||
_dns_client_server_pending_release(pending);
|
||||
pending->retry_cnt++;
|
||||
if (_dns_client_add_pendings(pending, pending->host) != 0) {
|
||||
pthread_mutex_unlock(&pending_server_mutex);
|
||||
tlog(TLOG_INFO, "add pending DNS server %s from resolv.conf failed, retry %d...", pending->host,
|
||||
pending->retry_cnt - 1);
|
||||
if (pending->retry_cnt - 1 > DNS_PENDING_SERVER_RETRY) {
|
||||
tlog(TLOG_WARN, "add pending DNS server %s from resolv.conf failed, exit...", pending->host);
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_dns_client_server_pending_release(pending);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pending->query_v4 == 0) {
|
||||
pending->query_v4 = 1;
|
||||
_dns_client_server_pending_get(pending);
|
||||
if (dns_server_query(pending->host, DNS_T_A, 0, _dns_client_pending_server_resolve, pending) != 0) {
|
||||
if (dns_server_query(pending->host, DNS_T_A, NULL, _dns_client_pending_server_resolve, pending) != 0) {
|
||||
_dns_client_server_pending_release(pending);
|
||||
pending->query_v4 = 0;
|
||||
}
|
||||
@@ -4019,9 +4272,9 @@ static void _dns_client_add_pending_servers(void)
|
||||
if (pending->query_v6 == 0) {
|
||||
pending->query_v6 = 1;
|
||||
_dns_client_server_pending_get(pending);
|
||||
if (dns_server_query(pending->host, DNS_T_AAAA, 0, _dns_client_pending_server_resolve, pending) != 0) {
|
||||
if (dns_server_query(pending->host, DNS_T_AAAA, NULL, _dns_client_pending_server_resolve, pending) != 0) {
|
||||
_dns_client_server_pending_release(pending);
|
||||
pending->query_v4 = 0;
|
||||
pending->query_v6 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4052,7 +4305,7 @@ static void _dns_client_add_pending_servers(void)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pending->has_soa && dnsserver_ip == NULL) {
|
||||
if (dnsserver_ip == NULL && pending->has_soa_v4 && pending->has_soa_v6) {
|
||||
tlog(TLOG_WARN, "add pending DNS server %s failed, no such host.", pending->host);
|
||||
_dns_client_server_pending_remove(pending);
|
||||
continue;
|
||||
@@ -4068,22 +4321,6 @@ static void _dns_client_add_pending_servers(void)
|
||||
pending->query_v4 = 0;
|
||||
pending->query_v6 = 0;
|
||||
}
|
||||
|
||||
/* if has no bootstrap DNS, just call getaddrinfo to get address */
|
||||
if (dns_client_has_bootstrap_dns == 0) {
|
||||
if (_dns_client_add_pendings(pending, pending->host) != 0) {
|
||||
pthread_mutex_unlock(&pending_server_mutex);
|
||||
tlog(TLOG_INFO, "add pending DNS server %s from resolv.conf failed, retry %d...", pending->host,
|
||||
pending->retry_cnt - 1);
|
||||
if (pending->retry_cnt - 1 > DNS_PENDING_SERVER_RETRY) {
|
||||
tlog(TLOG_WARN, "add pending DNS server %s from resolv.conf failed, exit...", pending->host);
|
||||
exit(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
_dns_client_server_pending_release(pending);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4117,14 +4354,19 @@ static void _dns_client_period_run(unsigned int msec)
|
||||
{
|
||||
/* free timed out query, and notify caller */
|
||||
list_del_init(&query->period_list);
|
||||
_dns_client_check_udp_nat(query);
|
||||
|
||||
/* check udp nat after retrying. */
|
||||
if (atomic_read(&query->retry_count) == 1) {
|
||||
_dns_client_check_udp_nat(query);
|
||||
}
|
||||
|
||||
if (atomic_dec_and_test(&query->retry_count) || (query->has_result != 0)) {
|
||||
_dns_client_query_remove(query);
|
||||
if (query->has_result == 0) {
|
||||
tlog(TLOG_INFO, "retry query %s, type: %d, id: %d failed", query->domain, query->qtype, query->sid);
|
||||
tlog(TLOG_DEBUG, "retry query %s, type: %d, id: %d failed", query->domain, query->qtype, query->sid);
|
||||
}
|
||||
} else {
|
||||
tlog(TLOG_INFO, "retry query %s, type: %d, id: %d", query->domain, query->qtype, query->sid);
|
||||
tlog(TLOG_DEBUG, "retry query %s, type: %d, id: %d", query->domain, query->qtype, query->sid);
|
||||
_dns_client_send_query(query);
|
||||
}
|
||||
_dns_client_query_release(query);
|
||||
@@ -4333,11 +4575,13 @@ int dns_client_init(void)
|
||||
int fd_wakeup = -1;
|
||||
int ret = 0;
|
||||
|
||||
if (client.epoll_fd > 0) {
|
||||
if (is_client_init == 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
srandom(time(NULL));
|
||||
if (client.epoll_fd > 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&client, 0, sizeof(client));
|
||||
pthread_attr_init(&attr);
|
||||
@@ -4382,6 +4626,7 @@ int dns_client_init(void)
|
||||
}
|
||||
|
||||
client.fd_wakeup = fd_wakeup;
|
||||
is_client_init = 1;
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
@@ -4408,6 +4653,10 @@ errout:
|
||||
|
||||
void dns_client_exit(void)
|
||||
{
|
||||
if (is_client_init == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (client.tid) {
|
||||
void *ret = NULL;
|
||||
atomic_set(&client.run, 0);
|
||||
@@ -4429,4 +4678,6 @@ void dns_client_exit(void)
|
||||
SSL_CTX_free(client.ssl_ctx);
|
||||
client.ssl_ctx = NULL;
|
||||
}
|
||||
|
||||
is_client_init = 0;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ typedef enum {
|
||||
DNS_SERVER_TCP,
|
||||
DNS_SERVER_TLS,
|
||||
DNS_SERVER_HTTPS,
|
||||
DNS_SERVER_QUIC,
|
||||
DNS_SERVER_TYPE_END,
|
||||
} dns_server_type_t;
|
||||
|
||||
|
||||
1651
src/dns_conf.c
1651
src/dns_conf.c
File diff suppressed because it is too large
Load Diff
126
src/dns_conf.h
126
src/dns_conf.h
@@ -56,7 +56,12 @@ extern "C" {
|
||||
#define DEFAULT_DNS_PORT 53
|
||||
#define DEFAULT_DNS_TLS_PORT 853
|
||||
#define DEFAULT_DNS_HTTPS_PORT 443
|
||||
#define DEFAULT_DNS_QUIC_PORT 853
|
||||
#define DNS_MAX_CONF_CNAME_LEN 256
|
||||
#define MAX_QTYPE_NUM 65535
|
||||
#define DNS_MAX_REPLY_IP_NUM 8
|
||||
#define DNS_DEFAULT_CHECKPOINT_TIME (3600 * 24)
|
||||
|
||||
#define SMARTDNS_CONF_FILE "/etc/smartdns/smartdns.conf"
|
||||
#define SMARTDNS_LOG_FILE "/var/log/smartdns/smartdns.log"
|
||||
#define SMARTDNS_AUDIT_FILE "/var/log/smartdns/smartdns-audit.log"
|
||||
@@ -82,6 +87,12 @@ enum domain_rule {
|
||||
DOMAIN_RULE_MAX,
|
||||
};
|
||||
|
||||
enum ip_rule {
|
||||
IP_RULE_FLAGS = 0,
|
||||
IP_RULE_ALIAS = 1,
|
||||
IP_RULE_MAX,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
DNS_BIND_TYPE_UDP,
|
||||
DNS_BIND_TYPE_TCP,
|
||||
@@ -114,8 +125,15 @@ typedef enum {
|
||||
#define DOMAIN_FLAG_NO_SERVE_EXPIRED (1 << 15)
|
||||
#define DOMAIN_FLAG_CNAME_IGN (1 << 16)
|
||||
#define DOMAIN_FLAG_NO_CACHE (1 << 17)
|
||||
#define DOMAIN_FLAG_NO_IPALIAS (1 << 18)
|
||||
|
||||
#define IP_RULE_FLAG_BLACKLIST (1 << 0)
|
||||
#define IP_RULE_FLAG_WHITELIST (1 << 1)
|
||||
#define IP_RULE_FLAG_BOGUS (1 << 2)
|
||||
#define IP_RULE_FLAG_IP_IGNORE (1 << 3)
|
||||
|
||||
#define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0)
|
||||
#define SERVER_FLAG_HITCHHIKING (1 << 1)
|
||||
|
||||
#define BIND_FLAG_NO_RULE_ADDR (1 << 0)
|
||||
#define BIND_FLAG_NO_RULE_NAMESERVER (1 << 1)
|
||||
@@ -128,6 +146,7 @@ typedef enum {
|
||||
#define BIND_FLAG_FORCE_AAAA_SOA (1 << 8)
|
||||
#define BIND_FLAG_NO_RULE_CNAME (1 << 9)
|
||||
#define BIND_FLAG_NO_RULE_NFTSET (1 << 10)
|
||||
#define BIND_FLAG_NO_IP_ALIAS (1 << 11)
|
||||
|
||||
enum response_mode_type {
|
||||
DNS_RESPONSE_MODE_FIRST_PING_IP = 0,
|
||||
@@ -148,12 +167,14 @@ struct dns_rule_flags {
|
||||
|
||||
struct dns_rule_address_IPV4 {
|
||||
struct dns_rule head;
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
char addr_num;
|
||||
unsigned char ipv4_addr[][DNS_RR_A_LEN];
|
||||
};
|
||||
|
||||
struct dns_rule_address_IPV6 {
|
||||
struct dns_rule head;
|
||||
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
||||
char addr_num;
|
||||
unsigned char ipv6_addr[][DNS_RR_AAAA_LEN];
|
||||
};
|
||||
|
||||
struct dns_ipset_name {
|
||||
@@ -212,8 +233,9 @@ extern struct dns_nftset_names dns_conf_nftset_no_speed;
|
||||
|
||||
struct dns_domain_rule {
|
||||
struct dns_rule head;
|
||||
unsigned char sub_rule_only : 1;
|
||||
unsigned char root_rule_only : 1;
|
||||
struct dns_rule *rules[DOMAIN_RULE_MAX];
|
||||
int is_sub_rule[DOMAIN_RULE_MAX];
|
||||
};
|
||||
|
||||
struct dns_nameserver_rule {
|
||||
@@ -303,7 +325,7 @@ struct dns_edns_client_subnet {
|
||||
};
|
||||
|
||||
struct dns_servers {
|
||||
char server[DNS_MAX_IPLEN];
|
||||
char server[DNS_MAX_CNAME_LEN];
|
||||
unsigned short port;
|
||||
unsigned int result_flag;
|
||||
unsigned int server_flag;
|
||||
@@ -343,18 +365,18 @@ struct dns_bogus_ip_address {
|
||||
};
|
||||
};
|
||||
|
||||
enum address_rule {
|
||||
ADDRESS_RULE_BLACKLIST = 1,
|
||||
ADDRESS_RULE_WHITELIST = 2,
|
||||
ADDRESS_RULE_BOGUS = 3,
|
||||
ADDRESS_RULE_IP_IGNORE = 4,
|
||||
struct dns_iplist_ip_address {
|
||||
int addr_len;
|
||||
union {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
||||
unsigned char addr[0];
|
||||
};
|
||||
};
|
||||
|
||||
struct dns_ip_address_rule {
|
||||
unsigned int blacklist : 1;
|
||||
unsigned int whitelist : 1;
|
||||
unsigned int bogus : 1;
|
||||
unsigned int ip_ignore : 1;
|
||||
struct dns_iplist_ip_addresses {
|
||||
int ipaddr_num;
|
||||
struct dns_iplist_ip_address *ipaddr;
|
||||
};
|
||||
|
||||
struct dns_conf_address_rule {
|
||||
@@ -381,15 +403,7 @@ struct dns_bind_ip {
|
||||
struct nftset_ipset_rules nftset_ipset_rule;
|
||||
};
|
||||
|
||||
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 uint8_t *dns_qtype_soa_table;
|
||||
|
||||
struct dns_domain_set_rule {
|
||||
struct list_head list;
|
||||
@@ -420,8 +434,48 @@ struct dns_domain_set_name_table {
|
||||
};
|
||||
extern struct dns_domain_set_name_table dns_domain_set_name_table;
|
||||
|
||||
struct dns_ip_rule {
|
||||
atomic_t refcnt;
|
||||
enum ip_rule rule;
|
||||
};
|
||||
|
||||
enum dns_ip_set_type {
|
||||
DNS_IP_SET_LIST = 0,
|
||||
};
|
||||
|
||||
struct dns_ip_rules {
|
||||
struct dns_ip_rule *rules[IP_RULE_MAX];
|
||||
};
|
||||
|
||||
struct ip_rule_flags {
|
||||
struct dns_ip_rule head;
|
||||
unsigned int flags;
|
||||
unsigned int is_flag_set;
|
||||
};
|
||||
|
||||
struct ip_rule_alias {
|
||||
struct dns_ip_rule head;
|
||||
struct dns_iplist_ip_addresses ip_alias;
|
||||
};
|
||||
|
||||
struct dns_ip_set_name {
|
||||
struct list_head list;
|
||||
enum dns_ip_set_type type;
|
||||
char file[DNS_MAX_PATH];
|
||||
};
|
||||
|
||||
struct dns_ip_set_name_list {
|
||||
struct hlist_node node;
|
||||
char name[DNS_MAX_CNAME_LEN];
|
||||
struct list_head set_name_list;
|
||||
};
|
||||
struct dns_ip_set_name_table {
|
||||
DECLARE_HASHTABLE(names, 4);
|
||||
};
|
||||
extern struct dns_ip_set_name_table dns_ip_set_name_table;
|
||||
|
||||
struct dns_set_rule_add_callback_args {
|
||||
enum domain_rule type;
|
||||
int type;
|
||||
void *rule;
|
||||
};
|
||||
|
||||
@@ -435,6 +489,25 @@ struct dns_dns64 {
|
||||
uint32_t prefix_len;
|
||||
};
|
||||
|
||||
struct dns_srv_record {
|
||||
struct list_head list;
|
||||
char host[DNS_MAX_CNAME_LEN];
|
||||
unsigned short priority;
|
||||
unsigned short weight;
|
||||
unsigned short port;
|
||||
};
|
||||
|
||||
struct dns_srv_records {
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
struct hlist_node node;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct dns_srv_record_table {
|
||||
DECLARE_HASHTABLE(srv, 4);
|
||||
};
|
||||
extern struct dns_srv_record_table dns_conf_srv_record_table;
|
||||
|
||||
extern struct dns_dns64 dns_conf_dns_dns64;
|
||||
|
||||
extern struct dns_bind_ip dns_conf_bind_ip[DNS_MAX_BIND_IP];
|
||||
@@ -520,6 +593,9 @@ extern int dns_save_fail_packet;
|
||||
extern char dns_save_fail_packet_dir[DNS_MAX_PATH];
|
||||
extern char dns_resolv_file[DNS_MAX_PATH];
|
||||
|
||||
extern int dns_no_pidfile;
|
||||
extern int dns_no_daemon;
|
||||
|
||||
void dns_server_load_exit(void);
|
||||
|
||||
int dns_server_load_conf(const char *file);
|
||||
@@ -528,6 +604,8 @@ int dns_server_check_update_hosts(void);
|
||||
|
||||
struct dns_proxy_names *dns_server_get_proxy_nams(const char *proxyname);
|
||||
|
||||
struct dns_srv_records *dns_server_get_srv_record(const char *domain);
|
||||
|
||||
extern int config_additional_file(void *data, int argc, char *argv[]);
|
||||
|
||||
const char *dns_conf_get_cache_dir(void);
|
||||
|
||||
1693
src/dns_server.c
1693
src/dns_server.c
File diff suppressed because it is too large
Load Diff
@@ -49,9 +49,21 @@ void dns_server_stop(void);
|
||||
|
||||
void dns_server_exit(void);
|
||||
|
||||
#define MAX_IP_NUM 16
|
||||
|
||||
struct dns_result {
|
||||
const char *domain;
|
||||
dns_rtcode_t rtcode;
|
||||
dns_type_t addr_type;
|
||||
const char *ip;
|
||||
const unsigned char *ip_addr[MAX_IP_NUM];
|
||||
int ip_num;
|
||||
int has_soa;
|
||||
unsigned int ping_time;
|
||||
};
|
||||
|
||||
/* query result notify function */
|
||||
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);
|
||||
typedef int (*dns_result_callback)(const struct dns_result *result, void *user_ptr);
|
||||
|
||||
/* query domain */
|
||||
int dns_server_query(const char *domain, int qtype, struct dns_server_query_option *server_query_option,
|
||||
|
||||
@@ -183,6 +183,7 @@ struct fast_ping_struct {
|
||||
int fake_ip_num;
|
||||
};
|
||||
|
||||
static int is_fast_ping_init;
|
||||
static struct fast_ping_struct ping;
|
||||
static atomic_t ping_sid = ATOMIC_INIT(0);
|
||||
static int bool_print_log = 1;
|
||||
@@ -726,7 +727,7 @@ static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host)
|
||||
|
||||
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)) {
|
||||
if (len != sizeof(struct fast_ping_packet)) {
|
||||
int err = errno;
|
||||
if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL || errno == EHOSTUNREACH) {
|
||||
goto errout;
|
||||
@@ -806,7 +807,7 @@ static int _fast_ping_sendping_v4(struct ping_host_struct *ping_host)
|
||||
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, &ping_host->addr, ping_host->addr_len);
|
||||
if (len < 0 || len != sizeof(struct fast_ping_packet)) {
|
||||
if (len != sizeof(struct fast_ping_packet)) {
|
||||
int err = errno;
|
||||
if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL || errno == EPERM || errno == EACCES) {
|
||||
goto errout;
|
||||
@@ -858,7 +859,7 @@ static int _fast_ping_sendping_udp(struct ping_host_struct *ping_host)
|
||||
|
||||
gettimeofday(&ping_host->last, NULL);
|
||||
len = sendto(fd, &dns_head, sizeof(dns_head), 0, &ping_host->addr, ping_host->addr_len);
|
||||
if (len < 0 || len != sizeof(dns_head)) {
|
||||
if (len != sizeof(dns_head)) {
|
||||
int err = errno;
|
||||
if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL || errno == EPERM || errno == EACCES) {
|
||||
goto errout;
|
||||
@@ -2187,6 +2188,10 @@ int fast_ping_init(void)
|
||||
int ret = 0;
|
||||
bool_print_log = 1;
|
||||
|
||||
if (is_fast_ping_init == 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ping.epoll_fd > 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -2232,6 +2237,7 @@ int fast_ping_init(void)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
is_fast_ping_init = 1;
|
||||
return 0;
|
||||
errout:
|
||||
if (ping.notify_tid) {
|
||||
@@ -2294,6 +2300,10 @@ static void _fast_ping_close_fds(void)
|
||||
|
||||
void fast_ping_exit(void)
|
||||
{
|
||||
if (is_fast_ping_init == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ping.notify_tid) {
|
||||
void *retval = NULL;
|
||||
atomic_set(&ping.run, 0);
|
||||
@@ -2324,4 +2334,6 @@ void fast_ping_exit(void)
|
||||
pthread_mutex_destroy(&ping.notify_lock);
|
||||
pthread_mutex_destroy(&ping.lock);
|
||||
pthread_mutex_destroy(&ping.map_lock);
|
||||
|
||||
is_fast_ping_init = 0;
|
||||
}
|
||||
|
||||
@@ -111,10 +111,10 @@ const char *http_head_get_fields_value(struct http_head *http_head, const char *
|
||||
uint32_t key;
|
||||
struct http_head_fields *filed;
|
||||
|
||||
key = hash_string(name);
|
||||
key = hash_string_case(name);
|
||||
hash_for_each_possible(http_head->field_map, filed, node, key)
|
||||
{
|
||||
if (strncmp(filed->name, name, 128) == 0) {
|
||||
if (strncasecmp(filed->name, name, 128) == 0) {
|
||||
return filed->value;
|
||||
}
|
||||
}
|
||||
@@ -205,7 +205,7 @@ static int _http_head_add_fields(struct http_head *http_head, char *name, char *
|
||||
fields->value = value;
|
||||
|
||||
list_add_tail(&fields->list, &http_head->field_head.list);
|
||||
key = hash_string(name);
|
||||
key = hash_string_case(name);
|
||||
hash_add(http_head->field_map, &fields->node, key);
|
||||
|
||||
return 0;
|
||||
@@ -384,6 +384,10 @@ int http_head_parse(struct http_head *http_head, const char *data, int data_len)
|
||||
if (http_head->head_ok == 0) {
|
||||
for (i = 0; i < data_len; i++, data++) {
|
||||
*(buff_end + i) = *data;
|
||||
if (isprint(*data) == 0 && isspace(*data) == 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (*data == '\n') {
|
||||
if (http_head->buff_len + i < 2) {
|
||||
continue;
|
||||
|
||||
@@ -122,9 +122,9 @@ struct config_enum {
|
||||
.data = value, .min = min_value, .max = max_value \
|
||||
} \
|
||||
}
|
||||
#define CONF_SSIZE(key, value, min_value, max_value) \
|
||||
#define CONF_SSIZE(key, value, min_value, max_value) \
|
||||
{ \
|
||||
key, conf_ssize, &(struct config_item_ssize) \
|
||||
key, conf_ssize, &(struct config_item_ssize) \
|
||||
{ \
|
||||
.data = value, .min = min_value, .max = max_value \
|
||||
} \
|
||||
@@ -189,6 +189,8 @@ int load_conf(const char *file, struct config_item items[], conf_error_handler h
|
||||
|
||||
void load_exit(void);
|
||||
|
||||
int conf_get_current_lineno(void);
|
||||
|
||||
const char *conf_get_conf_file(void);
|
||||
|
||||
const char *conf_get_conf_fullpath(const char *path, char *fullpath, size_t path_len);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "bitmap.h"
|
||||
#include "jhash.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/* Fast hashing routine for ints, longs and pointers.
|
||||
(C) 2002 Nadia Yvette Chambers, IBM */
|
||||
@@ -223,11 +224,28 @@ static inline uint32_t hash_string_initval(const char *s, uint32_t initval)
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline uint32_t hash_string_case_initval(const char *s, uint32_t initval)
|
||||
{
|
||||
uint32_t h = initval;
|
||||
|
||||
while (*s) {
|
||||
h = h * 31 + tolower(*s);
|
||||
s++;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline uint32_t hash_string(const char *s)
|
||||
{
|
||||
return hash_string_initval(s, 0);
|
||||
}
|
||||
|
||||
static inline uint32_t hash_string_case(const char *s)
|
||||
{
|
||||
return hash_string_case_initval(s, 0);
|
||||
}
|
||||
|
||||
static inline uint32_t hash_string_array(const char **a)
|
||||
{
|
||||
uint32_t h = 0;
|
||||
|
||||
@@ -29,6 +29,11 @@
|
||||
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
|
||||
|
||||
struct hash_table {
|
||||
struct hlist_head *table;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
#define DEFINE_HASHTABLE(name, bits) \
|
||||
struct hlist_head name[1 << (bits)] = \
|
||||
{ [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
|
||||
@@ -38,6 +43,8 @@
|
||||
|
||||
#define HASH_SIZE(name) (ARRAY_SIZE(name))
|
||||
#define HASH_BITS(name) ilog2(HASH_SIZE(name))
|
||||
#define HASH_TABLE_SIZE(name) (1 << ((name).size))
|
||||
#define HASH_TABLE_BITS(name) ((name).size)
|
||||
|
||||
/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
|
||||
#define hash_min(val, bits) \
|
||||
@@ -63,6 +70,16 @@ static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
|
||||
*/
|
||||
#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))
|
||||
|
||||
#define hash_table_init(hashtable, bits, malloc_func) \
|
||||
(hashtable).size = bits; \
|
||||
(hashtable).table = malloc_func(sizeof(struct hlist_head) * HASH_TABLE_SIZE((hashtable))); \
|
||||
__hash_init((hashtable).table, HASH_TABLE_SIZE((hashtable)))
|
||||
|
||||
#define hash_table_free(hashtable, free_func) \
|
||||
free_func((hashtable).table); \
|
||||
(hashtable).table = NULL; \
|
||||
(hashtable).size = 0;
|
||||
|
||||
/**
|
||||
* hash_add - add an object to a hashtable
|
||||
* @hashtable: hashtable to add to
|
||||
@@ -72,6 +89,9 @@ static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
|
||||
#define hash_add(hashtable, node, key) \
|
||||
hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
|
||||
|
||||
#define hash_table_add(hashtable, node, key) \
|
||||
hlist_add_head(node, &(hashtable).table[hash_min(key, HASH_TABLE_BITS(hashtable))])
|
||||
|
||||
/**
|
||||
* hash_hashed - check whether an object is in any hashtable
|
||||
* @node: the &struct hlist_node of the object to be checked
|
||||
@@ -101,6 +121,8 @@ static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz)
|
||||
*/
|
||||
#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable))
|
||||
|
||||
#define hash_table_empty(hashtable) __hash_empty((hashtable).table, HASH_TABLE_SIZE(hashtable))
|
||||
|
||||
/**
|
||||
* hash_del - remove an object from a hashtable
|
||||
* @node: &struct hlist_node of the object to remove
|
||||
@@ -122,6 +144,11 @@ static inline void hash_del(struct hlist_node *node)
|
||||
(bkt)++)\
|
||||
hlist_for_each_entry(obj, &name[bkt], member)
|
||||
|
||||
#define hash_table_for_each(name, bkt, obj, member) \
|
||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < (HASH_TABLE_SIZE(name));\
|
||||
(bkt)++)\
|
||||
hlist_for_each_entry(obj, &((name).table)[bkt], member)
|
||||
|
||||
/**
|
||||
* hash_for_each_safe - iterate over a hashtable safe against removal of
|
||||
* hash entry
|
||||
@@ -136,6 +163,11 @@ static inline void hash_del(struct hlist_node *node)
|
||||
(bkt)++)\
|
||||
hlist_for_each_entry_safe(obj, tmp, &name[bkt], member)
|
||||
|
||||
#define hash_table_for_each_safe(name, bkt, tmp, obj, member) \
|
||||
for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < (HASH_TABLE_SIZE(name));\
|
||||
(bkt)++)\
|
||||
hlist_for_each_entry_safe(obj, tmp, &((name).table)[bkt], member)
|
||||
|
||||
/**
|
||||
* hash_for_each_possible - iterate over all possible objects hashing to the
|
||||
* same bucket
|
||||
@@ -147,6 +179,9 @@ static inline void hash_del(struct hlist_node *node)
|
||||
#define hash_for_each_possible(name, obj, member, key) \
|
||||
hlist_for_each_entry(obj, &name[hash_min(key, HASH_BITS(name))], member)
|
||||
|
||||
#define hash_table_for_each_possible(name, obj, member, key) \
|
||||
hlist_for_each_entry(obj, &((name).table)[hash_min(key, HASH_TABLE_BITS(name))], member)
|
||||
|
||||
/**
|
||||
* hash_for_each_possible_safe - iterate over all possible objects hashing to the
|
||||
* same bucket safe against removals
|
||||
@@ -160,4 +195,8 @@ static inline void hash_del(struct hlist_node *node)
|
||||
hlist_for_each_entry_safe(obj, tmp,\
|
||||
&name[hash_min(key, HASH_BITS(name))], member)
|
||||
|
||||
#define hash_table_for_each_possible_safe(name, obj, tmp, member, key) \
|
||||
hlist_for_each_entry_safe(obj, tmp,\
|
||||
&((name).table)[hash_min(key, HASH_TABLE_BITS(name))], member)
|
||||
|
||||
#endif
|
||||
|
||||
32
src/include/idna.h
Normal file
32
src/include/idna.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SMARTDNS_IDNA_H
|
||||
#define _SMARTDNS_IDNA_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int utf8_to_punycode(const char *src, int src_len, char *dst, int dst_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !_SMARTDNS_IDNA_H
|
||||
57
src/include/timer_wheel.h
Normal file
57
src/include/timer_wheel.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TIMER_WHEEL_H
|
||||
#define __TIMER_WHEEL_H
|
||||
|
||||
#include "list.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct tw_base;
|
||||
struct tw_timer_list;
|
||||
|
||||
typedef void (*tw_func)(struct tw_base *, struct tw_timer_list *, void *, unsigned long);
|
||||
typedef void (*tw_del_func)(struct tw_base *, struct tw_timer_list *, void *);
|
||||
|
||||
struct tw_timer_list {
|
||||
void *data;
|
||||
unsigned long expires;
|
||||
tw_func function;
|
||||
tw_del_func del_function;
|
||||
struct list_head entry;
|
||||
};
|
||||
|
||||
struct tw_base *tw_init_timers(void);
|
||||
|
||||
int tw_cleanup_timers(struct tw_base *);
|
||||
|
||||
void tw_add_timer(struct tw_base *, struct tw_timer_list *);
|
||||
|
||||
int tw_del_timer(struct tw_base *, struct tw_timer_list *);
|
||||
|
||||
int tw_mod_timer_pending(struct tw_base *, struct tw_timer_list *, unsigned long);
|
||||
|
||||
int tw_mod_timer(struct tw_base *, struct tw_timer_list *, unsigned long);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -24,14 +24,21 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
static const char *current_conf_file = NULL;
|
||||
static int current_conf_lineno = 0;
|
||||
|
||||
const char *conf_get_conf_file(void)
|
||||
{
|
||||
return current_conf_file;
|
||||
}
|
||||
|
||||
int conf_get_current_lineno(void)
|
||||
{
|
||||
return current_conf_lineno;
|
||||
}
|
||||
|
||||
static char *get_dir_name(char *path)
|
||||
{
|
||||
if (strstr(path, "/") == NULL) {
|
||||
@@ -347,6 +354,7 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
||||
char value[MAX_LINE_LEN];
|
||||
int filed_num = 0;
|
||||
int i = 0;
|
||||
int last_item_index = -1;
|
||||
int argc = 0;
|
||||
char *argv[1024];
|
||||
int ret = 0;
|
||||
@@ -354,6 +362,9 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
||||
int line_no = 0;
|
||||
int line_len = 0;
|
||||
int read_len = 0;
|
||||
int is_last_line_wrap = 0;
|
||||
int current_line_wrap = 0;
|
||||
int is_func_found = 0;
|
||||
const char *last_file = NULL;
|
||||
|
||||
if (handler == NULL) {
|
||||
@@ -362,21 +373,52 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
||||
|
||||
fp = fopen(file, "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "open config file '%s' failed, %s\n", file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
line_no = 0;
|
||||
while (fgets(line + line_len, MAX_LINE_LEN - line_len, fp)) {
|
||||
current_line_wrap = 0;
|
||||
line_no++;
|
||||
read_len = strnlen(line + line_len, sizeof(line));
|
||||
if (read_len >= 2 && *(line + line_len + read_len - 2) == '\\') {
|
||||
line_len += read_len - 2;
|
||||
line[line_len] = '\0';
|
||||
continue;
|
||||
read_len -= 1;
|
||||
current_line_wrap = 1;
|
||||
}
|
||||
line_len = 0;
|
||||
|
||||
filed_num = sscanf(line, "%63s %8192[^\r\n]s", key, value);
|
||||
/* comment in wrap line, skip */
|
||||
if (is_last_line_wrap && read_len > 0) {
|
||||
if (*(line + line_len) == '#') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* trim prefix spaces in wrap line */
|
||||
if ((current_line_wrap == 1 || is_last_line_wrap == 1) && read_len > 0) {
|
||||
is_last_line_wrap = current_line_wrap;
|
||||
read_len -= 1;
|
||||
for (i = 0; i < read_len; i++) {
|
||||
char *ptr = line + line_len + i;
|
||||
if (*ptr == ' ' || *ptr == '\t') {
|
||||
continue;
|
||||
}
|
||||
|
||||
memmove(line + line_len, ptr, read_len - i + 1);
|
||||
line_len += read_len - i;
|
||||
break;
|
||||
}
|
||||
|
||||
line[line_len] = '\0';
|
||||
if (current_line_wrap) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
line_len = 0;
|
||||
is_last_line_wrap = 0;
|
||||
|
||||
filed_num = sscanf(line, "%63s %8191[^\r\n]s", key, value);
|
||||
if (filed_num <= 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -392,13 +434,22 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
||||
goto errout;
|
||||
}
|
||||
|
||||
for (i = 0;; i++) {
|
||||
is_func_found = 0;
|
||||
|
||||
for (i = last_item_index;; i++) {
|
||||
if (i < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (items[i].item == NULL) {
|
||||
handler(file, line_no, CONF_RET_NOENT);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp(items[i].item, key, MAX_KEY_LEN) != 0) {
|
||||
if (last_item_index >= 0) {
|
||||
i = -1;
|
||||
last_item_index = -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -410,6 +461,7 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
||||
/* call item function */
|
||||
last_file = current_conf_file;
|
||||
current_conf_file = file;
|
||||
current_conf_lineno = line_no;
|
||||
call_ret = items[i].item_func(items[i].item, items[i].data, argc, argv);
|
||||
ret = handler(file, line_no, call_ret);
|
||||
if (ret != 0) {
|
||||
@@ -422,8 +474,14 @@ static int load_conf_file(const char *file, struct config_item *items, conf_erro
|
||||
current_conf_file = last_file;
|
||||
}
|
||||
|
||||
last_item_index = i;
|
||||
is_func_found = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_func_found == 0) {
|
||||
handler(file, line_no, CONF_RET_NOENT);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
339
src/lib/idna.c
Normal file
339
src/lib/idna.c
Normal file
@@ -0,0 +1,339 @@
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "idna.h"
|
||||
#include <limits.h>
|
||||
|
||||
static unsigned _utf8_decode_slow(const char **p, const char *pe, unsigned a)
|
||||
{
|
||||
unsigned b;
|
||||
unsigned c;
|
||||
unsigned d;
|
||||
unsigned min;
|
||||
|
||||
if (a > 0xF7) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (pe - *p) {
|
||||
default:
|
||||
if (a > 0xEF) {
|
||||
min = 0x10000;
|
||||
a = a & 7;
|
||||
b = (unsigned char)*(*p)++;
|
||||
c = (unsigned char)*(*p)++;
|
||||
d = (unsigned char)*(*p)++;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
if (a > 0xDF) {
|
||||
min = 0x800;
|
||||
b = 0x80 | (a & 15);
|
||||
c = (unsigned char)*(*p)++;
|
||||
d = (unsigned char)*(*p)++;
|
||||
a = 0;
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
if (a > 0xBF) {
|
||||
min = 0x80;
|
||||
b = 0x80;
|
||||
c = 0x80 | (a & 31);
|
||||
d = (unsigned char)*(*p)++;
|
||||
a = 0;
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0x80 != (0xC0 & (b ^ c ^ d))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
b &= 63;
|
||||
c &= 63;
|
||||
d &= 63;
|
||||
a = (a << 18) | (b << 12) | (c << 6) | d;
|
||||
|
||||
if (a < min) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a > 0x10FFFF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a >= 0xD800 && a <= 0xDFFF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static unsigned _utf8_decode(const char **p, const char *pe)
|
||||
{
|
||||
unsigned a;
|
||||
|
||||
a = (unsigned char)*(*p)++;
|
||||
|
||||
if (a < 128) {
|
||||
return a;
|
||||
}
|
||||
|
||||
return _utf8_decode_slow(p, pe, a);
|
||||
}
|
||||
|
||||
static int _utf8_to_punycode_label(const char *s, const char *se, char **d, char *de)
|
||||
{
|
||||
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
const char *ss;
|
||||
unsigned c;
|
||||
unsigned h;
|
||||
unsigned k;
|
||||
unsigned n;
|
||||
unsigned m;
|
||||
unsigned q;
|
||||
unsigned t;
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
unsigned bias;
|
||||
unsigned delta;
|
||||
unsigned todo;
|
||||
int first;
|
||||
|
||||
h = 0;
|
||||
ss = s;
|
||||
todo = 0;
|
||||
|
||||
while (s < se) {
|
||||
c = _utf8_decode(&s, se);
|
||||
if (c == UINT_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (c < 128) {
|
||||
h++;
|
||||
} else {
|
||||
todo++;
|
||||
}
|
||||
}
|
||||
|
||||
if (todo > 0) {
|
||||
if (*d < de) {
|
||||
*(*d)++ = 'x';
|
||||
}
|
||||
if (*d < de) {
|
||||
*(*d)++ = 'n';
|
||||
}
|
||||
if (*d < de) {
|
||||
*(*d)++ = '-';
|
||||
}
|
||||
if (*d < de) {
|
||||
*(*d)++ = '-';
|
||||
}
|
||||
}
|
||||
|
||||
x = 0;
|
||||
s = ss;
|
||||
while (s < se) {
|
||||
c = _utf8_decode(&s, se);
|
||||
|
||||
if (c > 127) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*d < de) {
|
||||
*(*d)++ = c;
|
||||
}
|
||||
|
||||
if (++x == h) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (todo == 0) {
|
||||
return h;
|
||||
}
|
||||
|
||||
if (h > 0) {
|
||||
if (*d < de) {
|
||||
*(*d)++ = '-';
|
||||
}
|
||||
}
|
||||
|
||||
n = 128;
|
||||
bias = 72;
|
||||
delta = 0;
|
||||
first = 1;
|
||||
|
||||
while (todo > 0) {
|
||||
m = -1;
|
||||
s = ss;
|
||||
|
||||
while (s < se) {
|
||||
c = _utf8_decode(&s, se);
|
||||
|
||||
if (c >= n) {
|
||||
if (c < m) {
|
||||
m = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x = m - n;
|
||||
y = h + 1;
|
||||
|
||||
if (x > ~delta / y) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
delta += x * y;
|
||||
n = m;
|
||||
|
||||
s = ss;
|
||||
while (s < se) {
|
||||
c = _utf8_decode(&s, se);
|
||||
|
||||
if (c < n) {
|
||||
if (++delta == 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (c != n) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (k = 36, q = delta;; k += 36) {
|
||||
t = 1;
|
||||
|
||||
if (k > bias) {
|
||||
t = k - bias;
|
||||
}
|
||||
|
||||
if (t > 26) {
|
||||
t = 26;
|
||||
}
|
||||
|
||||
if (q < t) {
|
||||
break;
|
||||
}
|
||||
|
||||
x = q - t;
|
||||
y = 36 - t;
|
||||
q = x / y;
|
||||
t = t + x % y;
|
||||
|
||||
if (*d < de) {
|
||||
*(*d)++ = alphabet[t];
|
||||
}
|
||||
}
|
||||
|
||||
if (*d < de) {
|
||||
*(*d)++ = alphabet[q];
|
||||
}
|
||||
|
||||
delta /= 2;
|
||||
|
||||
if (first) {
|
||||
delta /= 350;
|
||||
first = 0;
|
||||
}
|
||||
|
||||
h++;
|
||||
delta += delta / h;
|
||||
|
||||
for (bias = 0; delta > 35 * 26 / 2; bias += 36) {
|
||||
delta /= 35;
|
||||
}
|
||||
|
||||
bias += 36 * delta / (delta + 38);
|
||||
delta = 0;
|
||||
todo--;
|
||||
}
|
||||
|
||||
delta++;
|
||||
n++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int utf8_to_punycode(const char *src, int src_len, char *dst, int dst_len)
|
||||
{
|
||||
const char *si;
|
||||
const char *se;
|
||||
const char *st;
|
||||
unsigned c;
|
||||
char *ds;
|
||||
char *de;
|
||||
int rc;
|
||||
|
||||
ds = dst;
|
||||
si = src;
|
||||
se = src + src_len;
|
||||
de = dst + dst_len;
|
||||
|
||||
while (si < se) {
|
||||
st = si;
|
||||
c = _utf8_decode(&si, se);
|
||||
|
||||
if (c == UINT_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (c != '.') {
|
||||
if (c != 0x3002) {
|
||||
if (c != 0xFF0E) {
|
||||
if (c != 0xFF61) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = _utf8_to_punycode_label(src, st, &dst, de);
|
||||
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (dst < de) {
|
||||
*dst++ = '.';
|
||||
}
|
||||
|
||||
src = si;
|
||||
}
|
||||
|
||||
if (src < se) {
|
||||
rc = _utf8_to_punycode_label(src, se, &dst, de);
|
||||
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (dst < de) {
|
||||
*dst++ = '\0';
|
||||
}
|
||||
|
||||
return dst - ds;
|
||||
}
|
||||
394
src/lib/timer_wheel.c
Normal file
394
src/lib/timer_wheel.c
Normal file
@@ -0,0 +1,394 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "bitops.h"
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "timer_wheel.h"
|
||||
|
||||
#define TVR_BITS 10
|
||||
#define TVN_BITS 6
|
||||
#define TVR_SIZE (1 << TVR_BITS)
|
||||
#define TVN_SIZE (1 << TVN_BITS)
|
||||
#define TVR_MASK (TVR_SIZE - 1)
|
||||
#define TVN_MASK (TVN_SIZE - 1)
|
||||
#define INDEX(N) ((base->jiffies >> (TVR_BITS + N * TVN_BITS)) & TVN_MASK)
|
||||
#define MAX_TVAL ((unsigned long)((1ULL << (TVR_BITS + 4 * TVN_BITS)) - 1))
|
||||
|
||||
struct tvec {
|
||||
struct list_head vec[TVN_SIZE];
|
||||
};
|
||||
|
||||
struct tvec_root {
|
||||
struct list_head vec[TVR_SIZE];
|
||||
};
|
||||
|
||||
struct tw_base {
|
||||
pthread_spinlock_t lock;
|
||||
|
||||
pthread_t runner;
|
||||
|
||||
unsigned long jiffies;
|
||||
|
||||
struct tvec_root tv1;
|
||||
struct tvec tv2;
|
||||
struct tvec tv3;
|
||||
struct tvec tv4;
|
||||
struct tvec tv5;
|
||||
};
|
||||
|
||||
static inline void _tw_add_timer(struct tw_base *base, struct tw_timer_list *timer)
|
||||
{
|
||||
int i;
|
||||
unsigned long idx;
|
||||
unsigned long expires;
|
||||
struct list_head *vec;
|
||||
|
||||
expires = timer->expires;
|
||||
idx = expires - base->jiffies;
|
||||
|
||||
if (idx < TVR_SIZE) {
|
||||
i = expires & TVR_MASK;
|
||||
vec = base->tv1.vec + i;
|
||||
} else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
|
||||
i = (expires >> TVR_BITS) & TVN_MASK;
|
||||
vec = base->tv2.vec + i;
|
||||
} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
|
||||
i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
|
||||
vec = base->tv3.vec + i;
|
||||
} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
|
||||
i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
|
||||
vec = base->tv4.vec + i;
|
||||
} else if ((signed long)idx < 0) {
|
||||
vec = base->tv1.vec + (base->jiffies & TVR_MASK);
|
||||
} else {
|
||||
if (idx > MAX_TVAL) {
|
||||
idx = MAX_TVAL;
|
||||
expires = idx + base->jiffies;
|
||||
}
|
||||
i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
|
||||
vec = base->tv5.vec + i;
|
||||
}
|
||||
|
||||
list_add_tail(&timer->entry, vec);
|
||||
}
|
||||
|
||||
static inline void _tw_detach_timer(struct tw_timer_list *timer)
|
||||
{
|
||||
struct list_head *entry = &timer->entry;
|
||||
|
||||
list_del(entry);
|
||||
entry->next = NULL;
|
||||
}
|
||||
|
||||
static inline int _tw_cascade(struct tw_base *base, struct tvec *tv, int index)
|
||||
{
|
||||
struct tw_timer_list *timer, *tmp;
|
||||
struct list_head tv_list;
|
||||
|
||||
list_replace_init(tv->vec + index, &tv_list);
|
||||
|
||||
list_for_each_entry_safe(timer, tmp, &tv_list, entry)
|
||||
{
|
||||
_tw_add_timer(base, timer);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static inline int timer_pending(struct tw_timer_list *timer)
|
||||
{
|
||||
struct list_head *entry = &timer->entry;
|
||||
|
||||
return (entry->next != NULL);
|
||||
}
|
||||
|
||||
static inline int __detach_if_pending(struct tw_timer_list *timer)
|
||||
{
|
||||
if (!timer_pending(timer)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_tw_detach_timer(timer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int __mod_timer(struct tw_base *base, struct tw_timer_list *timer, int pending_only)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = __detach_if_pending(timer);
|
||||
if (!ret && pending_only) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
_tw_add_timer(base, timer);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tw_add_timer(struct tw_base *base, struct tw_timer_list *timer)
|
||||
{
|
||||
if (timer->function == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_spin_lock(&base->lock);
|
||||
{
|
||||
timer->expires += base->jiffies - 1;
|
||||
_tw_add_timer(base, timer);
|
||||
}
|
||||
pthread_spin_unlock(&base->lock);
|
||||
}
|
||||
|
||||
int tw_del_timer(struct tw_base *base, struct tw_timer_list *timer)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
pthread_spin_lock(&base->lock);
|
||||
{
|
||||
if (timer_pending(timer)) {
|
||||
ret = 1;
|
||||
_tw_detach_timer(timer);
|
||||
}
|
||||
}
|
||||
pthread_spin_unlock(&base->lock);
|
||||
|
||||
if (ret == 1 && timer->del_function) {
|
||||
timer->del_function(base, timer, timer->data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tw_mod_timer_pending(struct tw_base *base, struct tw_timer_list *timer, unsigned long expires)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
pthread_spin_lock(&base->lock);
|
||||
{
|
||||
timer->expires = expires + base->jiffies - 1;
|
||||
ret = __mod_timer(base, timer, 1);
|
||||
}
|
||||
pthread_spin_unlock(&base->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tw_mod_timer(struct tw_base *base, struct tw_timer_list *timer, unsigned long expires)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
pthread_spin_lock(&base->lock);
|
||||
{
|
||||
if (timer_pending(timer) && timer->expires == expires) {
|
||||
goto unblock;
|
||||
}
|
||||
|
||||
timer->expires = expires + base->jiffies - 1;
|
||||
|
||||
ret = __mod_timer(base, timer, 0);
|
||||
}
|
||||
unblock:
|
||||
pthread_spin_unlock(&base->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tw_cleanup_timers(struct tw_base *base)
|
||||
{
|
||||
int ret = 0;
|
||||
void *res = NULL;
|
||||
|
||||
ret = pthread_cancel(base->runner);
|
||||
if (ret != 0) {
|
||||
goto errout;
|
||||
}
|
||||
ret = pthread_join(base->runner, &res);
|
||||
if (ret != 0) {
|
||||
goto errout;
|
||||
}
|
||||
if (res != PTHREAD_CANCELED) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = pthread_spin_destroy(&base->lock);
|
||||
if (ret != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
free(base);
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void run_timers(struct tw_base *base)
|
||||
{
|
||||
unsigned long index, call_time;
|
||||
struct tw_timer_list *timer;
|
||||
|
||||
struct list_head work_list;
|
||||
struct list_head *head = &work_list;
|
||||
|
||||
pthread_spin_lock(&base->lock);
|
||||
{
|
||||
index = base->jiffies & TVR_MASK;
|
||||
|
||||
if (!index && (!_tw_cascade(base, &base->tv2, INDEX(0))) && (!_tw_cascade(base, &base->tv3, INDEX(1))) &&
|
||||
(!_tw_cascade(base, &base->tv4, INDEX(2))))
|
||||
_tw_cascade(base, &base->tv5, INDEX(3));
|
||||
|
||||
call_time = base->jiffies++;
|
||||
list_replace_init(base->tv1.vec + index, head);
|
||||
while (!list_empty(head)) {
|
||||
tw_func fn;
|
||||
void *data;
|
||||
|
||||
timer = list_first_entry(head, struct tw_timer_list, entry);
|
||||
fn = timer->function;
|
||||
data = timer->data;
|
||||
|
||||
_tw_detach_timer(timer);
|
||||
pthread_spin_unlock(&base->lock);
|
||||
{
|
||||
fn(base, timer, data, call_time);
|
||||
}
|
||||
|
||||
pthread_spin_lock(&base->lock);
|
||||
if ((timer_pending(timer) == 0 && timer->del_function)) {
|
||||
pthread_spin_unlock(&base->lock);
|
||||
timer->del_function(base, timer, timer->data);
|
||||
pthread_spin_lock(&base->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_spin_unlock(&base->lock);
|
||||
}
|
||||
|
||||
static unsigned long _tw_tick_count(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
|
||||
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
|
||||
}
|
||||
|
||||
static void *timer_work(void *arg)
|
||||
{
|
||||
struct tw_base *base = arg;
|
||||
int sleep = 1000;
|
||||
int sleep_time = 0;
|
||||
unsigned long now = {0};
|
||||
unsigned long last = {0};
|
||||
unsigned long expect_time = 0;
|
||||
|
||||
sleep_time = sleep;
|
||||
now = _tw_tick_count() - sleep;
|
||||
last = now;
|
||||
expect_time = now + sleep;
|
||||
while (1) {
|
||||
run_timers(base);
|
||||
|
||||
now = _tw_tick_count();
|
||||
if (sleep_time > 0) {
|
||||
sleep_time -= now - last;
|
||||
if (sleep_time <= 0) {
|
||||
sleep_time = 0;
|
||||
}
|
||||
|
||||
int cnt = sleep_time / sleep;
|
||||
expect_time -= cnt * sleep;
|
||||
sleep_time -= cnt * sleep;
|
||||
}
|
||||
|
||||
if (now >= expect_time) {
|
||||
sleep_time = sleep - (now - expect_time);
|
||||
if (sleep_time < 0) {
|
||||
sleep_time = 0;
|
||||
expect_time = now;
|
||||
}
|
||||
expect_time += sleep;
|
||||
}
|
||||
last = now;
|
||||
|
||||
usleep(sleep_time * 1000);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct tw_base *tw_init_timers(void)
|
||||
{
|
||||
int j = 0;
|
||||
int ret = 0;
|
||||
struct timeval tv = {
|
||||
0,
|
||||
};
|
||||
struct tw_base *base = NULL;
|
||||
|
||||
base = malloc(sizeof(*base));
|
||||
if (!base) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ret = pthread_spin_init(&base->lock, 0);
|
||||
if (ret != 0) {
|
||||
goto errout2;
|
||||
}
|
||||
|
||||
for (j = 0; j < TVN_SIZE; j++) {
|
||||
INIT_LIST_HEAD(base->tv5.vec + j);
|
||||
INIT_LIST_HEAD(base->tv4.vec + j);
|
||||
INIT_LIST_HEAD(base->tv3.vec + j);
|
||||
INIT_LIST_HEAD(base->tv2.vec + j);
|
||||
}
|
||||
|
||||
for (j = 0; j < TVR_SIZE; j++) {
|
||||
INIT_LIST_HEAD(base->tv1.vec + j);
|
||||
}
|
||||
|
||||
ret = gettimeofday(&tv, 0);
|
||||
if (ret < 0) {
|
||||
goto errout1;
|
||||
}
|
||||
base->jiffies = tv.tv_sec;
|
||||
|
||||
ret = pthread_create(&base->runner, NULL, timer_work, base);
|
||||
if (ret != 0) {
|
||||
goto errout1;
|
||||
}
|
||||
return base;
|
||||
|
||||
errout1:
|
||||
(void)pthread_spin_destroy(&base->lock);
|
||||
errout2:
|
||||
free(base);
|
||||
errout:
|
||||
return NULL;
|
||||
}
|
||||
24
src/proxy.c
24
src/proxy.c
@@ -95,8 +95,9 @@ struct proxy_struct {
|
||||
};
|
||||
|
||||
static struct proxy_struct proxy;
|
||||
static int is_proxy_init;
|
||||
|
||||
const char *proxy_socks5_status_code[] = {
|
||||
static const char *proxy_socks5_status_code[] = {
|
||||
"success",
|
||||
"general SOCKS server failure",
|
||||
"connection not allowed by ruleset",
|
||||
@@ -234,7 +235,7 @@ int proxy_remove(const char *proxy_name)
|
||||
|
||||
static void _proxy_remove_all(void)
|
||||
{
|
||||
struct proxy_server_info *server_info;
|
||||
struct proxy_server_info *server_info = NULL;
|
||||
struct hlist_node *tmp = NULL;
|
||||
unsigned int i = 0;
|
||||
|
||||
@@ -957,7 +958,7 @@ int proxy_conn_recvfrom(struct proxy_conn *proxy_conn, void *buf, size_t len, in
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = recvfrom(proxy_conn->udp_fd, buffer, sizeof(buffer), MSG_NOSIGNAL, NULL, 0);
|
||||
ret = recvfrom(proxy_conn->udp_fd, buffer, sizeof(buffer), MSG_NOSIGNAL, NULL, NULL);
|
||||
if (ret <= 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1043,15 +1044,26 @@ int proxy_conn_is_udp(struct proxy_conn *proxy_conn)
|
||||
return proxy_conn->is_udp;
|
||||
}
|
||||
|
||||
int proxy_init()
|
||||
int proxy_init(void)
|
||||
{
|
||||
if (is_proxy_init == 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&proxy, 0, sizeof(proxy));
|
||||
hash_init(proxy.proxy_server);
|
||||
is_proxy_init = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int proxy_exit()
|
||||
void proxy_exit(void)
|
||||
{
|
||||
if (is_proxy_init == 0) {
|
||||
return;
|
||||
}
|
||||
_proxy_remove_all();
|
||||
return 0;
|
||||
|
||||
is_proxy_init = 0;
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ struct proxy_conn;
|
||||
|
||||
int proxy_init(void);
|
||||
|
||||
int proxy_exit(void);
|
||||
void proxy_exit(void);
|
||||
|
||||
int proxy_add(const char *proxy_name, struct proxy_info *info);
|
||||
|
||||
|
||||
323
src/smartdns.c
323
src/smartdns.c
@@ -20,6 +20,7 @@
|
||||
#include "smartdns.h"
|
||||
#include "art.h"
|
||||
#include "atomic.h"
|
||||
#include "dns_cache.h"
|
||||
#include "dns_client.h"
|
||||
#include "dns_conf.h"
|
||||
#include "dns_server.h"
|
||||
@@ -27,10 +28,12 @@
|
||||
#include "hashtable.h"
|
||||
#include "list.h"
|
||||
#include "rbtree.h"
|
||||
#include "timer.h"
|
||||
#include "tlog.h"
|
||||
#include "util.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <libgen.h>
|
||||
#include <linux/capability.h>
|
||||
#include <openssl/err.h>
|
||||
@@ -44,12 +47,21 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <syslog.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#define MAX_KEY_LEN 64
|
||||
#define SMARTDNS_PID_FILE "/run/smartdns.pid"
|
||||
#define SMARTDNS_LEGACY_PID_FILE "/var/run/smartdns.pid"
|
||||
#define TMP_BUFF_LEN_32 32
|
||||
#define SMARTDNS_CRASH_CODE 254
|
||||
|
||||
typedef enum {
|
||||
SMARTDNS_RUN_MONITOR_OK = 0,
|
||||
SMARTDNS_RUN_MONITOR_ERROR = 1,
|
||||
SMARTDNS_RUN_MONITOR_EXIT = 2,
|
||||
} smartdns_run_monitor_ret;
|
||||
|
||||
static int verbose_screen;
|
||||
|
||||
@@ -149,12 +161,13 @@ static void _help(void)
|
||||
" -f run foreground.\n"
|
||||
" -c [conf] config file.\n"
|
||||
" -p [pid] pid file path, '-' means don't create pid file.\n"
|
||||
" -R restart smartdns when crash.\n"
|
||||
" -S ignore segment fault signal.\n"
|
||||
" -x verbose screen.\n"
|
||||
" -v display version.\n"
|
||||
" -h show this help message.\n"
|
||||
|
||||
"Online help: http://pymumu.github.io/smartdns\n"
|
||||
"Online help: https://pymumu.github.io/smartdns\n"
|
||||
"Copyright (C) Nick Peng <pymumu@gmail.com>\n"
|
||||
;
|
||||
/* clang-format on */
|
||||
@@ -255,13 +268,13 @@ static int _smartdns_prepare_server_flags(struct client_dns_server_flags *flags,
|
||||
safe_strncpy(flag_http->tls_host_verify, server->tls_host_verify, sizeof(flag_http->tls_host_verify));
|
||||
flag_http->skip_check_cert = server->skip_check_cert;
|
||||
} break;
|
||||
case DNS_SERVER_QUIC:
|
||||
case DNS_SERVER_TLS: {
|
||||
struct client_dns_server_flag_tls *flag_tls = &flags->tls;
|
||||
flag_tls->spi_len = dns_client_spki_decode(server->spki, (unsigned char *)flag_tls->spki);
|
||||
safe_strncpy(flag_tls->hostname, server->hostname, sizeof(flag_tls->hostname));
|
||||
safe_strncpy(flag_tls->tls_host_verify, server->tls_host_verify, sizeof(flag_tls->tls_host_verify));
|
||||
flag_tls->skip_check_cert = server->skip_check_cert;
|
||||
|
||||
} break;
|
||||
case DNS_SERVER_TCP:
|
||||
break;
|
||||
@@ -459,14 +472,31 @@ static int _smartdns_init(void)
|
||||
int ret = 0;
|
||||
const char *logfile = _smartdns_log_path();
|
||||
int i = 0;
|
||||
char logdir[PATH_MAX] = {0};
|
||||
int logbuffersize = 0;
|
||||
int enable_log_screen = 0;
|
||||
|
||||
ret = tlog_init(logfile, dns_conf_log_size, dns_conf_log_num, 0, 0);
|
||||
if (get_system_mem_size() > 1024 * 1024 * 1024) {
|
||||
logbuffersize = 1024 * 1024;
|
||||
}
|
||||
|
||||
safe_strncpy(logdir, _smartdns_log_path(), PATH_MAX);
|
||||
if (verbose_screen != 0 || dns_conf_log_console != 0 || access(dir_name(logdir), W_OK) != 0) {
|
||||
enable_log_screen = 1;
|
||||
}
|
||||
|
||||
unsigned int tlog_flag = TLOG_NONBLOCK;
|
||||
if (isatty(1) && enable_log_screen == 1) {
|
||||
tlog_flag |= TLOG_SCREEN_COLOR;
|
||||
}
|
||||
|
||||
ret = tlog_init(logfile, dns_conf_log_size, dns_conf_log_num, logbuffersize, tlog_flag);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "start tlog failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (verbose_screen != 0 || dns_conf_log_console != 0) {
|
||||
if (enable_log_screen) {
|
||||
tlog_setlogscreen(1);
|
||||
}
|
||||
|
||||
@@ -478,6 +508,11 @@ static int _smartdns_init(void)
|
||||
tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <pymumu@gmail.com>, build: %s %s)", __DATE__,
|
||||
__TIME__);
|
||||
|
||||
if (dns_timer_init() != 0) {
|
||||
tlog(TLOG_ERROR, "init timer failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_smartdns_init_ssl() != 0) {
|
||||
tlog(TLOG_ERROR, "init ssl failed.");
|
||||
goto errout;
|
||||
@@ -559,12 +594,12 @@ static int _smartdns_run(void)
|
||||
|
||||
static void _smartdns_exit(void)
|
||||
{
|
||||
tlog(TLOG_INFO, "smartdns exit...");
|
||||
dns_client_exit();
|
||||
proxy_exit();
|
||||
fast_ping_exit();
|
||||
dns_server_exit();
|
||||
_smartdns_destroy_ssl();
|
||||
dns_timer_destroy();
|
||||
tlog_exit();
|
||||
dns_server_load_exit();
|
||||
}
|
||||
@@ -605,7 +640,7 @@ static void _sig_error_exit(int signo, siginfo_t *siginfo, void *ct)
|
||||
__DATE__, __TIME__, arch);
|
||||
print_stack();
|
||||
sleep(1);
|
||||
_exit(0);
|
||||
_exit(SMARTDNS_CRASH_CODE);
|
||||
}
|
||||
|
||||
static int sig_list[] = {SIGSEGV, SIGABRT, SIGBUS, SIGILL, SIGFPE};
|
||||
@@ -711,6 +746,169 @@ static int _smartdns_init_pre(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _smartdns_early_log(struct tlog_loginfo *loginfo, const char *format, va_list ap)
|
||||
{
|
||||
char log_buf[TLOG_MAX_LINE_LEN];
|
||||
int sys_log_level = LOG_INFO;
|
||||
int log_buf_maxlen = 0;
|
||||
|
||||
if (loginfo->level < TLOG_WARN) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_buf_maxlen = sizeof(log_buf) - 2;
|
||||
log_buf[log_buf_maxlen] = '\0';
|
||||
int len = vsnprintf(log_buf, log_buf_maxlen, format, ap);
|
||||
if (len <= 0) {
|
||||
return;
|
||||
} else if (len >= log_buf_maxlen) {
|
||||
log_buf[log_buf_maxlen - 2] = '.';
|
||||
log_buf[log_buf_maxlen - 3] = '.';
|
||||
log_buf[log_buf_maxlen - 4] = '.';
|
||||
len = log_buf_maxlen - 1;
|
||||
}
|
||||
|
||||
if (log_buf[len - 1] != '\n') {
|
||||
log_buf[len] = '\n';
|
||||
len++;
|
||||
}
|
||||
|
||||
log_buf[len] = '\0';
|
||||
|
||||
fprintf(stderr, "%s", log_buf);
|
||||
|
||||
switch (loginfo->level) {
|
||||
case TLOG_ERROR:
|
||||
sys_log_level = LOG_ERR;
|
||||
break;
|
||||
case TLOG_WARN:
|
||||
sys_log_level = LOG_WARNING;
|
||||
break;
|
||||
case TLOG_NOTICE:
|
||||
sys_log_level = LOG_NOTICE;
|
||||
break;
|
||||
case TLOG_INFO:
|
||||
sys_log_level = LOG_INFO;
|
||||
break;
|
||||
case TLOG_DEBUG:
|
||||
sys_log_level = LOG_DEBUG;
|
||||
break;
|
||||
default:
|
||||
sys_log_level = LOG_INFO;
|
||||
break;
|
||||
}
|
||||
|
||||
syslog(sys_log_level, "%s", log_buf);
|
||||
}
|
||||
|
||||
static int _smartdns_child_pid = 0;
|
||||
static int _smartdns_child_restart = 0;
|
||||
|
||||
static void _smartdns_run_monitor_sig(int sig)
|
||||
{
|
||||
if (_smartdns_child_pid > 0) {
|
||||
if (sig == SIGHUP) {
|
||||
_smartdns_child_restart = 1;
|
||||
kill(_smartdns_child_pid, SIGTERM);
|
||||
return;
|
||||
}
|
||||
kill(_smartdns_child_pid, SIGTERM);
|
||||
}
|
||||
waitpid(_smartdns_child_pid, NULL, 0);
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
static smartdns_run_monitor_ret _smartdns_run_monitor(int restart_when_crash, int is_run_as_daemon)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
if (restart_when_crash == 0) {
|
||||
return SMARTDNS_RUN_MONITOR_OK;
|
||||
}
|
||||
|
||||
if (is_run_as_daemon) {
|
||||
switch (daemon_run(NULL)) {
|
||||
case DAEMON_RET_CHILD_OK:
|
||||
break;
|
||||
case DAEMON_RET_PARENT_OK:
|
||||
return SMARTDNS_RUN_MONITOR_EXIT;
|
||||
default:
|
||||
return SMARTDNS_RUN_MONITOR_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
daemon_kickoff(0, 1);
|
||||
|
||||
restart:
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
fprintf(stderr, "fork failed, %s\n", strerror(errno));
|
||||
return SMARTDNS_RUN_MONITOR_ERROR;
|
||||
} else if (pid == 0) {
|
||||
return SMARTDNS_RUN_MONITOR_OK;
|
||||
}
|
||||
|
||||
_smartdns_child_pid = pid;
|
||||
|
||||
signal(SIGTERM, _smartdns_run_monitor_sig);
|
||||
signal(SIGHUP, _smartdns_run_monitor_sig);
|
||||
while (true) {
|
||||
pid = waitpid(-1, &status, 0);
|
||||
if (pid == _smartdns_child_pid) {
|
||||
int need_restart = 0;
|
||||
char signalmsg[64] = {0};
|
||||
|
||||
if (_smartdns_child_restart == 1) {
|
||||
_smartdns_child_restart = 0;
|
||||
goto restart;
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(status) == SMARTDNS_CRASH_CODE) {
|
||||
need_restart = 1;
|
||||
} else if (WEXITSTATUS(status) == 255) {
|
||||
fprintf(stderr, "run daemon failed, please check log.\n");
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
switch (WTERMSIG(status)) {
|
||||
case SIGSEGV:
|
||||
case SIGABRT:
|
||||
case SIGBUS:
|
||||
case SIGILL:
|
||||
case SIGFPE:
|
||||
snprintf(signalmsg, sizeof(signalmsg), " with signal %d", WTERMSIG(status));
|
||||
need_restart = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_restart == 1) {
|
||||
printf("smartdns crashed%s, restart...\n", signalmsg);
|
||||
goto restart;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (pid < 0) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
return SMARTDNS_RUN_MONITOR_ERROR;
|
||||
}
|
||||
|
||||
static void _smartdns_print_error_tip(void)
|
||||
{
|
||||
char buff[4096];
|
||||
char *log_path = realpath(_smartdns_log_path(), buff);
|
||||
|
||||
if (log_path != NULL && access(log_path, F_OK) == 0) {
|
||||
fprintf(stderr, "run daemon failed, please check log at %s\n", log_path);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
static smartdns_post_func _smartdns_post = NULL;
|
||||
@@ -736,21 +934,32 @@ static void smartdns_test_notify_func(int fd_notify, uint64_t retval)
|
||||
}
|
||||
}
|
||||
|
||||
int smartdns_main(int argc, char *argv[], int fd_notify)
|
||||
#define smartdns_close_allfds() \
|
||||
if (no_close_allfds == 0) { \
|
||||
close_all_fd(fd_notify); \
|
||||
}
|
||||
|
||||
int smartdns_main(int argc, char *argv[], int fd_notify, int no_close_allfds)
|
||||
#else
|
||||
#define smartdns_test_notify(retval)
|
||||
#define smartdns_close_allfds() close_all_fd(-1)
|
||||
int main(int argc, char *argv[])
|
||||
#endif
|
||||
{
|
||||
int ret = 0;
|
||||
int is_foreground = 0;
|
||||
int is_run_as_daemon = 1;
|
||||
int opt = 0;
|
||||
char config_file[MAX_LINE_LEN];
|
||||
char pid_file[MAX_LINE_LEN];
|
||||
int is_pid_file_set = 0;
|
||||
int signal_ignore = 0;
|
||||
int restart_when_crash = getpid() == 1 ? 1 : 0;
|
||||
sigset_t empty_sigblock;
|
||||
struct stat sb;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"cache-print", required_argument, NULL, 256}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}};
|
||||
|
||||
safe_strncpy(config_file, SMARTDNS_CONF_FILE, MAX_LINE_LEN);
|
||||
|
||||
if (stat("/run", &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
||||
@@ -762,17 +971,26 @@ int main(int argc, char *argv[])
|
||||
/* patch for Asus router: unblock all signal*/
|
||||
sigemptyset(&empty_sigblock);
|
||||
sigprocmask(SIG_SETMASK, &empty_sigblock, NULL);
|
||||
smartdns_close_allfds();
|
||||
|
||||
while ((opt = getopt(argc, argv, "fhc:p:SvxN:")) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "fhc:p:SvxN:R", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
is_foreground = 1;
|
||||
is_run_as_daemon = 0;
|
||||
break;
|
||||
case 'c':
|
||||
snprintf(config_file, sizeof(config_file), "%s", optarg);
|
||||
if (full_path(config_file, sizeof(config_file), optarg) != 0) {
|
||||
snprintf(config_file, sizeof(config_file), "%s", optarg);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
snprintf(pid_file, sizeof(pid_file), "%s", optarg);
|
||||
if (strncmp(optarg, "-", 2) == 0 || full_path(pid_file, sizeof(pid_file), optarg) != 0) {
|
||||
snprintf(pid_file, sizeof(pid_file), "%s", optarg);
|
||||
is_pid_file_set = 1;
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
restart_when_crash = 1;
|
||||
break;
|
||||
case 'S':
|
||||
signal_ignore = 1;
|
||||
@@ -790,19 +1008,54 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
case 'h':
|
||||
_help();
|
||||
return 0;
|
||||
case 256:
|
||||
return dns_cache_print(optarg);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown option, please run %s -h for help.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dns_server_load_conf(config_file) != 0) {
|
||||
smartdns_run_monitor_ret init_ret = _smartdns_run_monitor(restart_when_crash, is_run_as_daemon);
|
||||
if (init_ret != SMARTDNS_RUN_MONITOR_OK) {
|
||||
if (init_ret == SMARTDNS_RUN_MONITOR_EXIT) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
tlog_reg_early_printf_callback(_smartdns_early_log);
|
||||
|
||||
ret = dns_server_load_conf(config_file);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "load config failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (is_foreground == 0) {
|
||||
if (daemon(0, 0) < 0) {
|
||||
fprintf(stderr, "run daemon process failed, %s\n", strerror(errno));
|
||||
return 1;
|
||||
if (dns_no_daemon || restart_when_crash) {
|
||||
is_run_as_daemon = 0;
|
||||
}
|
||||
|
||||
if (is_run_as_daemon) {
|
||||
int child_status = -1;
|
||||
switch (daemon_run(&child_status)) {
|
||||
case DAEMON_RET_CHILD_OK:
|
||||
break;
|
||||
case DAEMON_RET_PARENT_OK: {
|
||||
if (child_status != 0 && child_status != -3) {
|
||||
_smartdns_print_error_tip();
|
||||
}
|
||||
|
||||
return child_status;
|
||||
} break;
|
||||
case DAEMON_RET_ERR:
|
||||
default:
|
||||
fprintf(stderr, "run daemon failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -810,7 +1063,18 @@ int main(int argc, char *argv[])
|
||||
_reg_signal();
|
||||
}
|
||||
|
||||
if (strncmp(pid_file, "-", 2) != 0 && create_pid_file(pid_file) != 0) {
|
||||
if (is_pid_file_set == 0) {
|
||||
char pid_file_path[MAX_LINE_LEN];
|
||||
safe_strncpy(pid_file_path, pid_file, MAX_LINE_LEN);
|
||||
dir_name(pid_file_path);
|
||||
|
||||
if (access(pid_file_path, W_OK) != 0) {
|
||||
dns_no_pidfile = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(pid_file, "-", 2) != 0 && dns_no_pidfile == 0 && create_pid_file(pid_file) != 0) {
|
||||
ret = -3;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -818,9 +1082,10 @@ int main(int argc, char *argv[])
|
||||
signal(SIGINT, _sig_exit);
|
||||
signal(SIGTERM, _sig_exit);
|
||||
|
||||
if (_smartdns_init_pre() != 0) {
|
||||
ret = _smartdns_init_pre();
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "init failed.\n");
|
||||
return 1;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
drop_root_privilege();
|
||||
@@ -831,11 +1096,27 @@ int main(int argc, char *argv[])
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (is_run_as_daemon) {
|
||||
ret = daemon_kickoff(0, dns_conf_log_console | verbose_screen);
|
||||
if (ret != 0) {
|
||||
goto errout;
|
||||
}
|
||||
} else if (dns_conf_log_console == 0 && verbose_screen == 0) {
|
||||
daemon_close_stdfds();
|
||||
}
|
||||
|
||||
smartdns_test_notify(1);
|
||||
ret = _smartdns_run();
|
||||
tlog(TLOG_INFO, "smartdns exit...");
|
||||
_smartdns_exit();
|
||||
return ret;
|
||||
errout:
|
||||
if (is_run_as_daemon) {
|
||||
daemon_kickoff(ret, dns_conf_log_console | verbose_screen);
|
||||
} else if (dns_conf_log_console == 0 && verbose_screen == 0) {
|
||||
_smartdns_print_error_tip();
|
||||
}
|
||||
smartdns_test_notify(2);
|
||||
return 1;
|
||||
_smartdns_exit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ typedef void (*smartdns_post_func)(void *arg);
|
||||
|
||||
int smartdns_reg_post_func(smartdns_post_func func, void *arg);
|
||||
|
||||
int smartdns_main(int argc, char *argv[], int fd_notify);
|
||||
int smartdns_main(int argc, char *argv[], int fd_notify, int no_close_allfds);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
70
src/timer.c
Normal file
70
src/timer.c
Normal file
@@ -0,0 +1,70 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "timer.h"
|
||||
#include "timer_wheel.h"
|
||||
|
||||
static struct tw_base *dns_timer_base = NULL;
|
||||
|
||||
int dns_timer_init(void)
|
||||
{
|
||||
struct tw_base *tw = tw_init_timers();
|
||||
if (tw == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dns_timer_base = tw;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dns_timer_destroy(void)
|
||||
{
|
||||
if (dns_timer_base != NULL) {
|
||||
tw_cleanup_timers(dns_timer_base);
|
||||
dns_timer_base = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void dns_timer_add(struct tw_timer_list *timer)
|
||||
{
|
||||
if (dns_timer_base == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
tw_add_timer(dns_timer_base, timer);
|
||||
}
|
||||
|
||||
int dns_timer_del(struct tw_timer_list *timer)
|
||||
{
|
||||
if (dns_timer_base == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tw_del_timer(dns_timer_base, timer);
|
||||
}
|
||||
|
||||
int dns_timer_mod(struct tw_timer_list *timer, unsigned long expires)
|
||||
{
|
||||
if (dns_timer_base == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return tw_mod_timer(dns_timer_base, timer, expires);
|
||||
}
|
||||
|
||||
41
src/timer.h
Normal file
41
src/timer.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SMART_DNS_TIMER_H
|
||||
#define SMART_DNS_TIMER_H
|
||||
|
||||
#include "timer_wheel.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /*__cplusplus */
|
||||
|
||||
int dns_timer_init(void);
|
||||
|
||||
void dns_timer_add(struct tw_timer_list *timer);
|
||||
|
||||
int dns_timer_del(struct tw_timer_list *timer);
|
||||
|
||||
int dns_timer_mod(struct tw_timer_list *timer, unsigned long expires);
|
||||
|
||||
void dns_timer_destroy(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus */
|
||||
#endif
|
||||
147
src/tlog.c
147
src/tlog.c
@@ -79,6 +79,7 @@ struct tlog_log {
|
||||
int zip_pid;
|
||||
int multi_log;
|
||||
int logscreen;
|
||||
int logscreen_color;
|
||||
int segment_log;
|
||||
int max_line_size;
|
||||
int print_errmsg;
|
||||
@@ -148,6 +149,7 @@ static struct tlog tlog;
|
||||
static int tlog_disable_early_print = 0;
|
||||
static tlog_level tlog_set_level = TLOG_INFO;
|
||||
static tlog_format_func tlog_format;
|
||||
static tlog_early_print_func tlog_early_print;
|
||||
static unsigned int tlog_localtime_lock = 0;
|
||||
|
||||
static const char *tlog_level_str[] = {
|
||||
@@ -187,7 +189,7 @@ static int _tlog_mkdir(const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (*path == ' ' && *path != '\0') {
|
||||
while (*path == ' ') {
|
||||
path++;
|
||||
}
|
||||
|
||||
@@ -330,7 +332,7 @@ void tlog_logcount(struct tlog_log *log, int count)
|
||||
log->logcount = count;
|
||||
}
|
||||
|
||||
void tlog_set_permission(struct tlog_log *log, unsigned int file, unsigned int archive)
|
||||
void tlog_set_permission(struct tlog_log *log, mode_t file, mode_t archive)
|
||||
{
|
||||
log->file_perm = file;
|
||||
log->archive_perm = archive;
|
||||
@@ -628,7 +630,7 @@ int tlog_printf(struct tlog_log *log, const char *format, ...)
|
||||
return len;
|
||||
}
|
||||
|
||||
static int _tlog_early_print(tlog_level level, const char *file, int line, const char *func, const char *format, va_list ap)
|
||||
static int _tlog_early_print(struct tlog_info_inter *info_inter, const char *format, va_list ap)
|
||||
{
|
||||
char log_buf[TLOG_MAX_LINE_LEN];
|
||||
size_t len = 0;
|
||||
@@ -644,9 +646,14 @@ static int _tlog_early_print(tlog_level level, const char *file, int line, const
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlog_early_print != NULL) {
|
||||
tlog_early_print(&info_inter->info, format, ap);
|
||||
return out_len;
|
||||
}
|
||||
|
||||
len = snprintf(log_buf, sizeof(log_buf), "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5s][%17s:%-4d] ",
|
||||
cur_time.year, cur_time.mon, cur_time.mday, cur_time.hour, cur_time.min, cur_time.sec, cur_time.usec / 1000,
|
||||
tlog_get_level_string(level), file, line);
|
||||
cur_time.year, cur_time.mon, cur_time.mday, cur_time.hour, cur_time.min, cur_time.sec, cur_time.usec / 1000,
|
||||
tlog_get_level_string(info_inter->info.level), info_inter->info.file, info_inter->info.line);
|
||||
out_len = len;
|
||||
len = vsnprintf(log_buf + out_len, sizeof(log_buf) - out_len - 1, format, ap);
|
||||
out_len += len;
|
||||
@@ -662,7 +669,7 @@ static int _tlog_early_print(tlog_level level, const char *file, int line, const
|
||||
}
|
||||
|
||||
unused = write(STDOUT_FILENO, log_buf, out_len);
|
||||
return len;
|
||||
return out_len;
|
||||
}
|
||||
|
||||
int tlog_vext(tlog_level level, const char *file, int line, const char *func, void *userptr, const char *format, va_list ap)
|
||||
@@ -673,14 +680,6 @@ int tlog_vext(tlog_level level, const char *file, int line, const char *func, vo
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tlog.root == NULL) {
|
||||
return _tlog_early_print(level, file, line, func, format, ap);
|
||||
}
|
||||
|
||||
if (unlikely(tlog.root->logsize <= 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (level >= TLOG_END) {
|
||||
return -1;
|
||||
}
|
||||
@@ -694,6 +693,14 @@ int tlog_vext(tlog_level level, const char *file, int line, const char *func, vo
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlog.root == NULL) {
|
||||
return _tlog_early_print(&info_inter, format, ap);
|
||||
}
|
||||
|
||||
if (unlikely(tlog.root->logsize <= 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _tlog_vprintf(tlog.root, _tlog_root_log_buffer, &info_inter, format, ap);
|
||||
}
|
||||
|
||||
@@ -748,7 +755,7 @@ static int _tlog_list_dir(const char *path, list_callback callback, void *userpt
|
||||
|
||||
dir = opendir(path);
|
||||
if (dir == NULL) {
|
||||
fprintf(stderr, "open directory failed, %s\n", strerror(errno));
|
||||
fprintf(stderr, "tlog: open directory failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -859,7 +866,7 @@ static int _tlog_remove_oldlog(struct tlog_log *log)
|
||||
|
||||
/* get total log file number */
|
||||
if (_tlog_list_dir(log->logdir, _tlog_count_log_callback, &count_log) != 0) {
|
||||
fprintf(stderr, "get log file count failed.\n");
|
||||
fprintf(stderr, "tlog: get log file count failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -896,7 +903,7 @@ static int _tlog_log_lock(struct tlog_log *log)
|
||||
snprintf(lock_file, sizeof(lock_file), "%s/%s.lock", log->logdir, log->logname);
|
||||
fd = open(lock_file, O_RDWR | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
|
||||
if (fd == -1) {
|
||||
fprintf(stderr, "create pid file failed, %s", strerror(errno));
|
||||
fprintf(stderr, "tlog: create lock file failed, %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1061,8 +1068,14 @@ static int _tlog_archive_log_compressed(struct tlog_log *log)
|
||||
if (pid == 0) {
|
||||
_tlog_close_all_fd();
|
||||
execl(tlog.gzip_cmd, tlog.gzip_cmd, "-1", pending_file, NULL);
|
||||
fprintf(stderr, "tlog: execl gzip failed, no compress\n");
|
||||
log->nocompress = 1;
|
||||
_exit(1);
|
||||
} else if (pid < 0) {
|
||||
if (errno == EPERM || errno == EACCES) {
|
||||
fprintf(stderr, "tlog: vfork failed, errno: %d, no compress\n", errno);
|
||||
log->nocompress = 1;
|
||||
}
|
||||
goto errout;
|
||||
}
|
||||
log->zip_pid = pid;
|
||||
@@ -1139,7 +1152,54 @@ static void _tlog_get_log_name_dir(struct tlog_log *log)
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
}
|
||||
|
||||
static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
static int _tlog_write_screen(struct tlog_log *log, struct tlog_loginfo *info, const char *buff, int bufflen)
|
||||
{
|
||||
int unused __attribute__((unused));
|
||||
|
||||
if (bufflen <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (log->logscreen == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (log->logscreen_color && info != NULL) {
|
||||
const char *color = NULL;
|
||||
switch (info->level) {
|
||||
case TLOG_DEBUG:
|
||||
color = "\033[0;90m";
|
||||
break;
|
||||
case TLOG_NOTICE:
|
||||
color = "\033[0;97m";
|
||||
break;
|
||||
case TLOG_WARN:
|
||||
color = "\033[0;33m";
|
||||
break;
|
||||
case TLOG_ERROR:
|
||||
color = "\033[0;31m";
|
||||
break;
|
||||
case TLOG_FATAL:
|
||||
color = "\033[31;1m";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (color != NULL) {
|
||||
fprintf(stdout, "%s%.*s\033[0m\n", color, bufflen - 2, buff);
|
||||
} else {
|
||||
fprintf(stdout, "%s", buff);
|
||||
}
|
||||
} else {
|
||||
/* output log to screen */
|
||||
unused = write(STDOUT_FILENO, buff, bufflen);
|
||||
}
|
||||
|
||||
return bufflen;
|
||||
}
|
||||
|
||||
static int _tlog_write_ext(struct tlog_log *log, struct tlog_loginfo *info, const char *buff, int bufflen)
|
||||
{
|
||||
int len;
|
||||
int unused __attribute__((unused));
|
||||
@@ -1155,7 +1215,7 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
|
||||
/* output log to screen */
|
||||
if (log->logscreen) {
|
||||
unused = write(STDOUT_FILENO, buff, bufflen);
|
||||
_tlog_write_screen(log, info, buff, bufflen);
|
||||
}
|
||||
|
||||
if (log->logcount <= 0) {
|
||||
@@ -1195,9 +1255,9 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
return -1;
|
||||
}
|
||||
log->print_errmsg = 0;
|
||||
fprintf(stderr, "create log dir %s failed, %s\n", log->logdir, strerror(errno));
|
||||
fprintf(stderr, "tlog: 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");
|
||||
fprintf(stderr, "tlog: no permission to write log file, output log to console\n");
|
||||
tlog_logscreen(log, 1);
|
||||
tlog_logcount(log, 0);
|
||||
}
|
||||
@@ -1211,7 +1271,7 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "open log file %s failed, %s\n", logfile, strerror(errno));
|
||||
fprintf(stderr, "tlog: open log file %s failed, %s\n", logfile, strerror(errno));
|
||||
log->print_errmsg = 0;
|
||||
return -1;
|
||||
}
|
||||
@@ -1239,6 +1299,11 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
{
|
||||
return _tlog_write_ext(log, NULL, buff, bufflen);
|
||||
}
|
||||
|
||||
int tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
{
|
||||
return _tlog_write(log, buff, bufflen);
|
||||
@@ -1472,7 +1537,7 @@ static int _tlog_root_write_log(struct tlog_log *log, const char *buff, int buff
|
||||
if (tlog.output_func == NULL) {
|
||||
if (log->segment_log) {
|
||||
head = (struct tlog_segment_log_head *)buff;
|
||||
return _tlog_write(log, head->data, head->len);
|
||||
return _tlog_write_ext(log, &head->info, head->data, head->len);
|
||||
}
|
||||
return _tlog_write(log, buff, bufflen);
|
||||
}
|
||||
@@ -1614,6 +1679,11 @@ void tlog_set_early_printf(int enable)
|
||||
tlog_disable_early_print = (enable == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
void tlog_reg_early_printf_callback(tlog_early_print_func callback)
|
||||
{
|
||||
tlog_early_print = callback;
|
||||
}
|
||||
|
||||
const char *tlog_get_level_string(tlog_level level)
|
||||
{
|
||||
if (level >= TLOG_END) {
|
||||
@@ -1739,7 +1809,7 @@ static void _tlog_get_gzip_cmd_path(void)
|
||||
if (access(gzip_cmd_path, X_OK) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
snprintf(tlog.gzip_cmd, sizeof(tlog.gzip_cmd), "%s", gzip_cmd_path);
|
||||
break;
|
||||
}
|
||||
@@ -1752,13 +1822,13 @@ tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int bu
|
||||
struct tlog_log *log = NULL;
|
||||
|
||||
if (tlog.run == 0) {
|
||||
fprintf(stderr, "tlog is not initialized.");
|
||||
fprintf(stderr, "tlog: tlog is not initialized.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log = (struct tlog_log *)malloc(sizeof(*log));
|
||||
if (log == NULL) {
|
||||
fprintf(stderr, "malloc log failed.");
|
||||
fprintf(stderr, "tlog: malloc log failed.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1780,6 +1850,7 @@ tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int bu
|
||||
log->block = ((flag & TLOG_NONBLOCK) == 0) ? 1 : 0;
|
||||
log->nocompress = ((flag & TLOG_NOCOMPRESS) == 0) ? 0 : 1;
|
||||
log->logscreen = ((flag & TLOG_SCREEN) == 0) ? 0 : 1;
|
||||
log->logscreen_color = ((flag & TLOG_SCREEN_COLOR) == 0) ? 0 : 1;
|
||||
log->multi_log = ((flag & TLOG_MULTI_WRITE) == 0) ? 0 : 1;
|
||||
log->segment_log = ((flag & TLOG_SEGMENT) == 0) ? 0 : 1;
|
||||
log->max_line_size = TLOG_MAX_LINE_LEN;
|
||||
@@ -1791,6 +1862,11 @@ tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int bu
|
||||
log->nocompress = 1;
|
||||
}
|
||||
|
||||
if (log->logscreen_color == 1) {
|
||||
log->logscreen = 1;
|
||||
log->segment_log = 1;
|
||||
}
|
||||
|
||||
tlog_rename_logfile(log, logfile);
|
||||
if (log->nocompress) {
|
||||
strncpy(log->suffix, TLOG_SUFFIX_LOG, sizeof(log->suffix));
|
||||
@@ -1800,7 +1876,7 @@ tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int bu
|
||||
|
||||
log->buff = (char *)malloc(log->buffsize);
|
||||
if (log->buff == NULL) {
|
||||
fprintf(stderr, "malloc log buffer failed, %s\n", strerror(errno));
|
||||
fprintf(stderr, "tlog: malloc log buffer failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -1888,7 +1964,7 @@ static void tlog_fork_child(void)
|
||||
pthread_attr_init(&attr);
|
||||
int ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "create tlog work thread failed, %s\n", strerror(errno));
|
||||
fprintf(stderr, "tlog: create tlog work thread failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -1910,12 +1986,12 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
|
||||
struct tlog_log *log = NULL;
|
||||
|
||||
if (tlog_format != NULL) {
|
||||
fprintf(stderr, "tlog already initialized.\n");
|
||||
fprintf(stderr, "tlog: already initialized.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffsize > 0 && buffsize < TLOG_MAX_LINE_SIZE_SET * 2) {
|
||||
fprintf(stderr, "buffer size is invalid.\n");
|
||||
fprintf(stderr, "tlog: buffer size is invalid.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1932,19 +2008,19 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
|
||||
|
||||
log = tlog_open(logfile, maxlogsize, maxlogcount, buffsize, flag);
|
||||
if (log == NULL) {
|
||||
fprintf(stderr, "init tlog root failed.\n");
|
||||
fprintf(stderr, "tlog: init tlog root failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
tlog_reg_output_func(log, _tlog_root_write_log);
|
||||
|
||||
if ((flag & TLOG_NOCOMPRESS) == 0 && tlog.gzip_cmd[0] == '\0') {
|
||||
fprintf(stderr, "can not find gzip command, disable compress.\n");
|
||||
fprintf(stderr, "tlog: can not find gzip command, disable compress.\n");
|
||||
}
|
||||
|
||||
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));
|
||||
fprintf(stderr, "tlog: create tlog work thread failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -1964,6 +2040,7 @@ errout:
|
||||
pthread_mutex_destroy(&tlog.lock);
|
||||
tlog.run = 0;
|
||||
tlog.root = NULL;
|
||||
tlog_format = NULL;
|
||||
|
||||
_tlog_close(log, 1);
|
||||
|
||||
@@ -1972,6 +2049,10 @@ errout:
|
||||
|
||||
void tlog_exit(void)
|
||||
{
|
||||
if (tlog_format == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tlog.tid) {
|
||||
void *ret = NULL;
|
||||
tlog.run = 0;
|
||||
|
||||
13
src/tlog.h
13
src/tlog.h
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* tinylog
|
||||
* Copyright (C) 2018-2021 Ruilin Peng (Nick) <pymumu@gmail.com>
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>
|
||||
* https://github.com/pymumu/tinylog
|
||||
*/
|
||||
|
||||
@@ -66,6 +66,9 @@ struct tlog_time {
|
||||
/* enable support fork process */
|
||||
#define TLOG_SUPPORT_FORK (1 << 5)
|
||||
|
||||
/* enable output to screen with color */
|
||||
#define TLOG_SCREEN_COLOR (1 << 6)
|
||||
|
||||
struct tlog_loginfo {
|
||||
tlog_level level;
|
||||
const char *file;
|
||||
@@ -111,6 +114,10 @@ extern void tlog_setlogscreen(int enable);
|
||||
/* enable early log to screen */
|
||||
extern void tlog_set_early_printf(int enable);
|
||||
|
||||
/* set early log callback */
|
||||
typedef void (*tlog_early_print_func)(struct tlog_loginfo *loginfo, const char *format, va_list ap);
|
||||
extern void tlog_reg_early_printf_callback(tlog_early_print_func callback);
|
||||
|
||||
/* Get log level in string */
|
||||
extern const char *tlog_get_level_string(tlog_level level);
|
||||
|
||||
@@ -139,7 +146,7 @@ steps:
|
||||
read _tlog_format for example.
|
||||
*/
|
||||
typedef int (*tlog_format_func)(char *buff, int maxlen, struct tlog_loginfo *info, void *userptr, const char *format, va_list ap);
|
||||
extern int tlog_reg_format_func(tlog_format_func func);
|
||||
extern int tlog_reg_format_func(tlog_format_func callback);
|
||||
|
||||
/* register log output callback
|
||||
Note: info is invalid when flag TLOG_SEGMENT is not set.
|
||||
@@ -297,4 +304,4 @@ private:
|
||||
#define tlog_error(...) tlog(TLOG_ERROR, ##__VA_ARGS__)
|
||||
#define tlog_fatal(...) tlog(TLOG_FATAL, ##__VA_ARGS__)
|
||||
#endif
|
||||
#endif // !TLOG_H
|
||||
#endif // !TLOG_H
|
||||
349
src/util.c
349
src/util.c
@@ -25,6 +25,7 @@
|
||||
#include "util.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@@ -38,11 +39,13 @@
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/sysinfo.h>
|
||||
@@ -100,8 +103,20 @@ struct ipset_netlink_msg {
|
||||
__be16 res_id;
|
||||
};
|
||||
|
||||
enum daemon_msg_type {
|
||||
DAEMON_MSG_KICKOFF,
|
||||
DAEMON_MSG_KEEPALIVE,
|
||||
DAEMON_MSG_DAEMON_PID,
|
||||
};
|
||||
|
||||
struct daemon_msg {
|
||||
enum daemon_msg_type type;
|
||||
int value;
|
||||
};
|
||||
|
||||
static int ipset_fd;
|
||||
static int pidfile_fd;
|
||||
static int daemon_fd;
|
||||
|
||||
unsigned long get_tick_count(void)
|
||||
{
|
||||
@@ -153,6 +168,56 @@ errout:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int generate_random_addr(unsigned char *addr, int addr_len, int mask)
|
||||
{
|
||||
if (mask / 8 > addr_len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int offset = mask / 8;
|
||||
int bit = 0;
|
||||
|
||||
for (int i = offset; i < addr_len; i++) {
|
||||
bit = 0xFF;
|
||||
if (i == offset) {
|
||||
bit = ~(0xFF << (8 - mask % 8)) & 0xFF;
|
||||
}
|
||||
addr[i] = jhash(&addr[i], 1, 0) & bit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generate_addr_map(const unsigned char *addr_from, const unsigned char *addr_to, unsigned char *addr_out,
|
||||
int addr_len, int mask)
|
||||
{
|
||||
if ((mask / 8) >= addr_len) {
|
||||
if (mask % 8 != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int offset = mask / 8;
|
||||
int bit = mask % 8;
|
||||
for (int i = 0; i < offset; i++) {
|
||||
addr_out[i] = addr_to[i];
|
||||
}
|
||||
|
||||
if (bit != 0) {
|
||||
int mask1 = 0xFF >> bit;
|
||||
int mask2 = (0xFF << (8 - bit)) & 0xFF;
|
||||
addr_out[offset] = addr_from[offset] & mask1;
|
||||
addr_out[offset] |= addr_to[offset] & mask2;
|
||||
offset = offset + 1;
|
||||
}
|
||||
|
||||
for (int i = offset; i < addr_len; i++) {
|
||||
addr_out[i] = addr_from[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getaddr_by_host(const char *host, struct sockaddr *addr, socklen_t *addr_len)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
@@ -806,7 +871,11 @@ int create_pid_file(const char *pid_file)
|
||||
}
|
||||
|
||||
if (lockf(fd, F_TLOCK, 0) < 0) {
|
||||
fprintf(stderr, "Server is already running.\n");
|
||||
memset(buff, 0, TMP_BUFF_LEN_32);
|
||||
if (read(fd, buff, TMP_BUFF_LEN_32) <= 0) {
|
||||
buff[0] = '\0';
|
||||
}
|
||||
fprintf(stderr, "Server is already running, pid is %s", buff);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -831,6 +900,27 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int full_path(char *normalized_path, int normalized_path_len, const char *path)
|
||||
{
|
||||
const char *p = path;
|
||||
|
||||
if (path == NULL || normalized_path == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (*p == ' ') {
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p == '\0' || *p == '/') {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buf[PATH_MAX];
|
||||
snprintf(normalized_path, normalized_path_len, "%s/%s", getcwd(buf, sizeof(buf)), path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generate_cert_key(const char *key_path, const char *cert_path, const char *san, int days)
|
||||
{
|
||||
int ret = -1;
|
||||
@@ -975,6 +1065,10 @@ void SSL_CRYPTO_thread_setup(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (lock_cs != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -1004,12 +1098,18 @@ void SSL_CRYPTO_thread_cleanup(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (lock_cs == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
CRYPTO_set_locking_callback(NULL);
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
pthread_mutex_destroy(&(lock_cs[i]));
|
||||
}
|
||||
OPENSSL_free(lock_cs);
|
||||
OPENSSL_free(lock_count);
|
||||
lock_cs = NULL;
|
||||
lock_count = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1286,8 +1386,8 @@ int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt)
|
||||
}
|
||||
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof(keepidle));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepinterval, sizeof(keepinterval));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepcnt, sizeof(keepcnt));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepinterval, sizeof(keepinterval));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof(keepcnt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1387,7 +1487,7 @@ void bug_ext(const char *file, int line, const char *func, const char *errfmt, .
|
||||
|
||||
int write_file(const char *filename, void *data, int data_len)
|
||||
{
|
||||
int fd = open(filename, O_WRONLY | O_CREAT, 0644);
|
||||
int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1435,9 +1535,9 @@ int dns_packet_save(const char *dir, const char *type, const char *from, const v
|
||||
|
||||
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)(tm_val.tv_usec / 1000));
|
||||
snprintf(filename, sizeof(filename) - 1, "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d%.1d.packet", dir, type,
|
||||
snprintf(filename, sizeof(filename) - 1, "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d%.3d.packet", dir, type,
|
||||
ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec,
|
||||
(int)(tm_val.tv_usec / 100000));
|
||||
(int)(tm_val.tv_usec / 1000));
|
||||
|
||||
data = malloc(PACKET_BUF_SIZE);
|
||||
if (data == NULL) {
|
||||
@@ -1479,6 +1579,223 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _close_all_fd_by_res(void)
|
||||
{
|
||||
struct rlimit lim;
|
||||
int maxfd = 0;
|
||||
int i = 0;
|
||||
|
||||
getrlimit(RLIMIT_NOFILE, &lim);
|
||||
|
||||
maxfd = lim.rlim_cur;
|
||||
if (maxfd > 4096) {
|
||||
maxfd = 4096;
|
||||
}
|
||||
|
||||
for (i = 3; i < maxfd; i++) {
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
|
||||
void close_all_fd(int keepfd)
|
||||
{
|
||||
DIR *dirp;
|
||||
int dir_fd = -1;
|
||||
struct dirent *dentp;
|
||||
|
||||
dirp = opendir("/proc/self/fd");
|
||||
if (dirp == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
dir_fd = dirfd(dirp);
|
||||
|
||||
while ((dentp = readdir(dirp)) != NULL) {
|
||||
int fd = atol(dentp->d_name);
|
||||
if (fd < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd == dir_fd || fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO || fd == keepfd) {
|
||||
continue;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
return;
|
||||
errout:
|
||||
if (dirp) {
|
||||
closedir(dirp);
|
||||
}
|
||||
_close_all_fd_by_res();
|
||||
return;
|
||||
}
|
||||
|
||||
void daemon_close_stdfds(void)
|
||||
{
|
||||
int fd_null = open("/dev/null", O_RDWR);
|
||||
if (fd_null < 0) {
|
||||
fprintf(stderr, "open /dev/null failed, %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
dup2(fd_null, STDIN_FILENO);
|
||||
dup2(fd_null, STDOUT_FILENO);
|
||||
dup2(fd_null, STDERR_FILENO);
|
||||
|
||||
if (fd_null > 2) {
|
||||
close(fd_null);
|
||||
}
|
||||
}
|
||||
|
||||
int daemon_kickoff(int status, int no_close)
|
||||
{
|
||||
struct daemon_msg msg;
|
||||
|
||||
if (daemon_fd <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg.type = DAEMON_MSG_KICKOFF;
|
||||
msg.value = status;
|
||||
|
||||
int ret = write(daemon_fd, &msg, sizeof(msg));
|
||||
if (ret != sizeof(msg)) {
|
||||
fprintf(stderr, "notify parent process failed, %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (no_close == 0) {
|
||||
daemon_close_stdfds();
|
||||
}
|
||||
|
||||
close(daemon_fd);
|
||||
daemon_fd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int daemon_keepalive(void)
|
||||
{
|
||||
struct daemon_msg msg;
|
||||
static time_t last = 0;
|
||||
time_t now = time(NULL);
|
||||
|
||||
if (daemon_fd <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (now == last) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
last = now;
|
||||
|
||||
msg.type = DAEMON_MSG_KEEPALIVE;
|
||||
msg.value = 0;
|
||||
|
||||
int ret = write(daemon_fd, &msg, sizeof(msg));
|
||||
if (ret != sizeof(msg)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
daemon_ret daemon_run(int *wstatus)
|
||||
{
|
||||
pid_t pid = 0;
|
||||
int fds[2] = {0};
|
||||
|
||||
if (pipe(fds) != 0) {
|
||||
fprintf(stderr, "run daemon process failed, pipe failed, %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
fprintf(stderr, "run daemon process failed, fork failed, %s\n", strerror(errno));
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return -1;
|
||||
} else if (pid > 0) {
|
||||
struct pollfd pfd;
|
||||
int ret = 0;
|
||||
|
||||
close(fds[1]);
|
||||
|
||||
pfd.fd = fds[0];
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
|
||||
do {
|
||||
ret = poll(&pfd, 1, 3000);
|
||||
if (ret <= 0) {
|
||||
fprintf(stderr, "run daemon process failed, wait child timeout, kill child.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (!(pfd.revents & POLLIN)) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
struct daemon_msg msg;
|
||||
|
||||
ret = read(fds[0], &msg, sizeof(msg));
|
||||
if (ret != sizeof(msg)) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (msg.type == DAEMON_MSG_KEEPALIVE) {
|
||||
continue;
|
||||
} else if (msg.type == DAEMON_MSG_DAEMON_PID) {
|
||||
pid = msg.value;
|
||||
continue;
|
||||
} else if (msg.type == DAEMON_MSG_KICKOFF) {
|
||||
if (wstatus != NULL) {
|
||||
*wstatus = msg.value;
|
||||
}
|
||||
return DAEMON_RET_PARENT_OK;
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
return DAEMON_RET_ERR;
|
||||
}
|
||||
|
||||
setsid();
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
fprintf(stderr, "double fork failed, %s\n", strerror(errno));
|
||||
_exit(1);
|
||||
} else if (pid > 0) {
|
||||
struct daemon_msg msg;
|
||||
int unused __attribute__((unused));
|
||||
msg.type = DAEMON_MSG_DAEMON_PID;
|
||||
msg.value = pid;
|
||||
unused = write(fds[1], &msg, sizeof(msg));
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
umask(0);
|
||||
if (chdir("/") != 0) {
|
||||
goto errout;
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
daemon_fd = fds[1];
|
||||
return DAEMON_RET_CHILD_OK;
|
||||
errout:
|
||||
kill(pid, SIGKILL);
|
||||
if (wstatus != NULL) {
|
||||
*wstatus = -1;
|
||||
}
|
||||
return DAEMON_RET_ERR;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
struct _dns_read_packet_info {
|
||||
int data_len;
|
||||
@@ -1596,6 +1913,24 @@ static int _dns_debug_display(struct dns_packet *packet)
|
||||
inet_ntop(AF_INET6, addr, req_host, sizeof(req_host));
|
||||
printf("domain: %s AAAA: %s TTL:%d\n", name, req_host, ttl);
|
||||
} break;
|
||||
case DNS_T_SRV: {
|
||||
unsigned short priority = 0;
|
||||
unsigned short weight = 0;
|
||||
unsigned short port = 0;
|
||||
int ret = 0;
|
||||
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
char target[DNS_MAX_CNAME_LEN];
|
||||
|
||||
ret = dns_get_SRV(rrs, name, DNS_MAX_CNAME_LEN, &ttl, &priority, &weight, &port, target, DNS_MAX_CNAME_LEN);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_DEBUG, "decode SRV failed, %s", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("domain: %s SRV: %s TTL: %d priority: %d weight: %d port: %d\n", name, target, ttl, priority,
|
||||
weight, port);
|
||||
} break;
|
||||
case DNS_T_HTTPS: {
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
char target[DNS_MAX_CNAME_LEN] = {0};
|
||||
@@ -1604,7 +1939,7 @@ static int _dns_debug_display(struct dns_packet *packet)
|
||||
int ret = 0;
|
||||
|
||||
ret = dns_get_HTTPS_svcparm_start(rrs, &p, name, DNS_MAX_CNAME_LEN, &ttl, &priority, target,
|
||||
DNS_MAX_CNAME_LEN);
|
||||
DNS_MAX_CNAME_LEN);
|
||||
if (ret != 0) {
|
||||
printf("get HTTPS svcparm failed\n");
|
||||
break;
|
||||
|
||||
24
src/util.h
24
src/util.h
@@ -59,6 +59,11 @@ char *dir_name(char *path);
|
||||
|
||||
char *get_host_by_addr(char *host, int maxsize, struct sockaddr *addr);
|
||||
|
||||
int generate_random_addr(unsigned char *addr, int addr_len, int mask);
|
||||
|
||||
int generate_addr_map(const unsigned char *addr_from, const unsigned char *addr_to, unsigned char *addr_out,
|
||||
int addr_len, int mask);
|
||||
|
||||
int getaddr_by_host(const char *host, struct sockaddr *addr, socklen_t *addr_len);
|
||||
|
||||
int getsocket_inet(int fd, struct sockaddr *addr, socklen_t *addr_len);
|
||||
@@ -105,6 +110,8 @@ int generate_cert_key(const char *key_path, const char *cert_path, const char *s
|
||||
|
||||
int create_pid_file(const char *pid_file);
|
||||
|
||||
int full_path(char *normalized_path, int normalized_path_len, const char *path);
|
||||
|
||||
/* Parse a TLS packet for the Server Name Indication extension in the client
|
||||
* hello handshake, returning the first server name found (pointer to static
|
||||
* array)
|
||||
@@ -138,6 +145,23 @@ uint64_t get_free_space(const char *path);
|
||||
|
||||
void print_stack(void);
|
||||
|
||||
void close_all_fd(int keepfd);
|
||||
|
||||
typedef enum daemon_ret {
|
||||
DAEMON_RET_OK = 0,
|
||||
DAEMON_RET_ERR = -1,
|
||||
DAEMON_RET_CHILD_OK = -2,
|
||||
DAEMON_RET_PARENT_OK = -3,
|
||||
} daemon_ret;
|
||||
|
||||
daemon_ret daemon_run(int *wstatus);
|
||||
|
||||
int daemon_kickoff(int status, int no_close);
|
||||
|
||||
int daemon_keepalive(void);
|
||||
|
||||
void daemon_close_stdfds(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);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
[Unit]
|
||||
Description=SmartDNS Server
|
||||
After=network.target
|
||||
After=network.target
|
||||
Before=network-online.target
|
||||
Before=nss-lookup.target
|
||||
Wants=nss-lookup.target
|
||||
StartLimitBurst=0
|
||||
StartLimitIntervalSec=60
|
||||
|
||||
@@ -8,7 +11,7 @@ StartLimitIntervalSec=60
|
||||
Type=forking
|
||||
PIDFile=@RUNSTATEDIR@/smartdns.pid
|
||||
EnvironmentFile=@SYSCONFDIR@/default/smartdns
|
||||
ExecStart=@SBINDIR@/smartdns -p @RUNSTATEDIR@/smartdns.pid $SMART_DNS_OPTS
|
||||
ExecStart=@SBINDIR@/smartdns -p @RUNSTATEDIR@/smartdns.pid $SMART_DNS_OPTS
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
TimeoutStopSec=15
|
||||
|
||||
@@ -23,8 +23,8 @@ CXXFLAGS += -g
|
||||
CXXFLAGS += -DTEST
|
||||
CXXFLAGS += -I./ -I../src -I../src/include
|
||||
|
||||
SMARTDNS_OBJS = lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o lib/nftset.o
|
||||
SMARTDNS_OBJS += smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o
|
||||
SMARTDNS_OBJS = lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o lib/nftset.o lib/timer_wheel.o lib/idna.o
|
||||
SMARTDNS_OBJS += smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o timer.o
|
||||
OBJS = $(addprefix ../src/, $(SMARTDNS_OBJS))
|
||||
|
||||
TEST_SOURCES := $(wildcard *.cc) $(wildcard */*.cc) $(wildcard */*/*.cc)
|
||||
|
||||
@@ -161,3 +161,140 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::1010:1010");
|
||||
}
|
||||
|
||||
TEST_F(Address, multiaddress)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype == DNS_T_A) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
speed-check-mode none
|
||||
address /a.com/10.10.10.10,11.11.11.11,22.22.22.22
|
||||
address /a.com/64:ff9b::1010:1010,64:ff9b::1111:1111,64:ff9b::2222:2222
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
std::map<std::string, smartdns::DNSRecord *> result;
|
||||
|
||||
ASSERT_EQ(client.GetAnswerNum(), 3);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
auto answers = client.GetAnswer();
|
||||
for (int i = 0; i < client.GetAnswerNum(); i++) {
|
||||
result[client.GetAnswer()[i].GetData()] = &answers[i];
|
||||
}
|
||||
|
||||
ASSERT_NE(result.find("10.10.10.10"), result.end());
|
||||
auto check_result = result["10.10.10.10"];
|
||||
EXPECT_EQ(check_result->GetName(), "a.com");
|
||||
EXPECT_EQ(check_result->GetTTL(), 600);
|
||||
EXPECT_EQ(check_result->GetType(), "A");
|
||||
EXPECT_EQ(check_result->GetData(), "10.10.10.10");
|
||||
|
||||
ASSERT_NE(result.find("11.11.11.11"), result.end());
|
||||
check_result = result["11.11.11.11"];
|
||||
EXPECT_EQ(check_result->GetName(), "a.com");
|
||||
EXPECT_EQ(check_result->GetTTL(), 600);
|
||||
EXPECT_EQ(check_result->GetType(), "A");
|
||||
EXPECT_EQ(check_result->GetData(), "11.11.11.11");
|
||||
|
||||
ASSERT_NE(result.find("22.22.22.22"), result.end());
|
||||
check_result = result["22.22.22.22"];
|
||||
EXPECT_EQ(check_result->GetName(), "a.com");
|
||||
EXPECT_EQ(check_result->GetTTL(), 600);
|
||||
EXPECT_EQ(check_result->GetType(), "A");
|
||||
EXPECT_EQ(check_result->GetData(), "22.22.22.22");
|
||||
|
||||
result.clear();
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 3);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
answers = client.GetAnswer();
|
||||
for (int i = 0; i < client.GetAnswerNum(); i++) {
|
||||
result[client.GetAnswer()[i].GetData()] = &answers[i];
|
||||
}
|
||||
|
||||
ASSERT_NE(result.find("64:ff9b::1010:1010"), result.end());
|
||||
check_result = result["64:ff9b::1010:1010"];
|
||||
EXPECT_EQ(check_result->GetName(), "a.com");
|
||||
EXPECT_EQ(check_result->GetTTL(), 600);
|
||||
EXPECT_EQ(check_result->GetType(), "AAAA");
|
||||
EXPECT_EQ(check_result->GetData(), "64:ff9b::1010:1010");
|
||||
|
||||
ASSERT_NE(result.find("64:ff9b::1111:1111"), result.end());
|
||||
check_result = result["64:ff9b::1111:1111"];
|
||||
EXPECT_EQ(check_result->GetName(), "a.com");
|
||||
EXPECT_EQ(check_result->GetTTL(), 600);
|
||||
EXPECT_EQ(check_result->GetType(), "AAAA");
|
||||
EXPECT_EQ(check_result->GetData(), "64:ff9b::1111:1111");
|
||||
|
||||
ASSERT_NE(result.find("64:ff9b::2222:2222"), result.end());
|
||||
check_result = result["64:ff9b::2222:2222"];
|
||||
EXPECT_EQ(check_result->GetName(), "a.com");
|
||||
EXPECT_EQ(check_result->GetTTL(), 600);
|
||||
EXPECT_EQ(check_result->GetType(), "AAAA");
|
||||
EXPECT_EQ(check_result->GetData(), "64:ff9b::2222:2222");
|
||||
}
|
||||
|
||||
TEST_F(Address, soa_sub_ip)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype == DNS_T_A) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
speed-check-mode none
|
||||
address /a.com/192.168.1.1
|
||||
address /com/#
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "192.168.1.1");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 0);
|
||||
EXPECT_EQ(client.GetStatus(), "NXDOMAIN");
|
||||
|
||||
ASSERT_TRUE(client.Query("b.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 0);
|
||||
EXPECT_EQ(client.GetStatus(), "NXDOMAIN");
|
||||
}
|
||||
@@ -56,6 +56,36 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
}
|
||||
|
||||
TEST(Bind, https)
|
||||
{
|
||||
Defer
|
||||
{
|
||||
unlink("/tmp/smartdns-cert.pem");
|
||||
unlink("/tmp/smartdns-key.pem");
|
||||
};
|
||||
|
||||
smartdns::Server server_wrap;
|
||||
smartdns::Server server;
|
||||
|
||||
server.Start(R"""(bind [::]:61053
|
||||
server https://127.0.0.1:60053 -no-check-certificate
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
server_wrap.Start(R"""(bind-https [::]:60053
|
||||
address /example.com/1.2.3.4
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("example.com", 61053));
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
}
|
||||
|
||||
TEST(Bind, udp_tcp)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
@@ -252,3 +282,71 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 3);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
}
|
||||
|
||||
|
||||
TEST(Bind, group)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::MockServer server_upstream1;
|
||||
smartdns::MockServer server_upstream2;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "9.10.11.12", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server_upstream1.Start("udp://0.0.0.0:62053", [](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server_upstream2.Start("udp://0.0.0.0:63053", [](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "5.6.7.8", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
bind [::]:60153 -group g1
|
||||
bind [::]:60253 -group g2
|
||||
server 127.0.0.1:61053
|
||||
server 127.0.0.1:62053 -group g1 -exclude-default-group
|
||||
server 127.0.0.1:63053 -group g2 -exclude-default-group
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "9.10.11.12");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com", 60153));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com", 60253));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
|
||||
}
|
||||
|
||||
@@ -127,6 +127,16 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 5);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
|
||||
sleep(1);
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 5);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
}
|
||||
|
||||
TEST_F(Cache, max_reply_ttl_expired)
|
||||
@@ -181,6 +191,89 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
}
|
||||
|
||||
TEST_F(Cache, prefetch)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::MockServer server_upstream1;
|
||||
smartdns::MockServer server_upstream2;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "9.10.11.12", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server_upstream1.Start("udp://0.0.0.0:62053", [](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server_upstream2.Start("udp://0.0.0.0:63053", [](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "5.6.7.8", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 100);
|
||||
server.MockPing(PING_TYPE_ICMP, "5.6.7.8", 60, 110);
|
||||
server.MockPing(PING_TYPE_ICMP, "9.10.11.12", 60, 110);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
bind [::]:60153 -group g1
|
||||
server 127.0.0.1:61053
|
||||
server 127.0.0.1:62053 -group g1 -exclude-default-group
|
||||
server 127.0.0.1:63053 -group g2
|
||||
log-num 0
|
||||
prefetch-domain yes
|
||||
rr-ttl-max 2
|
||||
serve-expired no
|
||||
log-console yes
|
||||
log-level debug
|
||||
srv-record-selection no
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com", 60153));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
|
||||
sleep(1);
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 2);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
|
||||
sleep(1);
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com", 60153));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
}
|
||||
|
||||
TEST_F(Cache, nocache)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
|
||||
@@ -77,7 +77,6 @@ TEST_F(Cname, subdomain1)
|
||||
if (request->domain == "s.a.com") {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
|
||||
@@ -114,7 +113,6 @@ TEST_F(Cname, subdomain2)
|
||||
if (request->domain == "a.s.a.com") {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
|
||||
@@ -139,7 +137,6 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAnswer()[1].GetData(), "4.5.6.7");
|
||||
}
|
||||
|
||||
|
||||
TEST_F(Cname, loop)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
@@ -153,7 +150,6 @@ TEST_F(Cname, loop)
|
||||
if (request->domain == "s.a.com") {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
|
||||
|
||||
124
test/cases/test-ddns.cc
Normal file
124
test/cases/test-ddns.cc
Normal file
@@ -0,0 +1,124 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "dns.h"
|
||||
#include "include/utils.h"
|
||||
#include "server.h"
|
||||
#include "util.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <fstream>
|
||||
|
||||
class DDNS : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
virtual void SetUp() {}
|
||||
virtual void TearDown() {}
|
||||
};
|
||||
|
||||
TEST_F(DDNS, smartdns)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
dualstack-ip-selection no
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("smartdns A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "smartdns");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "127.0.0.1");
|
||||
|
||||
ASSERT_TRUE(client.Query("smartdns AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "smartdns");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "::1");
|
||||
}
|
||||
|
||||
TEST_F(DDNS, ddns)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
ddns-domain test.ddns.com
|
||||
ddns-domain test.ddns.org
|
||||
log-console yes
|
||||
dualstack-ip-selection no
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("test.ddns.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "test.ddns.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "127.0.0.1");
|
||||
|
||||
ASSERT_TRUE(client.Query("test.ddns.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "test.ddns.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "::1");
|
||||
|
||||
ASSERT_TRUE(client.Query("test.ddns.org A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "test.ddns.org");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "127.0.0.1");
|
||||
|
||||
ASSERT_TRUE(client.Query("test.ddns.org AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "test.ddns.org");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "::1");
|
||||
}
|
||||
@@ -39,17 +39,17 @@ TEST_F(DomainRule, bogus_nxdomain)
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
if (request->domain == "a.com") {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "10.11.12.13", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
if (request->domain == "a.com") {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "10.11.12.13", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -blacklist-ip
|
||||
@@ -64,7 +64,7 @@ cache-persist no)""");
|
||||
ASSERT_EQ(client.GetAuthorityNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NXDOMAIN");
|
||||
|
||||
ASSERT_TRUE(client.Query("b.com", 60053));
|
||||
ASSERT_TRUE(client.Query("b.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
|
||||
77
test/cases/test-idna.cc
Normal file
77
test/cases/test-idna.cc
Normal file
@@ -0,0 +1,77 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "dns.h"
|
||||
#include "include/utils.h"
|
||||
#include "server.h"
|
||||
#include "util.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <fstream>
|
||||
|
||||
class IDNA : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
virtual void SetUp() {}
|
||||
virtual void TearDown() {}
|
||||
};
|
||||
|
||||
TEST_F(IDNA, match)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype == DNS_T_A) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
speed-check-mode none
|
||||
address /中国.com/10.10.10.10
|
||||
address /中国.com/64:ff9b::1010:1010
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("xn--fiqs8s.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "xn--fiqs8s.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "10.10.10.10");
|
||||
|
||||
ASSERT_TRUE(client.Query("xn--fiqs8s.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "xn--fiqs8s.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::1010:1010");
|
||||
}
|
||||
318
test/cases/test-ip-alias.cc
Normal file
318
test/cases/test-ip-alias.cc
Normal file
@@ -0,0 +1,318 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "dns.h"
|
||||
#include "include/utils.h"
|
||||
#include "server.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <fstream>
|
||||
|
||||
class IPAlias : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
virtual void SetUp() {}
|
||||
virtual void TearDown() {}
|
||||
};
|
||||
|
||||
TEST(IPAlias, map_multiip_nospeed_check)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
|
||||
std::string domain = request->domain;
|
||||
if (request->domain.length() == 0) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_A) {
|
||||
unsigned char addr[][4] = {{1, 2, 3, 1}, {1, 2, 3, 2}, {1, 2, 3, 3}};
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[0]);
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[1]);
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[2]);
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
unsigned char addr[][16] = {{1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||||
{1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2},
|
||||
{1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3}};
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[0]);
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[1]);
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[2]);
|
||||
} else {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 100);
|
||||
server.MockPing(PING_TYPE_ICMP, "5.6.7.8", 60, 110);
|
||||
server.MockPing(PING_TYPE_ICMP, "9.10.11.12", 60, 140);
|
||||
server.MockPing(PING_TYPE_ICMP, "10.10.10.10", 60, 120);
|
||||
server.MockPing(PING_TYPE_ICMP, "11.11.11.11", 60, 150);
|
||||
server.MockPing(PING_TYPE_ICMP, "0102:0304:0500::", 60, 100);
|
||||
server.MockPing(PING_TYPE_ICMP, "0506:0708:0900::", 60, 110);
|
||||
server.MockPing(PING_TYPE_ICMP, "0a0b:0c0d:0e00::", 60, 140);
|
||||
server.MockPing(PING_TYPE_ICMP, "ffff::1", 60, 120);
|
||||
server.MockPing(PING_TYPE_ICMP, "ffff::2", 60, 150);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
dualstack-ip-selection no
|
||||
speed-check-mode none
|
||||
ip-alias 1.2.3.0/24 10.10.10.10,12.12.12.12,13.13.13.13,15.15.15.15
|
||||
ip-alias 0102::/16 FFFF::0001,FFFF::0002,FFFF::0003,FFFF::0004
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 4);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "10.10.10.10");
|
||||
EXPECT_EQ(client.GetAnswer()[1].GetData(), "12.12.12.12");
|
||||
EXPECT_EQ(client.GetAnswer()[2].GetData(), "15.15.15.15");
|
||||
EXPECT_EQ(client.GetAnswer()[3].GetData(), "13.13.13.13");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 4);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "ffff::1");
|
||||
EXPECT_EQ(client.GetAnswer()[1].GetData(), "ffff::3");
|
||||
EXPECT_EQ(client.GetAnswer()[2].GetData(), "ffff::2");
|
||||
EXPECT_EQ(client.GetAnswer()[3].GetData(), "ffff::4");
|
||||
}
|
||||
|
||||
TEST(IPAlias, map_single_ip_nospeed_check)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
|
||||
std::string domain = request->domain;
|
||||
if (request->domain.length() == 0) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_A) {
|
||||
unsigned char addr[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[0]);
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[1]);
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[2]);
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
unsigned char addr[][16] = {{1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{10, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[0]);
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[1]);
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[2]);
|
||||
} else {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 100);
|
||||
server.MockPing(PING_TYPE_ICMP, "5.6.7.8", 60, 110);
|
||||
server.MockPing(PING_TYPE_ICMP, "9.10.11.12", 60, 140);
|
||||
server.MockPing(PING_TYPE_ICMP, "10.10.10.10", 60, 120);
|
||||
server.MockPing(PING_TYPE_ICMP, "11.11.11.11", 60, 150);
|
||||
server.MockPing(PING_TYPE_ICMP, "0102:0304:0500::", 60, 100);
|
||||
server.MockPing(PING_TYPE_ICMP, "0506:0708:0900::", 60, 110);
|
||||
server.MockPing(PING_TYPE_ICMP, "0a0b:0c0d:0e00::", 60, 140);
|
||||
server.MockPing(PING_TYPE_ICMP, "ffff::1", 60, 120);
|
||||
server.MockPing(PING_TYPE_ICMP, "ffff::2", 60, 150);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
dualstack-ip-selection no
|
||||
speed-check-mode none
|
||||
ip-alias 1.2.3.4 10.10.10.10
|
||||
ip-alias 5.6.7.8/32 11.11.11.11
|
||||
ip-alias 0102:0304:0500:: ffff::1
|
||||
ip-alias 0506:0708:0900:: ffff::2
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 3);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "10.10.10.10");
|
||||
EXPECT_EQ(client.GetAnswer()[1].GetData(), "11.11.11.11");
|
||||
EXPECT_EQ(client.GetAnswer()[2].GetData(), "9.10.11.12");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 3);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "ffff::1");
|
||||
EXPECT_EQ(client.GetAnswer()[1].GetData(), "a0b:c0d:e00::");
|
||||
EXPECT_EQ(client.GetAnswer()[2].GetData(), "ffff::2");
|
||||
}
|
||||
|
||||
TEST(IPAlias, mapip_withspeed_check)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
|
||||
std::string domain = request->domain;
|
||||
if (request->domain.length() == 0) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_A) {
|
||||
unsigned char addr[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[0]);
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[1]);
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[2]);
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
unsigned char addr[][16] = {{1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{10, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[0]);
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[1]);
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[2]);
|
||||
} else {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 100);
|
||||
server.MockPing(PING_TYPE_ICMP, "5.6.7.8", 60, 110);
|
||||
server.MockPing(PING_TYPE_ICMP, "9.10.11.12", 60, 140);
|
||||
server.MockPing(PING_TYPE_ICMP, "10.10.10.10", 60, 120);
|
||||
server.MockPing(PING_TYPE_ICMP, "11.11.11.11", 60, 150);
|
||||
server.MockPing(PING_TYPE_ICMP, "0102:0304:0500::", 60, 100);
|
||||
server.MockPing(PING_TYPE_ICMP, "0506:0708:0900::", 60, 110);
|
||||
server.MockPing(PING_TYPE_ICMP, "0a0b:0c0d:0e00::", 60, 140);
|
||||
server.MockPing(PING_TYPE_ICMP, "ffff::1", 60, 120);
|
||||
server.MockPing(PING_TYPE_ICMP, "ffff::2", 60, 150);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
dualstack-ip-selection no
|
||||
ip-alias 1.2.3.4 10.10.10.10
|
||||
ip-alias 5.6.7.8/32 11.11.11.11
|
||||
ip-alias 0102::/16 ffff::1
|
||||
ip-alias 0506::/16 ffff::2
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "10.10.10.10");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "ffff::1");
|
||||
}
|
||||
|
||||
TEST(IPAlias, no_ip_alias)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
|
||||
std::string domain = request->domain;
|
||||
if (request->domain.length() == 0) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_A) {
|
||||
unsigned char addr[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[0]);
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[1]);
|
||||
dns_add_A(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[2]);
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
unsigned char addr[][16] = {{1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{10, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[0]);
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[1]);
|
||||
dns_add_AAAA(request->response_packet, DNS_RRS_AN, domain.c_str(), 61, addr[2]);
|
||||
} else {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 100);
|
||||
server.MockPing(PING_TYPE_ICMP, "5.6.7.8", 60, 110);
|
||||
server.MockPing(PING_TYPE_ICMP, "9.10.11.12", 60, 140);
|
||||
server.MockPing(PING_TYPE_ICMP, "10.10.10.10", 60, 120);
|
||||
server.MockPing(PING_TYPE_ICMP, "11.11.11.11", 60, 150);
|
||||
server.MockPing(PING_TYPE_ICMP, "0102:0304:0500::", 60, 100);
|
||||
server.MockPing(PING_TYPE_ICMP, "0506:0708:0900::", 60, 110);
|
||||
server.MockPing(PING_TYPE_ICMP, "0a0b:0c0d:0e00::", 60, 140);
|
||||
server.MockPing(PING_TYPE_ICMP, "ffff::1", 60, 120);
|
||||
server.MockPing(PING_TYPE_ICMP, "ffff::2", 60, 150);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
dualstack-ip-selection no
|
||||
ip-alias 1.2.3.4 10.10.10.10
|
||||
ip-alias 5.6.7.8/32 11.11.11.11
|
||||
ip-alias 0102::/16 ffff::1
|
||||
ip-alias 0506::/16 ffff::2
|
||||
domain-rules /a.com/ -no-ip-alias
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "102:304:500::");
|
||||
}
|
||||
@@ -53,8 +53,8 @@ TEST_F(IPRule, white_list)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -whitelist-ip
|
||||
@@ -73,6 +73,48 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "4.5.6.7");
|
||||
}
|
||||
|
||||
TEST_F(IPRule, white_list_not_in)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::MockServer server_upstream2;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server_upstream2.Start("udp://0.0.0.0:62053", [](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "9.10.11.12", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -whitelist-ip
|
||||
server udp://127.0.0.1:62053 -whitelist-ip
|
||||
whitelist-ip 4.5.6.7/24
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 0);
|
||||
EXPECT_EQ(client.GetStatus(), "SERVFAIL");
|
||||
}
|
||||
|
||||
TEST_F(IPRule, black_list)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
@@ -97,8 +139,8 @@ TEST_F(IPRule, black_list)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 10);
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 10);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -blacklist-ip
|
||||
@@ -134,10 +176,10 @@ TEST_F(IPRule, ignore_ip)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 90);
|
||||
server.MockPing(PING_TYPE_ICMP, "7.8.9.10", 60, 40);
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 90);
|
||||
server.MockPing(PING_TYPE_ICMP, "7.8.9.10", 60, 40);
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -blacklist-ip
|
||||
@@ -154,3 +196,128 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "7.8.9.10");
|
||||
}
|
||||
|
||||
TEST_F(IPRule, ignore_ip_set)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::MockServer server_upstream2;
|
||||
smartdns::Server server;
|
||||
std::string file = "/tmp/smartdns_test_ip_set.list" + smartdns::GenerateRandomString(5);
|
||||
std::ofstream ofs(file);
|
||||
ASSERT_TRUE(ofs.is_open());
|
||||
Defer
|
||||
{
|
||||
ofs.close();
|
||||
unlink(file.c_str());
|
||||
};
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 611);
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "7.8.9.10", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
/* this ip will be discard, but is reachable */
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 90);
|
||||
server.MockPing(PING_TYPE_ICMP, "7.8.9.10", 60, 40);
|
||||
|
||||
std::string ipset_list = R"""(
|
||||
1.2.3.0/24
|
||||
4.5.6.0/24
|
||||
)""";
|
||||
ofs.write(ipset_list.c_str(), ipset_list.length());
|
||||
ofs.flush();
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -blacklist-ip
|
||||
ip-set -name ip-list -file )""" +
|
||||
file + R"""(
|
||||
ignore-ip ip-set:ip-list
|
||||
log-num 0
|
||||
speed-check-mode none
|
||||
log-console yes
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "7.8.9.10");
|
||||
}
|
||||
|
||||
TEST_F(IPRule, ip_alias_ip_set)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::MockServer server_upstream2;
|
||||
smartdns::Server server;
|
||||
std::string file = "/tmp/smartdns_test_ip_set.list" + smartdns::GenerateRandomString(5);
|
||||
std::string file_ip = "/tmp/smartdns_test_ip_set_ip.list" + smartdns::GenerateRandomString(5);
|
||||
std::ofstream ofs(file);
|
||||
std::ofstream ofs_ip(file_ip);
|
||||
ASSERT_TRUE(ofs.is_open());
|
||||
ASSERT_TRUE(ofs_ip.is_open());
|
||||
Defer
|
||||
{
|
||||
ofs.close();
|
||||
unlink(file.c_str());
|
||||
ofs_ip.close();
|
||||
unlink(file_ip.c_str());
|
||||
};
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_A) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 611);
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "4.5.6.7", 611);
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "7.8.9.10", 611);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.MockPing(PING_TYPE_ICMP, "1.2.3.4", 60, 10);
|
||||
server.MockPing(PING_TYPE_ICMP, "4.5.6.7", 60, 90);
|
||||
server.MockPing(PING_TYPE_ICMP, "7.8.9.10", 60, 40);
|
||||
|
||||
std::string ipset_list = R"""(
|
||||
1.2.3.0/24
|
||||
4.5.6.0/24
|
||||
7.8.9.0/24
|
||||
)""";
|
||||
ofs.write(ipset_list.c_str(), ipset_list.length());
|
||||
ofs.flush();
|
||||
|
||||
std::string ipset_list_ip = R"""(
|
||||
1.1.1.1
|
||||
)""";
|
||||
ofs_ip.write(ipset_list_ip.c_str(), ipset_list_ip.length());
|
||||
ofs_ip.flush();
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server udp://127.0.0.1:61053 -blacklist-ip
|
||||
ip-set -name ip-list -file )""" +
|
||||
file + R"""(
|
||||
ip-set -name ip-list-ip -file )""" +
|
||||
file_ip + R"""(
|
||||
ip-alias ip-set:ip-list ip-set:ip-list-ip
|
||||
log-num 0
|
||||
speed-check-mode none
|
||||
log-console yes
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.1.1.1");
|
||||
}
|
||||
|
||||
@@ -42,11 +42,11 @@ TEST_F(Ptr, query)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_PTR) {
|
||||
dns_add_PTR(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 30, "my-hostname");
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
if (request->qtype == DNS_T_PTR) {
|
||||
dns_add_PTR(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 30, "my-hostname");
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
@@ -127,11 +127,11 @@ TEST_F(Ptr, smartdns)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
|
||||
if (request->qtype == DNS_T_PTR) {
|
||||
dns_add_PTR(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 30, "my-hostname");
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
if (request->qtype == DNS_T_PTR) {
|
||||
dns_add_PTR(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 30, "my-hostname");
|
||||
request->response_packet->head.rcode = DNS_RC_NOERROR;
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
317
test/cases/test-rule.cc
Normal file
317
test/cases/test-rule.cc
Normal file
@@ -0,0 +1,317 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "dns.h"
|
||||
#include "include/utils.h"
|
||||
#include "server.h"
|
||||
#include "util.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <fstream>
|
||||
|
||||
class Rule : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
virtual void SetUp() {}
|
||||
virtual void TearDown() {}
|
||||
};
|
||||
|
||||
TEST_F(Rule, Match)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype == DNS_T_A) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
speed-check-mode none
|
||||
address /a.com/5.6.7.8
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
|
||||
|
||||
ASSERT_TRUE(client.Query("aa.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "aa.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
}
|
||||
|
||||
TEST_F(Rule, PrefixWildcardMatch)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype == DNS_T_A) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
speed-check-mode none
|
||||
address /*a.com/5.6.7.8
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
|
||||
|
||||
ASSERT_TRUE(client.Query("aa.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "aa.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
|
||||
|
||||
ASSERT_TRUE(client.Query("ab.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "ab.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
}
|
||||
|
||||
TEST_F(Rule, SubDomainMatchOnly)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype == DNS_T_A) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
speed-check-mode none
|
||||
address /*.a.com/5.6.7.8
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
|
||||
|
||||
ASSERT_TRUE(client.Query("aa.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "aa.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
}
|
||||
|
||||
TEST_F(Rule, RootDomainMatchOnly)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype == DNS_T_A) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
speed-check-mode none
|
||||
address /-.a.com/5.6.7.8
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
|
||||
ASSERT_TRUE(client.Query("b.a.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "b.a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
|
||||
ASSERT_TRUE(client.Query("ba.com A", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "ba.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "A");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
}
|
||||
|
||||
TEST_F(Rule, AAAA_SOA)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype == DNS_T_A) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "1.2.3.4", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
} else if (request->qtype == DNS_T_AAAA) {
|
||||
smartdns::MockServer::AddIP(request, request->domain.c_str(), "64:ff9b::102:304", 700);
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
}
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
speed-check-mode none
|
||||
address /-.a.com/#6
|
||||
address /*.b.com/#6
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 0);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.a.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::102:304");
|
||||
|
||||
ASSERT_TRUE(client.Query("a.b.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 0);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
|
||||
ASSERT_TRUE(client.Query("b.com AAAA", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "b.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 700);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "AAAA");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "64:ff9b::102:304");
|
||||
}
|
||||
@@ -44,7 +44,7 @@ TEST_F(Server, all_unreach)
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.MockPing(PING_TYPE_ICMP, "2001::", 128, 10000);
|
||||
server.MockPing(PING_TYPE_ICMP, "2001::", 128, 10000);
|
||||
server.Start(R"""(bind [::]:60053
|
||||
bind-tcp [::]:60053
|
||||
server tls://255.255.255.255
|
||||
@@ -58,11 +58,11 @@ cache-persist no)""");
|
||||
ASSERT_TRUE(client.Query("a.com", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
EXPECT_EQ(client.GetStatus(), "SERVFAIL");
|
||||
EXPECT_EQ(client.GetAnswerNum(), 0);
|
||||
EXPECT_EQ(client.GetAnswerNum(), 0);
|
||||
|
||||
/* server should not crash */
|
||||
ASSERT_TRUE(client.Query("a.com +tcp", 60053));
|
||||
/* server should not crash */
|
||||
ASSERT_TRUE(client.Query("a.com +tcp", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
EXPECT_EQ(client.GetStatus(), "SERVFAIL");
|
||||
EXPECT_EQ(client.GetAnswerNum(), 0);
|
||||
EXPECT_EQ(client.GetAnswerNum(), 0);
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ cache-persist no)""");
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 2);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_LT(client.GetQueryTime(), 20);
|
||||
EXPECT_LT(client.GetQueryTime(), 40);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "b.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
|
||||
@@ -107,7 +107,7 @@ cache-persist no)""");
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 2);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_LT(client.GetQueryTime(), 20);
|
||||
EXPECT_LT(client.GetQueryTime(), 40);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1.2.3.4");
|
||||
@@ -220,7 +220,6 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "5.6.7.8");
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SpeedCheck, tcp_faster_than_ping)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
|
||||
105
test/cases/test-srv.cc
Normal file
105
test/cases/test-srv.cc
Normal file
@@ -0,0 +1,105 @@
|
||||
/*************************************************************************
|
||||
*
|
||||
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||
*
|
||||
* smartdns is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* smartdns is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "client.h"
|
||||
#include "dns.h"
|
||||
#include "include/utils.h"
|
||||
#include "server.h"
|
||||
#include "util.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <fstream>
|
||||
|
||||
class SRV : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
virtual void SetUp() {}
|
||||
virtual void TearDown() {}
|
||||
};
|
||||
|
||||
TEST_F(SRV, query)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_SRV) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
struct dns_packet *packet = request->response_packet;
|
||||
dns_add_SRV(packet, DNS_RRS_AN, request->domain.c_str(), 603, 1, 1, 443, "www.example.com");
|
||||
dns_add_SRV(packet, DNS_RRS_AN, request->domain.c_str(), 603, 1, 1, 443, "www1.example.com");
|
||||
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
speed-check-mode none
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("_ldap._tcp.local.com SRV", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 2);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "_ldap._tcp.local.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 603);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "SRV");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1 1 443 www.example.com.");
|
||||
}
|
||||
|
||||
TEST_F(SRV, match)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_SRV) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
|
||||
struct dns_packet *packet = request->response_packet;
|
||||
dns_add_SRV(packet, DNS_RRS_AN, request->domain.c_str(), 603, 1, 1, 443, "www.example.com");
|
||||
dns_add_SRV(packet, DNS_RRS_AN, request->domain.c_str(), 603, 1, 1, 443, "www1.example.com");
|
||||
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
log-level debug
|
||||
srv-record /_ldap._tcp.local.com/www.a.com,443,1,1
|
||||
srv-record /_ldap._tcp.local.com/www1.a.com,443,1,1
|
||||
srv-record /_ldap._tcp.local.com/www2.a.com,443,1,1
|
||||
speed-check-mode none
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("_ldap._tcp.local.com SRV", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 3);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "_ldap._tcp.local.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 600);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "SRV");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "1 1 443 www.a.com.");
|
||||
}
|
||||
@@ -55,7 +55,7 @@ TEST_F(SubNet, pass_subnet)
|
||||
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
|
||||
memset(&ecs, 0, sizeof(ecs));
|
||||
ret = dns_get_OPT_ECS(rrs, NULL, NULL, &ecs);
|
||||
ret = dns_get_OPT_ECS(rrs, &ecs);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -125,7 +125,7 @@ TEST_F(SubNet, conf)
|
||||
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
|
||||
memset(&ecs, 0, sizeof(ecs));
|
||||
ret = dns_get_OPT_ECS(rrs, NULL, NULL, &ecs);
|
||||
ret = dns_get_OPT_ECS(rrs, &ecs);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -196,7 +196,7 @@ TEST_F(SubNet, conf_v6)
|
||||
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
|
||||
memset(&ecs, 0, sizeof(ecs));
|
||||
ret = dns_get_OPT_ECS(rrs, NULL, NULL, &ecs);
|
||||
ret = dns_get_OPT_ECS(rrs, &ecs);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -245,6 +245,148 @@ cache-persist no)""");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "2001:db8::1");
|
||||
}
|
||||
|
||||
TEST_F(SubNet, v4_server_subnet_txt)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_TXT) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
struct dns_opt_ecs ecs;
|
||||
struct dns_rrs *rrs = NULL;
|
||||
int rr_count = 0;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
int has_ecs = 0;
|
||||
|
||||
rr_count = 0;
|
||||
rrs = dns_get_rrs_start(request->packet, DNS_RRS_OPT, &rr_count);
|
||||
if (rr_count <= 0) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
|
||||
memset(&ecs, 0, sizeof(ecs));
|
||||
ret = dns_get_OPT_ECS(rrs, &ecs);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
has_ecs = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (has_ecs == 0) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (ecs.family != DNS_OPT_ECS_FAMILY_IPV4) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (memcmp(ecs.addr, "\x08\x08\x08\x00", 4) != 0) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (ecs.source_prefix != 24) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
dns_add_TXT(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 6, "hello world");
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053 -subnet 8.8.8.8/24
|
||||
log-num 0
|
||||
log-console yes
|
||||
dualstack-ip-selection no
|
||||
log-level debug
|
||||
rr-ttl-min 0
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com TXT", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 6);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "TXT");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "\"hello world\"");
|
||||
}
|
||||
|
||||
TEST_F(SubNet, v6_default_subnet_txt)
|
||||
{
|
||||
smartdns::MockServer server_upstream;
|
||||
smartdns::Server server;
|
||||
|
||||
server_upstream.Start("udp://0.0.0.0:61053", [&](struct smartdns::ServerRequestContext *request) {
|
||||
if (request->qtype != DNS_T_TXT) {
|
||||
return smartdns::SERVER_REQUEST_SOA;
|
||||
}
|
||||
struct dns_opt_ecs ecs;
|
||||
struct dns_rrs *rrs = NULL;
|
||||
int rr_count = 0;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
int has_ecs = 0;
|
||||
|
||||
rr_count = 0;
|
||||
rrs = dns_get_rrs_start(request->packet, DNS_RRS_OPT, &rr_count);
|
||||
if (rr_count <= 0) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
|
||||
memset(&ecs, 0, sizeof(ecs));
|
||||
ret = dns_get_OPT_ECS(rrs, &ecs);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
has_ecs = 1;
|
||||
break;
|
||||
}
|
||||
if (has_ecs == 0) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (ecs.family != DNS_OPT_ECS_FAMILY_IPV6) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (memcmp(ecs.addr, "\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00", 16) != 0) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if (ecs.source_prefix != 64) {
|
||||
return smartdns::SERVER_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
dns_add_TXT(request->response_packet, DNS_RRS_AN, request->domain.c_str(), 6, "hello world");
|
||||
return smartdns::SERVER_REQUEST_OK;
|
||||
});
|
||||
|
||||
server.Start(R"""(bind [::]:60053
|
||||
server 127.0.0.1:61053
|
||||
log-num 0
|
||||
log-console yes
|
||||
dualstack-ip-selection no
|
||||
rr-ttl-min 0
|
||||
edns-client-subnet ffff:ffff:ffff:ffff:ffff::/64
|
||||
log-level debug
|
||||
cache-persist no)""");
|
||||
smartdns::Client client;
|
||||
ASSERT_TRUE(client.Query("a.com TXT", 60053));
|
||||
std::cout << client.GetResult() << std::endl;
|
||||
ASSERT_EQ(client.GetAnswerNum(), 1);
|
||||
EXPECT_EQ(client.GetStatus(), "NOERROR");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetName(), "a.com");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetTTL(), 6);
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetType(), "TXT");
|
||||
EXPECT_EQ(client.GetAnswer()[0].GetData(), "\"hello world\"");
|
||||
}
|
||||
|
||||
TEST_F(SubNet, per_server)
|
||||
{
|
||||
smartdns::MockServer server_upstream1;
|
||||
@@ -268,7 +410,7 @@ TEST_F(SubNet, per_server)
|
||||
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
|
||||
memset(&ecs, 0, sizeof(ecs));
|
||||
ret = dns_get_OPT_ECS(rrs, NULL, NULL, &ecs);
|
||||
ret = dns_get_OPT_ECS(rrs, &ecs);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -300,7 +442,7 @@ TEST_F(SubNet, per_server)
|
||||
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
|
||||
memset(&ecs, 0, sizeof(ecs));
|
||||
ret = dns_get_OPT_ECS(rrs, NULL, NULL, &ecs);
|
||||
ret = dns_get_OPT_ECS(rrs, &ecs);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -337,7 +479,7 @@ TEST_F(SubNet, per_server)
|
||||
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
|
||||
memset(&ecs, 0, sizeof(ecs));
|
||||
ret = dns_get_OPT_ECS(rrs, NULL, NULL, &ecs);
|
||||
ret = dns_get_OPT_ECS(rrs, &ecs);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -382,7 +524,7 @@ TEST_F(SubNet, per_server)
|
||||
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(request->packet, rrs)) {
|
||||
memset(&ecs, 0, sizeof(ecs));
|
||||
ret = dns_get_OPT_ECS(rrs, NULL, NULL, &ecs);
|
||||
ret = dns_get_OPT_ECS(rrs, &ecs);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -376,23 +376,21 @@ bool Server::Start(const std::string &conf, enum CONF_TYPE type)
|
||||
}
|
||||
|
||||
smartdns_reg_post_func(Server::StartPost, this);
|
||||
smartdns_main(args.size(), argv, fds[1]);
|
||||
smartdns_main(args.size(), argv, fds[1], 0);
|
||||
_exit(1);
|
||||
} else if (pid < 0) {
|
||||
return false;
|
||||
}
|
||||
} else if (mode_ == CREATE_MODE_THREAD) {
|
||||
thread_ = std::thread([&]() {
|
||||
std::vector<std::string> args = {
|
||||
"smartdns", "-f", "-x", "-c", conf_file_, "-p", "-",
|
||||
};
|
||||
std::vector<std::string> args = {"smartdns", "-f", "-x", "-c", conf_file_, "-p", "-", "-S"};
|
||||
char *argv[args.size() + 1];
|
||||
for (size_t i = 0; i < args.size(); i++) {
|
||||
argv[i] = (char *)args[i].c_str();
|
||||
}
|
||||
|
||||
smartdns_reg_post_func(Server::StartPost, this);
|
||||
smartdns_main(args.size(), argv, fds[1]);
|
||||
smartdns_main(args.size(), argv, fds[1], 1);
|
||||
smartdns_reg_post_func(nullptr, nullptr);
|
||||
});
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user