Compare commits
6 Commits
Release32-
...
Release33
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86902d2e34 | ||
|
|
6f30fe6d05 | ||
|
|
0b45da29c7 | ||
|
|
2b81fffb7e | ||
|
|
7af6f475da | ||
|
|
c3b6560b46 |
@@ -504,6 +504,8 @@ 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-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
|
||||
|rr-ttl-min|允许的最小TTL值|远程查询结果|大于0的数字|rr-ttl-min 60
|
||||
@@ -535,6 +537,7 @@ https://github.com/pymumu/smartdns/releases
|
||||
|prefetch-domain|域名预先获取功能|no|[yes\|no]|prefetch-domain yes
|
||||
|serve-expired|过期缓存服务功能|no|[yes\|no],开启此功能后,如果有请求时尝试回应TTL为0的过期记录,并并发查询记录,以避免查询等待|serve-expired yes
|
||||
|serve-expired-ttl|过期缓存服务最长超时时间|0|秒,0:表示停用超时,> 0表示指定的超时的秒数|serve-expired-ttl 0
|
||||
|serve-expired-reply-ttl|回应的过期缓存TTL|5|秒,0:表示停用超时,> 0表示指定的超时的秒数|serve-expired-reply-ttl 30
|
||||
|dualstack-ip-selection|双栈IP优选|no|[yes\|no]|dualstack-ip-selection yes
|
||||
|dualstack-ip-selection-threshold|双栈IP优选阈值|30ms|毫秒|dualstack-ip-selection-threshold [0-1000]
|
||||
|ca-file|证书文件|/etc/ssl/certs/ca-certificates.crt|路径|ca-file /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
@@ -498,6 +498,8 @@ 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-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
|
||||
|rr-ttl-min|Domain name Minimum TTL|Remote query result|number greater than 0|rr-ttl-min 60
|
||||
@@ -529,6 +531,7 @@ Note: Merlin firmware is derived from ASUS firmware and can theoretically be use
|
||||
|prefetch-domain|domain prefetch feature|no|[yes\|no]|prefetch-domain yes
|
||||
|serve-expired|Cache serve expired feature|no|[yes\|no], Attempts to serve old responses from cache with a TTL of 0 in the response without waiting for the actual resolution to finish.|serve-expired yes
|
||||
|serve-expired-ttl|Cache serve expired limite TTL|0|second,0:disable,> 0 seconds after expiration|serve-expired-ttl 0
|
||||
|serve-expired-reply-ttl|TTL value to use when replying with expired data|5|second,0:disable,> 0 seconds after expiration|serve-expired-reply-ttl 30
|
||||
|dualstack-ip-selection|Dualstack ip selection|no|[yes\|no]|dualstack-ip-selection yes
|
||||
|dualstack-ip-selection-threshold|Dualstack ip select threadhold|30ms|millisecond|dualstack-ip-selection-threshold [0-1000]
|
||||
|ca-file|certificate file|/etc/ssl/certs/ca-certificates.crt|path|ca-file /etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
@@ -38,7 +38,13 @@ bind [::]:53
|
||||
# dns cache size
|
||||
# cache-size [number]
|
||||
# 0: for no cache
|
||||
cache-size 512
|
||||
cache-size 4096
|
||||
|
||||
# enable persist cache when restart
|
||||
# cache-persist yes
|
||||
|
||||
# cache persist file
|
||||
# cache-file /tmp/smartdns.cache
|
||||
|
||||
# prefetch domain
|
||||
# prefetch-domain [yes|no]
|
||||
@@ -52,6 +58,10 @@ cache-size 512
|
||||
# serve-expired-ttl [num]
|
||||
# serve-expired-ttl 0
|
||||
|
||||
# reply TTL value to use when replying with expired data
|
||||
# serve-expired-reply-ttl [num]
|
||||
# serve-expired-reply-ttl 30
|
||||
|
||||
# List of hosts that supply bogus NX domain results
|
||||
# bogus-nxdomain [ip/subnet]
|
||||
|
||||
|
||||
@@ -332,9 +332,28 @@ case "$1" in
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -d "/proc/$pid" ]; then
|
||||
return 0;
|
||||
kill -15 "$pid" 2>/dev/null
|
||||
SLEEP=`which usleep`
|
||||
SLEEPTIME=200000
|
||||
if [ -z "$SLEEP" ]; then
|
||||
SLEEP="sleep"
|
||||
SLEEPTIME=0.2
|
||||
fi
|
||||
N=30
|
||||
while [ $N -gt 0 ]
|
||||
do
|
||||
pid="$(cat "$SMARTDNS_PID" | head -n 1 2>/dev/null)"
|
||||
if [ -z "$pid" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ ! -d "/proc/$pid" ]; then
|
||||
return 0;
|
||||
fi
|
||||
|
||||
$SLEEP $SLEEPTIME 2>/dev/null
|
||||
N=$((N-1))
|
||||
done
|
||||
|
||||
kill -9 "$pid" 2>/dev/null
|
||||
;;
|
||||
|
||||
63
package/redhat/smartdns.spec
Normal file
63
package/redhat/smartdns.spec
Normal file
@@ -0,0 +1,63 @@
|
||||
Name: smartdns
|
||||
Version: 31
|
||||
Release: 1%{?dist}
|
||||
Summary: smartdns
|
||||
|
||||
License: GPL 3.0
|
||||
URL: https://github.com/pymumu/smartdns
|
||||
Source0: smartdns-Release31.tar.gz
|
||||
|
||||
BuildRequires: glibc
|
||||
Requires: glibc
|
||||
Requires: systemd
|
||||
|
||||
%description
|
||||
A local DNS server to obtain the fastest website IP for the best Internet experience.
|
||||
|
||||
%prep
|
||||
%setup -q -n smartdns-Release31
|
||||
|
||||
%build
|
||||
cd src
|
||||
make %{?_smp_mflags}
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%{__install} -D -m 755 src/smartdns $RPM_BUILD_ROOT%{_sbindir}/smartdns
|
||||
%{__install} -D -m 644 etc/smartdns/smartdns.conf $RPM_BUILD_ROOT%{_sysconfdir}/smartdns/smartdns.conf
|
||||
%{__install} -D -m 644 systemd/smartdns.service.in $RPM_BUILD_ROOT%{_unitdir}/smartdns.service
|
||||
|
||||
|
||||
cat > $RPM_BUILD_ROOT%{_unitdir}/smartdns.service <<EOF
|
||||
[Unit]
|
||||
Description=smartdns
|
||||
ConditionFileIsExecutable=/usr/sbin/smartdns
|
||||
After=syslog.target network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/sbin/smartdns -c /etc/smartdns/smartdns.conf -f
|
||||
PIDFile=/run/smartdns.pid
|
||||
Restart=on-failure
|
||||
KillMode=process
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{_sbindir}/smartdns
|
||||
%config(noreplace) %{_sysconfdir}/smartdns/smartdns.conf
|
||||
%{_unitdir}/smartdns.service
|
||||
|
||||
%post
|
||||
%systemd_post %{name}.service
|
||||
|
||||
%preun
|
||||
%systemd_preun %{name}.service
|
||||
|
||||
%postun
|
||||
%systemd_postun_with_restart %{name}.service
|
||||
318
src/dns_cache.c
318
src/dns_cache.c
@@ -19,7 +19,11 @@
|
||||
#include "dns_cache.h"
|
||||
#include "stringutil.h"
|
||||
#include "tlog.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define DNS_CACHE_MAX_HITNUM 5000
|
||||
#define DNS_CACHE_HITNUM_STEP 2
|
||||
@@ -65,7 +69,7 @@ static __attribute__((unused)) struct dns_cache *_dns_cache_last(void)
|
||||
return list_last_entry(&dns_cache_head.cache_list, struct dns_cache, list);
|
||||
}
|
||||
|
||||
static struct dns_cache *_dns_cache_first(void)
|
||||
static struct dns_cache *_dns_inactive_cache_first(void)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
@@ -162,7 +166,7 @@ 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_head);
|
||||
cache_addr->head.size = sizeof(struct dns_cache_addr) - sizeof(struct dns_cache_data_head);
|
||||
|
||||
return (struct dns_cache_data *)cache_addr;
|
||||
|
||||
@@ -219,12 +223,12 @@ int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
|
||||
/* update cache data */
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
dns_cache->ttl = ttl;
|
||||
dns_cache->qtype = qtype;
|
||||
dns_cache->ttl = ttl;
|
||||
dns_cache->del_pending = 0;
|
||||
dns_cache->speed = speed;
|
||||
time(&dns_cache->insert_time);
|
||||
dns_cache->info.ttl = ttl;
|
||||
dns_cache->info.qtype = qtype;
|
||||
dns_cache->info.ttl = ttl;
|
||||
dns_cache->info.speed = speed;
|
||||
time(&dns_cache->info.insert_time);
|
||||
old_cache_data = dns_cache->cache_data;
|
||||
dns_cache->cache_data = cache_data;
|
||||
list_del_init(&dns_cache->list);
|
||||
@@ -236,21 +240,13 @@ int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data *cache_data, struct list_head *head)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
if (cache_data == NULL || domain == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dns_cache_head.size <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if cache already exists, free */
|
||||
dns_cache = dns_cache_lookup(domain, qtype);
|
||||
dns_cache = dns_cache_lookup(info->domain, info->qtype);
|
||||
if (dns_cache) {
|
||||
dns_cache_delete(dns_cache);
|
||||
dns_cache_release(dns_cache);
|
||||
@@ -262,32 +258,22 @@ int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||
ttl = DNS_CACHE_TTL_MIN;
|
||||
}
|
||||
|
||||
memset(dns_cache, 0, sizeof(*dns_cache));
|
||||
key = hash_string(domain);
|
||||
key = jhash(&qtype, sizeof(qtype), key);
|
||||
safe_strncpy(dns_cache->domain, domain, DNS_MAX_CNAME_LEN);
|
||||
atomic_set(&dns_cache->hitnum, 3);
|
||||
key = hash_string(info->domain);
|
||||
key = jhash(&info->qtype, sizeof(info->qtype), key);
|
||||
atomic_set(&dns_cache->ref, 1);
|
||||
dns_cache->qtype = qtype;
|
||||
dns_cache->ttl = ttl;
|
||||
dns_cache->hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
||||
memcpy(&dns_cache->info, info, sizeof(*info));
|
||||
dns_cache->del_pending = 0;
|
||||
dns_cache->speed = speed;
|
||||
dns_cache->cache_data = cache_data;
|
||||
time(&dns_cache->insert_time);
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_add(dns_cache_head.cache_hash, &dns_cache->node, key);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
list_add_tail(&dns_cache->list, head);
|
||||
INIT_LIST_HEAD(&dns_cache->check_list);
|
||||
|
||||
/* Release extra cache, remove oldest cache record */
|
||||
if (atomic_inc_return(&dns_cache_head.num) > dns_cache_head.size) {
|
||||
struct dns_cache *del_cache;
|
||||
del_cache = _dns_cache_first();
|
||||
del_cache = _dns_inactive_cache_first();
|
||||
if (del_cache) {
|
||||
_dns_cache_remove(del_cache);
|
||||
}
|
||||
@@ -303,6 +289,33 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache_info info;
|
||||
|
||||
if (cache_data == NULL || domain == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dns_cache_head.size <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||
ttl = DNS_CACHE_TTL_MIN;
|
||||
}
|
||||
|
||||
info.hitnum = 3;
|
||||
safe_strncpy(info.domain, domain, DNS_MAX_CNAME_LEN);
|
||||
info.qtype = qtype;
|
||||
info.ttl = ttl;
|
||||
info.hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
||||
info.speed = speed;
|
||||
time(&info.insert_time);
|
||||
|
||||
return _dns_cache_insert(&info, cache_data, &dns_cache_head.cache_list);
|
||||
}
|
||||
|
||||
struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
{
|
||||
uint32_t key = 0;
|
||||
@@ -322,11 +335,11 @@ struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hash_for_each_possible(dns_cache_head.cache_hash, dns_cache, node, key)
|
||||
{
|
||||
if (dns_cache->qtype != qtype) {
|
||||
if (dns_cache->info.qtype != qtype) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(domain, dns_cache->domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||
if (strncmp(domain, dns_cache->info.domain, DNS_MAX_CNAME_LEN) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -336,7 +349,7 @@ struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
|
||||
|
||||
if (dns_cache_ret) {
|
||||
/* Return NULL if the cache times out */
|
||||
if (dns_cache_head.enable_inactive == 0 && (now - dns_cache_ret->insert_time > dns_cache_ret->ttl)) {
|
||||
if (dns_cache_head.enable_inactive == 0 && (now - dns_cache_ret->info.insert_time > dns_cache_ret->info.ttl)) {
|
||||
_dns_cache_remove(dns_cache_ret);
|
||||
dns_cache_ret = NULL;
|
||||
} else {
|
||||
@@ -355,7 +368,7 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache)
|
||||
int ttl = 0;
|
||||
time(&now);
|
||||
|
||||
ttl = dns_cache->insert_time + dns_cache->ttl - now;
|
||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - now;
|
||||
if (ttl < 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -377,15 +390,14 @@ void dns_cache_delete(struct dns_cache *dns_cache)
|
||||
|
||||
int dns_cache_hitnum_dec_get(struct dns_cache *dns_cache)
|
||||
{
|
||||
int hitnum = 0;
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
hitnum = atomic_dec_return(&dns_cache->hitnum);
|
||||
if (dns_cache->hitnum_update_add > DNS_CACHE_HITNUM_STEP) {
|
||||
dns_cache->hitnum_update_add--;
|
||||
dns_cache->info.hitnum--;
|
||||
if (dns_cache->info.hitnum_update_add > DNS_CACHE_HITNUM_STEP) {
|
||||
dns_cache->info.hitnum_update_add--;
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
return hitnum;
|
||||
return dns_cache->info.hitnum;
|
||||
}
|
||||
|
||||
void dns_cache_update(struct dns_cache *dns_cache)
|
||||
@@ -394,13 +406,13 @@ void dns_cache_update(struct dns_cache *dns_cache)
|
||||
if (!list_empty(&dns_cache->list)) {
|
||||
list_del_init(&dns_cache->list);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
atomic_add(dns_cache->hitnum_update_add, &dns_cache->hitnum);
|
||||
if (atomic_read(&dns_cache->hitnum) > DNS_CACHE_MAX_HITNUM) {
|
||||
atomic_set(&dns_cache->hitnum, DNS_CACHE_MAX_HITNUM);
|
||||
dns_cache->info.hitnum += dns_cache->info.hitnum_update_add;
|
||||
if (dns_cache->info.hitnum > DNS_CACHE_MAX_HITNUM) {
|
||||
dns_cache->info.hitnum = DNS_CACHE_MAX_HITNUM;
|
||||
}
|
||||
|
||||
if (dns_cache->hitnum_update_add < DNS_CACHE_HITNUM_STEP_MAX) {
|
||||
dns_cache->hitnum_update_add++;
|
||||
if (dns_cache->info.hitnum_update_add < DNS_CACHE_HITNUM_STEP_MAX) {
|
||||
dns_cache->info.hitnum_update_add++;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
@@ -414,7 +426,7 @@ void _dns_cache_remove_expired_ttl(time_t *now)
|
||||
|
||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.inactive_list, list)
|
||||
{
|
||||
ttl = dns_cache->insert_time + dns_cache->ttl - *now;
|
||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - *now;
|
||||
if (ttl > 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -443,7 +455,7 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list)
|
||||
{
|
||||
ttl = dns_cache->insert_time + dns_cache->ttl - now;
|
||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - now;
|
||||
if (ttl > 0 && ttl < ttl_pre) {
|
||||
/* If the TTL time is in the pre-timeout range, call callback function */
|
||||
if (callback && dns_cache->del_pending == 0) {
|
||||
@@ -479,6 +491,216 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
|
||||
}
|
||||
}
|
||||
|
||||
static int _dns_cache_read_record(int fd, uint32_t cache_number)
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
struct dns_cache_record cache_record;
|
||||
struct dns_cache_data_head data_head;
|
||||
struct dns_cache_data *cache_data = NULL;
|
||||
struct list_head *head = NULL;
|
||||
|
||||
for (i = 0; i < cache_number; i++) {
|
||||
ret = read(fd, &cache_record, sizeof(cache_record));
|
||||
if (ret != sizeof(cache_record)) {
|
||||
tlog(TLOG_ERROR, "read cache failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cache_record.magic != MAGIC_CACHE_DATA) {
|
||||
tlog(TLOG_ERROR, "magic is invalid.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cache_record.type == CACHE_RECORD_TYPE_ACTIVE) {
|
||||
head = &dns_cache_head.cache_list;
|
||||
} else {
|
||||
head = &dns_cache_head.inactive_list;
|
||||
}
|
||||
|
||||
ret = read(fd, &data_head, sizeof(data_head));
|
||||
if (ret != sizeof(data_head)) {
|
||||
tlog(TLOG_ERROR, "read data head failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (data_head.size > 1024 * 8) {
|
||||
tlog(TLOG_ERROR, "data may invalid, skip load cache.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
cache_data = malloc(data_head.size + sizeof(data_head));
|
||||
if (cache_data == NULL) {
|
||||
tlog(TLOG_ERROR, "malloc cache data failed %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
memcpy(&cache_data->head, &data_head, sizeof(data_head));
|
||||
ret = read(fd, cache_data->data, data_head.size);
|
||||
if (ret != data_head.size) {
|
||||
tlog(TLOG_ERROR, "read cache data failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_cache_insert(&cache_record.info, cache_data, head) != 0) {
|
||||
tlog(TLOG_ERROR, "insert cache data failed.");
|
||||
cache_data = NULL;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
cache_data = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (cache_data) {
|
||||
free(cache_data);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_cache_load(const char *file)
|
||||
{
|
||||
int fd = -1;
|
||||
int ret = 0;
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dns_cache_file cache_file;
|
||||
ret = read(fd, &cache_file, sizeof(cache_file));
|
||||
if (ret != sizeof(cache_file)) {
|
||||
tlog(TLOG_ERROR, "read cache head failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cache_file.magic != MAGIC_NUMBER) {
|
||||
tlog(TLOG_ERROR, "cache file is invalid.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (strncmp(cache_file.version, __TIMESTAMP__, DNS_CACHE_VERSION_LEN) != 0) {
|
||||
tlog(TLOG_WARN, "cache version is different, skip load cache.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_cache_read_record(fd, cache_file.cache_number) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
errout:
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_cache_write_record(int fd, uint32_t *cache_number, enum CACHE_RECORD_TYPE type, struct list_head *head)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *tmp = NULL;
|
||||
struct dns_cache_record cache_record;
|
||||
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
list_for_each_entry_safe_reverse(dns_cache, tmp, head, list)
|
||||
{
|
||||
cache_record.magic = MAGIC_CACHE_DATA;
|
||||
cache_record.type = type;
|
||||
memcpy(&cache_record.info, &dns_cache->info, sizeof(struct dns_cache_info));
|
||||
int ret = write(fd, &cache_record, sizeof(cache_record));
|
||||
if (ret != sizeof(cache_record)) {
|
||||
tlog(TLOG_ERROR, "write cache failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
struct dns_cache_data *cache_data = dns_cache->cache_data;
|
||||
ret = write(fd, cache_data, sizeof(*cache_data) + cache_data->head.size);
|
||||
if (ret != sizeof(*cache_data) + cache_data->head.size) {
|
||||
tlog(TLOG_ERROR, "write cache data failed, %s", strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
(*cache_number)++;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_cache_write_records(int fd, uint32_t *cache_number)
|
||||
{
|
||||
|
||||
if (_dns_cache_write_record(fd, cache_number, CACHE_RECORD_TYPE_ACTIVE, &dns_cache_head.cache_list) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_dns_cache_write_record(fd, cache_number, CACHE_RECORD_TYPE_INACTIVE, &dns_cache_head.inactive_list) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_cache_save(const char *file)
|
||||
{
|
||||
int fd = -1;
|
||||
uint32_t cache_number = 0;
|
||||
tlog(TLOG_DEBUG, "write cache file %s", file);
|
||||
|
||||
fd = open(file, O_TRUNC | O_CREAT | O_WRONLY, 0640);
|
||||
if (fd < 0) {
|
||||
tlog(TLOG_ERROR, "create file %s failed, %s", file, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
struct dns_cache_file cache_file;
|
||||
memset(&cache_file, 0, sizeof(cache_file));
|
||||
cache_file.magic = MAGIC_NUMBER;
|
||||
safe_strncpy(cache_file.version, __TIMESTAMP__, DNS_CACHE_VERSION_LEN);
|
||||
cache_file.cache_number = 0;
|
||||
|
||||
if (lseek(fd, sizeof(cache_file), SEEK_SET) < 0) {
|
||||
tlog(TLOG_ERROR, "seek file %s failed, %s", file, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_cache_write_records(fd, &cache_number) != 0) {
|
||||
tlog(TLOG_ERROR, "write record to file %s failed.", file);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (lseek(fd, 0, SEEK_SET) < 0) {
|
||||
tlog(TLOG_ERROR, "seek file %s failed, %s", file, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
cache_file.cache_number = cache_number;
|
||||
if (write(fd, &cache_file, sizeof(cache_file)) != sizeof(cache_file)) {
|
||||
tlog(TLOG_ERROR, "write file head %s failed, %s, %d", file, strerror(errno), fd);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "wrote total %d records.", cache_number);
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
errout:
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void dns_cache_destroy(void)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
|
||||
@@ -32,12 +32,21 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#define DNS_CACHE_TTL_MIN 30
|
||||
#define DNS_CACHE_VERSION_LEN 32
|
||||
#define MAGIC_NUMBER 0x6548634163536e44
|
||||
#define MAGIC_CACHE_DATA 0x44615461
|
||||
|
||||
enum CACHE_TYPE {
|
||||
CACHE_TYPE_NONE,
|
||||
CACHE_TYPE_ADDR,
|
||||
CACHE_TYPE_PACKET,
|
||||
};
|
||||
|
||||
enum CACHE_RECORD_TYPE {
|
||||
CACHE_RECORD_TYPE_ACTIVE,
|
||||
CACHE_RECORD_TYPE_INACTIVE,
|
||||
};
|
||||
|
||||
struct dns_cache_data_head {
|
||||
uint32_t cache_flag;
|
||||
enum CACHE_TYPE cache_type;
|
||||
@@ -67,32 +76,48 @@ struct dns_cache_packet {
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
struct dns_cache_info {
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
int ttl;
|
||||
int hitnum;
|
||||
int speed;
|
||||
int hitnum_update_add;
|
||||
time_t insert_time;
|
||||
dns_type_t qtype;
|
||||
};
|
||||
|
||||
struct dns_cache_record {
|
||||
uint32_t magic;
|
||||
enum CACHE_RECORD_TYPE type;
|
||||
struct dns_cache_info info;
|
||||
};
|
||||
|
||||
struct dns_cache {
|
||||
struct hlist_node node;
|
||||
struct list_head list;
|
||||
struct list_head check_list;
|
||||
|
||||
atomic_t ref;
|
||||
atomic_t hitnum;
|
||||
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
int ttl;
|
||||
int speed;
|
||||
int hitnum_update_add;
|
||||
atomic_t ref;
|
||||
int del_pending;
|
||||
time_t insert_time;
|
||||
|
||||
dns_type_t qtype;
|
||||
|
||||
struct dns_cache_info info;
|
||||
struct dns_cache_data *cache_data;
|
||||
};
|
||||
|
||||
struct dns_cache_file {
|
||||
uint64_t magic;
|
||||
char version[DNS_CACHE_VERSION_LEN];
|
||||
uint32_t cache_number;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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_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);
|
||||
|
||||
@@ -124,6 +149,10 @@ struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_destroy(void);
|
||||
|
||||
int dns_cache_load(const char *file);
|
||||
|
||||
int dns_cache_save(const char *file);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
#endif
|
||||
|
||||
116
src/dns_client.c
116
src/dns_client.c
@@ -108,6 +108,7 @@ struct dns_server_info {
|
||||
int ssl_write_len;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL_SESSION *ssl_session;
|
||||
pthread_mutex_t lock;
|
||||
char skip_check_cert;
|
||||
dns_server_status status;
|
||||
|
||||
@@ -249,6 +250,69 @@ static LIST_HEAD(pending_servers);
|
||||
static pthread_mutex_t pending_server_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int dns_client_has_bootstrap_dns = 0;
|
||||
|
||||
int _ssl_read(struct dns_server_info *server, void *buff, int num)
|
||||
{
|
||||
int ret = 0;
|
||||
pthread_mutex_lock(&server->lock);
|
||||
ret = SSL_read(server->ssl, buff, num);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _ssl_write(struct dns_server_info *server, const void *buff, int num)
|
||||
{
|
||||
int ret = 0;
|
||||
pthread_mutex_lock(&server->lock);
|
||||
ret = SSL_write(server->ssl, buff, num);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _ssl_shutdown(struct dns_server_info *server)
|
||||
{
|
||||
int ret = 0;
|
||||
pthread_mutex_lock(&server->lock);
|
||||
ret = SSL_shutdown(server->ssl);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int _ssl_get_error(struct dns_server_info *server, int ret)
|
||||
{
|
||||
int err = 0;
|
||||
pthread_mutex_lock(&server->lock);
|
||||
err = SSL_get_error(server->ssl, ret);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
int _ssl_do_handshake(struct dns_server_info *server)
|
||||
{
|
||||
int err = 0;
|
||||
pthread_mutex_lock(&server->lock);
|
||||
err = SSL_do_handshake(server->ssl);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
int _ssl_session_reused(struct dns_server_info *server)
|
||||
{
|
||||
int err = 0;
|
||||
pthread_mutex_lock(&server->lock);
|
||||
err = SSL_session_reused(server->ssl);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
SSL_SESSION *_ssl_get1_session(struct dns_server_info *server)
|
||||
{
|
||||
SSL_SESSION *ret = 0;
|
||||
pthread_mutex_lock(&server->lock);
|
||||
ret = SSL_get1_session(server->ssl);
|
||||
pthread_mutex_unlock(&server->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *_dns_server_get_type_string(dns_server_type_t type)
|
||||
{
|
||||
const char *type_str = "";
|
||||
@@ -837,6 +901,7 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
|
||||
server_info->ttl = ttl;
|
||||
server_info->ttl_range = 0;
|
||||
server_info->skip_check_cert = skip_check_cert;
|
||||
pthread_mutex_init(&server_info->lock, NULL);
|
||||
memcpy(&server_info->flags, flags, sizeof(server_info->flags));
|
||||
|
||||
/* exclude this server from default group */
|
||||
@@ -862,7 +927,7 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
|
||||
|
||||
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, 64);
|
||||
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);
|
||||
server_info->skip_check_cert = 1;
|
||||
@@ -916,6 +981,7 @@ errout:
|
||||
server_info->ssl_ctx = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&server_info->lock);
|
||||
free(server_info);
|
||||
}
|
||||
|
||||
@@ -935,7 +1001,7 @@ static void _dns_client_close_socket(struct dns_server_info *server_info)
|
||||
if (server_info->ssl) {
|
||||
/* Shutdown ssl */
|
||||
if (server_info->status == DNS_SERVER_STATUS_CONNECTED) {
|
||||
SSL_shutdown(server_info->ssl);
|
||||
_ssl_shutdown(server_info);
|
||||
}
|
||||
SSL_free(server_info->ssl);
|
||||
server_info->ssl = NULL;
|
||||
@@ -974,7 +1040,7 @@ static void _dns_client_shutdown_socket(struct dns_server_info *server_info)
|
||||
if (server_info->ssl) {
|
||||
/* Shutdown ssl */
|
||||
if (server_info->status == DNS_SERVER_STATUS_CONNECTED) {
|
||||
SSL_shutdown(server_info->ssl);
|
||||
_ssl_shutdown(server_info);
|
||||
}
|
||||
shutdown(server_info->fd, SHUT_RDWR);
|
||||
}
|
||||
@@ -1015,6 +1081,7 @@ static void _dns_client_server_remove_all(void)
|
||||
{
|
||||
list_del(&server_info->list);
|
||||
_dns_client_server_close(server_info);
|
||||
pthread_mutex_destroy(&server_info->lock);
|
||||
free(server_info);
|
||||
}
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
@@ -1782,23 +1849,23 @@ static int _dns_client_process_udp(struct dns_server_info *server_info, struct e
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_client_socket_ssl_send(SSL *ssl, const void *buf, int num)
|
||||
static int _dns_client_socket_ssl_send(struct dns_server_info *server, const void *buf, int num)
|
||||
{
|
||||
int ret = 0;
|
||||
int ssl_ret = 0;
|
||||
unsigned long ssl_err = 0;
|
||||
|
||||
if (ssl == NULL) {
|
||||
if (server->ssl == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = SSL_write(ssl, buf, num);
|
||||
ret = _ssl_write(server, buf, num);
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssl_ret = SSL_get_error(ssl, ret);
|
||||
ssl_ret = _ssl_get_error(server, ret);
|
||||
switch (ssl_ret) {
|
||||
case SSL_ERROR_NONE:
|
||||
return 0;
|
||||
@@ -1838,23 +1905,23 @@ static int _dns_client_socket_ssl_send(SSL *ssl, const void *buf, int num)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_client_socket_ssl_recv(SSL *ssl, void *buf, int num)
|
||||
static int _dns_client_socket_ssl_recv(struct dns_server_info *server, void *buf, int num)
|
||||
{
|
||||
int ret = 0;
|
||||
int ssl_ret = 0;
|
||||
unsigned long ssl_err = 0;
|
||||
|
||||
if (ssl == NULL) {
|
||||
if (server->ssl == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = SSL_read(ssl, buf, num);
|
||||
ret = _ssl_read(server, buf, num);
|
||||
if (ret >= 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssl_ret = SSL_get_error(ssl, ret);
|
||||
ssl_ret = _ssl_get_error(server, ret);
|
||||
switch (ssl_ret) {
|
||||
case SSL_ERROR_NONE:
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
@@ -1915,7 +1982,7 @@ static int _dns_client_socket_send(struct dns_server_info *server_info)
|
||||
write_len = server_info->ssl_write_len;
|
||||
server_info->ssl_write_len = -1;
|
||||
}
|
||||
int ret = _dns_client_socket_ssl_send(server_info->ssl, server_info->send_buff.data, write_len);
|
||||
int ret = _dns_client_socket_ssl_send(server_info, server_info->send_buff.data, write_len);
|
||||
if (ret != 0) {
|
||||
if (errno == EAGAIN) {
|
||||
server_info->ssl_write_len = write_len;
|
||||
@@ -1935,7 +2002,7 @@ static int _dns_client_socket_recv(struct dns_server_info *server_info)
|
||||
return recv(server_info->fd, server_info->recv_buff.data + server_info->recv_buff.len,
|
||||
DNS_TCP_BUFFER - server_info->recv_buff.len, 0);
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS) {
|
||||
return _dns_client_socket_ssl_recv(server_info->ssl, server_info->recv_buff.data + server_info->recv_buff.len,
|
||||
return _dns_client_socket_ssl_recv(server_info, server_info->recv_buff.data + server_info->recv_buff.len,
|
||||
DNS_TCP_BUFFER - server_info->recv_buff.len);
|
||||
} else {
|
||||
return -1;
|
||||
@@ -2053,6 +2120,11 @@ static int _dns_client_process_tcp(struct dns_server_info *server_info, struct e
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (errno == ETIMEDOUT) {
|
||||
tlog(TLOG_INFO, "recv failed, server %s:%d, %s\n", server_info->ip, server_info->port, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "recv failed, server %s:%d, %s\n", server_info->ip, server_info->port, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
@@ -2221,8 +2293,10 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&server_info->lock);
|
||||
cert = SSL_get_peer_certificate(server_info->ssl);
|
||||
if (cert == NULL) {
|
||||
pthread_mutex_unlock(&server_info->lock);
|
||||
tlog(TLOG_ERROR, "get peer certificate failed.");
|
||||
return -1;
|
||||
}
|
||||
@@ -2230,6 +2304,7 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
|
||||
if (server_info->skip_check_cert == 0) {
|
||||
long res = SSL_get_verify_result(server_info->ssl);
|
||||
if (res != X509_V_OK) {
|
||||
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);
|
||||
@@ -2237,6 +2312,7 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&server_info->lock);
|
||||
|
||||
if (_dns_client_tls_get_cert_CN(cert, peer_CN, sizeof(peer_CN)) != 0) {
|
||||
tlog(TLOG_ERROR, "get cert CN failed.");
|
||||
@@ -2336,12 +2412,12 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
|
||||
if (server_info->status == DNS_SERVER_STATUS_CONNECTING) {
|
||||
/* do SSL hand shake */
|
||||
ret = SSL_do_handshake(server_info->ssl);
|
||||
ret = _ssl_do_handshake(server_info);
|
||||
if (ret == 0) {
|
||||
goto errout;
|
||||
} else if (ret < 0) {
|
||||
memset(&fd_event, 0, sizeof(fd_event));
|
||||
ssl_ret = SSL_get_error(server_info->ssl, ret);
|
||||
ssl_ret = _ssl_get_error(server_info, ret);
|
||||
if (ssl_ret == SSL_ERROR_WANT_READ) {
|
||||
fd_event.events = EPOLLIN;
|
||||
} else if (ssl_ret == SSL_ERROR_WANT_WRITE) {
|
||||
@@ -2370,7 +2446,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
|
||||
tlog(TLOG_DEBUG, "tls server %s connected.\n", server_info->ip);
|
||||
/* Was the stored session reused? */
|
||||
if (SSL_session_reused(server_info->ssl)) {
|
||||
if (_ssl_session_reused(server_info)) {
|
||||
tlog(TLOG_DEBUG, "reused session");
|
||||
} else {
|
||||
tlog(TLOG_DEBUG, "new session");
|
||||
@@ -2388,7 +2464,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
}
|
||||
|
||||
/* save ssl session for next request */
|
||||
server_info->ssl_session = SSL_get1_session(server_info->ssl);
|
||||
server_info->ssl_session = _ssl_get1_session(server_info);
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
}
|
||||
|
||||
@@ -2539,7 +2615,7 @@ static int _dns_client_send_tls(struct dns_server_info *server_info, void *packe
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_len = _dns_client_socket_ssl_send(server_info->ssl, inpacket, len);
|
||||
send_len = _dns_client_socket_ssl_send(server_info, inpacket, len);
|
||||
if (send_len <= 0) {
|
||||
if (errno == EAGAIN || errno == EPIPE || server_info->ssl == NULL) {
|
||||
/* save data to buffer, and retry when EPOLLOUT is available */
|
||||
@@ -2590,13 +2666,13 @@ static int _dns_client_send_https(struct dns_server_info *server_info, void *pac
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_len = _dns_client_socket_ssl_send(server_info->ssl, inpacket, http_len);
|
||||
send_len = _dns_client_socket_ssl_send(server_info, inpacket, http_len);
|
||||
if (send_len <= 0) {
|
||||
if (errno == EAGAIN || errno == EPIPE || server_info->ssl == NULL) {
|
||||
/* 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_set_shutdown(server_info->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
|
||||
_ssl_shutdown(server_info);
|
||||
}
|
||||
return -1;
|
||||
} else if (send_len < http_len) {
|
||||
|
||||
@@ -50,6 +50,7 @@ int dns_conf_cachesize = DEFAULT_DNS_CACHE_SIZE;
|
||||
int dns_conf_prefetch = 0;
|
||||
int dns_conf_serve_expired = 0;
|
||||
int dns_conf_serve_expired_ttl = 0;
|
||||
int dns_conf_serve_expired_reply_ttl = 5;
|
||||
|
||||
/* upstream servers */
|
||||
struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
@@ -72,6 +73,9 @@ int dns_conf_log_num = 8;
|
||||
char dns_conf_ca_file[DNS_MAX_PATH];
|
||||
char dns_conf_ca_path[DNS_MAX_PATH];
|
||||
|
||||
char dns_conf_cache_file[DNS_MAX_PATH];
|
||||
int dns_conf_cache_persist = 2;
|
||||
|
||||
/* auditing */
|
||||
int dns_conf_audit_enable = 0;
|
||||
int dns_conf_audit_log_SOA;
|
||||
@@ -107,6 +111,10 @@ static int _get_domain(char *value, char *domain, int max_dmain_size, char **ptr
|
||||
char *end = NULL;
|
||||
int len = 0;
|
||||
|
||||
if (value == NULL || domain == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* first field */
|
||||
begin = strstr(value, "/");
|
||||
if (begin == NULL) {
|
||||
@@ -1354,9 +1362,12 @@ static struct config_item _config_item[] = {
|
||||
CONF_CUSTOM("speed-check-mode", _config_speed_check_mode, NULL),
|
||||
CONF_INT("tcp-idle-time", &dns_conf_tcp_idle_time, 0, 3600),
|
||||
CONF_INT("cache-size", &dns_conf_cachesize, 0, CONF_INT_MAX),
|
||||
CONF_STRING("cache-file", (char *)&dns_conf_cache_file, DNS_MAX_PATH),
|
||||
CONF_YESNO("cache-persist", &dns_conf_cache_persist),
|
||||
CONF_YESNO("prefetch-domain", &dns_conf_prefetch),
|
||||
CONF_YESNO("serve-expired", &dns_conf_serve_expired),
|
||||
CONF_INT("serve-expired-ttl", &dns_conf_serve_expired_ttl, 0, CONF_INT_MAX),
|
||||
CONF_INT("serve-expired-reply-ttl", &dns_conf_serve_expired_reply_ttl, 0, CONF_INT_MAX),
|
||||
CONF_YESNO("dualstack-ip-selection", &dns_conf_dualstack_ip_selection),
|
||||
CONF_INT("dualstack-ip-selection-threshold", &dns_conf_dualstack_ip_selection_threshold, 0, 1000),
|
||||
CONF_CUSTOM("log-level", _config_log_level, NULL),
|
||||
|
||||
@@ -49,6 +49,7 @@ extern "C" {
|
||||
#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_CACHE_FILE "/tmp/smartdns.cache"
|
||||
|
||||
enum domain_rule {
|
||||
DOMAIN_RULE_FLAGS = 0,
|
||||
@@ -90,7 +91,7 @@ typedef enum {
|
||||
#define BIND_FLAG_NO_SPEED_CHECK (1 << 5)
|
||||
#define BIND_FLAG_NO_CACHE (1 << 6)
|
||||
#define BIND_FLAG_NO_DUALSTACK_SELECTION (1 << 7)
|
||||
#define BIND_FLAG_FORCE_AAAA_SOA (1 << 8)
|
||||
#define BIND_FLAG_FORCE_AAAA_SOA (1 << 8)
|
||||
|
||||
struct dns_rule_flags {
|
||||
unsigned int flags;
|
||||
@@ -204,6 +205,7 @@ extern int dns_conf_cachesize;
|
||||
extern int dns_conf_prefetch;
|
||||
extern int dns_conf_serve_expired;
|
||||
extern int dns_conf_serve_expired_ttl;
|
||||
extern int dns_conf_serve_expired_reply_ttl;
|
||||
extern struct dns_servers dns_conf_servers[DNS_MAX_SERVERS];
|
||||
extern int dns_conf_server_num;
|
||||
|
||||
@@ -215,6 +217,9 @@ extern int dns_conf_log_num;
|
||||
extern char dns_conf_ca_file[DNS_MAX_PATH];
|
||||
extern char dns_conf_ca_path[DNS_MAX_PATH];
|
||||
|
||||
extern char dns_conf_cache_file[DNS_MAX_PATH];
|
||||
extern int dns_conf_cache_persist;
|
||||
|
||||
extern struct dns_domain_check_order dns_conf_check_order;
|
||||
|
||||
extern struct dns_server_groups dns_conf_server_groups[DNS_NAX_GROUP_NUMBER];
|
||||
|
||||
100
src/dns_server.c
100
src/dns_server.c
@@ -52,6 +52,7 @@
|
||||
#define DNS_PING_SECOND_TIMEOUT (DNS_REQUEST_MAX_TIMEOUT - DNS_TCPPING_START)
|
||||
#define SOCKET_IP_TOS (IPTOS_LOWDELAY | IPTOS_RELIABILITY)
|
||||
#define SOCKET_PRIORITY (6)
|
||||
#define CACHE_AUTO_ENABLE_SIZE (1024 * 1024 * 128)
|
||||
|
||||
#define RECV_ERROR_AGAIN 1
|
||||
#define RECV_ERROR_OK 0
|
||||
@@ -490,7 +491,7 @@ static int _dns_server_reply_udp(struct dns_request *request, struct dns_server_
|
||||
send_len =
|
||||
sendto(udpserver->head.fd, inpacket, inpacket_len, 0, (struct sockaddr *)&request->addr, request->addr_len);
|
||||
if (send_len != inpacket_len) {
|
||||
tlog(TLOG_ERROR, "send failed.");
|
||||
tlog(TLOG_ERROR, "send failed, %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1883,7 +1884,7 @@ static int _dns_server_reply_passthrouth(struct dns_request *request, struct dns
|
||||
}
|
||||
}
|
||||
|
||||
if(_dns_server_setup_ipset_packet(request, packet) != 0) {
|
||||
if (_dns_server_setup_ipset_packet(request, packet) != 0) {
|
||||
tlog(TLOG_DEBUG, "setup ipset failed.");
|
||||
}
|
||||
|
||||
@@ -2263,6 +2264,16 @@ static void _dns_server_process_speed_check_rule(struct dns_request *request)
|
||||
request->check_order_list = check_order;
|
||||
}
|
||||
|
||||
static int _dns_server_get_expired_ttl_reply(struct dns_cache *dns_cache)
|
||||
{
|
||||
int ttl = dns_cache_get_ttl(dns_cache);
|
||||
if (ttl > 0) {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
return dns_conf_serve_expired_reply_ttl;
|
||||
}
|
||||
|
||||
static int _dns_server_process_cache_addr(struct dns_request *request, struct dns_cache *dns_cache)
|
||||
{
|
||||
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache_get_data(dns_cache);
|
||||
@@ -2274,12 +2285,12 @@ static int _dns_server_process_cache_addr(struct dns_request *request, struct dn
|
||||
switch (request->qtype) {
|
||||
case DNS_T_A:
|
||||
memcpy(request->ipv4_addr, cache_addr->addr_data.ipv4_addr, DNS_RR_A_LEN);
|
||||
request->ttl_v4 = dns_cache_get_ttl(dns_cache);
|
||||
request->ttl_v4 = _dns_server_get_expired_ttl_reply(dns_cache);
|
||||
request->has_ipv4 = 1;
|
||||
break;
|
||||
case DNS_T_AAAA:
|
||||
memcpy(request->ipv6_addr, cache_addr->addr_data.ipv6_addr, DNS_RR_AAAA_LEN);
|
||||
request->ttl_v6 = dns_cache_get_ttl(dns_cache);
|
||||
request->ttl_v6 = _dns_server_get_expired_ttl_reply(dns_cache);
|
||||
request->has_ipv6 = 1;
|
||||
break;
|
||||
default:
|
||||
@@ -2314,7 +2325,7 @@ static int _dns_server_process_cache_packet(struct dns_request *request, struct
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (dns_cache->qtype != request->qtype) {
|
||||
if (dns_cache->info.qtype != request->qtype) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -2405,15 +2416,15 @@ static int _dns_server_process_cache(struct dns_request *request)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (request->qtype != dns_cache->qtype) {
|
||||
if (request->qtype != dns_cache->info.qtype) {
|
||||
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->speed > 0)) {
|
||||
if ((dns_cache_A->speed + (dns_conf_dualstack_ip_selection_threshold * 10)) < dns_cache->speed ||
|
||||
dns_cache->speed < 0) {
|
||||
if (dns_cache_A && (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.");
|
||||
ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request);
|
||||
goto out_update_cache;
|
||||
@@ -2430,7 +2441,7 @@ out_update_cache:
|
||||
if (dns_cache_get_ttl(dns_cache) == 0) {
|
||||
uint32_t server_flags = request->server_flags;
|
||||
if (request->conn == NULL) {
|
||||
server_flags = dns_cache_get_cache_flag(dns_cache_A->cache_data);
|
||||
server_flags = dns_cache_get_cache_flag(dns_cache->cache_data);
|
||||
}
|
||||
_dns_server_prefetch_request(request->domain, request->qtype, server_flags);
|
||||
} else {
|
||||
@@ -3158,11 +3169,11 @@ 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->domain, dns_cache->qtype,
|
||||
dns_cache->ttl, hitnum);
|
||||
if (_dns_server_prefetch_request(dns_cache->domain, dns_cache->qtype,
|
||||
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,
|
||||
dns_cache_get_cache_flag(dns_cache->cache_data)) != 0) {
|
||||
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->domain, dns_cache->qtype);
|
||||
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3568,6 +3579,60 @@ static int _dns_server_audit_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_cache_init(void)
|
||||
{
|
||||
if (dns_cache_init(dns_conf_cachesize, dns_conf_serve_expired, dns_conf_serve_expired_ttl) != 0) {
|
||||
tlog(TLOG_ERROR, "init cache failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *dns_cache_file = SMARTDNS_CACHE_FILE;
|
||||
if (dns_conf_cache_file[0] != 0) {
|
||||
dns_cache_file = dns_conf_cache_file;
|
||||
}
|
||||
|
||||
if (dns_conf_cache_persist == 2) {
|
||||
uint64_t freespace = get_free_space(dns_cache_file);
|
||||
if (freespace >= CACHE_AUTO_ENABLE_SIZE) {
|
||||
tlog(TLOG_INFO, "auto enable cache persist.");
|
||||
dns_conf_cache_persist = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dns_conf_cachesize <= 0 || dns_conf_cache_persist == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dns_cache_load(dns_cache_file) != 0) {
|
||||
tlog(TLOG_WARN, "Load cache failed.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_cache_save(void)
|
||||
{
|
||||
char *dns_cache_file = SMARTDNS_CACHE_FILE;
|
||||
if (dns_conf_cache_file[0] != 0) {
|
||||
dns_cache_file = dns_conf_cache_file;
|
||||
}
|
||||
|
||||
if (dns_conf_cache_persist == 0 || dns_conf_cachesize <= 0) {
|
||||
if (access(dns_cache_file, F_OK) == 0) {
|
||||
unlink(dns_cache_file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dns_cache_save(dns_cache_file) != 0) {
|
||||
tlog(TLOG_WARN, "save cache failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dns_server_init(void)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
@@ -3578,9 +3643,9 @@ int dns_server_init(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dns_cache_init(dns_conf_cachesize, dns_conf_serve_expired, dns_conf_serve_expired_ttl) != 0) {
|
||||
tlog(TLOG_ERROR, "init cache failed.");
|
||||
return -1;
|
||||
if (_dns_server_cache_init() != 0) {
|
||||
tlog(TLOG_ERROR, "init dns cache filed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_server_audit_init() != 0) {
|
||||
@@ -3656,5 +3721,6 @@ void dns_server_exit(void)
|
||||
|
||||
pthread_mutex_destroy(&server.request_list_lock);
|
||||
|
||||
_dns_server_cache_save();
|
||||
dns_cache_destroy();
|
||||
}
|
||||
|
||||
@@ -452,6 +452,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
signal(SIGINT, _sig_exit);
|
||||
signal(SIGTERM, _sig_exit);
|
||||
atexit(_smartdns_exit);
|
||||
|
||||
return _smartdns_run();
|
||||
|
||||
16
src/util.c
16
src/util.c
@@ -35,6 +35,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
@@ -994,4 +995,17 @@ int set_sock_lingertime(int fd, int time)
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t get_free_space(const char *path)
|
||||
{
|
||||
uint64_t size = 0;
|
||||
struct statvfs buf;
|
||||
if (statvfs(path, &buf) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = (uint64_t)buf.f_frsize * buf.f_bavail;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -106,6 +106,8 @@ int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt);
|
||||
|
||||
int set_sock_lingertime(int fd, int time);
|
||||
|
||||
uint64_t get_free_space(const char *path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus */
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
[Unit]
|
||||
Description=smart dns server
|
||||
Description=smartdns server
|
||||
After=network.target
|
||||
StartLimitBurst=0
|
||||
StartLimitIntervalSec=60
|
||||
TimeoutStopSec=5
|
||||
|
||||
[Service]
|
||||
Type=forking
|
||||
|
||||
Reference in New Issue
Block a user