Compare commits

..

34 Commits

Author SHA1 Message Date
Nick Peng
f50e4dd081 Revert "http: Fix http overflow bug"
This reverts commit ea8c1f47f8.
2021-08-27 19:22:20 +08:00
Nick Peng
ca6a9613d9 http: Fix http not working issue 2021-08-25 16:59:10 +08:00
Jian Chang
c88b334902 improve #754 (#756)
* improve #754
2021-08-25 16:55:16 +08:00
Jian Chang
017cd5cdc1 fix #689 2021-08-24 21:53:11 +08:00
Nick Peng
0e89d05ee7 Create c-cpp.yml 2021-08-24 16:44:44 +08:00
Nick Peng
772229c826 fast_ping: Avoid ping race condition crash issue 2021-08-23 14:19:22 +08:00
Nick Peng
7f1dc8a311 utils: Add print_stack function for debugging 2021-08-22 16:01:37 +08:00
Nick Peng
eff1f1b4c7 Updat readme 2021-08-21 20:42:25 +08:00
Nick Peng
ea8c1f47f8 http: Fix http overflow bug 2021-08-21 20:38:32 +08:00
Nick Peng
106ec6789c Make: update script mode 2021-08-21 20:38:32 +08:00
Nyaasu
8c271e34c1 Translate: Add units to reduce misunderstandings (#746)
* Translate: Add units to reduce misunderstandings
2021-08-09 22:21:35 +08:00
Nick Peng
756029f5e9 dns-client: avoid crash 2021-08-01 15:16:58 +08:00
Nick Peng
6338f1257c Update tlog 2021-08-01 15:12:41 +08:00
LoveSy
b77cea63e9 Update dns_server.c 2021-07-30 13:54:35 +08:00
LoveSy
f1ce462989 Support dual stack ipset 2021-07-30 13:54:35 +08:00
edison0354
e5eb562dee Update make.sh 2021-02-06 10:05:09 +08:00
Nick Peng
c53a87b8d9 SSL: reduce memory usage. 2021-01-31 03:04:17 +08:00
Nick Peng
f2fc970561 dns_client: check whether ssl cert is loaded. 2021-01-29 20:37:17 +08:00
J7S-xvH-rQV-sYR
328f44e800 Update ReadMe.md
点击第 20 行 的链接无法正常跳到对应 223 行的 openwrt 
因为 https://github.com/pymumu/smartdns#openwrtlede 不存在 对应的应该是 https://github.com/pymumu/smartdns#openwrt
修改后可以正常跳转。
2021-01-29 20:31:52 +08:00
Nick Peng
11cf7b614c dualstack: cache SOA record for speed. 2021-01-24 14:16:35 +08:00
Nick Peng
51e1e6565f MemLeak: fix memory leak when cache size is 0 2021-01-24 11:13:06 +08:00
dkadioglu
3ba8c418f7 Update luci-app-smartdns.json
With this small fix, the menu entry for smartdns is not shown anymore on the login page of openwrt.
2021-01-24 01:19:42 +08:00
Nick Peng
3e3859cfb1 BugFix: fix ssl cert load crash issue 2021-01-24 01:03:57 +08:00
Nick Peng
ac0ab0c916 Update ReadMe.md 2021-01-10 03:41:31 +08:00
Nick Peng
98be18f926 Domain-Rule: Support configuration of dualstack selection 2021-01-10 02:39:59 +08:00
Nick Peng
ed63c617bc BugFix: Fix issue #669, Contributed by Enna1 2021-01-09 12:31:15 +08:00
Felix Yan
81ce05e6af Improve systemd service description
It's used in journals.
2021-01-09 12:22:54 +08:00
Nick Peng
4e5248ebf3 BugFix: Fix issue #670, Contributed by Enna1 2021-01-09 12:19:07 +08:00
Nick Peng
ccd0f203fb dns-client: add some log 2021-01-09 12:06:58 +08:00
huyz-git
29d61d9373 Update ReadMe_en.md 2021-01-08 11:10:04 +08:00
huyz-git
4dcfd2c729 Update ReadMe.md 2021-01-08 11:10:04 +08:00
Purple Grape
42b3e98b2a drop el6 support
version of openssl must be 1.0.2 or higher
2020-09-29 23:46:07 +08:00
Purple Grape
81ecfa5dab Update smartdns.spec
mainly fix BuildRequires

now it's possiable to build rpm with the follow commands 
rpmbuild -ta smartdns-*.tar.gz
2020-09-19 21:19:53 +08:00
Felix Yan
baa1397fb0 Move TimeoutStopSec to [Service]
It belongs here. Setting it in [Unit] produces the following warning:

```
systemd[1]: /usr/lib/systemd/system/smartdns.service:6: Unknown key name 'TimeoutStopSec' in section 'Unit', ignoring.
```
2020-09-10 23:29:16 +08:00
33 changed files with 857 additions and 281 deletions

17
.github/workflows/c-cpp.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: C/C++ CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: make
run: make

4
.gitignore vendored
View File

@@ -1,4 +1,4 @@
.vscode
.o
*.o
.DS_Store
.swp.
*.swp.

View File

@@ -11,19 +11,26 @@ SmartDNS是一个运行在本地的DNS服务器SmartDNS接受本地客户端
## 目录
1. [软件效果展示](#软件效果展示)
1. [特性](#特性)
1. [架构](#架构)
1. [使用](#使用)
1. [下载配套安装包](#下载配套安装包)
1. [标准Linux系统安装](#标准linux系统安装树莓派x86_64系统)
1. [openwrt/LEDE](#openwrtlede)
1. [华硕路由器原生固件/梅林固件](#华硕路由器原生固件梅林固件)
1. [optware/entware](#optwareentware)
1. [Windows 10 WSL安装/WSL ubuntu](#windows-10-wsl安装wsl-ubuntu)
1. [配置参数](#配置参数)
1. [捐助](#donate)
1. [FAQ](#faq)
- [SmartDNS](#smartdns)
- [目录](#目录)
- [软件效果展示](#软件效果展示)
- [特性](#特性)
- [架构](#架构)
- [使用](#使用)
- [下载配套安装包](#下载配套安装包)
- [标准Linux系统安装/树莓派/X86_64系统](#标准linux系统安装树莓派x86_64系统)
- [openwrt](#openwrt)
- [华硕路由器原生固件/梅林固件](#华硕路由器原生固件梅林固件)
- [optware/entware](#optwareentware)
- [Windows 10 WSL安装/WSL ubuntu](#windows-10-wsl安装wsl-ubuntu)
- [配置参数](#配置参数)
- [FAQ](#faq)
- [编译](#编译)
- [Donate](#donate)
- [PayPal](#paypal)
- [Alipay 支付宝](#alipay-支付宝)
- [Wechat 微信](#wechat-微信)
- [开源声明](#开源声明)
## 软件效果展示
@@ -117,7 +124,7 @@ rtt min/avg/max/mdev = 5.954/6.133/6.313/0.195 ms
## 架构
![Architecture](doc/architecture.png)
![Architecture](https://github.com/pymumu/test/releases/download/blob/architecture.png)
1. SmartDNS接收本地网络设备的DNS查询请求如PC手机的查询请求。
2. SmartDNS将查询请求发送到多个上游DNS服务器可采用标准UDP查询非标准端口UDP查询及TCP查询。
@@ -504,7 +511,7 @@ https://github.com/pymumu/smartdns/releases
|bind|DNS监听端口号|[::]:53|可绑定多个端口<br>`IP:PORT`: 服务器IP端口号。<br>`[-group]`: 请求时使用的DNS服务器组。<br>`[-no-rule-addr]`跳过address规则。<br>`[-no-rule-nameserver]`跳过Nameserver规则。<br>`[-no-rule-ipset]`跳过Ipset规则。<br>`[no-rule-soa]`跳过SOA(#)规则.<br>`[no-dualstack-selection]`:停用双栈测速。<br>`[-no-speed-check]`:停用测速。<br>`[-no-cache]`:停止缓存|bind :53
|bind-tcp|TCP DNS监听端口号|[::]:53|可绑定多个端口<br>`IP:PORT`: 服务器IP端口号。<br>`[-group]`: 请求时使用的DNS服务器组。<br>`[-no-rule-addr]`跳过address规则。<br>`[-no-rule-nameserver]`跳过Nameserver规则。<br>`[-no-rule-ipset]`跳过Ipset规则。<br>`[no-rule-soa]`跳过SOA(#)规则.<br>`[no-dualstack-selection]`:停用双栈测速。<br>`[-no-speed-check]`:停用测速。<br>`[-no-cache]`:停止缓存|bind-tcp :53
|cache-size|域名结果缓存个数|512|数字|cache-size 512
|cache-persist|是否持久化缓存|no|[yes\|no]|cache-persist yes
|cache-persist|是否持久化缓存|自动<br>当 `cache-file` 所在的位置有超过 128MB 的可用空间时启用,否则禁用。|[yes\|no]|cache-persist yes
|cache-file|缓存持久化文件路径|/tmp/smartdns.cache|路径|cache-file /tmp/smartdns.cache
|tcp-idle-time|TCP链接空闲超时时间|120|数字|tcp-idle-time 120
|rr-ttl|域名结果TTL|远程查询结果|大于0的数字|rr-ttl 600
@@ -526,9 +533,9 @@ https://github.com/pymumu/smartdns/releases
|speed-check-mode|测速模式选择|无|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:80
|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|None|ipset /domain/[ipset\|-], `-`表示忽略|ipset /www.example.com/pass
|ipset|域名IPSET|None|ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]], `-`表示忽略|ipset /www.example.com/#4:dns4,#6:-
|ipset-timeout|设置IPSET超时功能启用|auto|[yes]|ipset-timeout yes
|domain-rules|设置域名规则|无|domain-rules /domain/ [-rules...]<br>`[-speed-check-mode]`: 测速模式,参考`speed-check-mode`配置<br>`[-address]`: 参考`address`配置<br>`[-nameserver]`: 参考`nameserver`配置<br>`[-ipset]`:参考`ipset`配置|domain-rules /www.example.com/ -speed-check-mode none
|domain-rules|设置域名规则|无|domain-rules /domain/ [-rules...]<br>`[-c\|-speed-check-mode]`: 测速模式,参考`speed-check-mode`配置<br>`[-a\|-address]`: 参考`address`配置<br>`[-n\|-nameserver]`: 参考`nameserver`配置<br>`[-p\|-ipset]`:参考`ipset`配置<br>`[-d\|-dualstack-ip-selection]`: 参考`dualstack-ip-selection`|domain-rules /www.example.com/ -speed-check-mode none
|bogus-nxdomain|假冒IP地址过滤|无|[ip/subnet],可重复| bogus-nxdomain 1.2.3.4/16
|ignore-ip|忽略IP地址|无|[ip/subnet],可重复| ignore-ip 1.2.3.4/16
|whitelist-ip|白名单IP地址|无|[ip/subnet],可重复| whitelist-ip 1.2.3.4/16

View File

@@ -498,7 +498,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|bind|DNS listening port number|[::]:53|Support binding multiple ports<br>`IP:PORT`: server IP, port number. <br>`[-group]`: The DNS server group used when requesting. <br>`[-no-rule-addr]`: Skip the address rule. <br>`[-no-rule-nameserver]`: Skip the Nameserver rule. <br>`[-no-rule-ipset]`: Skip the Ipset rule. <br>`[-no-rule-soa]`: Skip address SOA(#) rules.<br>`[-no-dualstack-selection]`: Disable dualstack ip selection.<br>`[-no-speed-check]`: Disable speed measurement. <br>`[-no-cache]`: stop caching |bind :53
|bind-tcp|TCP mode DNS listening port number|[::]:53|Support binding multiple ports<br>`IP:PORT`: server IP, port number. <br>`[-group]`: The DNS server group used when requesting. <br>`[-no-rule-addr]`: Skip the address rule. <br>`[-no-rule-nameserver]`: Skip the Nameserver rule. <br>`[-no-rule-ipset]`: Skip the Ipset rule. <br>`[-no-rule-soa]`: Skip address SOA(#) rules.<br>`[-no-dualstack-selection]`: Disable dualstack ip selection.<br>`[-no-speed-check]`: Disable speed measurement. <br>`[-no-cache]`: stop caching |bind-tcp :53
|cache-size|Domain name result cache number|512|integer|cache-size 512
|cache-persist|enable persist cache|no|[yes\|no]|cache-persist yes
|cache-persist|enable persist cache|Auto: Enabled if the location of `cache-file` has more than 128MB of free space.|[yes\|no]|cache-persist yes
|cache-file|cache persist file|/tmp/smartdns.cache|路径|cache-file /tmp/smartdns.cache
|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
@@ -520,9 +520,9 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|speed-check-mode|Speed mode|None|[ping\|tcp:[80]\|none]|speed-check-mode ping,tcp:443
|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\|-], `-` for ignore|ipset /www.example.com/pass
|ipset|Domain IPSet|None|ipset /domain/[ipset\|-\|#[4\|6]:[ipset\|-][,#[4\|6]:[ipset\|-]]], `-` for ignore|ipset /www.example.com/#4:dns4,#6:-
|ipset-timeout|ipset timeout enable|auto|[yes]|ipset-timeout yes
|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br>`[-speed-check-mode]`: set speed check modesame as parameter `speed-check-mode`<br>`[-address]`: same as parameter `address` <br>`[-nameserver]`: same as parameter `nameserver`<br>`[-ipset]`: same as parameter `ipset`|domain-rules /www.example.com/ -speed-check-mode none
|domain-rules|set domain rules|None|domain-rules /domain/ [-rules...]<br>`[-c\|-speed-check-mode]`: set speed check modesame as parameter `speed-check-mode`<br>`[-a\|-address]`: same as parameter `address` <br>`[-n\|-nameserver]`: same as parameter `nameserver`<br>`[-p\|-ipset]`: same as parameter `ipset`<br>`[-d\|-dualstack-ip-selection]`: same as parameter `dualstack-ip-selection`|domain-rules /www.example.com/ -speed-check-mode none
|bogus-nxdomain|bogus IP address|None|[IP/subnet], Repeatable| bogus-nxdomain 1.2.3.4/16
|ignore-ip|ignore ip address|None|[ip/subnet], Repeatable| ignore-ip 1.2.3.4/16
|whitelist-ip|ip whitelist|None|[ip/subnet], RepeatableWhen the filtering server responds IPs in the IP whitelist, only result in whitelist will be accepted| whitelist-ip 1.2.3.4/16

View File

@@ -189,8 +189,9 @@ log-level info
# set domain rules
# domain-rules /domain/ [-speed-check-mode [...]]
# rules:
# -speed-check-mode [mode]: speed check mode
# [-c] -speed-check-mode [mode]: speed check mode
# speed-check-mode [ping|tcp:port|none|,]
# -address [address|-]: same as address option
# -nameserver [group|-]: same as nameserver option
# -ipset [ipset|-]: same as ipset option
# [-a] -address [address|-]: same as address option
# [-n] -nameserver [group|-]: same as nameserver option
# [-p] -ipset [ipset|-]: same as ipset option
# [-d] -dualstack-ip-selection [yes|no]: same as dualstack-ip-selection option

0
package/build-pkg.sh Normal file → Executable file
View File

0
package/debian/make.sh Normal file → Executable file
View File

0
package/linux/make.sh Normal file → Executable file
View File

View File

@@ -104,13 +104,13 @@ msgid "Cache Size"
msgstr "缓存大小"
msgid "DNS domain result cache size"
msgstr "缓存DNS的结果缓存大小配置零则不缓存"
msgstr "缓存DNS的结果缓存大小配置零则不缓存(单位:条)"
msgid "Domain TTL"
msgstr "域名TTL"
msgid "TTL for all domain result."
msgstr "设置所有域名的TTL值"
msgstr "设置所有域名的TTL值(单位:秒,下同)"
msgid "Domain TTL Min"
msgstr "域名TTL最小值"

0
package/luci-compat/make.sh Normal file → Executable file
View File

View File

@@ -110,13 +110,13 @@ msgid "Cache Size"
msgstr "缓存大小"
msgid "DNS domain result cache size"
msgstr "缓存DNS的结果缓存大小配置零则不缓存"
msgstr "缓存DNS的结果缓存大小配置零则不缓存(单位:条)"
msgid "Domain TTL"
msgstr "域名TTL"
msgid "TTL for all domain result."
msgstr "设置所有域名的TTL值"
msgstr "设置所有域名的TTL值(单位:秒,下同)"
msgid "Domain TTL Min"
msgstr "域名TTL最小值"

View File

@@ -6,6 +6,7 @@
"path": "smartdns/smartdns"
},
"depends": {
"acl": [ "luci-app-smartdns" ],
"uci": { "smartdns": true }
}
}

0
package/luci/make.sh Normal file → Executable file
View File

2
package/openwrt/make.sh Normal file → Executable file
View File

@@ -74,7 +74,7 @@ build()
cd $ROOT
tar zcf $ROOT/data.tar.gz -C root --owner=0 --group=0 .
tar zcf $OUTPUTDIR/smartdns.$VER.$FILEARCH.ipk --owner=0 --group=0 control.tar.gz data.tar.gz debian-binary
tar zcf $OUTPUTDIR/smartdns.$VER.$FILEARCH.ipk --owner=0 --group=0 ./control.tar.gz ./data.tar.gz ./debian-binary
rm -fr $ROOT/
}

0
package/optware/make.sh Normal file → Executable file
View File

View File

@@ -1,21 +1,24 @@
Name: smartdns
Version: 31
Release: 1%{?dist}
Version: 1.2020.09.08
Release: 2235%{?dist}
Summary: smartdns
License: GPL 3.0
URL: https://github.com/pymumu/smartdns
Source0: smartdns-Release31.tar.gz
Source0: %{name}-%{version}.tar.gz
BuildRequires: glibc
BuildRequires: centos-release >= 7
BuildRequires: openssl-devel
Requires: glibc
Requires: openssl
Requires: systemd
%description
A local DNS server to obtain the fastest website IP for the best Internet experience.
%prep
%setup -q -n smartdns-Release31
%setup -q
%build
cd src

5
src/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.vscode
.o
.DS_Store
.swp.
smartdns

View File

@@ -20,7 +20,7 @@ OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_co
# cflags
ifndef CFLAGS
CFLAGS =-O2 -g -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing
CFLAGS =-O2 -g -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing -funwind-tables
endif
override CFLAGS +=-Iinclude
override CFLAGS += -DBASE_FILE_NAME=\"$(notdir $<)\"
@@ -35,7 +35,7 @@ override CXXFLAGS +=-Iinclude
ifeq ($(STATIC), yes)
override LDFLAGS += -lssl -lcrypto -Wl,--whole-archive -lpthread -Wl,--no-whole-archive -ldl -static
else
override LDFLAGS += -lssl -lcrypto -lpthread
override LDFLAGS += -lssl -lcrypto -lpthread -ldl
endif
.PHONY: all clean

View File

@@ -253,11 +253,8 @@ static int _dns_add_qr_head(struct dns_data_context *data_context, char *domain,
return -1;
}
*((unsigned short *)(data_context->ptr)) = qtype;
data_context->ptr += 2;
*((unsigned short *)(data_context->ptr)) = qclass;
data_context->ptr += 2;
_dns_write_short(&data_context->ptr, qtype);
_dns_write_short(&data_context->ptr, qclass);
return 0;
}
@@ -266,6 +263,10 @@ static int _dns_get_qr_head(struct dns_data_context *data_context, char *domain,
{
int i;
int is_read_all = 0;
if (domain == NULL || data_context == NULL) {
return -1;
}
/* question head */
/* |domain |
* |qtype | qclass |
@@ -296,11 +297,8 @@ static int _dns_get_qr_head(struct dns_data_context *data_context, char *domain,
return -1;
}
*qtype = *((unsigned short *)(data_context->ptr));
data_context->ptr += 2;
*qclass = *((unsigned short *)(data_context->ptr));
data_context->ptr += 2;
*qtype = _dns_read_short(&data_context->ptr);
*qclass = _dns_read_short(&data_context->ptr);
return 0;
}
@@ -325,11 +323,8 @@ static int _dns_add_rr_head(struct dns_data_context *data_context, char *domain,
return -1;
}
*((unsigned int *)(data_context->ptr)) = ttl;
data_context->ptr += 4;
*((unsigned short *)(data_context->ptr)) = rr_len;
data_context->ptr += 2;
_dns_write_int(&data_context->ptr, ttl);
_dns_write_short(&data_context->ptr, rr_len);
return 0;
}
@@ -351,11 +346,8 @@ static int _dns_get_rr_head(struct dns_data_context *data_context, char *domain,
return -1;
}
*ttl = *((unsigned int *)(data_context->ptr));
data_context->ptr += 4;
*rr_len = *((unsigned short *)(data_context->ptr));
data_context->ptr += 2;
*ttl = _dns_read_int(&data_context->ptr);
*rr_len = _dns_read_short(&data_context->ptr);
return len;
}
@@ -940,7 +932,7 @@ static int _dns_decode_domain(struct dns_context *context, char *output, int siz
/*[len]string[len]string...[0]0 */
while (1) {
if (ptr > context->data + context->maxsize || ptr < context->data || output_len >= size - 1 || ptr_jump > 4) {
if (ptr >= context->data + context->maxsize || ptr < context->data || output_len >= size - 1 || ptr_jump > 4) {
return -1;
}
@@ -1363,7 +1355,7 @@ static int _dns_decode_opt_ecs(struct dns_context *context, struct dns_opt_ecs *
len = (ecs->source_prefix / 8);
len += (ecs->source_prefix % 8 > 0) ? 1 : 0;
if (_dns_left_len(context) < len) {
if (_dns_left_len(context) < len || len > sizeof(ecs->addr)) {
return -1;
}

View File

@@ -142,8 +142,7 @@ void dns_cache_data_free(struct dns_cache_data *data)
free(data);
}
struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, int cname_ttl, unsigned char *addr,
int addr_len)
struct dns_cache_data *dns_cache_new_data(void)
{
struct dns_cache_addr *cache_addr = malloc(sizeof(struct dns_cache_addr));
memset(cache_addr, 0, sizeof(struct dns_cache_addr));
@@ -151,6 +150,50 @@ struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname,
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);
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)
{
if (dns_cache == NULL) {
goto errout;
}
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->head.cache_flag = cache_flag;
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, uint32_t cache_flag, 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) {
@@ -167,16 +210,8 @@ struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname,
cache_addr->head.cache_flag = cache_flag;
cache_addr->head.cache_type = CACHE_TYPE_ADDR;
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
return (struct dns_cache_data *)cache_addr;
errout:
if (cache_addr) {
free(cache_addr);
cache_addr = NULL;
}
return NULL;
return;
}
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len)
@@ -298,6 +333,7 @@ int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct
}
if (dns_cache_head.size <= 0) {
dns_cache_data_free(cache_data);
return 0;
}
@@ -376,6 +412,18 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache)
return ttl;
}
int dns_cache_is_soa(struct dns_cache *dns_cache) {
if (dns_cache == NULL) {
return 0;
}
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache_get_data(dns_cache);
if (cache_addr->head.cache_type == CACHE_TYPE_ADDR && cache_addr->addr_data.soa) {
return 1;
}
return 0;
}
struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache)
{
return dns_cache->cache_data;
@@ -467,7 +515,7 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
}
if (ttl < 0) {
if (dns_cache_head.enable_inactive) {
if (dns_cache_head.enable_inactive && (dns_cache_is_soa(dns_cache) == 0)) {
_dns_cache_move_inactive(dns_cache);
} else {
_dns_cache_remove(dns_cache);

View File

@@ -62,6 +62,7 @@ struct dns_cache_addr {
struct dns_cache_data_head head;
struct dns_cache_addr_data {
unsigned int cname_ttl;
char soa;
char cname[DNS_MAX_CNAME_LEN];
union {
unsigned char ipv4_addr[DNS_RR_A_LEN];
@@ -116,9 +117,6 @@ uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data);
void dns_cache_data_free(struct dns_cache_data *data);
struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, int cname_ttl, unsigned char *addr,
int addr_len);
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len);
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
@@ -145,8 +143,17 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre);
int dns_cache_get_ttl(struct dns_cache *dns_cache);
int dns_cache_is_soa(struct dns_cache *dns_cache);
struct dns_cache_data *dns_cache_new_data(void);
struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache);
void dns_cache_set_data_addr(struct dns_cache_data *dns_cache, uint32_t cache_flag, char *cname, int cname_ttl,
unsigned char *addr, int addr_len);
void dns_cache_set_data_soa(struct dns_cache_data *dns_cache, int32_t cache_flag, char *cname, int cname_ttl);
void dns_cache_destroy(void);
int dns_cache_load(const char *file);

View File

@@ -184,6 +184,9 @@ struct dns_client {
struct list_head dns_server_list;
struct dns_server_group *default_group;
SSL_CTX *ssl_ctx;
int ssl_verify_skip;
/* query list */
pthread_mutex_t dns_request_lock;
struct list_head dns_request_list;
@@ -253,6 +256,9 @@ static int dns_client_has_bootstrap_dns = 0;
int _ssl_read(struct dns_server_info *server, void *buff, int num)
{
int ret = 0;
if (server == NULL || buff == NULL) {
return SSL_ERROR_SYSCALL;
}
pthread_mutex_lock(&server->lock);
ret = SSL_read(server->ssl, buff, num);
pthread_mutex_unlock(&server->lock);
@@ -262,6 +268,10 @@ int _ssl_read(struct dns_server_info *server, void *buff, int num)
int _ssl_write(struct dns_server_info *server, const void *buff, int num)
{
int ret = 0;
if (server == NULL || buff == NULL || server->ssl == NULL) {
return SSL_ERROR_SYSCALL;
}
pthread_mutex_lock(&server->lock);
ret = SSL_write(server->ssl, buff, num);
pthread_mutex_unlock(&server->lock);
@@ -271,6 +281,10 @@ int _ssl_write(struct dns_server_info *server, const void *buff, int num)
int _ssl_shutdown(struct dns_server_info *server)
{
int ret = 0;
if (server == NULL || server->ssl == NULL) {
return SSL_ERROR_SYSCALL;
}
pthread_mutex_lock(&server->lock);
ret = SSL_shutdown(server->ssl);
pthread_mutex_unlock(&server->lock);
@@ -280,6 +294,10 @@ int _ssl_shutdown(struct dns_server_info *server)
int _ssl_get_error(struct dns_server_info *server, int ret)
{
int err = 0;
if (server == NULL || server->ssl == NULL) {
return SSL_ERROR_SYSCALL;
}
pthread_mutex_lock(&server->lock);
err = SSL_get_error(server->ssl, ret);
pthread_mutex_unlock(&server->lock);
@@ -289,6 +307,10 @@ int _ssl_get_error(struct dns_server_info *server, int ret)
int _ssl_do_handshake(struct dns_server_info *server)
{
int err = 0;
if (server == NULL || server->ssl == NULL) {
return SSL_ERROR_SYSCALL;
}
pthread_mutex_lock(&server->lock);
err = SSL_do_handshake(server->ssl);
pthread_mutex_unlock(&server->lock);
@@ -298,6 +320,10 @@ int _ssl_do_handshake(struct dns_server_info *server)
int _ssl_session_reused(struct dns_server_info *server)
{
int err = 0;
if (server == NULL || server->ssl == NULL) {
return SSL_ERROR_SYSCALL;
}
pthread_mutex_lock(&server->lock);
err = SSL_session_reused(server->ssl);
pthread_mutex_unlock(&server->lock);
@@ -307,6 +333,10 @@ int _ssl_session_reused(struct dns_server_info *server)
SSL_SESSION *_ssl_get1_session(struct dns_server_info *server)
{
SSL_SESSION *ret = 0;
if (server == NULL || server->ssl == NULL) {
return NULL;
}
pthread_mutex_lock(&server->lock);
ret = SSL_get1_session(server->ssl);
pthread_mutex_unlock(&server->lock);
@@ -407,6 +437,10 @@ static struct dns_server_info *_dns_client_get_server(char *server_ip, int port,
struct dns_server_info *server_info, *tmp;
struct dns_server_info *server_info_return = NULL;
if (server_ip == NULL) {
return NULL;
}
pthread_mutex_lock(&client.server_list_lock);
list_for_each_entry_safe(server_info, tmp, &client.dns_server_list, list)
{
@@ -509,6 +543,10 @@ static int _dns_client_add_to_pending_group(char *group_name, char *server_ip, i
struct dns_server_pending *pending = NULL;
struct dns_server_pending_group *group = NULL;
if (group_name == NULL || server_ip == NULL) {
goto errout;
}
pthread_mutex_lock(&pending_server_mutex);
list_for_each_entry_safe(item, tmp, &pending_servers, list)
{
@@ -550,6 +588,10 @@ static int _dns_client_add_to_group_pending(char *group_name, char *server_ip, i
{
struct dns_server_info *server_info = NULL;
if (group_name == NULL || server_ip == NULL) {
return -1;
}
server_info = _dns_client_get_server(server_ip, port, server_type);
if (server_info == NULL) {
if (ispending == 0) {
@@ -630,6 +672,10 @@ int dns_client_add_group(char *group_name)
unsigned long key;
struct dns_server_group *group = NULL;
if (group_name == NULL) {
return -1;
}
if (_dns_client_get_group(group_name) != NULL) {
tlog(TLOG_ERROR, "add group %s failed, group already exists", group_name);
return -1;
@@ -661,6 +707,10 @@ static int _dns_client_remove_group(struct dns_server_group *group)
struct dns_server_group_member *group_member;
struct dns_server_group_member *tmp;
if (group == NULL) {
return 0;
}
list_for_each_entry_safe(group_member, tmp, &group->head, list)
{
_dns_client_remove_member(group_member);
@@ -678,6 +728,10 @@ int dns_client_remove_group(char *group_name)
struct dns_server_group *group = NULL;
struct hlist_node *tmp = NULL;
if (group_name == NULL) {
return -1;
}
key = hash_string(group_name);
hash_for_each_possible_safe(client.group, group, tmp, node, key)
{
@@ -786,6 +840,10 @@ static int _dns_client_set_trusted_cert(SSL_CTX *ssl_ctx)
char *capath = NULL;
int cert_path_set = 0;
if (ssl_ctx == NULL) {
return -1;
}
if (dns_conf_ca_file[0]) {
cafile = dns_conf_ca_file;
}
@@ -796,15 +854,19 @@ static int _dns_client_set_trusted_cert(SSL_CTX *ssl_ctx)
if (cafile == NULL && capath == NULL) {
if (SSL_CTX_set_default_verify_paths(ssl_ctx)) {
cert_path_set = 1;
}
const STACK_OF(X509_NAME) *cas = SSL_CTX_get_client_CA_list(ssl_ctx);
if (cas && sk_X509_NAME_num(cas) == 0) {
cafile = "/etc/ssl/certs/ca-certificates.crt";
capath = "/etc/ssl/certs";
} else {
cert_path_set = 1;
cert_path_set = 0;
}
}
if (cert_path_set == 0) {
if (!SSL_CTX_load_verify_locations(ssl_ctx, cafile, capath)) {
if (SSL_CTX_load_verify_locations(ssl_ctx, cafile, capath) == 0) {
tlog(TLOG_WARN, "load certificate from %s:%s failed.", cafile, capath);
return -1;
}
@@ -813,6 +875,47 @@ static int _dns_client_set_trusted_cert(SSL_CTX *ssl_ctx)
return 0;
}
SSL_CTX *_ssl_ctx_get(void)
{
pthread_mutex_lock(&client.server_list_lock);
SSL_CTX *ssl_ctx = client.ssl_ctx;
if (ssl_ctx) {
pthread_mutex_unlock(&client.server_list_lock);
return ssl_ctx;
}
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
ssl_ctx = SSL_CTX_new(TLS_client_method());
#else
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
#endif
if (ssl_ctx == NULL) {
tlog(TLOG_ERROR, "init ssl failed.");
goto errout;
}
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_CLIENT);
SSL_CTX_sess_set_cache_size(ssl_ctx, DNS_MAX_SERVERS);
if (_dns_client_set_trusted_cert(ssl_ctx) != 0) {
SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
client.ssl_verify_skip = 1;
}
client.ssl_ctx = ssl_ctx;
pthread_mutex_unlock(&client.server_list_lock);
return client.ssl_ctx;
errout:
pthread_mutex_unlock(&client.server_list_lock);
if (ssl_ctx) {
SSL_CTX_free(ssl_ctx);
}
return NULL;
}
/* add dns server information */
static int _dns_client_server_add(char *server_ip, char *server_host, int port, dns_server_type_t server_type,
struct client_dns_server_flags *flags)
@@ -914,24 +1017,14 @@ 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) {
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
server_info->ssl_ctx = SSL_CTX_new(TLS_client_method());
#else
server_info->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
#endif
server_info->ssl_ctx = _ssl_ctx_get();
if (server_info->ssl_ctx == NULL) {
tlog(TLOG_ERROR, "init ssl failed.");
goto errout;
}
SSL_CTX_set_options(server_info->ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_CTX_set_session_cache_mode(server_info->ssl_ctx, SSL_SESS_CACHE_CLIENT);
SSL_CTX_sess_set_cache_size(server_info->ssl_ctx, 32);
if (_dns_client_set_trusted_cert(server_info->ssl_ctx) != 0) {
tlog(TLOG_WARN, "disable check certificate for %s.", server_info->ip);
if (client.ssl_verify_skip) {
server_info->skip_check_cert = 1;
SSL_CTX_set_verify(server_info->ssl_ctx, SSL_VERIFY_NONE, NULL);
}
}
@@ -976,11 +1069,6 @@ errout:
fast_ping_stop(server_info->ping_host);
}
if (server_info->ssl_ctx) {
SSL_CTX_free(server_info->ssl_ctx);
server_info->ssl_ctx = NULL;
}
pthread_mutex_destroy(&server_info->lock);
free(server_info);
}
@@ -1066,10 +1154,7 @@ static void _dns_client_server_close(struct dns_server_info *server_info)
server_info->ssl_session = NULL;
}
if (server_info->ssl_ctx) {
SSL_CTX_free(server_info->ssl_ctx);
server_info->ssl_ctx = NULL;
}
server_info->ssl_ctx = NULL;
}
/* remove all servers information */
@@ -1663,19 +1748,19 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
const int ip_tos = SOCKET_IP_TOS;
if (server_info->ssl_ctx == NULL) {
tlog(TLOG_ERROR, "create ssl ctx failed.");
tlog(TLOG_ERROR, "create ssl ctx failed, %s", server_info->ip);
goto errout;
}
ssl = SSL_new(server_info->ssl_ctx);
if (ssl == NULL) {
tlog(TLOG_ERROR, "new ssl failed.");
tlog(TLOG_ERROR, "new ssl failed, %s", server_info->ip);
goto errout;
}
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;
}
@@ -2307,7 +2392,7 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
pthread_mutex_unlock(&server_info->lock);
peer_CN[0] = '\0';
_dns_client_tls_get_cert_CN(cert, peer_CN, sizeof(peer_CN));
tlog(TLOG_WARN, "peer server %s certificate verify failed", server_info->ip);
tlog(TLOG_WARN, "peer server %s certificate verify failed, ret = %ld", server_info->ip, res);
tlog(TLOG_WARN, "peer CN: %s", peer_CN);
goto errout;
}
@@ -2577,7 +2662,7 @@ static int _dns_client_send_tcp(struct dns_server_info *server_info, void *packe
/* save data to buffer, and retry when EPOLLOUT is available */
return _dns_client_send_data_to_buffer(server_info, inpacket, len);
} else if (errno == EPIPE) {
shutdown(server_info->fd, SHUT_RDWR);
_dns_client_shutdown_socket(server_info);
}
return -1;
} else if (send_len < len) {
@@ -2621,7 +2706,7 @@ static int _dns_client_send_tls(struct dns_server_info *server_info, void *packe
/* save data to buffer, and retry when EPOLLOUT is available */
return _dns_client_send_data_to_buffer(server_info, inpacket, len);
} else if (server_info->ssl && errno != ENOMEM) {
SSL_shutdown(server_info->ssl);
_dns_client_shutdown_socket(server_info);
}
return -1;
} else if (send_len < len) {
@@ -2672,7 +2757,7 @@ static int _dns_client_send_https(struct dns_server_info *server_info, void *pac
/* save data to buffer, and retry when EPOLLOUT is available */
return _dns_client_send_data_to_buffer(server_info, inpacket, http_len);
} else if (server_info->ssl && errno != ENOMEM) {
_ssl_shutdown(server_info);
_dns_client_shutdown_socket(server_info);
}
return -1;
} else if (send_len < http_len) {
@@ -2691,15 +2776,19 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
int ret = 0;
int send_err = 0;
int i = 0;
int total_server = 0;
query->send_tick = get_tick_count();
/* send query to all dns servers */
for (i = 0; i < 2; i++) {
total_server = 0;
pthread_mutex_lock(&client.server_list_lock);
list_for_each_entry_safe(group_member, tmp, &query->server_group->head, list)
{
server_info = group_member->server;
total_server++;
tlog(TLOG_DEBUG, "send query to server %s", server_info->ip);
if (server_info->fd <= 0) {
ret = _dns_client_create_socket(server_info);
if (ret != 0) {
@@ -2765,7 +2854,7 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
}
if (atomic_read(&query->dns_request_sent) <= 0) {
tlog(TLOG_ERROR, "Send query to upstream server failed.");
tlog(TLOG_ERROR, "Send query to upstream server failed, total server number %d", total_server);
return -1;
}
@@ -2851,6 +2940,10 @@ int dns_client_query(char *domain, int qtype, dns_client_callback callback, void
int ret = 0;
uint32_t key = 0;
if (domain == NULL) {
goto errout;
}
query = malloc(sizeof(*query));
if (query == NULL) {
goto errout;
@@ -3045,6 +3138,7 @@ static void _dns_client_add_pending_servers(void)
if (add_success == 0) {
tlog(TLOG_WARN, "add pending DNS server %s failed.", pending->host);
}
list_del_init(&pending->list);
_dns_client_server_pending_release_lck(pending);
} else {
tlog(TLOG_DEBUG, "add pending DNS server %s failed, retry %d...", pending->host, pending->retry_cnt);
@@ -3247,4 +3341,8 @@ void dns_client_exit(void)
pthread_mutex_destroy(&client.server_list_lock);
pthread_mutex_destroy(&client.domain_map_lock);
if (client.ssl_ctx) {
SSL_CTX_free(client.ssl_ctx);
client.ssl_ctx = NULL;
}
}

View File

@@ -482,7 +482,7 @@ errout:
return -1;
}
static int _config_domain_rule_flag_set(char *domain, unsigned int flag)
static int _config_domain_rule_flag_set(char *domain, unsigned int flag, unsigned int is_clear)
{
struct dns_domain_rule *domain_rule = NULL;
struct dns_domain_rule *old_domain_rule = NULL;
@@ -516,12 +516,18 @@ static int _config_domain_rule_flag_set(char *domain, unsigned int flag)
/* add new rule to domain */
if (domain_rule->rules[DOMAIN_RULE_FLAGS] == NULL) {
rule_flags = malloc(sizeof(*rule_flags));
memset(rule_flags, 0, sizeof(*rule_flags));
rule_flags->flags = 0;
domain_rule->rules[DOMAIN_RULE_FLAGS] = rule_flags;
}
rule_flags = domain_rule->rules[DOMAIN_RULE_FLAGS];
rule_flags->flags |= flag;
if (is_clear == false) {
rule_flags->flags |= flag;
} else {
rule_flags->flags &= ~flag;
}
rule_flags->is_flag_set |= flag;
/* update domain rule */
if (add_domain_rule) {
@@ -589,11 +595,40 @@ static int _conf_domain_rule_ipset(char *domain, const char *ipsetname)
{
struct dns_ipset_rule *ipset_rule = NULL;
const char *ipset = NULL;
char *copied_name = NULL;
enum domain_rule type;
int ignore_flag;
copied_name = strdup(ipsetname);
if (copied_name == NULL) {
goto errout;
}
for (char *tok = strtok(copied_name, ","); tok; tok = strtok(NULL, ",")) {
if (tok[0] == '#') {
if (strncmp(tok, "#6:", 3u) == 0) {
type = DOMAIN_RULE_IPSET_IPV6;
ignore_flag = DOMAIN_FLAG_IPSET_IPV6_IGN;
} else if (strncmp(tok, "#4:", 3u) == 0) {
type = DOMAIN_RULE_IPSET_IPV4;
ignore_flag = DOMAIN_FLAG_IPSET_IPV4_IGN;
} else {
goto errout;
}
tok += 3;
} else {
type = DOMAIN_RULE_IPSET;
ignore_flag = DOMAIN_FLAG_IPSET_IGN;
}
if (strncmp(tok, "-", 1) == 0) {
_config_domain_rule_flag_set(domain, ignore_flag, 0);
continue;
}
/* Process domain option */
if (strncmp(ipsetname, "-", sizeof("-")) != 0) {
/* new ipset domain */
ipset = _dns_conf_get_ipset(ipsetname);
ipset = _dns_conf_get_ipset(tok);
if (ipset == NULL) {
goto errout;
}
@@ -604,26 +639,26 @@ static int _conf_domain_rule_ipset(char *domain, const char *ipsetname)
}
ipset_rule->ipsetname = ipset;
} else {
/* ignore this domain */
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_IPSET_IGNORE) != 0) {
if (_config_domain_rule_add(domain, type, ipset_rule) != 0) {
goto errout;
}
return 0;
}
if (_config_domain_rule_add(domain, DOMAIN_RULE_IPSET, ipset_rule) != 0) {
goto errout;
}
goto clear;
return 0;
errout:
tlog(TLOG_ERROR, "add ipset %s failed", ipsetname);
if (ipset_rule) {
free(ipset_rule);
}
tlog(TLOG_ERROR, "add ipset %s failed", ipsetname);
clear:
if (copied_name) {
free(copied_name);
}
return 0;
}
@@ -670,7 +705,7 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
}
/* add SOA rule */
if (_config_domain_rule_flag_set(domain, flag) != 0) {
if (_config_domain_rule_flag_set(domain, flag, 0) != 0) {
goto errout;
}
@@ -687,7 +722,7 @@ static int _conf_domain_rule_address(char *domain, const char *domain_address)
}
/* ignore rule */
if (_config_domain_rule_flag_set(domain, flag) != 0) {
if (_config_domain_rule_flag_set(domain, flag, 0) != 0) {
goto errout;
}
@@ -1008,7 +1043,7 @@ static int _conf_domain_rule_nameserver(char *domain, const char *group_name)
nameserver_rule->group_name = group;
} else {
/* ignore this domain */
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_NAMESERVER_IGNORE) != 0) {
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_NAMESERVER_IGNORE, 0) != 0) {
goto errout;
}
@@ -1029,6 +1064,26 @@ errout:
return 0;
}
static int _conf_domain_rule_dualstack_selection(char *domain, const char *yesno)
{
if (strncmp(yesno, "yes", sizeof("yes")) == 0 || strncmp(yesno, "Yes", sizeof("Yes")) == 0) {
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_DUALSTACK_SELECT, 0) != 0) {
goto errout;
}
} else {
/* ignore this domain */
if (_config_domain_rule_flag_set(domain, DOMAIN_FLAG_DUALSTACK_SELECT, 1) != 0) {
goto errout;
}
}
return 0;
errout:
tlog(TLOG_ERROR, "set dualstack for %s failed. ", domain);
return 1;
}
static int _config_nameserver(void *data, int argc, char *argv[])
{
char domain[DNS_MAX_CONF_CNAME_LEN];
@@ -1239,6 +1294,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
{"address", required_argument, NULL, 'a'},
{"ipset", required_argument, NULL, 'p'},
{"nameserver", required_argument, NULL, 'n'},
{"dualstack-ip-selection", required_argument, NULL, 'd'},
{NULL, no_argument, NULL, 0}
};
/* clang-format on */
@@ -1255,7 +1311,7 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
/* process extra options */
optind = 1;
while (1) {
opt = getopt_long_only(argc, argv, "", long_options, NULL);
opt = getopt_long_only(argc, argv, "c:a:p:n:d:", long_options, NULL);
if (opt == -1) {
break;
}
@@ -1313,6 +1369,15 @@ static int _conf_domain_rules(void *data, int argc, char *argv[])
break;
}
case 'd': {
const char *yesno = optarg;
if (_conf_domain_rule_dualstack_selection(domain, yesno) != 0) {
tlog(TLOG_ERROR, "set dualstack selection rule failed.");
goto errout;
}
break;
}
default:
break;
}
@@ -1419,8 +1484,14 @@ int config_addtional_file(void *data, int argc, char *argv[])
if (conf_file[0] != '/') {
safe_strncpy(file_path_dir, conf_get_conf_file(), DNS_MAX_PATH);
dirname(file_path_dir);
if (snprintf(file_path, DNS_MAX_PATH, "%s/%s", file_path_dir, conf_file) < 0) {
return -1;
if (strncmp(file_path_dir, conf_get_conf_file(), sizeof(file_path_dir)) == 0) {
if (snprintf(file_path, DNS_MAX_PATH, "%s", conf_file) < 0) {
return -1;
}
} else {
if (snprintf(file_path, DNS_MAX_PATH, "%s/%s", file_path_dir, conf_file) < 0) {
return -1;
}
}
} else {
safe_strncpy(file_path, conf_file, DNS_MAX_PATH);

View File

@@ -56,6 +56,8 @@ enum domain_rule {
DOMAIN_RULE_ADDRESS_IPV4,
DOMAIN_RULE_ADDRESS_IPV6,
DOMAIN_RULE_IPSET,
DOMAIN_RULE_IPSET_IPV4,
DOMAIN_RULE_IPSET_IPV6,
DOMAIN_RULE_NAMESERVER,
DOMAIN_RULE_CHECKSPEED,
DOMAIN_RULE_MAX,
@@ -78,8 +80,11 @@ typedef enum {
#define DOMAIN_FLAG_ADDR_IGN (1 << 3)
#define DOMAIN_FLAG_ADDR_IPV4_IGN (1 << 4)
#define DOMAIN_FLAG_ADDR_IPV6_IGN (1 << 5)
#define DOMAIN_FLAG_IPSET_IGNORE (1 << 6)
#define DOMAIN_FLAG_NAMESERVER_IGNORE (1 << 7)
#define DOMAIN_FLAG_IPSET_IGN (1 << 6)
#define DOMAIN_FLAG_IPSET_IPV4_IGN (1 << 7)
#define DOMAIN_FLAG_IPSET_IPV6_IGN (1 << 8)
#define DOMAIN_FLAG_NAMESERVER_IGNORE (1 << 9)
#define DOMAIN_FLAG_DUALSTACK_SELECT (1 << 10)
#define SERVER_FLAG_EXCLUDE_DEFAULT (1 << 0)
@@ -95,6 +100,7 @@ typedef enum {
struct dns_rule_flags {
unsigned int flags;
unsigned int is_flag_set;
};
struct dns_address_IPV4 {

View File

@@ -258,6 +258,21 @@ static int _dns_server_epoll_ctl(struct dns_server_conn_head *head, int op, uint
static void _dns_server_set_dualstack_selection(struct dns_request *request)
{
struct dns_rule_flags *rule_flag = NULL;
rule_flag = request->domain_rule.rules[DOMAIN_RULE_FLAGS];
if (rule_flag) {
if (rule_flag->flags & DOMAIN_FLAG_DUALSTACK_SELECT) {
request->dualstack_selection = 1;
return;
}
if (rule_flag->is_flag_set & DOMAIN_FLAG_DUALSTACK_SELECT) {
request->dualstack_selection = 0;
return;
}
}
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_DUALSTACK_SELECTION) == 0) {
request->dualstack_selection = 0;
return;
@@ -666,7 +681,7 @@ static int _dns_server_reply_SOA(int rcode, struct dns_request *request)
/* add ip to specific ipset */
static int _dns_setup_ipset(struct dns_request *request)
{
struct dns_ipset_rule *ipset_rule = NULL;
struct dns_ipset_rule *rule = NULL, *ipset_rule = NULL, *ipset_rule_v4 = NULL, *ipset_rule_v6 = NULL;
struct dns_rule_flags *rule_flags = NULL;
int ret = 0;
@@ -676,32 +691,56 @@ static int _dns_setup_ipset(struct dns_request *request)
/* check ipset rule */
rule_flags = request->domain_rule.rules[DOMAIN_RULE_FLAGS];
if (rule_flags) {
if (rule_flags->flags & DOMAIN_FLAG_IPSET_IGNORE) {
return 0;
}
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
ipset_rule = request->domain_rule.rules[DOMAIN_RULE_IPSET];
}
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
ipset_rule_v4 = request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV4];
}
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV6_IGN) == 0) {
ipset_rule_v6 = request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV6];
}
ipset_rule = request->domain_rule.rules[DOMAIN_RULE_IPSET];
if (ipset_rule == NULL) {
if (!(ipset_rule || ipset_rule_v4 || ipset_rule_v6)) {
return 0;
}
/* add IPV4 to ipset */
if (request->has_ipv4 && request->qtype == DNS_T_A) {
ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
if (rule) {
ret |= ipset_add(rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
tlog(TLOG_DEBUG, "IPSET-MATCH: domain:%s, ipset:%s, IP: %d.%d.%d.%d, result: %d", request->domain,
rule->ipsetname, request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2],
request->ipv4_addr[3], ret);
}
}
/* add IPV6 to ipset */
if (request->has_ipv6 && request->qtype == DNS_T_AAAA) {
if (request->has_ipv4) {
ret |= ipset_add(ipset_rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
if (rule) {
ret |= ipset_add(rule->ipsetname, request->ipv4_addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
tlog(TLOG_DEBUG, "IPSET-MATCH: domain:%s, ipset:%s, IP: %d.%d.%d.%d, result: %d", request->domain,
rule->ipsetname, request->ipv4_addr[0], request->ipv4_addr[1], request->ipv4_addr[2],
request->ipv4_addr[3], ret);
}
}
rule = ipset_rule_v6 ? ipset_rule_v6 : ipset_rule;
if (rule) {
ret |= ipset_add(rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
tlog(TLOG_DEBUG,
"IPSET-MATCH: domain:%s, ipset:%s, IP: "
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x, result: %d",
request->domain, rule->ipsetname, request->ipv6_addr[0], request->ipv6_addr[1], request->ipv6_addr[2],
request->ipv6_addr[3], request->ipv6_addr[4], request->ipv6_addr[5], request->ipv6_addr[6],
request->ipv6_addr[7], request->ipv6_addr[8], request->ipv6_addr[9], request->ipv6_addr[10],
request->ipv6_addr[11], request->ipv6_addr[12], request->ipv6_addr[13], request->ipv6_addr[14],
request->ipv6_addr[15], ret);
}
ret |= ipset_add(ipset_rule->ipsetname, request->ipv6_addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
}
tlog(TLOG_DEBUG, "IPSET-MATCH: domain:%s, ipset:%s, result: %d", request->domain, ipset_rule->ipsetname, ret);
return ret;
}
@@ -721,6 +760,10 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
goto errout;
}
if (request->has_soa) {
ttl = dns_conf_rr_ttl;
}
/* if doing prefetch, update cache only */
if (request->prefetch) {
if (dns_cache_replace(request->domain, ttl, qtype, speed, cache_data) != 0) {
@@ -744,7 +787,7 @@ errout:
static int _dns_server_request_complete_A(struct dns_request *request)
{
char *cname = NULL;
int cname_ttl = 0;
int cname_ttl = dns_conf_rr_ttl;
struct dns_cache_data *cache_data = NULL;
if (request->has_cname) {
@@ -752,27 +795,29 @@ static int _dns_server_request_complete_A(struct dns_request *request)
cname_ttl = request->ttl_cname;
}
if (request->has_ipv4 == 0) {
return 0;
cache_data = dns_cache_new_data();
if (cache_data == NULL) {
goto errout;
}
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0],
request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
if (request->has_ipv4 != 0) {
tlog(TLOG_INFO, "result: %s, rcode: %d, %d.%d.%d.%d\n", request->domain, request->rcode, request->ipv4_addr[0],
request->ipv4_addr[1], request->ipv4_addr[2], request->ipv4_addr[3]);
request->has_soa = 0;
if (request->has_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) {
request->ttl_v4 = DNS_SERVER_TMOUT_TTL;
request->has_soa = 0;
if (request->has_ping_result == 0 && request->ttl_v4 > DNS_SERVER_TMOUT_TTL) {
request->ttl_v4 = DNS_SERVER_TMOUT_TTL;
}
dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_RR_A_LEN);
} else {
dns_cache_set_data_soa(cache_data, request->server_flags, cname, cname_ttl);
}
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) == 0) {
dns_cache_data_free(cache_data);
return 0;
}
cache_data = dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_RR_A_LEN);
if (cache_data == NULL) {
goto errout;
}
if (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) {
goto errout;
}
@@ -792,7 +837,7 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
{
int ret = -1;
char *cname = NULL;
int cname_ttl = 0;
int cname_ttl = dns_conf_rr_ttl;
struct dns_cache_data *cache_data = NULL;
if (request->has_cname) {
@@ -800,6 +845,11 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
cname_ttl = request->ttl_cname;
}
cache_data = dns_cache_new_data();
if (cache_data == NULL) {
goto errout;
}
if (request->has_ipv6) {
tlog(TLOG_INFO,
"result: %s, rcode: %d, %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
@@ -814,19 +864,21 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
}
/* if doing prefetch, update cache only */
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
cache_data =
dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv6_addr, DNS_T_AAAA);
if (cache_data == NULL) {
goto errout;
}
if (_dns_server_request_update_cache(request, DNS_T_AAAA, cache_data) != 0) {
goto errout;
}
}
dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv6_addr, DNS_T_AAAA);
request->has_soa = 0;
} else {
dns_cache_set_data_soa(cache_data, request->server_flags, cname, cname_ttl);
}
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
if (_dns_server_request_update_cache(request, DNS_T_AAAA, cache_data) != 0) {
goto errout;
}
cache_data = NULL;
} else {
dns_cache_data_free(cache_data);
cache_data = NULL;
}
if (request->has_ipv4 && (request->ping_ttl_v4 > 0)) {
@@ -838,15 +890,17 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
request->ping_ttl_v6 < 0) {
tlog(TLOG_DEBUG, "Force IPV4 perfered.");
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0) {
cache_data =
dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_T_A);
cache_data = dns_cache_new_data();
if (cache_data == NULL) {
goto errout;
}
dns_cache_set_data_addr(cache_data, request->server_flags, cname, cname_ttl, request->ipv4_addr,
DNS_T_A);
if (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) {
goto errout;
}
cache_data = NULL;
}
if (request->dualstack_selection) {
@@ -866,7 +920,7 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
return 0;
errout:
if (cache_data == NULL) {
if (cache_data != NULL) {
dns_cache_data_free(cache_data);
cache_data = NULL;
}
@@ -1775,7 +1829,7 @@ static int _dns_server_setup_ipset_packet(struct dns_request *request, struct dn
int i = 0;
int j = 0;
struct dns_rrs *rrs = NULL;
struct dns_ipset_rule *ipset_rule = NULL;
struct dns_ipset_rule *rule = NULL, *ipset_rule = NULL, *ipset_rule_v4 = NULL, *ipset_rule_v6 = NULL;
struct dns_rule_flags *rule_flags = NULL;
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_IPSET) == 0) {
@@ -1783,14 +1837,17 @@ static int _dns_server_setup_ipset_packet(struct dns_request *request, struct dn
}
/* check ipset rule */
rule_flags = request->domain_rule.rules[DOMAIN_RULE_FLAGS];
if (rule_flags) {
if (rule_flags->flags & DOMAIN_FLAG_IPSET_IGNORE) {
return 0;
}
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IGN) == 0) {
ipset_rule = request->domain_rule.rules[DOMAIN_RULE_IPSET];
}
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV4_IGN) == 0) {
ipset_rule_v4 = request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV4];
}
if (!rule_flags || (rule_flags->flags & DOMAIN_FLAG_IPSET_IPV6_IGN) == 0) {
ipset_rule_v6 = request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV6];
}
ipset_rule = request->domain_rule.rules[DOMAIN_RULE_IPSET];
if (ipset_rule == NULL) {
if (!(ipset_rule || ipset_rule_v4 || ipset_rule_v6)) {
return 0;
}
@@ -1809,11 +1866,14 @@ static int _dns_server_setup_ipset_packet(struct dns_request *request, struct dn
/* get A result */
dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
/* add IPV4 to ipset */
ipset_add(ipset_rule->ipsetname, addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
tlog(TLOG_DEBUG, "IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: %d.%d.%d.%d", request->domain,
ipset_rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
if (rule) {
/* add IPV4 to ipset */
ipset_add(rule->ipsetname, addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
tlog(TLOG_DEBUG, "IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: %d.%d.%d.%d", request->domain,
rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
}
} break;
case DNS_T_AAAA: {
unsigned char addr[16];
@@ -1826,16 +1886,25 @@ static int _dns_server_setup_ipset_packet(struct dns_request *request, struct dn
/* add IPV6 to ipset */
if (request->has_ipv6) {
if (request->has_ipv4) {
ipset_add(ipset_rule->ipsetname, addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
rule = ipset_rule_v4 ? ipset_rule_v4 : ipset_rule;
if (rule) {
/* add IPV4 to ipset */
ipset_add(rule->ipsetname, addr, DNS_RR_A_LEN, request->ttl_v4 * 2);
tlog(TLOG_DEBUG, "IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: %d.%d.%d.%d",
request->domain, rule->ipsetname, addr[0], addr[1], addr[2], addr[3]);
}
}
rule = ipset_rule_v6 ? ipset_rule_v6 : ipset_rule;
if (rule) {
ipset_add(rule->ipsetname, addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
tlog(TLOG_DEBUG,
"IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: "
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
request->domain, rule->ipsetname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14],
addr[15]);
}
ipset_add(ipset_rule->ipsetname, addr, DNS_RR_AAAA_LEN, request->ttl_v6 * 2);
}
tlog(TLOG_DEBUG,
"IPSET-MATCH-PASSTHROUTH: domain: %s, ipset: %s, IP: "
"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
request->domain, ipset_rule->ipsetname, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
} break;
default:
break;
@@ -2062,10 +2131,18 @@ static void _dns_server_update_rule_by_flags(struct dns_request *request)
request->domain_rule.rules[DOMAIN_RULE_ADDRESS_IPV6] = NULL;
}
if (flags & DOMAIN_FLAG_IPSET_IGNORE) {
if (flags & DOMAIN_FLAG_IPSET_IGN) {
request->domain_rule.rules[DOMAIN_RULE_IPSET] = NULL;
}
if (flags & DOMAIN_FLAG_IPSET_IPV4_IGN) {
request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV4] = NULL;
}
if (flags & DOMAIN_FLAG_IPSET_IPV6_IGN) {
request->domain_rule.rules[DOMAIN_RULE_IPSET_IPV6] = NULL;
}
if (flags & DOMAIN_FLAG_NAMESERVER_IGNORE) {
request->domain_rule.rules[DOMAIN_RULE_NAMESERVER] = NULL;
}
@@ -2400,7 +2477,7 @@ static int _dns_server_process_cache(struct dns_request *request)
if (dns_cache == NULL) {
if (request->dualstack_selection && request->qtype == DNS_T_AAAA) {
dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A);
if (dns_cache_A) {
if (dns_cache_A && dns_cache_is_soa(dns_cache_A) == 0 && dns_cache_is_soa(dns_cache)) {
tlog(TLOG_DEBUG, "No IPV6 Found, Force IPV4 perfered.");
if (dns_cache_get_ttl(dns_cache_A) == 0) {
uint32_t server_flags = request->server_flags;
@@ -2420,9 +2497,14 @@ static int _dns_server_process_cache(struct dns_request *request)
goto out;
}
if (dns_cache_is_soa(dns_cache)) {
ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request);
goto out;
}
if (request->dualstack_selection && request->qtype == DNS_T_AAAA) {
dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A);
if (dns_cache_A && (dns_cache_A->info.speed > 0)) {
if (dns_cache_A && dns_cache_is_soa(dns_cache_A) == 0 && (dns_cache_A->info.speed > 0)) {
if ((dns_cache_A->info.speed + (dns_conf_dualstack_ip_selection_threshold * 10)) < dns_cache->info.speed ||
dns_cache->info.speed < 0) {
tlog(TLOG_DEBUG, "Force IPV4 perfered.");
@@ -2591,6 +2673,8 @@ static int _dns_server_do_query(struct dns_request *request, const char *domain,
group_name = dns_group;
}
_dns_server_set_dualstack_selection(request);
if (_dns_server_process_special_query(request) == 0) {
goto clean_exit;
}
@@ -2717,7 +2801,6 @@ static int _dns_server_recv(struct dns_server_conn_head *conn, unsigned char *in
_dns_server_request_set_client(request, conn);
_dns_server_request_set_client_addr(request, from, from_len);
_dns_server_request_set_id(request, packet->head.id);
_dns_server_set_dualstack_selection(request);
ret = _dns_server_do_query(request, domain, qtype);
if (ret != 0) {
tlog(TLOG_ERROR, "do query %s failed.\n", domain);

View File

@@ -365,7 +365,12 @@ static void _fast_ping_close_host_sock(struct ping_host_struct *ping_host)
static void _fast_ping_host_put(struct ping_host_struct *ping_host)
{
if (!atomic_dec_and_test(&ping_host->ref)) {
int ref_cnt = atomic_dec_and_test(&ping_host->ref);
if (!ref_cnt) {
if (ref_cnt < 0) {
tlog(TLOG_ERROR, "invalid refcount of ping_host %s", ping_host->host);
abort();
}
return;
}
@@ -1081,15 +1086,19 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c
pthread_mutex_unlock(&ping.map_lock);
_fast_ping_host_get(ping_host);
_fast_ping_host_get(ping_host);
// for ping race condition, get reference count twice
if (_fast_ping_sendping(ping_host) != 0) {
goto errout_remove;
}
ping_host->run = 1;
freeaddrinfo(gai);
_fast_ping_host_put(ping_host);
return ping_host;
errout_remove:
fast_ping_stop(ping_host);
_fast_ping_host_put(ping_host);
ping_host = NULL;
errout:
if (gai) {

View File

@@ -363,7 +363,7 @@ static void _sig_error_exit(int signo, siginfo_t *siginfo, void *ct)
"%s %s)\n",
signo, siginfo->si_code, siginfo->si_errno, siginfo->si_pid, getpid(), PC, (unsigned long)siginfo->si_addr,
__DATE__, __TIME__, arch);
print_stack();
sleep(1);
_exit(0);
}

View File

@@ -10,6 +10,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <pthread.h>
#include <stdarg.h>
@@ -21,7 +22,6 @@
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <libgen.h>
#include <unistd.h>
#ifndef likely
@@ -40,6 +40,8 @@
#define TLOG_BUFF_LEN (PATH_MAX + TLOG_LOG_NAME_LEN * 3)
#define TLOG_SUFFIX_GZ ".gz"
#define TLOG_SUFFIX_LOG ""
#define TLOG_MAX_LINE_SIZE_SET (1024 * 8)
#define TLOG_MIN_LINE_SIZE_SET (128)
#define TLOG_SEGMENT_MAGIC 0xFF446154
@@ -57,6 +59,9 @@ struct tlog_log {
char logdir[PATH_MAX];
char logname[TLOG_LOG_NAME_LEN];
char suffix[TLOG_LOG_NAME_LEN];
char pending_logfile[PATH_MAX];
int rename_pending;
int fail;
int logsize;
int logcount;
int block;
@@ -66,12 +71,15 @@ struct tlog_log {
int multi_log;
int logscreen;
int segment_log;
unsigned int max_line_size;
tlog_output_func output_func;
void *private_data;
time_t last_try;
time_t last_waitpid;
mode_t file_perm;
mode_t archive_perm;
int waiters;
int is_exit;
@@ -97,13 +105,13 @@ struct tlog_segment_log_head {
struct tlog_loginfo info;
unsigned short len;
char data[0];
} __attribute__((packed));
} __attribute__((packed));
struct tlog_segment_head {
unsigned int magic;
unsigned short len;
char data[0];
} __attribute__((packed));
} __attribute__((packed));
struct oldest_log {
char name[TLOG_LOG_NAME_LEN];
@@ -166,8 +174,8 @@ static int _tlog_mkdir(const char *path)
if (access(path, F_OK) == 0) {
return 0;
}
while(*path == ' ' && *path != '\0') {
while (*path == ' ' && *path != '\0') {
path++;
}
@@ -283,11 +291,37 @@ static int _tlog_gettime(struct tlog_time *cur_time)
return 0;
}
void tlog_set_maxline_size(struct tlog_log *log, int size)
{
if (log == NULL) {
return;
}
if (size < TLOG_MIN_LINE_SIZE_SET) {
size = TLOG_MIN_LINE_SIZE_SET;
} else if (size > TLOG_MAX_LINE_SIZE_SET) {
size = TLOG_MAX_LINE_SIZE_SET;
}
log->max_line_size = size;
}
void tlog_set_permission(struct tlog_log *log, unsigned int file, unsigned int archive)
{
log->file_perm = file;
log->archive_perm = archive;
}
int tlog_localtime(struct tlog_time *tm)
{
return _tlog_gettime(tm);
}
tlog_log *tlog_get_root()
{
return tlog.root;
}
void tlog_set_private(tlog_log *log, void *private_data)
{
if (log == NULL) {
@@ -311,19 +345,19 @@ static int _tlog_format(char *buff, int maxlen, struct tlog_loginfo *info, void
int len = 0;
int total_len = 0;
struct tlog_time *tm = &info->time;
void* unused __attribute__ ((unused));
void *unused __attribute__((unused));
unused = userptr;
if (tlog.root->multi_log) {
/* format prefix */
len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5d][%4s][%17s:%-4d] ",
tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000, getpid(),
len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5d][%4s][%17s:%-4d] ",
tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000, getpid(),
tlog_get_level_string(info->level), info->file, info->line);
} else {
/* format prefix */
len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5s][%17s:%-4d] ",
tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000,
len = snprintf(buff, maxlen, "[%.4d-%.2d-%.2d %.2d:%.2d:%.2d,%.3d][%5s][%17s:%-4d] ",
tm->year, tm->mon, tm->mday, tm->hour, tm->min, tm->sec, tm->usec / 1000,
tlog_get_level_string(info->level), info->file, info->line);
}
@@ -359,7 +393,7 @@ static int _tlog_root_log_buffer(char *buff, int maxlen, void *userptr, const ch
}
if (tlog.root->segment_log) {
log_head = (struct tlog_segment_log_head *) buff;
log_head = (struct tlog_segment_log_head *)buff;
len += sizeof(*log_head);
memcpy(&log_head->info, &info_inter->info, sizeof(log_head->info));
}
@@ -400,7 +434,7 @@ static int _tlog_print_buffer(char *buff, int maxlen, void *userptr, const char
{
int len;
int total_len = 0;
void* unused __attribute__ ((unused));
void *unused __attribute__((unused));
unused = userptr;
@@ -438,7 +472,7 @@ static int _tlog_need_drop(struct tlog_log *log)
}
/* if free buffer length is less than min line length */
if (maxlen < TLOG_MAX_LINE_LEN) {
if (maxlen < log->max_line_size) {
log->dropped++;
ret = 0;
}
@@ -450,14 +484,14 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
{
int len;
int maxlen = 0;
char buff[TLOG_MAX_LINE_LEN];
struct tlog_segment_head *segment_head = NULL;
if (log == NULL || format == NULL) {
return -1;
}
char buff[log->max_line_size];
if (log->buff == NULL) {
return -1;
}
@@ -469,7 +503,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
len = print_callback(buff, sizeof(buff), userptr, format, ap);
if (len <= 0) {
return -1;
} else if (len >= TLOG_MAX_LINE_LEN) {
} else if (len >= log->max_line_size) {
strncpy(buff, "[LOG TOO LONG, DISCARD]\n", sizeof(buff));
buff[sizeof(buff) - 1] = '\0';
len = strnlen(buff, sizeof(buff));
@@ -490,7 +524,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
}
/* if free buffer length is less than min line length */
if (maxlen < TLOG_MAX_LINE_LEN) {
if (maxlen < log->max_line_size) {
if (log->end != log->start) {
tlog.notify_log = log;
pthread_cond_signal(&tlog.cond);
@@ -502,7 +536,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
pthread_mutex_unlock(&tlog.lock);
return -1;
}
pthread_mutex_unlock(&tlog.lock);
pthread_mutex_lock(&log->lock);
log->waiters++;
@@ -516,7 +550,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
pthread_mutex_lock(&tlog.lock);
}
} while (maxlen < TLOG_MAX_LINE_LEN);
} while (maxlen < log->max_line_size);
if (log->segment_log) {
segment_head = (struct tlog_segment_head *)(log->buff + log->end);
@@ -532,7 +566,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
}
/* if remain buffer is not enough for a line, move end to start of buffer. */
if (log->end > log->buffsize - TLOG_MAX_LINE_LEN) {
if (log->end > log->buffsize - log->max_line_size) {
log->ext_end = log->end;
log->end = 0;
}
@@ -562,12 +596,12 @@ int tlog_printf(struct tlog_log *log, const char *format, ...)
return len;
}
static int _tlog_early_print(const char *format, va_list ap)
static int _tlog_early_print(const char *format, va_list ap)
{
char log_buf[TLOG_MAX_LINE_LEN];
size_t len = 0;
size_t out_len = 0;
int unused __attribute__ ((unused));
int unused __attribute__((unused));
if (tlog_disable_early_print) {
return 0;
@@ -643,13 +677,13 @@ static int _tlog_rename_logfile(struct tlog_log *log, const char *log_file)
return -1;
}
snprintf(archive_file, sizeof(archive_file), "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d%s",
snprintf(archive_file, sizeof(archive_file), "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d%s",
log->logdir, log->logname, logtime.year, logtime.mon, logtime.mday,
logtime.hour, logtime.min, logtime.sec, log->suffix);
while (access(archive_file, F_OK) == 0) {
i++;
snprintf(archive_file, sizeof(archive_file), "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d-%d%s",
snprintf(archive_file, sizeof(archive_file), "%s/%s-%.4d%.2d%.2d-%.2d%.2d%.2d-%d%s",
log->logdir, log->logname, logtime.year, logtime.mon,
logtime.mday, logtime.hour, logtime.min, logtime.sec, i, log->suffix);
}
@@ -658,6 +692,8 @@ static int _tlog_rename_logfile(struct tlog_log *log, const char *log_file)
return -1;
}
chmod(archive_file, log->archive_perm);
return 0;
}
@@ -666,7 +702,7 @@ static int _tlog_list_dir(const char *path, list_callback callback, void *userpt
DIR *dir = NULL;
struct dirent *ent;
int ret = 0;
const char* unused __attribute__ ((unused)) = path;
const char *unused __attribute__((unused)) = path;
dir = opendir(path);
if (dir == NULL) {
@@ -699,7 +735,7 @@ static int _tlog_count_log_callback(const char *path, struct dirent *entry, void
struct count_log *count_log = (struct count_log *)userptr;
struct tlog_log *log = count_log->log;
char logname[TLOG_LOG_NAME_LEN * 2];
const char* unused __attribute__ ((unused)) = path;
const char *unused __attribute__((unused)) = path;
if (strstr(entry->d_name, log->suffix) == NULL) {
return 0;
@@ -1023,16 +1059,41 @@ static int _tlog_archive_log(struct tlog_log *log)
}
}
void _tlog_get_log_name_dir(struct tlog_log *log)
{
char log_file[PATH_MAX];
if (log->fd > 0) {
close(log->fd);
log->fd = -1;
}
pthread_mutex_lock(&tlog.lock);
strncpy(log_file, log->pending_logfile, sizeof(log_file) - 1);
log_file[sizeof(log_file) - 1] = '\0';
strncpy(log->logdir, dirname(log_file), sizeof(log->logdir));
log->logdir[sizeof(log->logdir) - 1] = '\0';
strncpy(log_file, log->pending_logfile, PATH_MAX);
log_file[sizeof(log_file) - 1] = '\0';
strncpy(log->logname, basename(log_file), sizeof(log->logname));
log->logname[sizeof(log->logname) - 1] = '\0';
pthread_mutex_unlock(&tlog.lock);
}
static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
{
int len;
int unused __attribute__ ((unused));
int unused __attribute__((unused));
if (bufflen <= 0) {
if (bufflen <= 0 || log->fail) {
return 0;
}
/* output log to screen */
if (log->rename_pending) {
_tlog_get_log_name_dir(log);
log->rename_pending = 0;
}
/* output log to screen */
if (log->logscreen) {
unused = write(STDOUT_FILENO, buff, bufflen);
}
@@ -1072,7 +1133,7 @@ static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
}
snprintf(logfile, sizeof(logfile), "%s/%s", log->logdir, log->logname);
log->filesize = 0;
log->fd = open(logfile, O_APPEND | O_CREAT | O_WRONLY | O_CLOEXEC, 0640);
log->fd = open(logfile, O_APPEND | O_CREAT | O_WRONLY | O_CLOEXEC, log->file_perm);
if (log->fd < 0) {
if (print_errmsg == 0) {
return -1;
@@ -1131,7 +1192,6 @@ static int _tlog_any_has_data_locked(void)
return 0;
}
static int _tlog_any_has_data(void)
{
int ret = 0;
@@ -1162,7 +1222,7 @@ static int _tlog_wait_pids(void)
continue;
}
last_log = next;
last_log = next;
next->last_waitpid = now;
pthread_mutex_unlock(&tlog.lock);
_tlog_wait_pid(next, 0);
@@ -1263,7 +1323,6 @@ static void _tlog_wakeup_waiters(struct tlog_log *log)
pthread_mutex_unlock(&log->lock);
}
static void _tlog_write_one_segment_log(struct tlog_log *log, char *buff, int bufflen)
{
struct tlog_segment_head *segment_head = NULL;
@@ -1345,10 +1404,10 @@ static void *_tlog_work(void *arg)
int log_dropped = 0;
struct tlog_log *log = NULL;
struct tlog_log *loop_log = NULL;
void* unused __attribute__ ((unused));
void *unused __attribute__((unused));
unused = arg;
while (1) {
log_len = 0;
log_extlen = 0;
@@ -1430,7 +1489,7 @@ static void *_tlog_work(void *arg)
void tlog_set_early_printf(int enable)
{
tlog_disable_early_print = (enable == 0) ? 1 : 0;
tlog_disable_early_print = (enable == 0) ? 1 : 0;
}
const char *tlog_get_level_string(tlog_level level)
@@ -1518,10 +1577,14 @@ tlog_level tlog_getlevel(void)
return tlog_set_level;
}
void tlog_set_logfile(const char *logfile)
{
tlog_rename_logfile(tlog.root, logfile);
}
tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag)
{
struct tlog_log *log = NULL;
char log_file[PATH_MAX];
if (tlog.run == 0) {
fprintf(stderr, "tlog is not initialized.");
@@ -1546,22 +1609,19 @@ tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int bu
log->filesize = 0;
log->zip_pid = -1;
log->is_exit = 0;
log->fail = 0;
log->waiters = 0;
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->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;
log->output_func = _tlog_write;
log->file_perm = S_IRUSR | S_IWUSR | S_IRGRP;
log->archive_perm = S_IRUSR | S_IRGRP;
strncpy(log_file, logfile, sizeof(log_file) - 1);
log_file[sizeof(log_file) - 1] = '\0';
strncpy(log->logdir, dirname(log_file), sizeof(log->logdir));
log->logdir[sizeof(log->logdir) - 1] = '\0';
strncpy(log_file, logfile, PATH_MAX);
log_file[sizeof(log_file) - 1] = '\0';
strncpy(log->logname, basename(log_file), sizeof(log->logname));
log->logname[sizeof(log->logname) - 1] = '\0';
tlog_rename_logfile(log, logfile);
if (log->nocompress) {
strncpy(log->suffix, TLOG_SUFFIX_LOG, sizeof(log->suffix));
} else {
@@ -1605,6 +1665,58 @@ void tlog_close(tlog_log *log)
log->is_exit = 1;
}
void tlog_rename_logfile(struct tlog_log *log, const char *logfile)
{
pthread_mutex_lock(&tlog.lock);
strncpy(log->pending_logfile, logfile, sizeof(log->pending_logfile) - 1);
pthread_mutex_unlock(&tlog.lock);
log->rename_pending = 1;
}
static void tlog_fork_prepare(void)
{
if (tlog.root == NULL) {
return;
}
pthread_mutex_lock(&tlog.lock);
}
static void tlog_fork_parent(void)
{
if (tlog.root == NULL) {
return;
}
pthread_mutex_unlock(&tlog.lock);
}
static void tlog_fork_child(void)
{
pthread_attr_t attr;
tlog_log *next;
if (tlog.root == NULL) {
return;
}
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));
goto errout;
}
goto out;
errout:
next = tlog.log;
while (next) {
next->fail = 1;
next = next->next;
}
out:
pthread_mutex_unlock(&tlog.lock);
}
int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag)
{
pthread_attr_t attr;
@@ -1616,7 +1728,7 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
return -1;
}
if (buffsize > 0 && buffsize < TLOG_MAX_LINE_LEN * 2) {
if (buffsize > 0 && buffsize < TLOG_MAX_LINE_SIZE_SET * 2) {
fprintf(stderr, "buffer size is invalid.\n");
return -1;
}
@@ -1645,6 +1757,9 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
}
tlog.root = log;
if (flag & TLOG_SUPPORT_FORK) {
pthread_atfork(&tlog_fork_prepare, &tlog_fork_parent, &tlog_fork_child);
}
return 0;
errout:
if (tlog.tid > 0) {

View File

@@ -1,19 +1,20 @@
/*
* tinylog
* Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com>
* Copyright (C) 2018-2021 Ruilin Peng (Nick) <pymumu@gmail.com>
* https://github.com/pymumu/tinylog
*/
#ifndef TLOG_H
#define TLOG_H
#include <stdarg.h>
#include <sys/stat.h>
#ifdef __cplusplus
#include <string>
#include <functional>
#include <iostream>
#include <memory>
#include <sstream>
#include <iostream>
#include <functional>
#include <string>
extern "C" {
#endif /*__cplusplus */
@@ -60,6 +61,9 @@ struct tlog_time {
/* enable log to screen */
#define TLOG_SCREEN (1 << 4)
/* enable suppport fork process */
#define TLOG_SUPPORT_FORK (1 << 5)
struct tlog_loginfo {
tlog_level level;
const char *file;
@@ -79,7 +83,7 @@ format: Log formats
#define tlog(level, format, ...) tlog_ext(level, BASE_FILE_NAME, __LINE__, __func__, NULL, format, ##__VA_ARGS__)
extern int tlog_ext(tlog_level level, const char *file, int line, const char *func, void *userptr, const char *format, ...)
__attribute__((format(printf, 6, 7))) __attribute__((nonnull (6)));
__attribute__((format(printf, 6, 7))) __attribute__((nonnull(6)));
extern int tlog_vext(tlog_level level, const char *file, int line, const char *func, void *userptr, const char *format, va_list ap);
/* write buff to log file */
@@ -91,6 +95,9 @@ extern int tlog_setlevel(tlog_level level);
/* get log level */
extern tlog_level tlog_getlevel(void);
/* set log file */
extern void tlog_set_logfile(const char *logfile);
/* enalbe log to screen */
extern void tlog_setlogscreen(int enable);
@@ -132,6 +139,10 @@ extern int tlog_reg_log_output_func(tlog_log_output_func output, void *private_d
struct tlog_log;
typedef struct tlog_log tlog_log;
/* get root log handler */
extern tlog_log *tlog_get_root(void);
/*
Function: open a new log stream, handler should close by tlog_close
logfile: log file.
@@ -149,12 +160,15 @@ extern int tlog_write(struct tlog_log *log, const char *buff, int bufflen);
/* close log stream */
extern void tlog_close(tlog_log *log);
/* change log file */
extern void tlog_rename_logfile(struct tlog_log *log, const char *logfile);
/*
Function: Print log to log stream
log: log stream
format: Log formats
*/
extern int tlog_printf(tlog_log *log, const char *format, ...) __attribute__((format(printf, 2, 3))) __attribute__((nonnull (1, 2)));
extern int tlog_printf(tlog_log *log, const char *format, ...) __attribute__((format(printf, 2, 3))) __attribute__((nonnull(1, 2)));
/*
Function: Print log to log stream with ap
@@ -180,49 +194,78 @@ extern void *tlog_get_private(tlog_log *log);
/* get local time */
extern int tlog_localtime(struct tlog_time *tm);
/* set max line size */
extern void tlog_set_maxline_size(struct tlog_log *log, int size);
/*
Function: set log file and archive permission
log: log stream
file: log file permission, default is 640
archive: archive file permission, default is 440
*/
extern void tlog_set_permission(struct tlog_log *log, mode_t file, mode_t archive);
#ifdef __cplusplus
class Tlog {
using Stream = std::ostringstream;
using Buffer = std::unique_ptr<Stream, std::function<void(Stream*)>>;
public:
Tlog(){}
~Tlog(){}
static Tlog &Instance() {
static Tlog logger;
return logger;
Tlog(tlog_level level, const char *file, int line, const char *func, void *userptr)
{
level_ = level;
file_ = file;
line_ = line;
func_ = func;
userptr_ = userptr;
}
Buffer LogStream(tlog_level level, const char *file, int line, const char *func, void *userptr) {
return Buffer(new Stream, [=](Stream *st) {
tlog_ext(level, file, line, func, userptr, "%s", st->str().c_str());
delete st;
});
~Tlog()
{
tlog_ext(level_, file_, line_, func_, userptr_, "%s", msg_.str().c_str());
}
std::ostream &Stream()
{
return msg_;
}
private:
tlog_level level_;
const char *file_;
int line_;
const char *func_;
void *userptr_;
std::ostringstream msg_;
};
class TlogOut {
using Stream = std::ostringstream;
using Buffer = std::unique_ptr<Stream, std::function<void(Stream*)>>;
public:
TlogOut(){}
~TlogOut(){}
static TlogOut &Instance() {
static TlogOut logger;
return logger;
TlogOut(tlog_log *log)
{
log_ = log;
}
Buffer Out(tlog_log *log) {
return Buffer(new Stream, [=](Stream *st) {
tlog_printf(log, "%s", st->str().c_str());
delete st;
});
~TlogOut()
{
if (log_ == nullptr) {
return;
}
tlog_printf(log_, "%s", msg_.str().c_str());
}
std::ostream &Stream()
{
return msg_;
}
private:
tlog_log *log_;
std::ostringstream msg_;
};
#define Tlog_logger (Tlog::Instance())
#define Tlog_stream(level) if (tlog_getlevel() <= level) *Tlog_logger.LogStream(level, BASE_FILE_NAME, __LINE__, __func__, NULL)
#define Tlog_stream(level) \
if (tlog_getlevel() <= level) \
Tlog(level, BASE_FILE_NAME, __LINE__, __func__, NULL).Stream()
#define tlog_debug Tlog_stream(TLOG_DEBUG)
#define tlog_info Tlog_stream(TLOG_INFO)
#define tlog_notice Tlog_stream(TLOG_NOTICE)
@@ -230,8 +273,7 @@ public:
#define tlog_error Tlog_stream(TLOG_ERROR)
#define tlog_fatal Tlog_stream(TLOG_FATAL)
#define Tlog_out_logger (TlogOut::Instance())
#define tlog_out(stream) (*Tlog_out_logger.Out(stream))
#define tlog_out(stream) TlogOut(stream).Stream()
} /*__cplusplus */
#else
@@ -241,5 +283,5 @@ public:
#define tlog_warn(...) tlog(TLOG_WARN, ##__VA_ARGS__)
#define tlog_error(...) tlog(TLOG_ERROR, ##__VA_ARGS__)
#define tlog_fatal(...) tlog(TLOG_FATAL, ##__VA_ARGS__)
#endif
#endif
#endif // !TLOG_H

View File

@@ -21,7 +21,9 @@
#endif
#include "util.h"
#include "dns_conf.h"
#include "tlog.h"
#include <arpa/inet.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -39,6 +41,7 @@
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <unwind.h>
#define TMP_BUFF_LEN_32 32
@@ -936,7 +939,7 @@ void get_compiled_time(struct tm *tm)
int hour, min, sec;
static const char *month_names = "JanFebMarAprMayJunJulAugSepOctNovDec";
sscanf(__DATE__, "%5s %d %d", s_month, &day, &year);
sscanf(__DATE__, "%4s %d %d", s_month, &day, &year);
month = (strstr(month_names, s_month) - month_names) / 3;
sscanf(__TIME__, "%d:%d:%d", &hour, &min, &sec);
tm->tm_year = year - 1900;
@@ -1009,3 +1012,50 @@ uint64_t get_free_space(const char *path)
return size;
}
struct backtrace_state {
void **current;
void **end;
};
static _Unwind_Reason_Code unwind_callback(struct _Unwind_Context *context, void *arg)
{
struct backtrace_state *state = (struct backtrace_state *)(arg);
uintptr_t pc = _Unwind_GetIP(context);
if (pc) {
if (state->current == state->end) {
return _URC_END_OF_STACK;
} else {
*state->current++ = (void *)(pc);
}
}
return _URC_NO_REASON;
}
void print_stack(void)
{
const size_t max_buffer = 30;
void *buffer[max_buffer];
struct backtrace_state state = {buffer, buffer + max_buffer};
_Unwind_Backtrace(unwind_callback, &state);
int frame_num = state.current - buffer;
if (frame_num == 0) {
return;
}
tlog(TLOG_FATAL, "Stack:");
for (int idx = 0; idx < frame_num; ++idx) {
const void *addr = buffer[idx];
const char *symbol = "";
Dl_info info;
memset(&info, 0, sizeof(info));
if (dladdr(addr, &info) && info.dli_sname) {
symbol = info.dli_sname;
}
void *offset = (void *)((char *)(addr) - (char *)(info.dli_fbase));
tlog(TLOG_FATAL, "#%.2d: %p %s from %s+%p", idx + 1, addr, symbol, info.dli_fname, offset);
}
}

View File

@@ -108,6 +108,8 @@ int set_sock_lingertime(int fd, int time);
uint64_t get_free_space(const char *path);
void print_stack(void);
#ifdef __cplusplus
}
#endif /*__cplusplus */

19
systemd/smartdns.service Normal file
View File

@@ -0,0 +1,19 @@
[Unit]
Description=SmartDNS Server
After=network.target
StartLimitBurst=0
StartLimitIntervalSec=60
[Service]
Type=forking
PIDFile=/var/run/smartdns.pid
EnvironmentFile=/etc/default/smartdns
ExecStart=/usr/sbin/smartdns -p /var/run/smartdns.pid $SMART_DNS_OPTS
KillMode=process
Restart=always
RestartSec=2
TimeoutStopSec=5
[Install]
WantedBy=multi-user.target
Alias=smartdns.service

View File

@@ -1,9 +1,8 @@
[Unit]
Description=smartdns server
Description=SmartDNS Server
After=network.target
StartLimitBurst=0
StartLimitIntervalSec=60
TimeoutStopSec=5
[Service]
Type=forking
@@ -13,6 +12,7 @@ ExecStart=@SBINDIR@/smartdns -p @RUNSTATEDIR@/smartdns.pid $SMART_DNS_OPTS
KillMode=process
Restart=always
RestartSec=2
TimeoutStopSec=5
[Install]
WantedBy=multi-user.target