Compare commits
14 Commits
Release37-
...
Release37.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96d3deb595 | ||
|
|
584480dda1 | ||
|
|
2848aa0ac7 | ||
|
|
c156595f61 | ||
|
|
9dfe51c5ed | ||
|
|
5a2559f064 | ||
|
|
3605e6ed71 | ||
|
|
6588c9822f | ||
|
|
2f1d83cc2c | ||
|
|
ac042e8bee | ||
|
|
ab415f2ee9 | ||
|
|
d3bbd8edd7 | ||
|
|
9390a49a72 | ||
|
|
798226ddb3 |
40
Dockerfile
40
Dockerfile
@@ -1,35 +1,41 @@
|
||||
FROM ubuntu:latest as smartdns-builder
|
||||
LABEL previous-stage=smartdns-builder
|
||||
COPY . /smartdns/
|
||||
|
||||
# prepare builder
|
||||
ARG OPENSSL_VER=1.1.1f
|
||||
RUN apt update && \
|
||||
apt install -y perl wget make musl-tools musl-dev && \
|
||||
OPENSSL_VER=1.1.1f && \
|
||||
mkdir /build -p && \
|
||||
apt install -y perl curl make musl-tools musl-dev && \
|
||||
ln -s /usr/include/linux /usr/include/$(uname -m)-linux-musl && \
|
||||
ln -s /usr/include/asm-generic /usr/include/$(uname -m)-linux-musl && \
|
||||
ln -s /usr/include/$(uname -m)-linux-gnu/asm /usr/include/$(uname -m)-linux-musl && \
|
||||
cd /build && \
|
||||
wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/openssl_${OPENSSL_VER}.orig.tar.gz && \
|
||||
tar xf openssl_${OPENSSL_VER}.orig.tar.gz && \
|
||||
cd openssl-${OPENSSL_VER} && \
|
||||
\
|
||||
mkdir -p /build/openssl && \
|
||||
cd /build/openssl && \
|
||||
curl -sSL http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/openssl_${OPENSSL_VER}.orig.tar.gz | tar --strip-components=1 -zxv && \
|
||||
\
|
||||
export CC=musl-gcc && \
|
||||
if [ "$(uname -m)" = "aarch64" ]; then \
|
||||
./config --prefix=/opt/build no-tests -mno-outline-atomics ; \
|
||||
else \
|
||||
./config --prefix=/opt/build no-tests; \
|
||||
./config --prefix=/opt/build no-tests ; \
|
||||
fi && \
|
||||
make all -j8 && make install_sw && \
|
||||
cd /smartdns && \
|
||||
cd / && rm -rf /build
|
||||
|
||||
# do make
|
||||
COPY . /build/smartdns/
|
||||
RUN cd /build/smartdns && \
|
||||
export CC=musl-gcc && \
|
||||
export CFLAGS="-I /opt/build/include" && \
|
||||
export LDFLAGS="-L /opt/build/lib" && \
|
||||
sh ./package/build-pkg.sh --platform linux --arch `dpkg --print-architecture` --static && \
|
||||
mkdir /release -p && \
|
||||
cd /smartdns/package && tar xf *.tar.gz && \
|
||||
cp /smartdns/package/smartdns/etc /release/ -a && \
|
||||
cp /smartdns/package/smartdns/usr /release/ -a && \
|
||||
chmod +x /release/etc/init.d/smartdns && \
|
||||
mkdir /release/var/log/ /release/var/run/ -p && \
|
||||
rm -fr /build /smartdns
|
||||
\
|
||||
( cd package && tar -xvf *.tar.gz && chmod a+x smartdns/etc/init.d/smartdns ) && \
|
||||
\
|
||||
mkdir -p /release/var/log /release/var/run && \
|
||||
cp package/smartdns/etc /release/ -a && \
|
||||
cp package/smartdns/usr /release/ -a && \
|
||||
cd / && rm -rf /build
|
||||
|
||||
FROM busybox:latest
|
||||
COPY --from=smartdns-builder /release/ /
|
||||
|
||||
@@ -548,6 +548,8 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
|
||||
## 配置文件说明
|
||||
|
||||
配置建议:**smartdns默认已设置为最优模式,适合大部分场景的DNS查询体验改善,一般情况只需要增加上游服务器地址即可,无需做其他配置修改;如有其他配置修改,请务必了解其用途,避免修改后起到反作用。**
|
||||
|
||||
| 键名 | 功能说明 | 默认值 | 可用值/要求 | 举例 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| server-name | DNS 服务器名称 | 操作系统主机名 / smartdns | 符合主机名规格的字符串 | server-name smartdns |
|
||||
@@ -561,13 +563,14 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
| rr-ttl-min | 允许的最小 TTL 值 | 远程查询结果 | 大于 0 的数字 | rr-ttl-min 60 |
|
||||
| rr-ttl-max | 允许的最大 TTL 值 | 远程查询结果 | 大于 0 的数字 | rr-ttl-max 600 |
|
||||
| rr-ttl-reply-max | 允许返回给客户端的最大 TTL 值 | 远程查询结果 | 大于 0 的数字 | rr-ttl-reply-max 60 |
|
||||
| local-ttl | 本地HOST,address的TTL值 | rr-ttl-min | 大于 0 的数字 | local-ttl 60 |
|
||||
| max-reply-ip-num | 允许返回给客户的最大IP数量 | IP数量 | 大于 0 的数字 | max-reply-ip-num 1 |
|
||||
| log-level | 设置日志级别 | error | fatal、error、warn、notice、info 或 debug | log-level error |
|
||||
| log-file | 日志文件路径 | /var/log/smartdns.log | 合法路径字符串 | log-file /var/log/smartdns.log |
|
||||
| log-file | 日志文件路径 | /var/log/smartdns/smartdns.log | 合法路径字符串 | log-file /var/log/smartdns/smartdns.log |
|
||||
| log-size | 日志大小 | 128K | 数字 + K、M 或 G | log-size 128K |
|
||||
| log-num | 日志归档个数 | 2 | 大于等于 0 的数字 | log-num 2 |
|
||||
| audit-enable | 设置审计启用 | no | [yes\|no] | audit-enable yes |
|
||||
| audit-file | 审计文件路径 | /var/log/smartdns-audit.log | 合法路径字符串 | audit-file /var/log/smartdns-audit.log |
|
||||
| audit-file | 审计文件路径 | /var/log/smartdns/smartdns-audit.log | 合法路径字符串 | audit-file /var/log/smartdns/smartdns-audit.log |
|
||||
| audit-size | 审计大小 | 128K | 数字 + K、M 或 G | audit-size 128K |
|
||||
| audit-num | 审计归档个数 | 2 | 大于等于 0 的数字 | audit-num 2 |
|
||||
| conf-file | 附加配置文件 | 无 | 合法路径字符串 | conf-file /etc/smartdns/smartdns.more.conf |
|
||||
@@ -576,6 +579,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
| server-tls | 上游 TLS DNS | 无 | 可重复。<br>[ip][:port]:服务器 IP:端口(可选)<br>[-spki-pin [sha256-pin]]:TLS 合法性校验 SPKI 值,base64 编码的 sha256 SPKI pin 值<br>[-host-name]:TLS SNI 名称<br>[-tls-host-verify]:TLS 证书主机名校验<br> [-no-check-certificate]:跳过证书校验<br>[-blacklist-ip]:配置 IP 过滤结果<br>[-whitelist-ip]:仅接受参数中配置的 IP 范围<br>[-group [group] ...]:DNS 服务器所属组,比如 office 和 foreign,和 nameserver 配套使用<br>[-exclude-default-group]:将 DNS 服务器从默认组中排除 | server-tls 8.8.8.8:853 |
|
||||
| server-https | 上游 HTTPS DNS | 无 | 可重复。<br>https://[host][:port]/path:服务器 IP:端口(可选)<br>[-spki-pin [sha256-pin]]:TLS 合法性校验 SPKI 值,base64 编码的 sha256 SPKI pin 值<br>[-host-name]:TLS SNI 名称<br>[-http-host]:http 协议头主机名<br>[-tls-host-verify]:TLS 证书主机名校验<br> [-no-check-certificate]:跳过证书校验<br>[-blacklist-ip]:配置 IP 过滤结果<br>[-whitelist-ip]:仅接受参数中配置的 IP 范围。<br>[-group [group] ...]:DNS 服务器所属组,比如 office 和 foreign,和 nameserver 配套使用<br>[-exclude-default-group]:将 DNS 服务器从默认组中排除 | server-https https://cloudflare-dns.com/dns-query |
|
||||
| speed-check-mode | 测速模式选择 | 无 | [ping\|tcp:[80]\|none] | speed-check-mode ping,tcp:80,tcp:443 |
|
||||
| response-mode | 首次查询响应模式 | first-ping |模式:[fisrt-ping\|fastest-ip\|first-response]<br> [first-ping]: 最快ping响应地址模式,DNS上游最快查询时延+ping时延最短,查询等待与链接体验最佳;<br>[fastest-ip]: 最快IP地址模式,查询到的所有IP地址中ping最短的IP。需等待IP测速; <br>[first-response]: 最快响应的DNS结果,DNS查询等待时间最短,返回的IP地址可能不是最快。| response-mode first-ping |
|
||||
| address | 指定域名 IP 地址 | 无 | address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6] <br>- 表示忽略 <br># 表示返回 SOA <br>4 表示 IPv4 <br>6 表示 IPv6 | address /www.example.com/1.2.3.4 |
|
||||
| nameserver | 指定域名使用 server 组解析 | 无 | nameserver /domain/[group\|-], group 为组名,- 表示忽略此规则,配套 server 中的 -group 参数使用 | nameserver /www.example.com/office |
|
||||
| ipset | 域名 ipset | 无 | ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]],-表示忽略 | ipset /www.example.com/#4:dns4,#6:- |
|
||||
@@ -594,6 +598,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
|
||||
| serve-expired-reply-ttl | 回应的过期缓存 TTL | 5 | 秒,0 表示停用超时,大于 0 表示指定的超时的秒数 | serve-expired-reply-ttl 30 |
|
||||
| dualstack-ip-selection | 双栈 IP 优选 | yes | [yes\|no] | dualstack-ip-selection yes |
|
||||
| dualstack-ip-selection-threshold | 双栈 IP 优选阈值 | 15ms | 单位为毫秒(ms) | dualstack-ip-selection-threshold [0-1000] |
|
||||
| user | 进程运行用户 | root | user [username] | user nobody |
|
||||
| ca-file | 证书文件 | /etc/ssl/certs/ca-certificates.crt | 合法路径字符串 | ca-file /etc/ssl/certs/ca-certificates.crt |
|
||||
| ca-path | 证书文件路径 | /etc/ssl/certs | 合法路径字符串 | ca-path /etc/ssl/certs |
|
||||
|
||||
|
||||
@@ -497,15 +497,16 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|tcp-idle-time|TCP connection idle timeout|120|integer|tcp-idle-time 120
|
||||
|rr-ttl|Domain name TTL|Remote query result|number greater than 0|rr-ttl 600
|
||||
|rr-ttl-min|Domain name Minimum TTL|Remote query result|number greater than 0|rr-ttl-min 60
|
||||
|local-ttl|ttl for address and host|rr-ttl-min|number greater than 0|local-ttl 600
|
||||
|rr-ttl-reply-max|Domain name Minimum Reply TTL|Remote query result|number greater than 0|rr-ttl-reply-max 60
|
||||
|rr-ttl-max|Domain name Maximum TTL|Remote query result|number greater than 0|rr-ttl-max 600
|
||||
|max-reply-ip-num|Maximum number of IPs returned to the client|8|number of IPs, 1~16 |max-reply-ip-num 1
|
||||
|log-level|log level|error|fatal,error,warn,notice,info,debug|log-level error
|
||||
|log-file|log path|/var/log/smartdns.log|File Pah|log-file /var/log/smartdns.log
|
||||
|log-file|log path|/var/log/smartdns/smartdns.log|File Pah|log-file /var/log/smartdns/smartdns.log
|
||||
|log-size|log size|128K|number+K,M,G|log-size 128K
|
||||
|log-num|archived log number|2|Integer|log-num 2
|
||||
|audit-enable|audit log enable|no|[yes\|no]|audit-enable yes
|
||||
|audit-file|audit log file|/var/log/smartdns-audit.log|File Path|audit-file /var/log/smartdns-audit.log
|
||||
|audit-file|audit log file|/var/log/smartdns/smartdns-audit.log|File Path|audit-file /var/log/smartdns/smartdns-audit.log
|
||||
|audit-size|audit log size|128K|number+K,M,G|audit-size 128K
|
||||
|audit-num|archived audit log number|2|Integer|audit-num 2
|
||||
|conf-file|additional conf file|None|File path|conf-file /etc/smartdns/smartdns.more.conf
|
||||
@@ -514,6 +515,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|server-tls|Upstream TLS DNS server|None|Repeatable <br>`[ip][:port]`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name. <br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-tls 8.8.8.8:853
|
||||
|server-https|Upstream HTTPS DNS server|None|Repeatable <br>`https://[host][:port]/path`: Server IP, port optional. <br>`[-spki-pin [sha256-pin]]`: TLS verify SPKI value, a base64 encoded SHA256 hash<br>`[-host-name]`:TLS Server name<br>`[-http-host]`:http header host. <br>`[-tls-host-verify]`: TLS cert hostname to verify. <br>`-no-check-certificate:`: No check certificate. <br>`[-blacklist-ip]`: The "-blacklist-ip" parameter is to filtering IPs which is configured by "blacklist-ip". <br>`[-whitelist-ip]`: whitelist-ip parameter specifies that only the IP range configured in whitelist-ip is accepted. <br>`[-group [group] ...]`: The group to which the DNS server belongs, such as office, foreign, use with nameserver. <br>`[-exclude-default-group]`: Exclude DNS servers from the default group| server-https https://cloudflare-dns.com/dns-query
|
||||
|speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:80,tcp:443
|
||||
|response-mode|First query response mode|first-ping|Mode: [fisrt-ping\|fastest-ip\|first-response]<br> [first-ping]: The fastest dns + ping response mode, DNS query delay + ping delay is the shortest;<br>[fastest-ip]: The fastest IP address mode, return the fastest ip address, may take some time to test speed. <br>[first-response]: The fastest response DNS result mode, the DNS query waiting time is the shortest. | response-mode first-ping |
|
||||
|address|Domain IP address|None|address /domain/[ip\|-\|-4\|-6\|#\|#4\|#6], `-` for ignore, `#` for return SOA, `4` for IPV4, `6` for IPV6| address /www.example.com/1.2.3.4
|
||||
|nameserver|To query domain with specific server group|None|nameserver /domain/[group\|-], `group` is the group name, `-` means ignore this rule, use the `-group` parameter in the related server|nameserver /www.example.com/office
|
||||
|ipset|Domain IPSet|None|ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]], `-` for ignore|ipset /www.example.com/#4:dns4,#6:-
|
||||
@@ -532,6 +534,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|serve-expired-reply-ttl|TTL value to use when replying with expired data|5|second,0:disable,> 0 seconds after expiration|serve-expired-reply-ttl 30
|
||||
|dualstack-ip-selection|Dualstack ip selection|yes|[yes\|no]|dualstack-ip-selection yes
|
||||
|dualstack-ip-selection-threshold|Dualstack ip select threadhold|15ms|millisecond|dualstack-ip-selection-threshold [0-1000]
|
||||
|user|run as user|root|user [username]|user nobody
|
||||
|ca-file|certificate file|/etc/ssl/certs/ca-certificates.crt|path|ca-file /etc/ssl/certs/ca-certificates.crt
|
||||
|ca-path|certificates path|/etc/ssl/certs|path|ca-path /etc/ssl/certs
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
# server-name smartdns
|
||||
#
|
||||
|
||||
# dns server run ser
|
||||
# dns server run user
|
||||
# user [username]
|
||||
# example: run as nobody
|
||||
# user nobody
|
||||
@@ -109,7 +109,7 @@ cache-size 16384
|
||||
# rr-ttl: ttl for all record
|
||||
# rr-ttl-min: minimum ttl for resource record
|
||||
# rr-ttl-max: maximum ttl for resource record
|
||||
# tr-ttl-reply-max: maximum reply ttl for resource record
|
||||
# rr-ttl-reply-max: maximum reply ttl for resource record
|
||||
# example:
|
||||
# rr-ttl 300
|
||||
# rr-ttl-min 60
|
||||
@@ -120,13 +120,17 @@ cache-size 16384
|
||||
# example:
|
||||
# max-reply-ip-num 1
|
||||
|
||||
# response mode
|
||||
# Experimental feature
|
||||
# response-mode [first-ping|fastest-ip|fastest-response]
|
||||
|
||||
# set log level
|
||||
# log-level: [level], level=fatal, error, warn, notice, info, debug
|
||||
# log-file: file path of log file.
|
||||
# log-size: size of each log file, support k,m,g
|
||||
# log-num: number of logs
|
||||
log-level info
|
||||
# log-file /var/log/smartdns.log
|
||||
# log-file /var/log/smartdns/smartdns.log
|
||||
# log-size 128k
|
||||
# log-num 2
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ init_dir()
|
||||
which systemctl >/dev/null 2>&1
|
||||
ISSYSTEMD="$?"
|
||||
# Running under WSL (Windows Subsystem for Linux)?
|
||||
cat /proc/version | grep Microsoft >/dev/null 2>&1;
|
||||
cat /proc/version | grep -E '[Mm]icrosoft' >/dev/null 2>&1;
|
||||
if [ $? -eq 0 ]; then
|
||||
ISSYSTEMD=1
|
||||
ISWSL=0
|
||||
|
||||
@@ -22,6 +22,7 @@ SMARTDNS_PID=/var/run/smartdns.pid
|
||||
SMARTDNS_PORT=535
|
||||
SMARTDNS_OPT=/opt/etc/smartdns/smartdns-opt.conf
|
||||
# workmode
|
||||
# DO NOT CHANGE THIS, CHANGE MODE IN smartdns-opt.conf
|
||||
# 0: run as port only
|
||||
# 1: redirect port
|
||||
# 2: replace
|
||||
@@ -232,11 +233,11 @@ set_smartdns_port()
|
||||
if [ "$SMARTDNS_WORKMODE" = "0" ]; then
|
||||
return 0
|
||||
elif [ "$SMARTDNS_WORKMODE" = "1" ]; then
|
||||
sed -i "s/^\\(bind .*\\):53 *\\(.*\\)\$/\\1:$SMARTDNS_PORT \\2/g" $SMARTDNS_CONF
|
||||
sed -i "s/^\\(bind-tcp .*\\):53 *\\(.*\\)\$/\\1:$SMARTDNS_PORT \\2/g" $SMARTDNS_CONF
|
||||
sed -i "s/^\(bind .*\):53\( .*\)\?$/\1:$SMARTDNS_PORT \2/g" $SMARTDNS_CONF
|
||||
sed -i "s/^\(bind-tcp .*\):53\( .*\)\?$/\1:$SMARTDNS_PORT \2/g" $SMARTDNS_CONF
|
||||
elif [ "$SMARTDNS_WORKMODE" = "2" ]; then
|
||||
sed -i "s/^\\(bind .*\\):$SMARTDNS_PORT *\\(.*\\)\$/\\1:53 \\2/g" $SMARTDNS_CONF
|
||||
sed -i "s/^\\(bind-tcp .*\\):$SMARTDNS_PORT *\\(.*\\)\$/\\1:53 \\2/g" $SMARTDNS_CONF
|
||||
sed -i "s/^\(bind .*\):$SMARTDNS_PORT\( .*\)\?$/\1:53 \2/g" $SMARTDNS_CONF
|
||||
sed -i "s/^\(bind-tcp .*\):$SMARTDNS_PORT\( .*\)\?$/\1:53 \2/g" $SMARTDNS_CONF
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
87
src/dns.c
87
src/dns.c
@@ -43,7 +43,7 @@
|
||||
} while (0)
|
||||
|
||||
/* read short and move pointer */
|
||||
static short _dns_read_short(unsigned char **buffer)
|
||||
static unsigned short _dns_read_short(unsigned char **buffer)
|
||||
{
|
||||
unsigned short value = 0;
|
||||
|
||||
@@ -342,7 +342,7 @@ struct dns_rrs *dns_get_rrs_start(struct dns_packet *packet, dns_rr_type type, i
|
||||
break;
|
||||
}
|
||||
|
||||
/* if not resource record, reutrn null */
|
||||
/* if not resource record, return null */
|
||||
if (start == DNS_RR_END) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -431,7 +431,7 @@ static int _dns_rr_add_end(struct dns_packet *packet, int type, dns_type_t rtype
|
||||
break;
|
||||
}
|
||||
|
||||
/* add data to end of dns_packet, and set previouse rrs point to this rrs */
|
||||
/* add data to end of dns_packet, and set previous rrs point to this rrs */
|
||||
if (*start != DNS_RR_END) {
|
||||
rrs_next = (struct dns_rrs *)(packet->data + *start);
|
||||
while (rrs_next->next != DNS_RR_END) {
|
||||
@@ -549,6 +549,10 @@ static int _dns_add_RAW(struct dns_packet *packet, dns_rr_type rrtype, dns_type_
|
||||
struct dns_context context;
|
||||
int ret = 0;
|
||||
|
||||
if (raw_len < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* resource record */
|
||||
/* |domain |
|
||||
* |qtype | qclass |
|
||||
@@ -731,7 +735,8 @@ int dns_get_CNAME(struct dns_rrs *rrs, char *domain, int maxsize, int *ttl, char
|
||||
return _dns_get_RAW(rrs, domain, maxsize, ttl, cname, &len);
|
||||
}
|
||||
|
||||
int dns_add_A(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl, unsigned char addr[DNS_RR_A_LEN])
|
||||
int dns_add_A(struct dns_packet *packet, dns_rr_type type, const char *domain, int ttl,
|
||||
unsigned char addr[DNS_RR_A_LEN])
|
||||
{
|
||||
return _dns_add_RAW(packet, type, DNS_T_A, domain, ttl, addr, DNS_RR_A_LEN);
|
||||
}
|
||||
@@ -1152,6 +1157,11 @@ static int _dns_decode_rr_head(struct dns_context *context, char *domain, int do
|
||||
*ttl = _dns_read_int(&context->ptr);
|
||||
*rr_len = _dns_read_short(&context->ptr);
|
||||
|
||||
if (*rr_len < 0 || *ttl < 0) {
|
||||
tlog(TLOG_DEBUG, "rr len or ttl is invalid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1232,7 +1242,7 @@ static int _dns_encode_raw(struct dns_context *context, struct dns_rrs *rrs)
|
||||
|
||||
static int _dns_decode_raw(struct dns_context *context, unsigned char *raw, int len)
|
||||
{
|
||||
if (_dns_left_len(context) < len) {
|
||||
if (_dns_left_len(context) < len || len < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1594,6 +1604,11 @@ static int _dns_decode_opt(struct dns_context *context, dns_rr_type type, unsign
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*/
|
||||
|
||||
if (rr_len < 0) {
|
||||
tlog(TLOG_DEBUG, "opt len is invalid.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ercode != 0) {
|
||||
tlog(TLOG_ERROR, "extend rcode invalid.");
|
||||
return -1;
|
||||
@@ -1681,7 +1696,7 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
|
||||
/* decode rr head */
|
||||
ret = _dns_decode_rr_head(context, domain, DNS_MAX_CNAME_LEN, &qtype, &qclass, &ttl, &rr_len);
|
||||
if (ret < 0) {
|
||||
if (ret < 0 || qclass < 0) {
|
||||
tlog(TLOG_DEBUG, "decode head failed.");
|
||||
return -1;
|
||||
}
|
||||
@@ -1693,7 +1708,8 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
unsigned char addr[DNS_RR_A_LEN];
|
||||
ret = _dns_decode_raw(context, addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_ERROR, "decode A failed, %s", domain);
|
||||
tlog(TLOG_DEBUG, "decode A failed, %s, len: %d:%d", domain, (int)(context->ptr - context->data),
|
||||
_dns_left_len(context));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1707,7 +1723,8 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
ret = _dns_decode_CNAME(context, cname, DNS_MAX_CNAME_LEN);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_ERROR, "decode CNAME failed, %s", domain);
|
||||
tlog(TLOG_DEBUG, "decode CNAME failed, %s, len: %d:%d", domain, (int)(context->ptr - context->data),
|
||||
_dns_left_len(context));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1721,7 +1738,7 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
struct dns_soa soa;
|
||||
ret = _dns_decode_SOA(context, &soa);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_ERROR, "decode SOA failed, %s", domain);
|
||||
tlog(TLOG_DEBUG, "decode SOA failed, %s", domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1735,7 +1752,7 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
char ns[DNS_MAX_CNAME_LEN];
|
||||
ret = _dns_decode_CNAME(context, ns, DNS_MAX_CNAME_LEN);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_ERROR, "decode NS failed, %s", domain);
|
||||
tlog(TLOG_DEBUG, "decode NS failed, %s", domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1749,7 +1766,7 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
char name[DNS_MAX_CNAME_LEN];
|
||||
ret = _dns_decode_CNAME(context, name, DNS_MAX_CNAME_LEN);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_ERROR, "decode PTR failed, %s", domain);
|
||||
tlog(TLOG_DEBUG, "decode PTR failed, %s", domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1763,7 +1780,7 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
unsigned char addr[DNS_RR_AAAA_LEN];
|
||||
ret = _dns_decode_raw(context, addr, sizeof(addr));
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_ERROR, "decode AAAA failed, %s", domain);
|
||||
tlog(TLOG_DEBUG, "decode AAAA failed, %s", domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1777,12 +1794,12 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
unsigned char *opt_start = context->ptr;
|
||||
ret = _dns_decode_opt(context, type, ttl, rr_len);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_ERROR, "decode opt failed, %s", domain);
|
||||
tlog(TLOG_DEBUG, "decode opt failed, %s", domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (context->ptr - opt_start != rr_len) {
|
||||
tlog(TLOG_ERROR, "opt length mismatch, %s\n", domain);
|
||||
tlog(TLOG_DEBUG, "opt length mismatch, %s\n", domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1797,7 +1814,7 @@ static int _dns_decode_an(struct dns_context *context, dns_rr_type type)
|
||||
|
||||
ret = _dns_decode_raw(context, raw_data, rr_len);
|
||||
if (ret < 0) {
|
||||
tlog(TLOG_ERROR, "decode A failed, %s", domain);
|
||||
tlog(TLOG_DEBUG, "decode A failed, %s", domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -2220,43 +2237,3 @@ int dns_packet_update(unsigned char *data, int size, struct dns_update_param *pa
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void dns_debug(void)
|
||||
{
|
||||
unsigned char data[1024];
|
||||
ssize_t len;
|
||||
char buff[4096];
|
||||
|
||||
int fd = open("dns.bin", O_RDWR);
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
len = read(fd, data, 1024);
|
||||
close(fd);
|
||||
if (len < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct dns_packet *packet = (struct dns_packet *)buff;
|
||||
if (dns_decode(packet, 4096, data, len) != 0) {
|
||||
tlog(TLOG_ERROR, "decode failed.\n");
|
||||
}
|
||||
|
||||
memset(data, 0, sizeof(data));
|
||||
len = dns_encode(data, 1024, packet);
|
||||
if (len < 0) {
|
||||
tlog(TLOG_ERROR, "encode failed.");
|
||||
}
|
||||
|
||||
fd = open("dns-cmp.bin", O_CREAT | O_TRUNC | O_RDWR, 0660);
|
||||
write(fd, data, len);
|
||||
close(fd);
|
||||
|
||||
packet = (struct dns_packet *)buff;
|
||||
if (dns_decode(packet, 4096, data, len) != 0) {
|
||||
tlog(TLOG_ERROR, "decode failed.\n");
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -128,9 +128,14 @@ enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data)
|
||||
return cache_data->head.cache_type;
|
||||
}
|
||||
|
||||
uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data)
|
||||
uint32_t dns_cache_get_query_flag(struct dns_cache_data *cache_data)
|
||||
{
|
||||
return cache_data->head.cache_flag;
|
||||
return cache_data->head.query_flag;
|
||||
}
|
||||
|
||||
const char *dns_cache_get_dns_group_name(struct dns_cache_data *cache_data)
|
||||
{
|
||||
return cache_data->head.dns_group_name;
|
||||
}
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data)
|
||||
@@ -156,7 +161,8 @@ struct dns_cache_data *dns_cache_new_data(void)
|
||||
return (struct dns_cache_data *)cache_addr;
|
||||
}
|
||||
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl)
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
goto errout;
|
||||
@@ -179,7 +185,13 @@ void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag
|
||||
cache_addr->addr_data.cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
cache_addr->head.cache_flag = cache_flag;
|
||||
if (query_option) {
|
||||
cache_addr->head.query_flag = query_option->query_flag;
|
||||
if (query_option->dns_group_name) {
|
||||
safe_strncpy(cache_addr->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
cache_addr->addr_data.soa = 1;
|
||||
cache_addr->head.cache_type = CACHE_TYPE_ADDR;
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
@@ -187,8 +199,8 @@ errout:
|
||||
return;
|
||||
}
|
||||
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl,
|
||||
unsigned char *addr, int addr_len)
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl, unsigned char *addr, int addr_len)
|
||||
{
|
||||
if (dns_cache == NULL) {
|
||||
goto errout;
|
||||
@@ -212,14 +224,21 @@ void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_fl
|
||||
cache_addr->addr_data.cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
cache_addr->head.cache_flag = cache_flag;
|
||||
if (query_option) {
|
||||
cache_addr->head.query_flag = query_option->query_flag;
|
||||
if (query_option->dns_group_name) {
|
||||
safe_strncpy(cache_addr->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
cache_addr->head.cache_type = CACHE_TYPE_ADDR;
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
errout:
|
||||
return;
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len)
|
||||
struct dns_cache_data *dns_cache_new_data_packet(struct dns_cache_query_option *query_option, void *packet,
|
||||
size_t packet_len)
|
||||
{
|
||||
struct dns_cache_packet *cache_packet = NULL;
|
||||
size_t data_size = 0;
|
||||
@@ -236,7 +255,12 @@ struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *pack
|
||||
memcpy(cache_packet->data, packet, packet_len);
|
||||
memset(&cache_packet->head, 0, sizeof(cache_packet->head));
|
||||
|
||||
cache_packet->head.cache_flag = cache_flag;
|
||||
if (query_option) {
|
||||
cache_packet->head.query_flag = query_option->query_flag;
|
||||
if (query_option->dns_group_name) {
|
||||
strncpy(cache_packet->head.dns_group_name, query_option->dns_group_name, DNS_CACHE_GROUP_NAME_LEN - 1);
|
||||
}
|
||||
}
|
||||
cache_packet->head.cache_type = CACHE_TYPE_PACKET;
|
||||
cache_packet->head.size = packet_len;
|
||||
|
||||
|
||||
@@ -31,8 +31,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DNS_CACHE_TTL_MIN 30
|
||||
#define DNS_CACHE_TTL_MIN 1
|
||||
#define DNS_CACHE_VERSION_LEN 32
|
||||
#define DNS_CACHE_GROUP_NAME_LEN 32
|
||||
#define MAGIC_NUMBER 0x6548634163536e44
|
||||
#define MAGIC_CACHE_DATA 0x44615461
|
||||
|
||||
@@ -47,9 +48,15 @@ enum CACHE_RECORD_TYPE {
|
||||
CACHE_RECORD_TYPE_INACTIVE,
|
||||
};
|
||||
|
||||
struct dns_cache_query_option {
|
||||
uint32_t query_flag;
|
||||
const char *dns_group_name;
|
||||
};
|
||||
|
||||
struct dns_cache_data_head {
|
||||
uint32_t cache_flag;
|
||||
enum CACHE_TYPE cache_type;
|
||||
uint32_t query_flag;
|
||||
char dns_group_name[DNS_CACHE_GROUP_NAME_LEN];
|
||||
int is_soa;
|
||||
ssize_t size;
|
||||
};
|
||||
@@ -115,11 +122,14 @@ struct dns_cache_file {
|
||||
|
||||
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data);
|
||||
|
||||
uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data);
|
||||
uint32_t dns_cache_get_query_flag(struct dns_cache_data *cache_data);
|
||||
|
||||
const char *dns_cache_get_dns_group_name(struct dns_cache_data *cache_data);
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data);
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len);
|
||||
struct dns_cache_data *dns_cache_new_data_packet(struct dns_cache_query_option *query_option, void *packet,
|
||||
size_t packet_len);
|
||||
|
||||
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
|
||||
|
||||
@@ -156,10 +166,11 @@ struct dns_cache_data *dns_cache_new_data(void);
|
||||
|
||||
struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl,
|
||||
unsigned char *addr, int addr_len);
|
||||
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl, unsigned char *addr, int addr_len);
|
||||
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl);
|
||||
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, struct dns_cache_query_option *query_option, char *cname,
|
||||
int cname_ttl);
|
||||
|
||||
void dns_cache_destroy(void);
|
||||
|
||||
|
||||
@@ -574,7 +574,8 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_client_add_to_pending_group(const char *group_name, char *server_ip, int port, dns_server_type_t server_type)
|
||||
static int _dns_client_add_to_pending_group(const char *group_name, char *server_ip, int port,
|
||||
dns_server_type_t server_type)
|
||||
{
|
||||
struct dns_server_pending *item = NULL;
|
||||
struct dns_server_pending *tmp = NULL;
|
||||
@@ -621,8 +622,8 @@ errout:
|
||||
}
|
||||
|
||||
/* add server to group */
|
||||
static int _dns_client_add_to_group_pending(const char *group_name, char *server_ip, int port, dns_server_type_t server_type,
|
||||
int ispending)
|
||||
static int _dns_client_add_to_group_pending(const char *group_name, char *server_ip, int port,
|
||||
dns_server_type_t server_type, int ispending)
|
||||
{
|
||||
struct dns_server_info *server_info = NULL;
|
||||
|
||||
@@ -1415,10 +1416,6 @@ static void _dns_client_query_remove(struct dns_query_struct *query)
|
||||
{
|
||||
/* remove query from period check list, and release reference*/
|
||||
pthread_mutex_lock(&client.domain_map_lock);
|
||||
if (list_empty(&query->dns_request_list)) {
|
||||
pthread_mutex_unlock(&client.domain_map_lock);
|
||||
return;
|
||||
}
|
||||
list_del_init(&query->dns_request_list);
|
||||
hash_del(&query->domain_node);
|
||||
pthread_mutex_unlock(&client.domain_map_lock);
|
||||
@@ -1591,8 +1588,11 @@ static int _dns_client_recv(struct dns_server_info *server_info, unsigned char *
|
||||
len = dns_decode(packet, DNS_PACKSIZE, inpacket, inpacket_len);
|
||||
if (len != 0) {
|
||||
char host_name[DNS_MAX_CNAME_LEN];
|
||||
tlog(TLOG_WARN, "decode failed, packet len = %d, tc = %d, id = %d, from = %s\n", inpacket_len, packet->head.tc,
|
||||
tlog(TLOG_INFO, "decode failed, packet len = %d, tc = %d, id = %d, from = %s\n", inpacket_len, packet->head.tc,
|
||||
packet->head.id, gethost_by_addr(host_name, sizeof(host_name), from));
|
||||
if (dns_save_fail_packet) {
|
||||
dns_packet_save(dns_save_fail_packet_dir, "client", host_name, inpacket, inpacket_len);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1721,7 +1721,7 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
|
||||
|
||||
fd = socket(server_info->ai_family, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
tlog(TLOG_ERROR, "create socket failed.");
|
||||
tlog(TLOG_ERROR, "create socket failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -1732,7 +1732,7 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
|
||||
|
||||
/* enable tcp fast open */
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, &yes, sizeof(yes)) != 0) {
|
||||
tlog(TLOG_DEBUG, "enable TCP fast open failed.");
|
||||
tlog(TLOG_DEBUG, "enable TCP fast open failed, %s", strerror(errno));
|
||||
}
|
||||
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes));
|
||||
@@ -1988,6 +1988,11 @@ static int _dns_client_socket_ssl_send(struct dns_server_info *server, const voi
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (num < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = _ssl_write(server, buf, num);
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
@@ -2075,7 +2080,7 @@ static int _dns_client_socket_ssl_recv(struct dns_server_info *server, void *buf
|
||||
return 0;
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "SSL read fail error no: %s(%lx)\n", ERR_reason_error_string(ssl_err), ssl_err);
|
||||
tlog(TLOG_INFO, "SSL read fail error no: %s(%lx), len: %d\n", ERR_reason_error_string(ssl_err), ssl_err, num);
|
||||
errno = EFAULT;
|
||||
ret = -1;
|
||||
break;
|
||||
|
||||
@@ -59,6 +59,14 @@ int dns_conf_tcp_idle_time = 120;
|
||||
|
||||
int dns_conf_max_reply_ip_num = DNS_MAX_REPLY_IP_NUM;
|
||||
|
||||
static struct config_enum_list dns_conf_response_mode_enum[] = {
|
||||
{"first-ping", DNS_RESPONSE_MODE_FIRST_PING_IP},
|
||||
{"fastest-ip", DNS_RESPONSE_MODE_FASTEST_IP},
|
||||
{"fastest-response", DNS_RESPONSE_MODE_FASTEST_RESPONSE},
|
||||
{0, 0}};
|
||||
|
||||
enum response_mode_type dns_conf_response_mode;
|
||||
|
||||
/* cache */
|
||||
int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
|
||||
int dns_conf_prefetch = 0;
|
||||
@@ -116,12 +124,16 @@ int dns_conf_rr_ttl;
|
||||
int dns_conf_rr_ttl_reply_max;
|
||||
int dns_conf_rr_ttl_min = 600;
|
||||
int dns_conf_rr_ttl_max;
|
||||
int dns_conf_local_ttl;
|
||||
int dns_conf_force_AAAA_SOA;
|
||||
int dns_conf_force_no_cname;
|
||||
int dns_conf_ipset_timeout_enable;
|
||||
|
||||
char dns_conf_user[DNS_CONF_USRNAME_LEN];
|
||||
|
||||
int dns_save_fail_packet;
|
||||
char dns_save_fail_packet_dir[DNS_MAX_PATH];
|
||||
|
||||
/* ECS */
|
||||
struct dns_edns_client_subnet dns_conf_ipv4_ecs;
|
||||
struct dns_edns_client_subnet dns_conf_ipv6_ecs;
|
||||
@@ -1022,7 +1034,7 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
|
||||
bind_ip->flags = server_flag;
|
||||
bind_ip->group = group;
|
||||
dns_conf_bind_ip_num++;
|
||||
tlog(TLOG_DEBUG, "bind ip %s, type:%d, flag: %X", ip, type, server_flag);
|
||||
tlog(TLOG_DEBUG, "bind ip %s, type: %d, flag: %X", ip, type, server_flag);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1896,7 +1908,9 @@ static struct config_item _config_item[] = {
|
||||
CONF_INT("rr-ttl-min", &dns_conf_rr_ttl_min, 0, CONF_INT_MAX),
|
||||
CONF_INT("rr-ttl-max", &dns_conf_rr_ttl_max, 0, CONF_INT_MAX),
|
||||
CONF_INT("rr-ttl-reply-max", &dns_conf_rr_ttl_reply_max, 0, CONF_INT_MAX),
|
||||
CONF_INT("local-ttl", &dns_conf_local_ttl, 0, CONF_INT_MAX),
|
||||
CONF_INT("max-reply-ip-num", &dns_conf_max_reply_ip_num, 1, CONF_INT_MAX),
|
||||
CONF_ENUM("response-mode", &dns_conf_response_mode, &dns_conf_response_mode_enum),
|
||||
CONF_YESNO("force-AAAA-SOA", &dns_conf_force_AAAA_SOA),
|
||||
CONF_YESNO("force-no-CNAME", &dns_conf_force_no_cname),
|
||||
CONF_CUSTOM("force-qtype-SOA", _config_qtype_soa, NULL),
|
||||
@@ -1911,6 +1925,8 @@ static struct config_item _config_item[] = {
|
||||
CONF_STRING("ca-file", (char *)&dns_conf_ca_file, DNS_MAX_PATH),
|
||||
CONF_STRING("ca-path", (char *)&dns_conf_ca_path, DNS_MAX_PATH),
|
||||
CONF_STRING("user", (char *)&dns_conf_user, sizeof(dns_conf_user)),
|
||||
CONF_YESNO("debug-save-fail-packet", &dns_save_fail_packet),
|
||||
CONF_STRING("debug-save-fail-packet-dir", (char *)&dns_save_fail_packet_dir, sizeof(dns_save_fail_packet_dir)),
|
||||
CONF_CUSTOM("conf-file", config_addtional_file, NULL),
|
||||
CONF_END(),
|
||||
};
|
||||
@@ -2059,6 +2075,8 @@ static int _dns_conf_load_pre(void)
|
||||
|
||||
_dns_ping_cap_check();
|
||||
|
||||
safe_strncpy(dns_save_fail_packet_dir, SMARTDNS_DEBUG_DIR, sizeof(dns_save_fail_packet_dir));
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
@@ -2069,6 +2087,16 @@ static int _dns_conf_load_post(void)
|
||||
{
|
||||
_dns_conf_speed_check_mode_verify();
|
||||
|
||||
if (dns_conf_cachesize == 0 && dns_conf_response_mode == DNS_RESPONSE_MODE_FASTEST_RESPONSE) {
|
||||
dns_conf_response_mode = DNS_RESPONSE_MODE_FASTEST_IP;
|
||||
tlog(TLOG_WARN, "force set response to %s as cache size is 0",
|
||||
dns_conf_response_mode_enum[dns_conf_response_mode].name);
|
||||
}
|
||||
|
||||
if (dns_conf_local_ttl == 0) {
|
||||
dns_conf_local_ttl = dns_conf_rr_ttl_min;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,9 +49,10 @@ extern "C" {
|
||||
#define DEFAULT_DNS_HTTPS_PORT 443
|
||||
#define DNS_MAX_CONF_CNAME_LEN 256
|
||||
#define SMARTDNS_CONF_FILE "/etc/smartdns/smartdns.conf"
|
||||
#define SMARTDNS_LOG_FILE "/var/log/smartdns.log"
|
||||
#define SMARTDNS_AUDIT_FILE "/var/log/smartdns-audit.log"
|
||||
#define SMARTDNS_LOG_FILE "/var/log/smartdns/smartdns.log"
|
||||
#define SMARTDNS_AUDIT_FILE "/var/log/smartdns/smartdns-audit.log"
|
||||
#define SMARTDNS_CACHE_FILE "/tmp/smartdns.cache"
|
||||
#define SMARTDNS_DEBUG_DIR "/tmp/smartdns"
|
||||
|
||||
enum domain_rule {
|
||||
DOMAIN_RULE_FLAGS = 0,
|
||||
@@ -298,6 +299,12 @@ extern int dns_conf_dualstack_ip_allow_force_AAAA;
|
||||
extern int dns_conf_dualstack_ip_selection_threshold;
|
||||
|
||||
extern int dns_conf_max_reply_ip_num;
|
||||
enum response_mode_type {
|
||||
DNS_RESPONSE_MODE_FIRST_PING_IP = 0,
|
||||
DNS_RESPONSE_MODE_FASTEST_IP,
|
||||
DNS_RESPONSE_MODE_FASTEST_RESPONSE,
|
||||
};
|
||||
extern enum response_mode_type dns_conf_response_mode;
|
||||
|
||||
extern int dns_conf_rr_ttl;
|
||||
extern int dns_conf_rr_ttl_reply_max;
|
||||
@@ -305,6 +312,7 @@ extern int dns_conf_rr_ttl_min;
|
||||
extern int dns_conf_rr_ttl_max;
|
||||
extern int dns_conf_force_AAAA_SOA;
|
||||
extern int dns_conf_ipset_timeout_enable;
|
||||
extern int dns_conf_local_ttl;
|
||||
|
||||
extern int dns_conf_force_no_cname;
|
||||
|
||||
@@ -315,6 +323,9 @@ extern struct dns_edns_client_subnet dns_conf_ipv6_ecs;
|
||||
|
||||
extern char dns_conf_sni_proxy_ip[DNS_MAX_IPLEN];
|
||||
|
||||
extern int dns_save_fail_packet;
|
||||
extern char dns_save_fail_packet_dir[DNS_MAX_PATH];
|
||||
|
||||
void dns_server_load_exit(void);
|
||||
|
||||
int dns_server_load_conf(const char *file);
|
||||
|
||||
266
src/dns_server.c
266
src/dns_server.c
@@ -110,6 +110,8 @@ struct dns_server_post_context {
|
||||
int do_ipset;
|
||||
int do_log_result;
|
||||
int reply_ttl;
|
||||
int cache_ttl;
|
||||
int no_check_add_ip;
|
||||
int do_audit;
|
||||
int do_force_soa;
|
||||
int skip_notify_count;
|
||||
@@ -161,6 +163,7 @@ struct dns_request {
|
||||
|
||||
struct dns_server_conn_head *conn;
|
||||
uint32_t server_flags;
|
||||
char dns_group_name[DNS_GROUP_NAME_LEN];
|
||||
|
||||
/* dns request list */
|
||||
struct list_head list;
|
||||
@@ -259,8 +262,8 @@ static tlog_log *dns_audit;
|
||||
|
||||
static int is_ipv6_ready;
|
||||
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expired_domain, uint32_t server_flags,
|
||||
struct dns_query_options *options);
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expired_domain,
|
||||
struct dns_server_query_option *server_query_option);
|
||||
static int _dns_server_get_answer(struct dns_server_post_context *context);
|
||||
static void _dns_server_request_get(struct dns_request *request);
|
||||
static void _dns_server_request_release(struct dns_request *request);
|
||||
@@ -477,6 +480,11 @@ static void _dns_server_audit_log(struct dns_server_post_context *context)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
|
||||
strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *fmt = "%d.%d.%d.%d";
|
||||
if (ip_num > 0) {
|
||||
fmt = ", %d.%d.%d.%d";
|
||||
@@ -492,6 +500,12 @@ static void _dns_server_audit_log(struct dns_server_post_context *context)
|
||||
if (dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, ipv6_addr) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
|
||||
strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char *fmt = "%s";
|
||||
if (ip_num > 0) {
|
||||
fmt = ", %s";
|
||||
@@ -543,8 +557,9 @@ static void _dns_server_audit_log(struct dns_server_post_context *context)
|
||||
snprintf(req_time, sizeof(req_time), "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d]", tm.year, tm.mon, tm.mday, tm.hour,
|
||||
tm.min, tm.sec, tm.usec / 1000);
|
||||
|
||||
tlog_printf(dns_audit, "%s %s query %s, time %lums, type %d, result %s\n", req_time, req_host, request->domain,
|
||||
get_tick_count() - request->send_tick, request->qtype, req_result);
|
||||
tlog_printf(dns_audit, "%s %s query %s, type %d, time %lums, speed: %.1fms, result %s\n", req_time, req_host,
|
||||
request->domain, request->qtype, get_tick_count() - request->send_tick,
|
||||
((float)request->ping_time) / 10, req_result);
|
||||
}
|
||||
|
||||
static void _dns_rrs_result_log(struct dns_server_post_context *context, struct dns_ip_address *addr_map)
|
||||
@@ -872,7 +887,7 @@ static int _dns_server_reply_udp(struct dns_request *request, struct dns_server_
|
||||
unsigned char *inpacket, int inpacket_len)
|
||||
{
|
||||
int send_len = 0;
|
||||
if (atomic_read(&server.run) == 0) {
|
||||
if (atomic_read(&server.run) == 0 || inpacket == NULL || inpacket_len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -909,7 +924,7 @@ static int _dns_reply_inpacket(struct dns_request *request, unsigned char *inpac
|
||||
}
|
||||
|
||||
static int _dns_server_request_update_cache(struct dns_request *request, dns_type_t qtype,
|
||||
struct dns_cache_data *cache_data, int has_soa)
|
||||
struct dns_cache_data *cache_data, int has_soa, int cache_ttl)
|
||||
{
|
||||
int ttl = 0;
|
||||
int speed = 0;
|
||||
@@ -918,19 +933,31 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ttl = _dns_server_get_conf_ttl(request->ip_ttl);
|
||||
if (cache_ttl > 0) {
|
||||
ttl = cache_ttl;
|
||||
} else {
|
||||
ttl = _dns_server_get_conf_ttl(request->ip_ttl);
|
||||
}
|
||||
speed = request->ping_time;
|
||||
|
||||
if (has_soa) {
|
||||
struct dns_cache_query_option cache_option;
|
||||
|
||||
if (request->dualstack_selection && request->has_ip && request->qtype == DNS_T_AAAA) {
|
||||
ttl = _dns_server_get_conf_ttl(request->ip_ttl);
|
||||
} else {
|
||||
ttl = dns_conf_rr_ttl;
|
||||
if (ttl == 0) {
|
||||
ttl = DNS_SERVER_TMOUT_TTL;
|
||||
}
|
||||
}
|
||||
dns_cache_set_data_soa(cache_data, request->server_flags, request->cname, request->ttl_cname);
|
||||
|
||||
cache_option.query_flag = request->server_flags;
|
||||
cache_option.dns_group_name = 0;
|
||||
dns_cache_set_data_soa(cache_data, &cache_option, request->cname, request->ttl_cname);
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "cache %s qtype:%d ttl: %d\n", request->domain, qtype, ttl);
|
||||
tlog(TLOG_DEBUG, "cache %s qtype: %d ttl: %d\n", request->domain, qtype, ttl);
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
if (request->prefetch) {
|
||||
@@ -962,6 +989,7 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
||||
{
|
||||
struct dns_packet *packet = context->packet;
|
||||
struct dns_packet *cname_packet = NULL;
|
||||
struct dns_cache_query_option cache_option;
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
@@ -1006,6 +1034,10 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(request->cname, name, DNS_MAX_CNAME_LEN - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = dns_add_A(cname_packet, DNS_RRS_AN, request->cname, ttl, ipv4_addr);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
@@ -1018,6 +1050,10 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(request->cname, name, DNS_MAX_CNAME_LEN - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = dns_add_AAAA(cname_packet, DNS_RRS_AN, request->cname, ttl, ipv6_addr);
|
||||
if (ret != 0) {
|
||||
return -1;
|
||||
@@ -1051,7 +1087,10 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
||||
if (inpacket_len <= 0) {
|
||||
return -1;
|
||||
}
|
||||
cache_packet = dns_cache_new_data_packet(request->server_flags, inpacket_buff, inpacket_len);
|
||||
|
||||
cache_option.query_flag = request->server_flags;
|
||||
cache_option.dns_group_name = request->dns_group_name;
|
||||
cache_packet = dns_cache_new_data_packet(&cache_option, inpacket_buff, inpacket_len);
|
||||
if (cache_packet == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1094,9 +1133,13 @@ errout:
|
||||
|
||||
static int _dns_cache_packet(struct dns_server_post_context *context)
|
||||
{
|
||||
struct dns_cache_query_option cache_option;
|
||||
struct dns_request *request = context->request;
|
||||
|
||||
cache_option.query_flag = request->server_flags;
|
||||
cache_option.dns_group_name = request->dns_group_name;
|
||||
struct dns_cache_data *cache_packet =
|
||||
dns_cache_new_data_packet(request->server_flags, context->inpacket, context->inpacket_len);
|
||||
dns_cache_new_data_packet(&cache_option, context->inpacket, context->inpacket_len);
|
||||
if (cache_packet == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1220,8 +1263,11 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
|
||||
return _dns_cache_specify_packet(context);
|
||||
}
|
||||
|
||||
struct dns_cache_query_option cache_option;
|
||||
cache_option.query_flag = request->server_flags;
|
||||
cache_option.dns_group_name = request->dns_group_name;
|
||||
struct dns_cache_data *cache_packet =
|
||||
dns_cache_new_data_packet(request->server_flags, context->inpacket, context->inpacket_len);
|
||||
dns_cache_new_data_packet(&cache_option, context->inpacket, context->inpacket_len);
|
||||
if (cache_packet == NULL) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1234,7 +1280,7 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
|
||||
has_soa = 0;
|
||||
}
|
||||
|
||||
if (_dns_server_request_update_cache(request, context->qtype, cache_packet, has_soa) != 0) {
|
||||
if (_dns_server_request_update_cache(request, context->qtype, cache_packet, has_soa, context->cache_ttl) != 0) {
|
||||
tlog(TLOG_WARN, "update packet cache failed.");
|
||||
}
|
||||
|
||||
@@ -1759,10 +1805,6 @@ static void _dns_server_complete_with_multi_ipaddress(struct dns_request *reques
|
||||
struct dns_server_post_context context;
|
||||
int do_reply = 0;
|
||||
|
||||
if (request->passthrough) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_read(&request->ip_map_num) > 0) {
|
||||
request->has_soa = 0;
|
||||
}
|
||||
@@ -1937,6 +1979,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
int may_complete = 0;
|
||||
int threshold = 100;
|
||||
struct dns_ip_address *addr_map = NULL;
|
||||
int last_rtt = request->ping_time;
|
||||
|
||||
if (request == NULL) {
|
||||
return;
|
||||
@@ -1948,6 +1991,7 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
return;
|
||||
} else if (result == PING_RESULT_TIMEOUT) {
|
||||
tlog(TLOG_DEBUG, "ping %s timeout", host);
|
||||
goto out;
|
||||
return;
|
||||
} else if (result == PING_RESULT_ERROR) {
|
||||
if (addr->sa_family != AF_INET6) {
|
||||
@@ -1965,7 +2009,6 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
}
|
||||
|
||||
int rtt = tv->tv_sec * 10000 + tv->tv_usec / 100;
|
||||
int last_rtt = request->ping_time;
|
||||
|
||||
if (result == PING_RESULT_RESPONSE) {
|
||||
tlog(TLOG_DEBUG, "from %s: seq=%d time=%d, lasttime=%d id=%d", host, seqno, rtt, last_rtt, request->id);
|
||||
@@ -2058,10 +2101,18 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
/* If the ping delay is less than the threshold, the result is returned */
|
||||
if (rtt < threshold) {
|
||||
may_complete = 1;
|
||||
} else if (rtt < (int)(get_tick_count() - request->send_tick) * 8) {
|
||||
if (request->ping_time > 0) {
|
||||
if (request->ping_time < threshold) {
|
||||
may_complete = 1;
|
||||
} else if (request->ping_time < (int)(get_tick_count() - request->send_tick) * 8) {
|
||||
may_complete = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get first ping result */
|
||||
if (dns_conf_response_mode == DNS_RESPONSE_MODE_FIRST_PING_IP && last_rtt == -1 && request->ping_time > 0) {
|
||||
may_complete = 1;
|
||||
}
|
||||
|
||||
@@ -2204,8 +2255,8 @@ static int _dns_server_is_adblock_ipv6(const unsigned char addr[16])
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request *request, const char *domain, char *cname,
|
||||
unsigned int result_flag)
|
||||
static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request *request, const char *domain,
|
||||
char *cname, unsigned int result_flag)
|
||||
{
|
||||
int ttl = 0;
|
||||
int ip_check_result = 0;
|
||||
@@ -2282,8 +2333,8 @@ static int _dns_server_process_answer_A(struct dns_rrs *rrs, struct dns_request
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_request *request, const char *domain, char *cname,
|
||||
unsigned int result_flag)
|
||||
static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_request *request, const char *domain,
|
||||
char *cname, unsigned int result_flag)
|
||||
{
|
||||
unsigned char addr[16];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
@@ -2408,10 +2459,17 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
|
||||
case DNS_T_NS: {
|
||||
char nsname[DNS_MAX_CNAME_LEN];
|
||||
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, nsname, DNS_MAX_CNAME_LEN);
|
||||
tlog(TLOG_DEBUG, "NS: %s ttl:%d nsname: %s\n", name, ttl, nsname);
|
||||
tlog(TLOG_DEBUG, "NS: %s ttl: %d nsname: %s\n", name, ttl, nsname);
|
||||
} break;
|
||||
case DNS_T_CNAME: {
|
||||
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
|
||||
char domain_name[DNS_MAX_CNAME_LEN] = {0};
|
||||
char domain_cname[DNS_MAX_CNAME_LEN] = {0};
|
||||
dns_get_CNAME(rrs, domain_name, DNS_MAX_CNAME_LEN, &ttl, domain_cname, DNS_MAX_CNAME_LEN);
|
||||
if (strncmp(domain_name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
|
||||
strncmp(domain_name, cname, DNS_MAX_CNAME_LEN - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
safe_strncpy(cname, domain_cname, DNS_MAX_CNAME_LEN);
|
||||
tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", name, ttl, cname);
|
||||
} break;
|
||||
case DNS_T_SOA: {
|
||||
@@ -2440,8 +2498,8 @@ static int _dns_server_process_answer(struct dns_request *request, const char *d
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_passthrough_rule_check(struct dns_request *request, const char *domain, struct dns_packet *packet,
|
||||
unsigned int result_flag, int *pttl)
|
||||
static int _dns_server_passthrough_rule_check(struct dns_request *request, const char *domain,
|
||||
struct dns_packet *packet, unsigned int result_flag, int *pttl)
|
||||
{
|
||||
int ttl = 0;
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
@@ -2486,7 +2544,7 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, const
|
||||
continue;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "domain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl_tmp, addr[0], addr[1], addr[2],
|
||||
tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %d.%d.%d.%d", name, ttl_tmp, addr[0], addr[1], addr[2],
|
||||
addr[3]);
|
||||
|
||||
/* ip rule check */
|
||||
@@ -2575,7 +2633,13 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
|
||||
/* get A result */
|
||||
dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
if (_dns_ip_address_check_add(request, name, addr, DNS_T_A) != 0) {
|
||||
|
||||
if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
|
||||
strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (context->no_check_add_ip == 0 && _dns_ip_address_check_add(request, name, addr, DNS_T_A) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2599,7 +2663,13 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
continue;
|
||||
}
|
||||
dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
if (_dns_ip_address_check_add(request, name, addr, DNS_T_AAAA) != 0) {
|
||||
|
||||
if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
|
||||
strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (context->no_check_add_ip == 0 && _dns_ip_address_check_add(request, name, addr, DNS_T_AAAA) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2617,7 +2687,7 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
|
||||
tlog(TLOG_DEBUG, "NS: %s ttl:%d cname: %s\n", name, ttl, cname);
|
||||
tlog(TLOG_DEBUG, "NS: %s ttl: %d cname: %s\n", name, ttl, cname);
|
||||
} break;
|
||||
case DNS_T_CNAME: {
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
@@ -2627,7 +2697,12 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
}
|
||||
|
||||
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
|
||||
tlog(TLOG_DEBUG, "name:%s ttl: %d cname: %s\n", name, ttl, cname);
|
||||
tlog(TLOG_DEBUG, "name: %s ttl: %d cname: %s\n", name, ttl, cname);
|
||||
if (strncmp(name, request->domain, DNS_MAX_CNAME_LEN - 1) != 0 &&
|
||||
strncmp(name, request->cname, DNS_MAX_CNAME_LEN - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
request->ttl_cname = _dns_server_get_conf_ttl(ttl);
|
||||
request->has_cname = 1;
|
||||
@@ -2644,9 +2719,6 @@ static int _dns_server_get_answer(struct dns_server_post_context *context)
|
||||
"%d, minimum: %d",
|
||||
request->domain, request->qtype, request->soa.mname, request->soa.rname, request->soa.serial,
|
||||
request->soa.refresh, request->soa.retry, request->soa.expire, request->soa.minimum);
|
||||
if (atomic_inc_return(&request->soa_num) >= (dns_server_num() / 2)) {
|
||||
_dns_server_request_complete(request);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
@@ -2754,10 +2826,10 @@ static int dns_server_resolve_callback(const char *domain, dns_result_type rtype
|
||||
}
|
||||
|
||||
if (rtype == DNS_QUERY_RESULT) {
|
||||
tlog(TLOG_DEBUG, "query result from server %s:%d, type: %d", dns_client_get_server_ip(server_info),
|
||||
tlog(TLOG_DEBUG, "query result from server %s: %d, type: %d", dns_client_get_server_ip(server_info),
|
||||
dns_client_get_server_port(server_info), dns_client_get_server_type(server_info));
|
||||
|
||||
if (request->passthrough) {
|
||||
if (request->passthrough && atomic_read(&request->notified) == 0) {
|
||||
struct dns_server_post_context context;
|
||||
int ttl = 0;
|
||||
ret = _dns_server_passthrough_rule_check(request, domain, packet, result_flag, &ttl);
|
||||
@@ -2778,6 +2850,33 @@ static int dns_server_resolve_callback(const char *domain, dns_result_type rtype
|
||||
context.reply_ttl = ttl;
|
||||
return _dns_server_reply_passthrouth(&context);
|
||||
}
|
||||
|
||||
if (request->prefetch == 0 && dns_conf_response_mode == DNS_RESPONSE_MODE_FASTEST_RESPONSE &&
|
||||
atomic_read(&request->notified) == 0) {
|
||||
struct dns_server_post_context context;
|
||||
int ttl = 0;
|
||||
ret = _dns_server_passthrough_rule_check(request, domain, packet, result_flag, &ttl);
|
||||
if (ret != 0) {
|
||||
_dns_server_post_context_init_from(&context, request, packet, inpacket, inpacket_len);
|
||||
context.do_cache = 1;
|
||||
context.do_audit = 1;
|
||||
context.do_reply = 1;
|
||||
context.do_ipset = 1;
|
||||
context.reply_ttl = 2;
|
||||
context.cache_ttl = 2;
|
||||
context.no_check_add_ip = 1;
|
||||
_dns_server_reply_passthrouth(&context);
|
||||
request->cname[0] = 0;
|
||||
request->has_ip = 0;
|
||||
request->has_cname = 0;
|
||||
request->has_ping_result = 0;
|
||||
request->has_soa = 0;
|
||||
request->has_ptr = 0;
|
||||
request->ping_time = -1;
|
||||
request->ip_ttl = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_dns_server_process_answer(request, domain, packet, result_flag);
|
||||
return 0;
|
||||
} else if (rtype == DNS_QUERY_ERR) {
|
||||
@@ -3314,7 +3413,7 @@ static int _dns_server_process_address(struct dns_request *request)
|
||||
}
|
||||
|
||||
request->rcode = DNS_RC_NOERROR;
|
||||
request->ip_ttl = 600;
|
||||
request->ip_ttl = dns_conf_local_ttl;
|
||||
request->has_ip = 1;
|
||||
|
||||
struct dns_server_post_context context;
|
||||
@@ -3447,6 +3546,7 @@ static int _dns_server_process_cache_packet(struct dns_request *request, struct
|
||||
request->ping_time = dns_cache->info.speed;
|
||||
|
||||
if (dns_decode(context.packet, context.packet_maxlen, cache_packet->data, cache_packet->head.size) != 0) {
|
||||
tlog(TLOG_ERROR, "decode cache failed, %d, %d", context.packet_maxlen, context.inpacket_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -3560,18 +3660,21 @@ reply_cache:
|
||||
|
||||
out_update_cache:
|
||||
if (dns_cache_get_ttl(dns_cache) == 0) {
|
||||
uint32_t server_flags = request->server_flags;
|
||||
struct dns_query_options options;
|
||||
struct dns_server_query_option dns_query_options;
|
||||
dns_query_options.server_flags = request->server_flags;
|
||||
dns_query_options.dns_group_name = request->dns_group_name;
|
||||
if (request->conn == NULL) {
|
||||
server_flags = dns_cache_get_cache_flag(dns_cache->cache_data);
|
||||
dns_query_options.server_flags = dns_cache_get_query_flag(dns_cache->cache_data);
|
||||
dns_query_options.dns_group_name = dns_cache_get_dns_group_name(dns_cache->cache_data);
|
||||
}
|
||||
|
||||
options.enable_flag = 0;
|
||||
dns_query_options.ecs_enable_flag = 0;
|
||||
if (request->has_ecs) {
|
||||
options.enable_flag |= DNS_QUEY_OPTION_ECS_DNS;
|
||||
memcpy(&options.ecs_dns, &request->ecs, sizeof(options.ecs_dns));
|
||||
dns_query_options.ecs_enable_flag |= DNS_QUEY_OPTION_ECS_DNS;
|
||||
memcpy(&dns_query_options.ecs_dns, &request->ecs, sizeof(dns_query_options.ecs_dns));
|
||||
}
|
||||
_dns_server_prefetch_request(request->domain, request->qtype, 0, server_flags, &options);
|
||||
|
||||
_dns_server_prefetch_request(request->domain, request->qtype, 0, &dns_query_options);
|
||||
} else {
|
||||
dns_cache_update(dns_cache);
|
||||
}
|
||||
@@ -3831,7 +3934,7 @@ static int _dns_server_process_host(struct dns_request *request)
|
||||
}
|
||||
|
||||
request->rcode = DNS_RC_NOERROR;
|
||||
request->ip_ttl = 600;
|
||||
request->ip_ttl = dns_conf_local_ttl;
|
||||
request->has_ip = 1;
|
||||
|
||||
struct dns_server_post_context context;
|
||||
@@ -3882,6 +3985,7 @@ static int _dns_server_query_dualstack(struct dns_request *request)
|
||||
}
|
||||
|
||||
request_dualstack->server_flags = request->server_flags;
|
||||
safe_strncpy(request_dualstack->dns_group_name, request->dns_group_name, sizeof(request->dns_group_name));
|
||||
safe_strncpy(request_dualstack->domain, request->domain, sizeof(request->domain));
|
||||
request_dualstack->qtype = qtype;
|
||||
request_dualstack->dualstack_selection_query = 1;
|
||||
@@ -3926,14 +4030,16 @@ static int _dns_server_do_query(struct dns_request *request)
|
||||
|
||||
/* lookup domain rule */
|
||||
_dns_server_get_domain_rule(request);
|
||||
group_name = _dns_server_get_request_groupname(request);
|
||||
if (group_name == NULL) {
|
||||
group_name = dns_group;
|
||||
|
||||
group_name = request->dns_group_name;
|
||||
if (request->dns_group_name[0] == '\0') {
|
||||
group_name = _dns_server_get_request_groupname(request);
|
||||
if (group_name == NULL) {
|
||||
group_name = dns_group;
|
||||
}
|
||||
safe_strncpy(request->dns_group_name, group_name, DNS_GROUP_NAME_LEN);
|
||||
}
|
||||
|
||||
if (_dns_server_process_host(request) == 0) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
_dns_server_set_dualstack_selection(request);
|
||||
|
||||
@@ -3951,6 +4057,10 @@ static int _dns_server_do_query(struct dns_request *request)
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
if (_dns_server_process_host(request) == 0) {
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
/* process qtype soa */
|
||||
if (_dns_server_qtype_soa(request) == 0) {
|
||||
goto clean_exit;
|
||||
@@ -4073,6 +4183,9 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
|
||||
if (decode_len < 0) {
|
||||
tlog(TLOG_DEBUG, "decode failed.\n");
|
||||
ret = RECV_ERROR_INVALID_PACKET;
|
||||
if (dns_save_fail_packet) {
|
||||
dns_packet_save(dns_save_fail_packet_dir, "server", name, inpacket, inpacket_len);
|
||||
}
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -4089,6 +4202,8 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
|
||||
}
|
||||
|
||||
if (_dns_server_parser_request(request, packet) != 0) {
|
||||
tlog(TLOG_DEBUG, "parser request failed.");
|
||||
ret = RECV_ERROR_INVALID_PACKET;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -4107,29 +4222,35 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
|
||||
return ret;
|
||||
errout:
|
||||
if (request) {
|
||||
ret = _dns_server_forward_request(inpacket, inpacket_len);
|
||||
_dns_server_forward_request(inpacket, inpacket_len);
|
||||
_dns_server_request_release(request);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_server_prefetch_setup_options(struct dns_request *request, struct dns_query_options *options)
|
||||
static int _dns_server_setup_server_query_options(struct dns_request *request,
|
||||
struct dns_server_query_option *server_query_option)
|
||||
{
|
||||
if (options == NULL) {
|
||||
if (server_query_option == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options->enable_flag & DNS_QUEY_OPTION_ECS_DNS) {
|
||||
request->server_flags = server_query_option->server_flags;
|
||||
if (server_query_option->dns_group_name) {
|
||||
safe_strncpy(request->dns_group_name, server_query_option->dns_group_name, DNS_GROUP_NAME_LEN);
|
||||
}
|
||||
|
||||
if (server_query_option->ecs_enable_flag & DNS_QUEY_OPTION_ECS_DNS) {
|
||||
request->has_ecs = 1;
|
||||
memcpy(&request->ecs, &options->ecs_dns, sizeof(request->ecs));
|
||||
memcpy(&request->ecs, &server_query_option->ecs_dns, sizeof(request->ecs));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expired_domain, uint32_t server_flags,
|
||||
struct dns_query_options *options)
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expired_domain,
|
||||
struct dns_server_query_option *server_query_option)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dns_request *request = NULL;
|
||||
@@ -4142,8 +4263,7 @@ static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, int expi
|
||||
|
||||
safe_strncpy(request->domain, domain, sizeof(request->domain));
|
||||
request->qtype = qtype;
|
||||
request->server_flags = server_flags;
|
||||
_dns_server_prefetch_setup_options(request, options);
|
||||
_dns_server_setup_server_query_options(request, server_query_option);
|
||||
_dns_server_request_set_enable_prefetch(request, expired_domain);
|
||||
ret = _dns_server_do_query(request);
|
||||
if (ret != 0) {
|
||||
@@ -4161,7 +4281,8 @@ errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dns_server_query(const char *domain, int qtype, uint32_t server_flags, dns_result_callback callback, void *user_ptr)
|
||||
int dns_server_query(const char *domain, int qtype, struct dns_server_query_option *server_query_option,
|
||||
dns_result_callback callback, void *user_ptr)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dns_request *request = NULL;
|
||||
@@ -4172,9 +4293,9 @@ int dns_server_query(const char *domain, int qtype, uint32_t server_flags, dns_r
|
||||
goto errout;
|
||||
}
|
||||
|
||||
request->server_flags = server_flags;
|
||||
safe_strncpy(request->domain, domain, sizeof(request->domain));
|
||||
request->qtype = qtype;
|
||||
_dns_server_setup_server_query_options(request, server_query_option);
|
||||
_dns_server_request_set_callback(request, callback, user_ptr);
|
||||
ret = _dns_server_do_query(request);
|
||||
if (ret != 0) {
|
||||
@@ -4570,6 +4691,7 @@ static int _dns_server_second_ping_check(struct dns_request *request)
|
||||
static void _dns_server_prefetch_domain(struct dns_cache *dns_cache)
|
||||
{
|
||||
/* If there are still hits, continue pre-fetching */
|
||||
struct dns_server_query_option server_query_option;
|
||||
int hitnum = dns_cache_hitnum_dec_get(dns_cache);
|
||||
if (hitnum <= 0) {
|
||||
return;
|
||||
@@ -4578,8 +4700,10 @@ static void _dns_server_prefetch_domain(struct dns_cache *dns_cache)
|
||||
/* start prefetch domain */
|
||||
tlog(TLOG_DEBUG, "prefetch by cache %s, qtype %d, ttl %d, hitnum %d", dns_cache->info.domain, dns_cache->info.qtype,
|
||||
dns_cache->info.ttl, hitnum);
|
||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 0,
|
||||
dns_cache_get_cache_flag(dns_cache->cache_data), NULL) != 0) {
|
||||
server_query_option.dns_group_name = dns_cache_get_dns_group_name(dns_cache->cache_data);
|
||||
server_query_option.server_flags = dns_cache_get_query_flag(dns_cache->cache_data);
|
||||
server_query_option.ecs_enable_flag = 0;
|
||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 0, &server_query_option) != 0) {
|
||||
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
|
||||
}
|
||||
}
|
||||
@@ -4590,8 +4714,12 @@ static void _dns_server_prefetch_expired_domain(struct dns_cache *dns_cache)
|
||||
tlog(TLOG_DEBUG, "expired domain, prefetch by cache %s, qtype %d, ttl %d", dns_cache->info.domain,
|
||||
dns_cache->info.qtype, dns_cache->info.ttl);
|
||||
|
||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 1,
|
||||
dns_cache_get_cache_flag(dns_cache->cache_data), NULL) != 0) {
|
||||
struct dns_server_query_option server_query_option;
|
||||
server_query_option.dns_group_name = dns_cache_get_dns_group_name(dns_cache->cache_data);
|
||||
server_query_option.server_flags = dns_cache_get_query_flag(dns_cache->cache_data);
|
||||
server_query_option.ecs_enable_flag = 0;
|
||||
|
||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 1, &server_query_option) != 0) {
|
||||
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,20 @@
|
||||
|
||||
#include "dns.h"
|
||||
#include <stdint.h>
|
||||
#include "dns_client.h"
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct dns_server_query_option {
|
||||
uint32_t server_flags;
|
||||
const char *dns_group_name;
|
||||
unsigned long ecs_enable_flag;
|
||||
struct dns_opt_ecs ecs_dns;
|
||||
struct dns_query_ecs_ip ecs_ip;
|
||||
};
|
||||
|
||||
int dns_server_init(void);
|
||||
|
||||
int dns_server_run(void);
|
||||
@@ -41,7 +50,8 @@ typedef int (*dns_result_callback)(const char *domain, dns_rtcode_t rtcode, dns_
|
||||
unsigned int ping_time, void *user_ptr);
|
||||
|
||||
/* query domain */
|
||||
int dns_server_query(const char *domain, int qtype, uint32_t server_flags, dns_result_callback callback, void *user_ptr);
|
||||
int dns_server_query(const char *domain, int qtype, struct dns_server_query_option *server_query_option,
|
||||
dns_result_callback callback, void *user_ptr);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
|
||||
@@ -673,6 +673,12 @@ static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type)
|
||||
}
|
||||
}
|
||||
if (fd < 0) {
|
||||
if (errno == EACCES || errno == EAFNOSUPPORT) {
|
||||
if (bool_print_log == 0) {
|
||||
goto errout;
|
||||
}
|
||||
bool_print_log = 0;
|
||||
}
|
||||
tlog(TLOG_ERROR, "create icmp socket failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
@@ -689,6 +695,12 @@ static int _fast_ping_create_icmp_sock(FAST_PING_TYPE type)
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
if (errno == EACCES || errno == EAFNOSUPPORT) {
|
||||
if (bool_print_log == 0) {
|
||||
goto errout;
|
||||
}
|
||||
bool_print_log = 0;
|
||||
}
|
||||
tlog(TLOG_ERROR, "create icmp socket failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,16 @@ struct config_item_size {
|
||||
size_t max;
|
||||
};
|
||||
|
||||
struct config_enum_list {
|
||||
char *name;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct config_enum {
|
||||
int *data;
|
||||
struct config_enum_list *list;
|
||||
};
|
||||
|
||||
#define CONF_INT(key, value, min_value, max_value) \
|
||||
{ \
|
||||
key, conf_int, &(struct config_item_int) \
|
||||
@@ -92,6 +102,15 @@ struct config_item_size {
|
||||
.data = value, .min = min_value, .max = max_value \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CONF_ENUM(key, value, enum) \
|
||||
{ \
|
||||
key, conf_enum, &(struct config_enum) \
|
||||
{ \
|
||||
.data = (int *)value, .list = (struct config_enum_list *)enum \
|
||||
} \
|
||||
}
|
||||
|
||||
/*
|
||||
* func: int (*func)(void *data, int argc, char *argv[]);
|
||||
*/
|
||||
@@ -118,6 +137,8 @@ extern int conf_yesno(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
extern int conf_size(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
extern int conf_enum(const char *item, void *data, int argc, char *argv[]);
|
||||
|
||||
/*
|
||||
* Example:
|
||||
* int num = 0;
|
||||
|
||||
@@ -24,6 +24,15 @@
|
||||
|
||||
static inline char *safe_strncpy(char *dest, const char *src, size_t n)
|
||||
{
|
||||
if (src == NULL) {
|
||||
dest[0] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
if (n <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if __GNUC__ > 7
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstringop-truncation"
|
||||
|
||||
@@ -97,7 +97,6 @@ int conf_yesno(const char *item, void *data, int argc, char *argv[])
|
||||
|
||||
int conf_size(const char *item, void *data, int argc, char *argv[])
|
||||
{
|
||||
/* read dns cache size */
|
||||
int base = 1;
|
||||
size_t size = 0;
|
||||
int num = 0;
|
||||
@@ -129,6 +128,31 @@ int conf_size(const char *item, void *data, int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conf_enum(const char *item, void *data, int argc, char *argv[])
|
||||
{
|
||||
struct config_enum *item_enum = data;
|
||||
char *enum_name = argv[1];
|
||||
int i = 0;
|
||||
|
||||
if (argc <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; item_enum->list[i].name != NULL; i++) {
|
||||
if (strcmp(enum_name, item_enum->list[i].name) == 0) {
|
||||
*(item_enum->data) = item_enum->list[i].id;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Not found config value '%s', valid value is:\n", enum_name);
|
||||
for (i = 0; item_enum->list[i].name != NULL; i++) {
|
||||
printf(" %s\n", item_enum->list[i].name);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void conf_getopt_reset(void)
|
||||
{
|
||||
static struct option long_options[] = {{"-", 0, 0, 0}, {0, 0, 0, 0}};
|
||||
|
||||
@@ -114,8 +114,8 @@ static int drop_root_privilege(void)
|
||||
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
|
||||
cap.effective |= (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN);
|
||||
cap.permitted |= (1 << CAP_NET_RAW | 1 << CAP_NET_ADMIN);
|
||||
unused = setuid(uid);
|
||||
unused = setgid(gid);
|
||||
unused = setuid(uid);
|
||||
if (capset(&header, &cap) < 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -132,7 +132,7 @@ static void _help(void)
|
||||
"Start smartdns server.\n"
|
||||
" -f run forground.\n"
|
||||
" -c [conf] config file.\n"
|
||||
" -p [pid] pid file path\n"
|
||||
" -p [pid] pid file path, '-' means don't create pid file.\n"
|
||||
" -S ignore segment fault signal.\n"
|
||||
" -x verbose screen.\n"
|
||||
" -v dispaly version.\n"
|
||||
@@ -323,15 +323,22 @@ static int _smartdns_destroy_ssl(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _smartdns_init(void)
|
||||
static const char *_smartdns_log_path(void)
|
||||
{
|
||||
int ret = 0;
|
||||
char *logfile = SMARTDNS_LOG_FILE;
|
||||
|
||||
if (dns_conf_log_file[0] != 0) {
|
||||
logfile = dns_conf_log_file;
|
||||
}
|
||||
|
||||
return logfile;
|
||||
}
|
||||
|
||||
static int _smartdns_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
const char *logfile = _smartdns_log_path();
|
||||
|
||||
ret = tlog_init(logfile, dns_conf_log_size, dns_conf_log_num, 0, 0);
|
||||
if (ret != 0) {
|
||||
tlog(TLOG_ERROR, "start tlog failed.\n");
|
||||
@@ -341,7 +348,7 @@ static int _smartdns_init(void)
|
||||
tlog_setlogscreen(verbose_screen);
|
||||
tlog_setlevel(dns_conf_log_level);
|
||||
|
||||
tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <pymumu@gmail.com>, build:%s %s)", __DATE__,
|
||||
tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <pymumu@gmail.com>, build: %s %s)", __DATE__,
|
||||
__TIME__);
|
||||
|
||||
if (_smartdns_init_ssl() != 0) {
|
||||
@@ -463,6 +470,43 @@ static void _reg_signal(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int _smartdns_create_logdir(void)
|
||||
{
|
||||
int uid = 0;
|
||||
int gid = 0;
|
||||
char logdir[PATH_MAX] = {0};
|
||||
safe_strncpy(logdir, _smartdns_log_path(), PATH_MAX);
|
||||
dirname(logdir);
|
||||
|
||||
if (access(logdir, F_OK) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mkdir(logdir, 0750) != 0) {
|
||||
if (errno == EEXIST) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unused __attribute__((unused)) = 0;
|
||||
|
||||
if (get_uid_gid(&uid, &gid) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
chown(logdir, uid, gid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _smartdns_init_pre(void)
|
||||
{
|
||||
_smartdns_create_logdir();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -480,7 +524,7 @@ int main(int argc, char *argv[])
|
||||
sigemptyset(&empty_sigblock);
|
||||
sigprocmask(SIG_SETMASK, &empty_sigblock, NULL);
|
||||
|
||||
while ((opt = getopt(argc, argv, "fhc:p:Svx")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "fhc:p:SvxN:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
is_forground = 1;
|
||||
@@ -501,6 +545,10 @@ int main(int argc, char *argv[])
|
||||
_show_version();
|
||||
return 0;
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
case 'N':
|
||||
return dns_packet_debug(optarg);
|
||||
#endif
|
||||
case 'h':
|
||||
_help();
|
||||
return 1;
|
||||
@@ -523,7 +571,7 @@ int main(int argc, char *argv[])
|
||||
_reg_signal();
|
||||
}
|
||||
|
||||
if (create_pid_file(pid_file) != 0) {
|
||||
if (strncmp(pid_file, "-", 2) != 0 && create_pid_file(pid_file) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -531,6 +579,11 @@ int main(int argc, char *argv[])
|
||||
signal(SIGINT, _sig_exit);
|
||||
signal(SIGTERM, _sig_exit);
|
||||
|
||||
if (_smartdns_init_pre() != 0) {
|
||||
fprintf(stderr, "init failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
drop_root_privilege();
|
||||
|
||||
ret = _smartdns_init();
|
||||
|
||||
43
src/tlog.c
43
src/tlog.c
@@ -79,6 +79,7 @@ struct tlog_log {
|
||||
int zip_pid;
|
||||
int multi_log;
|
||||
int logscreen;
|
||||
int no_write_log;
|
||||
int segment_log;
|
||||
int max_line_size;
|
||||
|
||||
@@ -216,7 +217,6 @@ static int _tlog_mkdir(const char *path)
|
||||
}
|
||||
|
||||
if (mkdir(path_c, 0750) != 0) {
|
||||
fprintf(stderr, "create directory %s failed, %s\n", path_c, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1130,6 +1130,10 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
unused = write(STDOUT_FILENO, buff, bufflen);
|
||||
}
|
||||
|
||||
if (log->no_write_log) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if log file size exceeds threshold, start to compress */
|
||||
if (log->multi_log && log->fd > 0) {
|
||||
log->filesize = lseek(log->fd, 0, SEEK_END);
|
||||
@@ -1160,7 +1164,15 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
|
||||
char logfile[PATH_MAX * 2];
|
||||
if (_tlog_mkdir(log->logdir) != 0) {
|
||||
fprintf(stderr, "create log dir %s failed.\n", log->logdir);
|
||||
if (print_errmsg == 0) {
|
||||
return -1;
|
||||
}
|
||||
print_errmsg = 0;
|
||||
fprintf(stderr, "create log dir %s failed, %s\n", log->logdir, strerror(errno));
|
||||
if (errno == EACCES && log->logscreen == 0) {
|
||||
fprintf(stderr, "no permission to write log file, output log to console\n");
|
||||
tlog_logscreen_only(log, 1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
snprintf(logfile, sizeof(logfile), "%s/%s", log->logdir, log->logname);
|
||||
@@ -1574,11 +1586,26 @@ static void _tlog_log_setlogscreen(struct tlog_log *log, int enable)
|
||||
log->logscreen = (enable != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void _tlog_log_setlogscreen_only(struct tlog_log *log, int enable)
|
||||
{
|
||||
if (log == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
log->logscreen = (enable != 0) ? 1 : 0;
|
||||
log->no_write_log = (enable != 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
void tlog_setlogscreen(int enable)
|
||||
{
|
||||
_tlog_log_setlogscreen(tlog.root, enable);
|
||||
}
|
||||
|
||||
void tlog_setlogscreen_only(int enable)
|
||||
{
|
||||
_tlog_log_setlogscreen_only(tlog.root, enable);
|
||||
}
|
||||
|
||||
int tlog_write_log(char *buff, int bufflen)
|
||||
{
|
||||
if (unlikely(tlog.root == NULL)) {
|
||||
@@ -1597,6 +1624,15 @@ void tlog_logscreen(tlog_log *log, int enable)
|
||||
_tlog_log_setlogscreen(log, enable);
|
||||
}
|
||||
|
||||
void tlog_logscreen_only(tlog_log *log, int enable)
|
||||
{
|
||||
if (log == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
_tlog_log_setlogscreen_only(log, enable);
|
||||
}
|
||||
|
||||
int tlog_reg_output_func(tlog_log *log, tlog_output_func output)
|
||||
{
|
||||
if (log == NULL) {
|
||||
@@ -1830,13 +1866,13 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
|
||||
}
|
||||
tlog_reg_output_func(log, _tlog_root_write_log);
|
||||
|
||||
tlog.root = log;
|
||||
ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "create tlog work thread failed, %s\n", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog.root = log;
|
||||
if (flag & TLOG_SUPPORT_FORK) {
|
||||
pthread_atfork(&tlog_fork_prepare, &tlog_fork_parent, &tlog_fork_child);
|
||||
}
|
||||
@@ -1852,6 +1888,7 @@ errout:
|
||||
pthread_cond_destroy(&tlog.cond);
|
||||
pthread_mutex_destroy(&tlog.lock);
|
||||
tlog.run = 0;
|
||||
tlog.root = NULL;
|
||||
|
||||
_tlog_close(log, 1);
|
||||
|
||||
|
||||
@@ -104,6 +104,9 @@ extern void tlog_set_logfile(const char *logfile);
|
||||
/* enalbe log to screen */
|
||||
extern void tlog_setlogscreen(int enable);
|
||||
|
||||
/* output log to screen only */
|
||||
extern void tlog_setlogscreen_only(int enable);
|
||||
|
||||
/* enalbe early log to screen */
|
||||
extern void tlog_set_early_printf(int enable);
|
||||
|
||||
@@ -184,6 +187,9 @@ extern int tlog_vprintf(tlog_log *log, const char *format, va_list ap);
|
||||
/* enalbe log to screen */
|
||||
extern void tlog_logscreen(tlog_log *log, int enable);
|
||||
|
||||
/* enalbe log to screen only*/
|
||||
extern void tlog_logscreen_only(tlog_log *log, int enable);
|
||||
|
||||
/* register output callback */
|
||||
typedef int (*tlog_output_func)(struct tlog_log *log, const char *buff, int bufflen);
|
||||
extern int tlog_reg_output_func(tlog_log *log, tlog_output_func output);
|
||||
|
||||
283
src/util.c
283
src/util.c
@@ -34,12 +34,13 @@
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
@@ -79,6 +80,8 @@
|
||||
#define NETLINK_ALIGN(len) (((len) + 3) & ~(3))
|
||||
|
||||
#define BUFF_SZ 1024
|
||||
#define PACKET_BUF_SIZE 8192
|
||||
#define PACKET_MAGIC 0X11040918
|
||||
|
||||
struct ipset_netlink_attr {
|
||||
unsigned short len;
|
||||
@@ -641,7 +644,7 @@ unsigned char *SSL_SHA256(const unsigned char *d, size_t n, unsigned char *md)
|
||||
md = m;
|
||||
}
|
||||
|
||||
EVP_MD_CTX* ctx = EVP_MD_CTX_create();
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -1159,7 +1162,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, 0644);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1178,3 +1181,277 @@ errout:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_packet_save(const char *dir, const char *type, const char *from, const void *packet, int packet_len)
|
||||
{
|
||||
char *data = NULL;
|
||||
int data_len = 0;
|
||||
char filename[BUFF_SZ];
|
||||
char time_s[BUFF_SZ];
|
||||
int ret = -1;
|
||||
|
||||
struct tm *ptm;
|
||||
struct tm tm;
|
||||
struct timeval tmval;
|
||||
struct stat sb;
|
||||
|
||||
if (stat(dir, &sb) != 0) {
|
||||
mkdir(dir, 0750);
|
||||
}
|
||||
|
||||
if (gettimeofday(&tmval, NULL) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ptm = localtime_r(&tmval.tv_sec, &tm);
|
||||
if (ptm == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = snprintf(time_s, sizeof(time_s) - 1, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d.%.3d", ptm->tm_year + 1900,
|
||||
ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int)(tmval.tv_usec / 1000));
|
||||
ret = snprintf(filename, sizeof(filename) - 1, "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d%.1d.packet", dir, type,
|
||||
ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec,
|
||||
(int)(tmval.tv_usec / 100000));
|
||||
|
||||
data = malloc(PACKET_BUF_SIZE);
|
||||
if (data == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
data_len = snprintf(data, PACKET_BUF_SIZE,
|
||||
"type: %s\n"
|
||||
"from: %s\n"
|
||||
"time: %s\n"
|
||||
"packet-len: %d\n",
|
||||
type, from, time_s, packet_len);
|
||||
if (data_len <= 0 || data_len >= PACKET_BUF_SIZE) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
data[data_len] = 0;
|
||||
data_len++;
|
||||
uint32_t magic = htonl(PACKET_MAGIC);
|
||||
memcpy(data + data_len, &magic, sizeof(magic));
|
||||
data_len += sizeof(magic);
|
||||
int len_in_h = htonl(packet_len);
|
||||
memcpy(data + data_len, &len_in_h, sizeof(len_in_h));
|
||||
data_len += 4;
|
||||
memcpy(data + data_len, packet, packet_len);
|
||||
data_len += packet_len;
|
||||
|
||||
ret = write_file(filename, data, data_len);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (data) {
|
||||
free(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
struct _dns_read_packet_info {
|
||||
int data_len;
|
||||
int message_len;
|
||||
char *message;
|
||||
int packet_len;
|
||||
uint8_t *packet;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
static struct _dns_read_packet_info *_dns_read_packet_file(const char *packet_file)
|
||||
{
|
||||
struct _dns_read_packet_info *info = NULL;
|
||||
int fd = 0;
|
||||
int len = 0;
|
||||
int message_len = 0;
|
||||
uint8_t *ptr = NULL;
|
||||
|
||||
info = malloc(sizeof(struct _dns_read_packet_info) + PACKET_BUF_SIZE);
|
||||
fd = open(packet_file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
printf("open file %s failed, %s\n", packet_file, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
len = read(fd, info->data, PACKET_BUF_SIZE);
|
||||
if (len < 0) {
|
||||
printf("read file %s failed, %s\n", packet_file, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
message_len = strnlen((char *)info->data, PACKET_BUF_SIZE);
|
||||
if (message_len >= 512 || message_len >= len) {
|
||||
printf("invalid packet file, bad message len\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
info->message_len = message_len;
|
||||
info->message = (char *)info->data;
|
||||
|
||||
ptr = info->data + message_len + 1;
|
||||
uint32_t magic = 0;
|
||||
if (ptr - (uint8_t *)info + sizeof(magic) >= (size_t)len) {
|
||||
printf("invalid packet file, magic length is invalid.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memcpy(&magic, ptr, sizeof(magic));
|
||||
if (magic != htonl(PACKET_MAGIC)) {
|
||||
printf("invalid packet file, bad magic\n");
|
||||
goto errout;
|
||||
}
|
||||
ptr += sizeof(magic);
|
||||
|
||||
uint32_t packet_len = 0;
|
||||
if (ptr - info->data + sizeof(packet_len) >= (size_t)len) {
|
||||
printf("invalid packet file, packet length is invalid.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memcpy(&packet_len, ptr, sizeof(packet_len));
|
||||
packet_len = ntohl(packet_len);
|
||||
ptr += sizeof(packet_len);
|
||||
if (packet_len != (size_t)len - (ptr - info->data)) {
|
||||
printf("invalid packet file, packet length is invalid\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
info->packet_len = packet_len;
|
||||
info->packet = ptr;
|
||||
|
||||
close(fd);
|
||||
return info;
|
||||
errout:
|
||||
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (info) {
|
||||
free(info);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _dns_debug_display(struct dns_packet *packet)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int ttl = 0;
|
||||
struct dns_rrs *rrs = NULL;
|
||||
int rr_count = 0;
|
||||
char req_host[MAX_IP_LEN];
|
||||
|
||||
for (j = 1; j < DNS_RRS_END; j++) {
|
||||
rrs = dns_get_rrs_start(packet, j, &rr_count);
|
||||
printf("section: %d\n", j);
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
|
||||
switch (rrs->type) {
|
||||
case DNS_T_A: {
|
||||
unsigned char addr[4];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
/* get A result */
|
||||
dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
req_host[0] = '\0';
|
||||
inet_ntop(AF_INET, addr, req_host, sizeof(req_host));
|
||||
printf("domain: %s A: %s TTL: %d\n", name, req_host, ttl);
|
||||
} break;
|
||||
case DNS_T_AAAA: {
|
||||
unsigned char addr[16];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
req_host[0] = '\0';
|
||||
inet_ntop(AF_INET6, addr, req_host, sizeof(req_host));
|
||||
printf("domain: %s AAAA: %s TTL:%d\n", name, req_host, ttl);
|
||||
} break;
|
||||
case DNS_T_NS: {
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
|
||||
printf("domain: %s TTL: %d NS: %s\n", name, ttl, cname);
|
||||
} break;
|
||||
case DNS_T_CNAME: {
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
if (dns_conf_force_no_cname) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
|
||||
printf("domain: %s TTL: %d CNAME: %s\n", name, ttl, cname);
|
||||
} break;
|
||||
case DNS_T_SOA: {
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
struct dns_soa soa;
|
||||
dns_get_SOA(rrs, name, 128, &ttl, &soa);
|
||||
printf("domain: %s SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, expire: "
|
||||
"%d, minimum: %d",
|
||||
name, soa.mname, soa.rname, soa.serial, soa.refresh, soa.retry, soa.expire, soa.minimum);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_packet_debug(const char *packet_file)
|
||||
{
|
||||
struct _dns_read_packet_info *info = NULL;
|
||||
char buff[DNS_PACKSIZE];
|
||||
|
||||
tlog_setlogscreen_only(1);
|
||||
tlog_setlevel(TLOG_DEBUG);
|
||||
|
||||
info = _dns_read_packet_file(packet_file);
|
||||
if (info == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
const char *send_env = getenv("SMARTDNS_DEBUG_SEND");
|
||||
if (send_env != NULL) {
|
||||
char ip[32];
|
||||
int port = 53;
|
||||
if (parse_ip(send_env, ip, &port) == 0) {
|
||||
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sockfd > 0) {
|
||||
struct sockaddr_in server;
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons(port);
|
||||
server.sin_addr.s_addr = inet_addr(ip);
|
||||
sendto(sockfd, info->packet, info->packet_len, 0, (struct sockaddr *)&server, sizeof(server));
|
||||
close(sockfd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct dns_packet *packet = (struct dns_packet *)buff;
|
||||
if (dns_decode(packet, DNS_PACKSIZE, info->packet, info->packet_len) != 0) {
|
||||
printf("decode failed.\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
_dns_debug_display(packet);
|
||||
|
||||
free(info);
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (info) {
|
||||
free(info);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -126,6 +126,10 @@ void print_stack(void);
|
||||
|
||||
int write_file(const char *filename, void *data, int data_len);
|
||||
|
||||
int dns_packet_save(const char *dir, const char *type, const char *from, const void *packet, int packet_len);
|
||||
|
||||
int dns_packet_debug(const char *packet_file);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus */
|
||||
|
||||
Reference in New Issue
Block a user