Compare commits
20 Commits
Release31
...
Release32-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3d3364a32 | ||
|
|
b8a36ccb8c | ||
|
|
aee19be262 | ||
|
|
98429e88f1 | ||
|
|
80cb27c795 | ||
|
|
cb73eadf01 | ||
|
|
69ba3f8789 | ||
|
|
c380bbe0e3 | ||
|
|
da74e877c5 | ||
|
|
a300873b3f | ||
|
|
a9829f6155 | ||
|
|
1923271630 | ||
|
|
c23ec7ea8f | ||
|
|
aad751c1f5 | ||
|
|
138df2fd5d | ||
|
|
297ea29639 | ||
|
|
bc0d6b89ca | ||
|
|
2148efd262 | ||
|
|
ce46ac58a7 | ||
|
|
c1f9941427 |
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
||||
FROM debian:buster-slim
|
||||
|
||||
RUN apt update && \
|
||||
apt install -y git make gcc libssl-dev && \
|
||||
git clone https://github.com/pymumu/smartdns.git --depth 1 && \
|
||||
cd smartdns && \
|
||||
sh ./package/build-pkg.sh --platform debian --arch `dpkg --print-architecture` && \
|
||||
dpkg -i package/*.deb && \
|
||||
cd / && \
|
||||
rm -rf smartdns/ && \
|
||||
apt autoremove -y git make gcc libssl-dev && \
|
||||
apt clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
EXPOSE 53/udp
|
||||
VOLUME "/etc/smartdns/"
|
||||
|
||||
CMD ["/usr/sbin/smartdns", "-f"]
|
||||
@@ -156,7 +156,7 @@ load_server()
|
||||
config_get type "$section" "type" "udp"
|
||||
config_get ip "$section" "ip" ""
|
||||
config_get tls_host_verify "$section" "tls_host_verify" ""
|
||||
config_get no_check_certificate "$section" "no_check_certificate" ""
|
||||
config_get no_check_certificate "$section" "no_check_certificate" "0"
|
||||
config_get host_name "$section" "host_name" ""
|
||||
config_get http_host "$section" "http_host" ""
|
||||
config_get server_group "$section" "server_group" ""
|
||||
@@ -187,7 +187,7 @@ load_server()
|
||||
fi
|
||||
|
||||
[ -z "$tls_host_verify" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -tls-host-verify $tls_host_verify"
|
||||
[ -z "$no_check_certificate" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -no-check-certificate"
|
||||
[ "$no_check_certificate" = "0" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -no-check-certificate"
|
||||
[ -z "$host_name" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -host-name $host_name"
|
||||
[ -z "$http_host" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -http-host $http_host"
|
||||
[ -z "$server_group" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -group $server_group"
|
||||
|
||||
@@ -110,7 +110,7 @@ struct dns_head {
|
||||
unsigned short ancount; /* number of answer entries */
|
||||
unsigned short nscount; /* number of authority entries */
|
||||
unsigned short nrcount; /* number of addititional resource entries */
|
||||
} __attribute__((packed));
|
||||
} __attribute__((packed, aligned(2)));
|
||||
|
||||
struct dns_rrs {
|
||||
unsigned short next;
|
||||
|
||||
153
src/dns_cache.c
153
src/dns_cache.c
@@ -82,6 +82,7 @@ static void _dns_cache_delete(struct dns_cache *dns_cache)
|
||||
hash_del(&dns_cache->node);
|
||||
list_del_init(&dns_cache->list);
|
||||
atomic_dec(&dns_cache_head.num);
|
||||
dns_cache_data_free(dns_cache->cache_data);
|
||||
free(dns_cache);
|
||||
}
|
||||
|
||||
@@ -118,10 +119,89 @@ static void _dns_cache_move_inactive(struct dns_cache *dns_cache)
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list);
|
||||
}
|
||||
|
||||
int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr,
|
||||
int addr_len, int speed)
|
||||
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data)
|
||||
{
|
||||
return cache_data->head.cache_type;
|
||||
}
|
||||
|
||||
uint32_t dns_cache_get_cache_flag(struct dns_cache_data *cache_data)
|
||||
{
|
||||
return cache_data->head.cache_flag;
|
||||
}
|
||||
|
||||
void dns_cache_data_free(struct dns_cache_data *data)
|
||||
{
|
||||
if (data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_addr(uint32_t cache_flag, char *cname, int cname_ttl, unsigned char *addr,
|
||||
int addr_len)
|
||||
{
|
||||
struct dns_cache_addr *cache_addr = malloc(sizeof(struct dns_cache_addr));
|
||||
memset(cache_addr, 0, sizeof(struct dns_cache_addr));
|
||||
if (cache_addr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (addr_len == DNS_RR_A_LEN) {
|
||||
memcpy(cache_addr->addr_data.addr, addr, DNS_RR_A_LEN);
|
||||
} else if (addr_len != DNS_RR_AAAA_LEN) {
|
||||
memcpy(cache_addr->addr_data.addr, addr, DNS_RR_AAAA_LEN);
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cname) {
|
||||
safe_strncpy(cache_addr->addr_data.cname, cname, DNS_MAX_CNAME_LEN);
|
||||
cache_addr->addr_data.cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
cache_addr->head.cache_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);
|
||||
|
||||
return (struct dns_cache_data *)cache_addr;
|
||||
|
||||
errout:
|
||||
if (cache_addr) {
|
||||
free(cache_addr);
|
||||
cache_addr = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_new_data_packet(uint32_t cache_flag, void *packet, size_t packet_len)
|
||||
{
|
||||
struct dns_cache_packet *cache_packet = NULL;
|
||||
size_t data_size = 0;
|
||||
if (packet == NULL || packet_len <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data_size = sizeof(*cache_packet) + packet_len;
|
||||
cache_packet = malloc(data_size);
|
||||
if (cache_packet == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(cache_packet->data, packet, packet_len);
|
||||
|
||||
cache_packet->head.cache_flag = cache_flag;
|
||||
cache_packet->head.cache_type = CACHE_TYPE_PACKET;
|
||||
cache_packet->head.size = packet_len;
|
||||
|
||||
return (struct dns_cache_data *)cache_packet;
|
||||
}
|
||||
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache_data *old_cache_data = NULL;
|
||||
|
||||
if (dns_cache_head.size <= 0) {
|
||||
return 0;
|
||||
@@ -130,7 +210,7 @@ int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_typ
|
||||
/* lookup existing cache */
|
||||
dns_cache = dns_cache_lookup(domain, qtype);
|
||||
if (dns_cache == NULL) {
|
||||
return 0;
|
||||
return dns_cache_insert(domain, ttl, qtype, speed, cache_data);
|
||||
}
|
||||
|
||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||
@@ -145,46 +225,26 @@ int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_typ
|
||||
dns_cache->del_pending = 0;
|
||||
dns_cache->speed = speed;
|
||||
time(&dns_cache->insert_time);
|
||||
if (qtype == DNS_T_A) {
|
||||
if (addr_len != DNS_RR_A_LEN) {
|
||||
goto errout_unlock;
|
||||
}
|
||||
memcpy(dns_cache->addr, addr, DNS_RR_A_LEN);
|
||||
} else if (qtype == DNS_T_AAAA) {
|
||||
if (addr_len != DNS_RR_AAAA_LEN) {
|
||||
goto errout_unlock;
|
||||
}
|
||||
memcpy(dns_cache->addr, addr, DNS_RR_AAAA_LEN);
|
||||
} else {
|
||||
goto errout_unlock;
|
||||
}
|
||||
|
||||
if (cname) {
|
||||
safe_strncpy(dns_cache->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
dns_cache->cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
old_cache_data = dns_cache->cache_data;
|
||||
dns_cache->cache_data = cache_data;
|
||||
list_del_init(&dns_cache->list);
|
||||
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
|
||||
dns_cache_data_free(old_cache_data);
|
||||
dns_cache_release(dns_cache);
|
||||
return 0;
|
||||
errout_unlock:
|
||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||
// errout:
|
||||
if (dns_cache) {
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr,
|
||||
int addr_len, int speed)
|
||||
int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -206,37 +266,19 @@ int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type
|
||||
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);
|
||||
dns_cache->cname[0] = 0;
|
||||
atomic_set(&dns_cache->hitnum, 3);
|
||||
atomic_set(&dns_cache->ref, 1);
|
||||
dns_cache->qtype = qtype;
|
||||
dns_cache->ttl = ttl;
|
||||
atomic_set(&dns_cache->hitnum, 3);
|
||||
dns_cache->hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
||||
dns_cache->del_pending = 0;
|
||||
dns_cache->speed = speed;
|
||||
atomic_set(&dns_cache->ref, 1);
|
||||
dns_cache->cache_data = cache_data;
|
||||
time(&dns_cache->insert_time);
|
||||
if (qtype == DNS_T_A) {
|
||||
if (addr_len != DNS_RR_A_LEN) {
|
||||
goto errout;
|
||||
}
|
||||
memcpy(dns_cache->addr, addr, DNS_RR_A_LEN);
|
||||
} else if (qtype == DNS_T_AAAA) {
|
||||
if (addr_len != DNS_RR_AAAA_LEN) {
|
||||
goto errout;
|
||||
}
|
||||
memcpy(dns_cache->addr, addr, DNS_RR_AAAA_LEN);
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (cname) {
|
||||
safe_strncpy(dns_cache->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
dns_cache->cname_ttl = cname_ttl;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -321,6 +363,11 @@ int dns_cache_get_ttl(struct dns_cache *dns_cache)
|
||||
return ttl;
|
||||
}
|
||||
|
||||
struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache)
|
||||
{
|
||||
return dns_cache->cache_data;
|
||||
}
|
||||
|
||||
void dns_cache_delete(struct dns_cache *dns_cache)
|
||||
{
|
||||
pthread_mutex_lock(&dns_cache_head.lock);
|
||||
|
||||
@@ -33,35 +33,74 @@ extern "C" {
|
||||
|
||||
#define DNS_CACHE_TTL_MIN 30
|
||||
|
||||
enum CACHE_TYPE {
|
||||
CACHE_TYPE_NONE,
|
||||
CACHE_TYPE_ADDR,
|
||||
CACHE_TYPE_PACKET,
|
||||
};
|
||||
struct dns_cache_data_head {
|
||||
uint32_t cache_flag;
|
||||
enum CACHE_TYPE cache_type;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct dns_cache_data {
|
||||
struct dns_cache_data_head head;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
struct dns_cache_addr {
|
||||
struct dns_cache_data_head head;
|
||||
struct dns_cache_addr_data {
|
||||
unsigned int cname_ttl;
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
union {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
||||
unsigned char addr[0];
|
||||
};
|
||||
} addr_data;
|
||||
};
|
||||
|
||||
struct dns_cache_packet {
|
||||
struct dns_cache_data_head head;
|
||||
unsigned char data[0];
|
||||
};
|
||||
|
||||
struct dns_cache {
|
||||
struct hlist_node node;
|
||||
struct list_head list;
|
||||
struct list_head check_list;
|
||||
|
||||
atomic_t ref;
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
unsigned int cname_ttl;
|
||||
unsigned int ttl;
|
||||
int speed;
|
||||
atomic_t hitnum;
|
||||
|
||||
char domain[DNS_MAX_CNAME_LEN];
|
||||
int ttl;
|
||||
int speed;
|
||||
int hitnum_update_add;
|
||||
int del_pending;
|
||||
time_t insert_time;
|
||||
|
||||
dns_type_t qtype;
|
||||
union {
|
||||
unsigned char ipv4_addr[DNS_RR_A_LEN];
|
||||
unsigned char ipv6_addr[DNS_RR_AAAA_LEN];
|
||||
unsigned char addr[0];
|
||||
};
|
||||
struct dns_cache_data *cache_data;
|
||||
};
|
||||
|
||||
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_packet(uint32_t cache_flag, void *packet, size_t packet_len);
|
||||
|
||||
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
|
||||
|
||||
int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr,
|
||||
int addr_len, int speed);
|
||||
int dns_cache_replace(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr,
|
||||
int addr_len, int speed);
|
||||
int dns_cache_insert(char *domain, int ttl, dns_type_t qtype, int speed, struct dns_cache_data *cache_data);
|
||||
|
||||
struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype);
|
||||
|
||||
@@ -81,6 +120,8 @@ void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre);
|
||||
|
||||
int dns_cache_get_ttl(struct dns_cache *dns_cache);
|
||||
|
||||
struct dns_cache_data *dns_cache_get_data(struct dns_cache *dns_cache);
|
||||
|
||||
void dns_cache_destroy(void);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
|
||||
344
src/dns_client.c
344
src/dns_client.c
@@ -105,6 +105,7 @@ struct dns_server_info {
|
||||
int ttl;
|
||||
int ttl_range;
|
||||
SSL *ssl;
|
||||
int ssl_write_len;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSL_SESSION *ssl_session;
|
||||
char skip_check_cert;
|
||||
@@ -853,15 +854,20 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
|
||||
#else
|
||||
server_info->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
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, 64);
|
||||
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;
|
||||
SSL_CTX_set_verify(server_info->ssl_ctx, SSL_VERIFY_NONE, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* safe address info */
|
||||
@@ -901,13 +907,14 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
|
||||
return 0;
|
||||
errout:
|
||||
if (server_info) {
|
||||
if (server_info->ping_host) {
|
||||
fast_ping_stop(server_info->ping_host);
|
||||
}
|
||||
|
||||
if (server_info->ssl_ctx) {
|
||||
SSL_CTX_free(server_info->ssl_ctx);
|
||||
server_info->ssl_ctx = NULL;
|
||||
}
|
||||
if (server_info->ping_host) {
|
||||
fast_ping_stop(server_info->ping_host);
|
||||
}
|
||||
|
||||
free(server_info);
|
||||
}
|
||||
@@ -927,8 +934,12 @@ 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_free(server_info->ssl);
|
||||
server_info->ssl = NULL;
|
||||
server_info->ssl_write_len = -1;
|
||||
}
|
||||
|
||||
/* remove fd from epoll */
|
||||
@@ -943,6 +954,36 @@ static void _dns_client_close_socket(struct dns_server_info *server_info)
|
||||
tlog(TLOG_DEBUG, "server %s closed.", server_info->ip);
|
||||
}
|
||||
|
||||
static void _dns_client_shutdown_socket(struct dns_server_info *server_info)
|
||||
{
|
||||
if (server_info->fd <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (server_info->type) {
|
||||
case DNS_SERVER_UDP:
|
||||
return;
|
||||
break;
|
||||
case DNS_SERVER_TCP:
|
||||
if (server_info->fd > 0) {
|
||||
shutdown(server_info->fd, SHUT_RDWR);
|
||||
}
|
||||
break;
|
||||
case DNS_SERVER_TLS:
|
||||
case DNS_SERVER_HTTPS:
|
||||
if (server_info->ssl) {
|
||||
/* Shutdown ssl */
|
||||
if (server_info->status == DNS_SERVER_STATUS_CONNECTED) {
|
||||
SSL_shutdown(server_info->ssl);
|
||||
}
|
||||
shutdown(server_info->fd, SHUT_RDWR);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _dns_client_server_close(struct dns_server_info *server_info)
|
||||
{
|
||||
/* stop ping task */
|
||||
@@ -1427,7 +1468,7 @@ static int _dns_client_recv(struct dns_server_info *server_info, unsigned char *
|
||||
}
|
||||
|
||||
_dns_client_query_release(query);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_client_create_socket_udp(struct dns_server_info *server_info)
|
||||
@@ -1507,31 +1548,41 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
|
||||
set_sock_keepalive(fd, 15, 3, 4);
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
if (errno != EINPROGRESS) {
|
||||
tlog(TLOG_ERROR, "connect failed.");
|
||||
if (errno == ENETUNREACH) {
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN | EPOLLOUT;
|
||||
event.data.ptr = server_info;
|
||||
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
|
||||
tlog(TLOG_ERROR, "epoll ctl failed.");
|
||||
return -1;
|
||||
if (errno != EINPROGRESS) {
|
||||
tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
server_info->fd = fd;
|
||||
server_info->status = DNS_SERVER_STATUS_CONNECTING;
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN | EPOLLOUT;
|
||||
event.data.ptr = server_info;
|
||||
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
|
||||
tlog(TLOG_ERROR, "epoll ctl failed, %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "tcp server %s connecting.\n", server_info->ip);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (server_info->fd > 0) {
|
||||
server_info->fd = -1;
|
||||
}
|
||||
|
||||
server_info->status = DNS_SERVER_STATUS_INIT;
|
||||
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1571,20 +1622,26 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
|
||||
}
|
||||
|
||||
// ? this cause ssl crash ?
|
||||
// setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes));
|
||||
// setsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof(yes));
|
||||
// setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof(yes));
|
||||
// set_sock_keepalive(fd, 15, 3, 4);
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof(yes));
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof(yes));
|
||||
set_sock_keepalive(fd, 15, 3, 4);
|
||||
setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority));
|
||||
setsockopt(fd, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos));
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen) != 0) {
|
||||
if (errno == ENETUNREACH) {
|
||||
tlog(TLOG_DEBUG, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (errno != EINPROGRESS) {
|
||||
tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
SSL_set_connect_state(ssl);
|
||||
if (SSL_set_fd(ssl, fd) == 0) {
|
||||
tlog(TLOG_ERROR, "ssl set fd failed.");
|
||||
goto errout;
|
||||
@@ -1595,11 +1652,16 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
|
||||
SSL_set_session(ssl, server_info->ssl_session);
|
||||
}
|
||||
|
||||
SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||
SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
if (hostname[0] != 0) {
|
||||
SSL_set_tlsext_host_name(ssl, hostname);
|
||||
}
|
||||
|
||||
server_info->fd = fd;
|
||||
server_info->ssl = ssl;
|
||||
server_info->ssl_write_len = -1;
|
||||
server_info->status = DNS_SERVER_STATUS_CONNECTING;
|
||||
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN | EPOLLOUT;
|
||||
event.data.ptr = server_info;
|
||||
@@ -1608,14 +1670,20 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
|
||||
goto errout;
|
||||
}
|
||||
|
||||
server_info->fd = fd;
|
||||
server_info->ssl = ssl;
|
||||
server_info->status = DNS_SERVER_STATUS_CONNECTING;
|
||||
|
||||
tlog(TLOG_DEBUG, "tls server %s connecting.\n", server_info->ip);
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (server_info->fd > 0) {
|
||||
server_info->fd = -1;
|
||||
}
|
||||
|
||||
if (server_info->ssl) {
|
||||
server_info->ssl = NULL;
|
||||
}
|
||||
|
||||
server_info->status = DNS_SERVER_STATUS_INIT;
|
||||
|
||||
if (fd > 0) {
|
||||
close(fd);
|
||||
}
|
||||
@@ -1721,23 +1789,21 @@ static int _dns_client_socket_ssl_send(SSL *ssl, const void *buf, int num)
|
||||
unsigned long ssl_err = 0;
|
||||
|
||||
if (ssl == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = SSL_write(ssl, buf, num);
|
||||
if (ret >= 0) {
|
||||
if (ret > 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssl_ret = SSL_get_error(ssl, ret);
|
||||
switch (ssl_ret) {
|
||||
case SSL_ERROR_NONE:
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return 0;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
case SSL_ERROR_WANT_READ:
|
||||
errno = EAGAIN;
|
||||
ret = -1;
|
||||
@@ -1748,12 +1814,15 @@ static int _dns_client_socket_ssl_send(SSL *ssl, const void *buf, int num)
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
ssl_err = ERR_get_error();
|
||||
if (ERR_GET_REASON(ssl_err) == SSL_R_UNINITIALIZED || ERR_GET_REASON(ssl_err) == SSL_R_PROTOCOL_IS_SHUTDOWN) {
|
||||
int ssl_reason = ERR_GET_REASON(ssl_err);
|
||||
if (ssl_reason == SSL_R_UNINITIALIZED || ssl_reason == SSL_R_PROTOCOL_IS_SHUTDOWN ||
|
||||
ssl_reason == SSL_R_BAD_LENGTH || ssl_reason == SSL_R_SHUTDOWN_WHILE_IN_INIT ||
|
||||
ssl_reason == SSL_R_BAD_WRITE_RETRY) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "SSL write fail error no: %s(%ld)\n", ERR_reason_error_string(ssl_err), ssl_err);
|
||||
tlog(TLOG_ERROR, "SSL write fail error no: %s(%d)\n", ERR_reason_error_string(ssl_err), ssl_reason);
|
||||
errno = EFAULT;
|
||||
ret = -1;
|
||||
break;
|
||||
@@ -1788,9 +1857,6 @@ static int _dns_client_socket_ssl_recv(SSL *ssl, void *buf, int num)
|
||||
ssl_ret = SSL_get_error(ssl, ret);
|
||||
switch (ssl_ret) {
|
||||
case SSL_ERROR_NONE:
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
break;
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
return 0;
|
||||
break;
|
||||
@@ -1804,16 +1870,25 @@ static int _dns_client_socket_ssl_recv(SSL *ssl, void *buf, int num)
|
||||
break;
|
||||
case SSL_ERROR_SSL:
|
||||
ssl_err = ERR_get_error();
|
||||
if (ERR_GET_REASON(ssl_err) == SSL_R_UNINITIALIZED) {
|
||||
int ssl_reason = ERR_GET_REASON(ssl_err);
|
||||
if (ssl_reason == SSL_R_UNINITIALIZED) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "SSL read fail error no: %s(%ld)\n", ERR_reason_error_string(ssl_err), ssl_err);
|
||||
if (ssl_reason == SSL_R_SHUTDOWN_WHILE_IN_INIT || ssl_reason == SSL_R_PROTOCOL_IS_SHUTDOWN) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
tlog(TLOG_ERROR, "SSL read fail error no: %s(%lx)\n", ERR_reason_error_string(ssl_err), ssl_err);
|
||||
errno = EFAULT;
|
||||
ret = -1;
|
||||
break;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
if (errno == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (errno != ECONNRESET) {
|
||||
tlog(TLOG_INFO, "SSL syscall failed, %s ", strerror(errno));
|
||||
}
|
||||
@@ -1835,7 +1910,18 @@ static int _dns_client_socket_send(struct dns_server_info *server_info)
|
||||
} else if (server_info->type == DNS_SERVER_TCP) {
|
||||
return send(server_info->fd, server_info->send_buff.data, server_info->send_buff.len, MSG_NOSIGNAL);
|
||||
} else if (server_info->type == DNS_SERVER_TLS || server_info->type == DNS_SERVER_HTTPS) {
|
||||
return _dns_client_socket_ssl_send(server_info->ssl, server_info->send_buff.data, server_info->send_buff.len);
|
||||
int write_len = server_info->send_buff.len;
|
||||
if (server_info->ssl_write_len > 0) {
|
||||
write_len = server_info->ssl_write_len;
|
||||
server_info->ssl_write_len = -1;
|
||||
}
|
||||
int ret = _dns_client_socket_ssl_send(server_info->ssl, server_info->send_buff.data, write_len);
|
||||
if (ret != 0) {
|
||||
if (errno == EAGAIN) {
|
||||
server_info->ssl_write_len = write_len;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
@@ -2096,11 +2182,31 @@ static int _dns_client_tls_matchName(const char *host, const char *pattern, int
|
||||
return match;
|
||||
}
|
||||
|
||||
static int _dns_client_tls_get_cert_CN(X509 *cert, char *cn, int max_cn_len)
|
||||
{
|
||||
X509_NAME *cert_name = NULL;
|
||||
|
||||
cert_name = X509_get_subject_name(cert);
|
||||
if (cert_name == NULL) {
|
||||
tlog(TLOG_ERROR, "get subject name failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (X509_NAME_get_text_by_NID(cert_name, NID_commonName, cn, max_cn_len) == -1) {
|
||||
tlog(TLOG_ERROR, "cannot found x509 name");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_client_tls_verify(struct dns_server_info *server_info)
|
||||
{
|
||||
X509 *cert = NULL;
|
||||
X509_PUBKEY *pubkey = NULL;
|
||||
X509_NAME *cert_name = NULL;
|
||||
char peer_CN[256];
|
||||
char cert_fingerprint[256];
|
||||
int i = 0;
|
||||
@@ -2124,24 +2230,20 @@ 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) {
|
||||
tlog(TLOG_WARN, "peer server certificate verify failed.");
|
||||
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 CN: %s", peer_CN);
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
cert_name = X509_get_subject_name(cert);
|
||||
if (cert_name == NULL) {
|
||||
tlog(TLOG_ERROR, "get subject name failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (X509_NAME_get_text_by_NID(cert_name, NID_commonName, peer_CN, 256) == -1) {
|
||||
tlog(TLOG_ERROR, "cannot found x509 name");
|
||||
if (_dns_client_tls_get_cert_CN(cert, peer_CN, sizeof(peer_CN)) != 0) {
|
||||
tlog(TLOG_ERROR, "get cert CN failed.");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
tlog(TLOG_DEBUG, "peer CN: %s", peer_CN);
|
||||
|
||||
/* check tls host */
|
||||
tls_host_verify = _dns_client_server_get_tls_host_verify(server_info);
|
||||
if (tls_host_verify) {
|
||||
@@ -2234,7 +2336,7 @@ 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_connect(server_info->ssl);
|
||||
ret = SSL_do_handshake(server_info->ssl);
|
||||
if (ret == 0) {
|
||||
goto errout;
|
||||
} else if (ret < 0) {
|
||||
@@ -2243,8 +2345,17 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
|
||||
if (ssl_ret == SSL_ERROR_WANT_READ) {
|
||||
fd_event.events = EPOLLIN;
|
||||
} else if (ssl_ret == SSL_ERROR_WANT_WRITE) {
|
||||
fd_event.events = EPOLLOUT;
|
||||
fd_event.events = EPOLLOUT | EPOLLIN;
|
||||
} else if (ssl_ret == SSL_ERROR_SYSCALL) {
|
||||
if (errno != ENETUNREACH) {
|
||||
tlog(TLOG_WARN, "Handshake with %s failed, %s", server_info->ip, strerror(errno));
|
||||
}
|
||||
goto errout;
|
||||
} else {
|
||||
unsigned long ssl_err = ERR_get_error();
|
||||
int ssl_reason = ERR_GET_REASON(ssl_err);
|
||||
tlog(TLOG_WARN, "Handshake with %s failed, error no: %s(%d, %d, %d)\n", server_info->ip,
|
||||
ERR_reason_error_string(ssl_err), ret, ssl_ret, ssl_reason);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@@ -2351,7 +2462,7 @@ static int _dns_client_send_data_to_buffer(struct dns_server_info *server_info,
|
||||
event.events = EPOLLIN | EPOLLOUT;
|
||||
event.data.ptr = server_info;
|
||||
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_MOD, server_info->fd, &event) != 0) {
|
||||
tlog(TLOG_ERROR, "epoll ctl failed.");
|
||||
tlog(TLOG_ERROR, "epoll ctl failed, %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -2424,16 +2535,17 @@ static int _dns_client_send_tls(struct dns_server_info *server_info, void *packe
|
||||
}
|
||||
|
||||
if (server_info->ssl == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_len = _dns_client_socket_ssl_send(server_info->ssl, inpacket, len);
|
||||
if (send_len < 0) {
|
||||
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, len);
|
||||
} else if (server_info->ssl && errno != ENOMEM) {
|
||||
SSL_set_shutdown(server_info->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
|
||||
SSL_shutdown(server_info->ssl);
|
||||
}
|
||||
return -1;
|
||||
} else if (send_len < len) {
|
||||
@@ -2474,11 +2586,12 @@ static int _dns_client_send_https(struct dns_server_info *server_info, void *pac
|
||||
}
|
||||
|
||||
if (server_info->ssl == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
send_len = _dns_client_socket_ssl_send(server_info->ssl, inpacket, http_len);
|
||||
if (send_len < 0) {
|
||||
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);
|
||||
@@ -2501,63 +2614,85 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
|
||||
struct dns_server_group_member *tmp = NULL;
|
||||
int ret = 0;
|
||||
int send_err = 0;
|
||||
int i = 0;
|
||||
|
||||
query->send_tick = get_tick_count();
|
||||
|
||||
/* send query to all dns servers */
|
||||
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;
|
||||
if (server_info->fd <= 0) {
|
||||
ret = _dns_client_create_socket(server_info);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
for (i = 0; i < 2; i++) {
|
||||
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;
|
||||
if (server_info->fd <= 0) {
|
||||
ret = _dns_client_create_socket(server_info);
|
||||
if (ret != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
atomic_inc(&query->dns_request_sent);
|
||||
switch (server_info->type) {
|
||||
case DNS_SERVER_UDP:
|
||||
/* udp query */
|
||||
ret = _dns_client_send_udp(server_info, packet, len);
|
||||
send_err = errno;
|
||||
break;
|
||||
case DNS_SERVER_TCP:
|
||||
/* tcp query */
|
||||
ret = _dns_client_send_tcp(server_info, packet, len);
|
||||
send_err = errno;
|
||||
break;
|
||||
case DNS_SERVER_TLS:
|
||||
/* tls query */
|
||||
ret = _dns_client_send_tls(server_info, packet, len);
|
||||
send_err = errno;
|
||||
break;
|
||||
case DNS_SERVER_HTTPS:
|
||||
/* https query */
|
||||
ret = _dns_client_send_https(server_info, packet, len);
|
||||
send_err = errno;
|
||||
break;
|
||||
default:
|
||||
/* unsupport query type */
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
atomic_inc(&query->dns_request_sent);
|
||||
switch (server_info->type) {
|
||||
case DNS_SERVER_UDP:
|
||||
/* udp query */
|
||||
ret = _dns_client_send_udp(server_info, packet, len);
|
||||
send_err = errno;
|
||||
break;
|
||||
case DNS_SERVER_TCP:
|
||||
/* tcp query */
|
||||
ret = _dns_client_send_tcp(server_info, packet, len);
|
||||
send_err = errno;
|
||||
break;
|
||||
case DNS_SERVER_TLS:
|
||||
/* tls query */
|
||||
ret = _dns_client_send_tls(server_info, packet, len);
|
||||
send_err = errno;
|
||||
break;
|
||||
case DNS_SERVER_HTTPS:
|
||||
/* https query */
|
||||
ret = _dns_client_send_https(server_info, packet, len);
|
||||
send_err = errno;
|
||||
break;
|
||||
default:
|
||||
/* unsupport query type */
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (send_err == ENETUNREACH) {
|
||||
tlog(TLOG_DEBUG, "send query to %s failed, %s, type: %d", server_info->ip, strerror(send_err),
|
||||
server_info->type);
|
||||
_dns_client_close_socket(server_info);
|
||||
atomic_dec(&query->dns_request_sent);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (send_err != ENOMEM) {
|
||||
tlog(TLOG_ERROR, "send query to %s failed, %s, type: %d", server_info->ip, strerror(send_err),
|
||||
server_info->type);
|
||||
} else {
|
||||
tlog(TLOG_DEBUG, "send query to %s failed, %s, type: %d", server_info->ip, strerror(send_err),
|
||||
server_info->type);
|
||||
time_t now;
|
||||
time(&now);
|
||||
if (now - 5 > server_info->last_recv || send_err != ENOMEM) {
|
||||
_dns_client_shutdown_socket(server_info);
|
||||
}
|
||||
|
||||
atomic_dec(&query->dns_request_sent);
|
||||
continue;
|
||||
}
|
||||
atomic_dec(&query->dns_request_sent);
|
||||
continue;
|
||||
time(&server_info->last_send);
|
||||
}
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
|
||||
if (atomic_read(&query->dns_request_sent) > 0) {
|
||||
break;
|
||||
}
|
||||
time(&server_info->last_send);
|
||||
}
|
||||
pthread_mutex_unlock(&client.server_list_lock);
|
||||
|
||||
if (atomic_read(&query->dns_request_sent) <= 0) {
|
||||
tlog(TLOG_ERROR, "Send query to upstream server failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2797,7 +2932,7 @@ static void _dns_client_add_pending_servers(void)
|
||||
if (pending->query_v4 == 0) {
|
||||
pending->query_v4 = 1;
|
||||
_dns_client_server_pending_get(pending);
|
||||
if (dns_server_query(pending->host, DNS_T_A, _dns_client_pending_server_resolve, pending) != 0) {
|
||||
if (dns_server_query(pending->host, DNS_T_A, 0, _dns_client_pending_server_resolve, pending) != 0) {
|
||||
_dns_client_server_pending_release_lck(pending);
|
||||
}
|
||||
}
|
||||
@@ -2805,14 +2940,13 @@ static void _dns_client_add_pending_servers(void)
|
||||
if (pending->query_v6 == 0) {
|
||||
pending->query_v6 = 1;
|
||||
_dns_client_server_pending_get(pending);
|
||||
if (dns_server_query(pending->host, DNS_T_AAAA, _dns_client_pending_server_resolve, pending) != 0) {
|
||||
if (dns_server_query(pending->host, DNS_T_AAAA, 0, _dns_client_pending_server_resolve, pending) != 0) {
|
||||
_dns_client_server_pending_release_lck(pending);
|
||||
}
|
||||
}
|
||||
|
||||
/* if both A, AAAA has query result, select fastest IP address */
|
||||
if (pending->has_v4 && pending->has_v6) {
|
||||
|
||||
if (pending->ping_time_v4 <= pending->ping_time_v6 && pending->ipv4[0]) {
|
||||
dnsserver_ip = pending->ipv4;
|
||||
} else {
|
||||
|
||||
@@ -262,6 +262,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
return -1;
|
||||
}
|
||||
|
||||
ip = argv[1];
|
||||
if (index >= DNS_MAX_SERVERS) {
|
||||
tlog(TLOG_WARN, "exceeds max server number, %s", ip);
|
||||
return 0;
|
||||
@@ -274,8 +275,6 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
|
||||
server->httphost[0] = '\0';
|
||||
server->tls_host_verify[0] = '\0';
|
||||
|
||||
ip = argv[1];
|
||||
|
||||
if (type == DNS_SERVER_HTTPS) {
|
||||
if (parse_uri(ip, NULL, server->server, &port, server->path) != 0) {
|
||||
return -1;
|
||||
@@ -871,6 +870,7 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
ip = argv[1];
|
||||
if (index >= DNS_MAX_SERVERS) {
|
||||
tlog(TLOG_WARN, "exceeds max server number, %s", ip);
|
||||
return 0;
|
||||
@@ -879,7 +879,6 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
|
||||
bind_ip = &dns_conf_bind_ip[index];
|
||||
bind_ip->type = type;
|
||||
bind_ip->flags = 0;
|
||||
ip = argv[1];
|
||||
safe_strncpy(bind_ip->ip, ip, DNS_MAX_IPLEN);
|
||||
|
||||
/* process extra options */
|
||||
|
||||
550
src/dns_server.c
550
src/dns_server.c
@@ -137,6 +137,8 @@ struct dns_request {
|
||||
atomic_t refcnt;
|
||||
|
||||
struct dns_server_conn_head *conn;
|
||||
uint32_t server_flags;
|
||||
|
||||
/* dns request list */
|
||||
struct list_head list;
|
||||
|
||||
@@ -206,7 +208,7 @@ static struct dns_server server;
|
||||
|
||||
static tlog_log *dns_audit;
|
||||
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype);
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, uint32_t server_flags);
|
||||
|
||||
static int _dns_server_forward_request(unsigned char *inpacket, int inpacket_len)
|
||||
{
|
||||
@@ -216,17 +218,27 @@ static int _dns_server_forward_request(unsigned char *inpacket, int inpacket_len
|
||||
|
||||
static int _dns_server_has_bind_flag(struct dns_request *request, uint32_t flag)
|
||||
{
|
||||
if (request->conn == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (request->conn->server_flags & flag) {
|
||||
if (request->server_flags & flag) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_get_conf_ttl(int ttl)
|
||||
{
|
||||
if (dns_conf_rr_ttl > 0) {
|
||||
return dns_conf_rr_ttl;
|
||||
}
|
||||
|
||||
if (dns_conf_rr_ttl_max > 0 && ttl > dns_conf_rr_ttl_max) {
|
||||
ttl = dns_conf_rr_ttl_max;
|
||||
} else if (dns_conf_rr_ttl_min > 0 && ttl < dns_conf_rr_ttl_min) {
|
||||
ttl = dns_conf_rr_ttl_min;
|
||||
}
|
||||
return ttl;
|
||||
}
|
||||
|
||||
static int _dns_server_epoll_ctl(struct dns_server_conn_head *head, int op, uint32_t events)
|
||||
{
|
||||
struct epoll_event event;
|
||||
@@ -692,10 +704,47 @@ static int _dns_setup_ipset(struct dns_request *request)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_server_request_update_cache(struct dns_request *request, dns_type_t qtype,
|
||||
struct dns_cache_data *cache_data)
|
||||
{
|
||||
int ttl;
|
||||
int speed = 0;
|
||||
|
||||
if (qtype == DNS_T_A) {
|
||||
ttl = _dns_server_get_conf_ttl(request->ttl_v4);
|
||||
speed = request->ping_ttl_v4;
|
||||
} else if (qtype == DNS_T_AAAA) {
|
||||
ttl = _dns_server_get_conf_ttl(request->ttl_v6);
|
||||
speed = request->ping_ttl_v6;
|
||||
} else {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
if (request->prefetch) {
|
||||
if (dns_cache_replace(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
} else {
|
||||
/* insert result to cache */
|
||||
if (dns_cache_insert(request->domain, ttl, qtype, speed, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
if (cache_data) {
|
||||
dns_cache_data_free(cache_data);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_request_complete_A(struct dns_request *request)
|
||||
{
|
||||
char *cname = NULL;
|
||||
int cname_ttl = 0;
|
||||
struct dns_cache_data *cache_data = NULL;
|
||||
|
||||
if (request->has_cname) {
|
||||
cname = request->cname;
|
||||
@@ -718,23 +767,32 @@ static int _dns_server_request_complete_A(struct dns_request *request)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if doing prefetch, update cache only */
|
||||
if (request->prefetch) {
|
||||
dns_cache_replace(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN,
|
||||
request->ping_ttl_v4);
|
||||
} else {
|
||||
/* insert result to cache */
|
||||
dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr, DNS_RR_A_LEN,
|
||||
request->ping_ttl_v4);
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (cache_data) {
|
||||
dns_cache_data_free(cache_data);
|
||||
cache_data = NULL;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_request_complete_AAAA(struct dns_request *request)
|
||||
{
|
||||
int ret = -1;
|
||||
char *cname = NULL;
|
||||
int cname_ttl = 0;
|
||||
struct dns_cache_data *cache_data = NULL;
|
||||
|
||||
if (request->has_cname) {
|
||||
cname = request->cname;
|
||||
@@ -756,13 +814,14 @@ 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) {
|
||||
if (request->prefetch) {
|
||||
dns_cache_replace(request->domain, cname, cname_ttl, request->ttl_v6, DNS_T_AAAA, request->ipv6_addr,
|
||||
DNS_RR_AAAA_LEN, request->ping_ttl_v6);
|
||||
} else {
|
||||
/* insert result to cache */
|
||||
dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v6, DNS_T_AAAA, request->ipv6_addr,
|
||||
DNS_RR_AAAA_LEN, request->ping_ttl_v6);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,21 +837,25 @@ 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) {
|
||||
if (request->prefetch) {
|
||||
dns_cache_replace(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr,
|
||||
DNS_RR_A_LEN, request->ping_ttl_v4);
|
||||
} else {
|
||||
dns_cache_insert(request->domain, cname, cname_ttl, request->ttl_v4, DNS_T_A, request->ipv4_addr,
|
||||
DNS_RR_A_LEN, request->ping_ttl_v4);
|
||||
cache_data =
|
||||
dns_cache_new_data_addr(request->server_flags, cname, cname_ttl, request->ipv4_addr, DNS_T_A);
|
||||
if (cache_data == NULL) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (_dns_server_request_update_cache(request, DNS_T_A, cache_data) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if (request->dualstack_selection) {
|
||||
if (_dns_server_reply_SOA(DNS_RC_NOERROR, request) != 0) {
|
||||
return -1;
|
||||
ret = -1;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 1;
|
||||
ret = 1;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -800,6 +863,14 @@ static int _dns_server_request_complete_AAAA(struct dns_request *request)
|
||||
request->has_ipv4 = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
if (cache_data == NULL) {
|
||||
dns_cache_data_free(cache_data);
|
||||
cache_data = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_server_request_complete(struct dns_request *request)
|
||||
@@ -880,6 +951,7 @@ static void _dns_server_select_possible_ipaddress(struct dns_request *request)
|
||||
|
||||
/* Return the most likely correct IP address */
|
||||
/* Returns the IP with the most hits, or the last returned record is considered to be the most likely correct. */
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
|
||||
{
|
||||
if (addr_map->addr_type != request->qtype) {
|
||||
@@ -896,6 +968,7 @@ static void _dns_server_select_possible_ipaddress(struct dns_request *request)
|
||||
maxhit_addr_map = addr_map;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
|
||||
if (maxhit_addr_map && maxhit > 1) {
|
||||
selected_addr_map = maxhit_addr_map;
|
||||
@@ -966,11 +1039,13 @@ static void _dns_server_request_release_complete(struct dns_request *request, in
|
||||
_dns_server_request_complete(request);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&request->ip_map_lock);
|
||||
hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
|
||||
{
|
||||
hash_del(&addr_map->node);
|
||||
free(addr_map);
|
||||
}
|
||||
pthread_mutex_unlock(&request->ip_map_lock);
|
||||
|
||||
_dns_server_delete_request(request);
|
||||
}
|
||||
@@ -1192,20 +1267,6 @@ static int _dns_ip_address_check_add(struct dns_request *request, unsigned char
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_get_conf_ttl(int ttl)
|
||||
{
|
||||
if (dns_conf_rr_ttl > 0) {
|
||||
return dns_conf_rr_ttl;
|
||||
}
|
||||
|
||||
if (dns_conf_rr_ttl_max > 0 && ttl > dns_conf_rr_ttl_max) {
|
||||
ttl = dns_conf_rr_ttl_max;
|
||||
} else if (dns_conf_rr_ttl_min > 0 && ttl < dns_conf_rr_ttl_min) {
|
||||
ttl = dns_conf_rr_ttl_min;
|
||||
}
|
||||
return ttl;
|
||||
}
|
||||
|
||||
static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char *addr, int addr_len,
|
||||
dns_type_t addr_type, int result_flag)
|
||||
{
|
||||
@@ -1627,6 +1688,163 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, char
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_get_answer(struct dns_request *request, struct dns_packet *packet)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int ttl = 0;
|
||||
struct dns_rrs *rrs = NULL;
|
||||
int rr_count = 0;
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
|
||||
for (j = 1; j < DNS_RRS_END; j++) {
|
||||
rrs = dns_get_rrs_start(packet, j, &rr_count);
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
|
||||
switch (rrs->type) {
|
||||
case DNS_T_A: {
|
||||
unsigned char addr[4];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
|
||||
if (request->qtype != DNS_T_A) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* get A result */
|
||||
dns_get_A(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
memcpy(request->ipv4_addr, addr, DNS_RR_A_LEN);
|
||||
request->ttl_v4 = _dns_server_get_conf_ttl(ttl);
|
||||
request->has_ipv4 = 1;
|
||||
request->rcode = packet->head.rcode;
|
||||
} break;
|
||||
case DNS_T_AAAA: {
|
||||
unsigned char addr[16];
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
|
||||
if (request->qtype != DNS_T_AAAA) {
|
||||
/* ignore non-matched query type */
|
||||
continue;
|
||||
}
|
||||
dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
memcpy(request->ipv6_addr, addr, DNS_RR_AAAA_LEN);
|
||||
request->ttl_v6 = _dns_server_get_conf_ttl(ttl);
|
||||
request->has_ipv6 = 1;
|
||||
request->rcode = packet->head.rcode;
|
||||
} break;
|
||||
case DNS_T_NS: {
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
|
||||
tlog(TLOG_DEBUG, "NS: %s ttl:%d cname: %s\n", name, ttl, cname);
|
||||
} break;
|
||||
case DNS_T_CNAME: {
|
||||
char cname[DNS_MAX_CNAME_LEN];
|
||||
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
|
||||
tlog(TLOG_DEBUG, "name:%s ttl: %d cname: %s\n", name, ttl, cname);
|
||||
safe_strncpy(request->cname, cname, DNS_MAX_CNAME_LEN);
|
||||
request->ttl_cname = ttl;
|
||||
request->has_cname = 1;
|
||||
} break;
|
||||
case DNS_T_SOA: {
|
||||
request->has_soa = 1;
|
||||
request->rcode = packet->head.rcode;
|
||||
dns_get_SOA(rrs, name, 128, &ttl, &request->soa);
|
||||
tlog(TLOG_DEBUG,
|
||||
"domain: %s, qtype: %d, SOA: mname: %s, rname: %s, serial: %d, refresh: %d, retry: %d, expire: "
|
||||
"%d, minimum: %d",
|
||||
request->domain, request->qtype, request->soa.mname, request->soa.rname, request->soa.serial,
|
||||
request->soa.refresh, request->soa.retry, request->soa.expire, request->soa.minimum);
|
||||
if (atomic_inc_return(&request->soa_num) >= (dns_server_num() / 2)) {
|
||||
_dns_server_request_complete(request);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
tlog(TLOG_DEBUG, "%s, qtype: %d", name, rrs->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_setup_ipset_packet(struct dns_request *request, struct dns_packet *packet)
|
||||
{
|
||||
int ttl;
|
||||
char name[DNS_MAX_CNAME_LEN] = {0};
|
||||
int rr_count;
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
struct dns_rrs *rrs = NULL;
|
||||
struct dns_ipset_rule *ipset_rule = NULL;
|
||||
struct dns_rule_flags *rule_flags = NULL;
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_RULE_IPSET) == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
ipset_rule = request->domain_rule.rules[DOMAIN_RULE_IPSET];
|
||||
if (ipset_rule == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (j = 1; j < DNS_RRS_END; j++) {
|
||||
rrs = dns_get_rrs_start(packet, j, &rr_count);
|
||||
for (i = 0; i < rr_count && rrs; i++, rrs = dns_get_rrs_next(packet, rrs)) {
|
||||
switch (rrs->type) {
|
||||
case DNS_T_A: {
|
||||
unsigned char addr[4];
|
||||
if (request->qtype != DNS_T_A) {
|
||||
/* ignore non-matched query type */
|
||||
if (request->dualstack_selection == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* 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);
|
||||
|
||||
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]);
|
||||
} break;
|
||||
case DNS_T_AAAA: {
|
||||
unsigned char addr[16];
|
||||
if (request->qtype != DNS_T_AAAA) {
|
||||
/* ignore non-matched query type */
|
||||
break;
|
||||
}
|
||||
dns_get_AAAA(rrs, name, DNS_MAX_CNAME_LEN, &ttl, addr);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dns_server_reply_passthrouth(struct dns_request *request, struct dns_packet *packet,
|
||||
unsigned char *inpacket, int inpacket_len)
|
||||
{
|
||||
@@ -1636,6 +1854,11 @@ static int _dns_server_reply_passthrouth(struct dns_request *request, struct dns
|
||||
return 0;
|
||||
}
|
||||
|
||||
_dns_server_get_answer(request, packet);
|
||||
if (request->result_callback) {
|
||||
_dns_result_callback(request);
|
||||
}
|
||||
|
||||
if (request->conn == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@@ -1644,7 +1867,27 @@ static int _dns_server_reply_passthrouth(struct dns_request *request, struct dns
|
||||
dns_server_update_reply_packet_id(request, inpacket, inpacket_len);
|
||||
ret = _dns_reply_inpacket(request, inpacket, inpacket_len);
|
||||
|
||||
return ret;
|
||||
if (packet->head.rcode != DNS_RC_NOERROR && packet->head.rcode != DNS_RC_NXDOMAIN) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) != 0 &&
|
||||
(request->qtype == DNS_T_AAAA || request->qtype == DNS_T_A)) {
|
||||
struct dns_cache_data *cache_packet = dns_cache_new_data_packet(request->server_flags, inpacket, inpacket_len);
|
||||
if (cache_packet == NULL) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (_dns_server_request_update_cache(request, request->qtype, cache_packet) != 0) {
|
||||
tlog(TLOG_WARN, "update packet cache failed.");
|
||||
}
|
||||
}
|
||||
|
||||
if(_dns_server_setup_ipset_packet(request, packet) != 0) {
|
||||
tlog(TLOG_DEBUG, "setup ipset failed.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dns_server_resolve_callback(char *domain, dns_result_type rtype, unsigned int result_flag,
|
||||
@@ -1669,7 +1912,6 @@ static int dns_server_resolve_callback(char *domain, dns_result_type rtype, unsi
|
||||
|
||||
return _dns_server_reply_passthrouth(request, packet, inpacket, inpacket_len);
|
||||
}
|
||||
|
||||
_dns_server_process_answer(request, domain, packet, result_flag);
|
||||
return 0;
|
||||
} else if (rtype == DNS_QUERY_ERR) {
|
||||
@@ -1787,7 +2029,6 @@ static void _dns_server_log_rule(const char *domain, enum domain_rule rule_type,
|
||||
int rule_key_len)
|
||||
{
|
||||
char rule_name[DNS_MAX_CNAME_LEN];
|
||||
|
||||
if (rule_key_len <= 0) {
|
||||
return;
|
||||
}
|
||||
@@ -2009,7 +2250,7 @@ errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _dns_server_prolcess_speed_check_rule(struct dns_request *request)
|
||||
static void _dns_server_process_speed_check_rule(struct dns_request *request)
|
||||
{
|
||||
struct dns_domain_check_order *check_order = NULL;
|
||||
|
||||
@@ -2022,55 +2263,22 @@ static void _dns_server_prolcess_speed_check_rule(struct dns_request *request)
|
||||
request->check_order_list = check_order;
|
||||
}
|
||||
|
||||
static int _dns_server_process_cache(struct dns_request *request)
|
||||
static int _dns_server_process_cache_addr(struct dns_request *request, struct dns_cache *dns_cache)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *dns_cache_A = NULL;
|
||||
struct dns_cache_addr *cache_addr = (struct dns_cache_addr *)dns_cache_get_data(dns_cache);
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) == 0) {
|
||||
if (cache_addr->head.cache_type != CACHE_TYPE_ADDR) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
dns_cache = dns_cache_lookup(request->domain, request->qtype);
|
||||
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) {
|
||||
tlog(TLOG_DEBUG, "No IPV6 Found, Force IPV4 perfered.");
|
||||
dns_cache_release(dns_cache_A);
|
||||
dns_cache_release(dns_cache);
|
||||
return _dns_server_reply_SOA(DNS_RC_NOERROR, request);
|
||||
}
|
||||
}
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (request->qtype != dns_cache->qtype) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
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) {
|
||||
tlog(TLOG_DEBUG, "Force IPV4 perfered.");
|
||||
dns_cache_release(dns_cache_A);
|
||||
dns_cache_release(dns_cache);
|
||||
return _dns_server_reply_SOA(DNS_RC_NOERROR, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Cache hits, returning results in the cache */
|
||||
switch (request->qtype) {
|
||||
case DNS_T_A:
|
||||
memcpy(request->ipv4_addr, dns_cache->ipv4_addr, DNS_RR_A_LEN);
|
||||
memcpy(request->ipv4_addr, cache_addr->addr_data.ipv4_addr, DNS_RR_A_LEN);
|
||||
request->ttl_v4 = dns_cache_get_ttl(dns_cache);
|
||||
request->has_ipv4 = 1;
|
||||
break;
|
||||
case DNS_T_AAAA:
|
||||
memcpy(request->ipv6_addr, dns_cache->ipv6_addr, DNS_RR_AAAA_LEN);
|
||||
memcpy(request->ipv6_addr, cache_addr->addr_data.ipv6_addr, DNS_RR_AAAA_LEN);
|
||||
request->ttl_v6 = dns_cache_get_ttl(dns_cache);
|
||||
request->has_ipv6 = 1;
|
||||
break;
|
||||
@@ -2079,10 +2287,10 @@ static int _dns_server_process_cache(struct dns_request *request)
|
||||
break;
|
||||
}
|
||||
|
||||
if (dns_cache->cname[0] != 0) {
|
||||
safe_strncpy(request->cname, dns_cache->cname, DNS_MAX_CNAME_LEN);
|
||||
if (cache_addr->addr_data.cname[0] != 0) {
|
||||
safe_strncpy(request->cname, cache_addr->addr_data.cname, DNS_MAX_CNAME_LEN);
|
||||
request->has_cname = 1;
|
||||
request->ttl_cname = dns_cache->cname_ttl;
|
||||
request->ttl_cname = cache_addr->addr_data.cname_ttl;
|
||||
}
|
||||
|
||||
request->rcode = DNS_RC_NOERROR;
|
||||
@@ -2093,33 +2301,159 @@ static int _dns_server_process_cache(struct dns_request *request)
|
||||
_dns_reply(request);
|
||||
}
|
||||
|
||||
if (dns_cache_get_ttl(dns_cache) == 0) {
|
||||
_dns_server_prefetch_request(request->domain, request->qtype);
|
||||
} else {
|
||||
dns_cache_update(dns_cache);
|
||||
}
|
||||
dns_cache_release(dns_cache);
|
||||
return 0;
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dns_cache_A) {
|
||||
dns_cache_release(dns_cache_A);
|
||||
dns_cache_A = NULL;
|
||||
static int _dns_server_process_cache_packet(struct dns_request *request, struct dns_cache *dns_cache)
|
||||
{
|
||||
struct dns_cache_packet *cache_packet = (struct dns_cache_packet *)dns_cache_get_data(dns_cache);
|
||||
|
||||
if (cache_packet->head.cache_type != CACHE_TYPE_PACKET) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (dns_cache->qtype != request->qtype) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (atomic_inc_return(&request->notified) != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (request->result_callback) {
|
||||
unsigned char packet_buff[DNS_PACKSIZE];
|
||||
struct dns_packet *packet = (struct dns_packet *)packet_buff;
|
||||
|
||||
if (dns_decode(packet, DNS_PACKSIZE, cache_packet->data, cache_packet->head.size) != 0) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
_dns_server_get_answer(request, packet);
|
||||
_dns_result_callback(request);
|
||||
}
|
||||
|
||||
if (request->conn == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* When passthrough, modify the id to be the id of the client request. */
|
||||
dns_server_update_reply_packet_id(request, cache_packet->data, cache_packet->head.size);
|
||||
return _dns_reply_inpacket(request, cache_packet->data, cache_packet->head.size);
|
||||
errout:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_process_cache_data(struct dns_request *request, struct dns_cache *dns_cache)
|
||||
{
|
||||
enum CACHE_TYPE cache_type = CACHE_TYPE_NONE;
|
||||
int ret = -1;
|
||||
|
||||
cache_type = dns_cache_data_type(dns_cache->cache_data);
|
||||
switch (cache_type) {
|
||||
case CACHE_TYPE_ADDR:
|
||||
ret = _dns_server_process_cache_addr(request, dns_cache);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case CACHE_TYPE_PACKET:
|
||||
ret = _dns_server_process_cache_packet(request, dns_cache);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
errout:
|
||||
out:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _dns_server_process_cache(struct dns_request *request)
|
||||
{
|
||||
struct dns_cache *dns_cache = NULL;
|
||||
struct dns_cache *dns_cache_A = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
dns_cache = dns_cache_lookup(request->domain, request->qtype);
|
||||
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) {
|
||||
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;
|
||||
if (request->conn == NULL) {
|
||||
server_flags = dns_cache_get_cache_flag(dns_cache_A->cache_data);
|
||||
}
|
||||
_dns_server_prefetch_request(request->domain, request->qtype, server_flags);
|
||||
}
|
||||
ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (request->qtype != dns_cache->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) {
|
||||
tlog(TLOG_DEBUG, "Force IPV4 perfered.");
|
||||
ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request);
|
||||
goto out_update_cache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = _dns_server_process_cache_data(request, dns_cache);
|
||||
if (ret != 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
_dns_server_prefetch_request(request->domain, request->qtype, server_flags);
|
||||
} else {
|
||||
dns_cache_update(dns_cache);
|
||||
}
|
||||
|
||||
out:
|
||||
if (dns_cache) {
|
||||
dns_cache_release(dns_cache);
|
||||
}
|
||||
|
||||
if (dns_cache_A) {
|
||||
dns_cache_release(dns_cache_A);
|
||||
dns_cache_A = NULL;
|
||||
}
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _dns_server_request_set_client(struct dns_request *request, struct dns_server_conn_head *conn)
|
||||
{
|
||||
request->conn = conn;
|
||||
request->server_flags = conn->server_flags;
|
||||
_dns_server_conn_get(conn);
|
||||
}
|
||||
|
||||
@@ -2220,6 +2554,10 @@ static void _dns_server_check_set_passthrough(struct dns_request *request)
|
||||
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_SPEED_CHECK) == 0) {
|
||||
request->passthrough = 1;
|
||||
}
|
||||
|
||||
if (request->passthrough == 1) {
|
||||
request->dualstack_selection = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int _dns_server_do_query(struct dns_request *request, const char *domain, int qtype)
|
||||
@@ -2257,7 +2595,7 @@ static int _dns_server_do_query(struct dns_request *request, const char *domain,
|
||||
}
|
||||
|
||||
/* process speed check rule */
|
||||
_dns_server_prolcess_speed_check_rule(request);
|
||||
_dns_server_process_speed_check_rule(request);
|
||||
|
||||
/* check and set passthrough */
|
||||
_dns_server_check_set_passthrough(request);
|
||||
@@ -2385,7 +2723,7 @@ errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype)
|
||||
static int _dns_server_prefetch_request(char *domain, dns_type_t qtype, uint32_t server_flags)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dns_request *request = NULL;
|
||||
@@ -2396,6 +2734,7 @@ static int _dns_server_prefetch_request(char *domain, dns_type_t qtype)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
request->server_flags = server_flags;
|
||||
_dns_server_request_set_enable_prefetch(request);
|
||||
ret = _dns_server_do_query(request, domain, qtype);
|
||||
if (ret != 0) {
|
||||
@@ -2413,7 +2752,7 @@ errout:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dns_server_query(char *domain, int qtype, dns_result_callback callback, void *user_ptr)
|
||||
int dns_server_query(char *domain, int qtype, uint32_t server_flags, dns_result_callback callback, void *user_ptr)
|
||||
{
|
||||
int ret = -1;
|
||||
struct dns_request *request = NULL;
|
||||
@@ -2424,6 +2763,7 @@ int dns_server_query(char *domain, int qtype, dns_result_callback callback, void
|
||||
goto errout;
|
||||
}
|
||||
|
||||
request->server_flags = server_flags;
|
||||
_dns_server_request_set_callback(request, callback, user_ptr);
|
||||
ret = _dns_server_do_query(request, domain, qtype);
|
||||
if (ret != 0) {
|
||||
@@ -2435,6 +2775,7 @@ int dns_server_query(char *domain, int qtype, dns_result_callback callback, void
|
||||
return ret;
|
||||
errout:
|
||||
if (request) {
|
||||
_dns_server_request_set_callback(request, NULL, NULL);
|
||||
_dns_server_request_release(request);
|
||||
}
|
||||
|
||||
@@ -2819,7 +3160,8 @@ 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) != 0) {
|
||||
if (_dns_server_prefetch_request(dns_cache->domain, dns_cache->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);
|
||||
}
|
||||
}
|
||||
@@ -3069,7 +3411,7 @@ static int _dns_create_socket(const char *host_ip, int type)
|
||||
setsockopt(fd, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos));
|
||||
|
||||
if (bind(fd, gai->ai_addr, gai->ai_addrlen) != 0) {
|
||||
tlog(TLOG_ERROR, "bind service failed, %s\n", strerror(errno));
|
||||
tlog(TLOG_ERROR, "bind service %s failed, %s\n", host_ip, strerror(errno));
|
||||
goto errout;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#define _SMART_DNS_SERVER_H
|
||||
|
||||
#include "dns.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cpluscplus
|
||||
extern "C" {
|
||||
@@ -40,7 +41,7 @@ typedef int (*dns_result_callback)(char *domain, dns_rtcode_t rtcode, dns_type_t
|
||||
unsigned int ping_time, void *user_ptr);
|
||||
|
||||
/* query domain */
|
||||
int dns_server_query(char *domain, int qtype, dns_result_callback callback, void *user_ptr);
|
||||
int dns_server_query(char *domain, int qtype, uint32_t server_flags, dns_result_callback callback, void *user_ptr);
|
||||
|
||||
#ifdef __cpluscplus
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "http_parse.h"
|
||||
#include "hash.h"
|
||||
#include "hashtable.h"
|
||||
#include "util.h"
|
||||
#include "jhash.h"
|
||||
#include "list.h"
|
||||
#include <stdlib.h>
|
||||
@@ -214,7 +215,7 @@ static int _http_head_parse_response(struct http_head *http_head, char *key, cha
|
||||
{
|
||||
char *field_start = NULL;
|
||||
char *tmp_ptr = NULL;
|
||||
char *result = NULL;
|
||||
char *ret_msg = NULL;
|
||||
char *ret_code = NULL;
|
||||
|
||||
if (strstr(key, "HTTP/") == NULL) {
|
||||
@@ -226,29 +227,27 @@ static int _http_head_parse_response(struct http_head *http_head, char *key, cha
|
||||
field_start = tmp_ptr;
|
||||
}
|
||||
|
||||
if (*tmp_ptr == ' ') {
|
||||
*tmp_ptr = '\0';
|
||||
if (ret_code == NULL) {
|
||||
ret_code = field_start;
|
||||
} else if (result == NULL) {
|
||||
result = field_start;
|
||||
break;
|
||||
}
|
||||
|
||||
field_start = NULL;
|
||||
if (*tmp_ptr != ' ') {
|
||||
continue;
|
||||
}
|
||||
|
||||
*tmp_ptr = '\0';
|
||||
ret_code = field_start;
|
||||
ret_msg = tmp_ptr + 1;
|
||||
field_start = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (field_start && result == NULL) {
|
||||
result = field_start;
|
||||
if (ret_code == NULL || ret_msg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret_code == NULL || result == NULL) {
|
||||
if (is_numeric(ret_code) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
http_head->code = atol(ret_code);
|
||||
http_head->code_msg = result;
|
||||
http_head->code_msg = ret_msg;
|
||||
http_head->version = key;
|
||||
http_head->head_type = HTTP_HEAD_RESPONSE;
|
||||
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
#ifndef _GENERIC_ATOMIC_H
|
||||
#define _GENERIC_ATOMIC_H
|
||||
|
||||
|
||||
/* Check GCC version, just to be safe */
|
||||
#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC_MINOR__ < 1)
|
||||
# error atomic.h works only with GCC newer than version 4.1
|
||||
#endif /* GNUC >= 4.1 */
|
||||
|
||||
/**
|
||||
* Atomic type.
|
||||
*/
|
||||
|
||||
@@ -339,24 +339,30 @@ static void _sig_error_exit(int signo, siginfo_t *siginfo, void *ct)
|
||||
{
|
||||
unsigned long PC = 0;
|
||||
ucontext_t *context = ct;
|
||||
const char *arch = NULL;
|
||||
#if defined(__i386__)
|
||||
int *pgregs = (int *)(&(context->uc_mcontext.gregs));
|
||||
PC = pgregs[REG_EIP];
|
||||
arch = "i386";
|
||||
#elif defined(__x86_64__)
|
||||
int *pgregs = (int *)(&(context->uc_mcontext.gregs));
|
||||
PC = pgregs[REG_RIP];
|
||||
arch = "x86_64";
|
||||
#elif defined(__arm__)
|
||||
PC = context->uc_mcontext.arm_pc;
|
||||
arch = "arm";
|
||||
#elif defined(__aarch64__)
|
||||
PC = context->uc_mcontext.pc;
|
||||
arch = "arm64";
|
||||
#elif defined(__mips__)
|
||||
PC = context->uc_mcontext.pc;
|
||||
arch = "mips";
|
||||
#endif
|
||||
tlog(TLOG_FATAL,
|
||||
"process exit with signal %d, code = %d, errno = %d, pid = %d, self = %d, pc = %#lx, addr = %#lx, build(%s "
|
||||
"%s)\n",
|
||||
"%s %s)\n",
|
||||
signo, siginfo->si_code, siginfo->si_errno, siginfo->si_pid, getpid(), PC, (unsigned long)siginfo->si_addr,
|
||||
__DATE__, __TIME__);
|
||||
__DATE__, __TIME__, arch);
|
||||
|
||||
sleep(1);
|
||||
_exit(0);
|
||||
@@ -433,6 +439,7 @@ int main(int argc, char *argv[])
|
||||
goto errout;
|
||||
}
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
if (dns_server_load_conf(config_file) != 0) {
|
||||
fprintf(stderr, "load config failed.\n");
|
||||
goto errout;
|
||||
@@ -445,7 +452,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
signal(SIGINT, _sig_exit);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
atexit(_smartdns_exit);
|
||||
|
||||
return _smartdns_run();
|
||||
|
||||
57
src/tlog.c
57
src/tlog.c
@@ -94,7 +94,7 @@ struct tlog {
|
||||
};
|
||||
|
||||
struct tlog_segment_log_head {
|
||||
struct tlog_info info;
|
||||
struct tlog_loginfo info;
|
||||
unsigned short len;
|
||||
char data[0];
|
||||
} __attribute__((packed));
|
||||
@@ -117,7 +117,7 @@ struct count_log {
|
||||
};
|
||||
|
||||
struct tlog_info_inter {
|
||||
struct tlog_info info;
|
||||
struct tlog_loginfo info;
|
||||
void *userptr;
|
||||
};
|
||||
|
||||
@@ -166,6 +166,10 @@ static int _tlog_mkdir(const char *path)
|
||||
if (access(path, F_OK) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(*path == ' ' && *path != '\0') {
|
||||
path++;
|
||||
}
|
||||
|
||||
strncpy(path_c, path, sizeof(path_c) - 1);
|
||||
path_c[sizeof(path_c) - 1] = '\0';
|
||||
@@ -181,6 +185,11 @@ static int _tlog_mkdir(const char *path)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (path_end == path_c) {
|
||||
path_end++;
|
||||
continue;
|
||||
}
|
||||
|
||||
str = *path_end;
|
||||
*path_end = '\0';
|
||||
if (access(path_c, F_OK) == 0) {
|
||||
@@ -203,8 +212,8 @@ static int _tlog_mkdir(const char *path)
|
||||
|
||||
static struct tm *_tlog_localtime(time_t *timep, struct tm *tm)
|
||||
{
|
||||
static time_t last_time = {0};
|
||||
static struct tm last_tm = {0};
|
||||
static time_t last_time;
|
||||
static struct tm last_tm;
|
||||
|
||||
/* localtime_r has a global timezone lock, it's about 8 times slower than gmtime
|
||||
* this code is used to speed up localtime_r call.
|
||||
@@ -297,11 +306,14 @@ void *tlog_get_private(tlog_log *log)
|
||||
return log->private_data;
|
||||
}
|
||||
|
||||
static int _tlog_format(char *buff, int maxlen, struct tlog_info *info, void *userptr, const char *format, va_list ap)
|
||||
static int _tlog_format(char *buff, int maxlen, struct tlog_loginfo *info, void *userptr, const char *format, va_list ap)
|
||||
{
|
||||
int len = 0;
|
||||
int total_len = 0;
|
||||
struct tlog_time *tm = &info->time;
|
||||
void* unused __attribute__ ((unused));
|
||||
|
||||
unused = userptr;
|
||||
|
||||
if (tlog.root->multi_log) {
|
||||
/* format prefix */
|
||||
@@ -388,6 +400,9 @@ static int _tlog_print_buffer(char *buff, int maxlen, void *userptr, const char
|
||||
{
|
||||
int len;
|
||||
int total_len = 0;
|
||||
void* unused __attribute__ ((unused));
|
||||
|
||||
unused = userptr;
|
||||
|
||||
/* format log message */
|
||||
len = vsnprintf(buff, maxlen, format, ap);
|
||||
@@ -550,8 +565,9 @@ int tlog_printf(struct tlog_log *log, const char *format, ...)
|
||||
static int _tlog_early_print(const char *format, va_list ap)
|
||||
{
|
||||
char log_buf[TLOG_MAX_LINE_LEN];
|
||||
int len = 0;
|
||||
int out_len = 0;
|
||||
size_t len = 0;
|
||||
size_t out_len = 0;
|
||||
int unused __attribute__ ((unused));
|
||||
|
||||
if (tlog_disable_early_print) {
|
||||
return 0;
|
||||
@@ -565,9 +581,9 @@ static int _tlog_early_print(const char *format, va_list ap)
|
||||
out_len = sizeof(log_buf);
|
||||
}
|
||||
|
||||
write(STDOUT_FILENO, log_buf, out_len);
|
||||
unused = write(STDOUT_FILENO, log_buf, out_len);
|
||||
if (log_buf[out_len - 1] != '\n') {
|
||||
write(STDOUT_FILENO, "\n", 1);
|
||||
unused = write(STDOUT_FILENO, "\n", 1);
|
||||
}
|
||||
|
||||
return len;
|
||||
@@ -650,6 +666,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;
|
||||
|
||||
dir = opendir(path);
|
||||
if (dir == NULL) {
|
||||
@@ -682,6 +699,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;
|
||||
|
||||
if (strstr(entry->d_name, log->suffix) == NULL) {
|
||||
return 0;
|
||||
@@ -1005,9 +1023,10 @@ static int _tlog_archive_log(struct tlog_log *log)
|
||||
}
|
||||
}
|
||||
|
||||
static int _tlog_write(struct tlog_log *log, char *buff, int bufflen)
|
||||
static int _tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
{
|
||||
int len;
|
||||
int unused __attribute__ ((unused));
|
||||
|
||||
if (bufflen <= 0) {
|
||||
return 0;
|
||||
@@ -1015,7 +1034,7 @@ static int _tlog_write(struct tlog_log *log, char *buff, int bufflen)
|
||||
|
||||
/* output log to screen */
|
||||
if (log->logscreen) {
|
||||
write(STDOUT_FILENO, buff, bufflen);
|
||||
unused = write(STDOUT_FILENO, buff, bufflen);
|
||||
}
|
||||
|
||||
/* if log file size exceeds threshold, start to compress */
|
||||
@@ -1027,7 +1046,7 @@ static int _tlog_write(struct tlog_log *log, char *buff, int bufflen)
|
||||
if (log->filesize < lseek(log->fd, 0, SEEK_END) && log->multi_log == 0) {
|
||||
const char *msg = "[Auto enable multi-process write mode, log may be lost, please enable multi-process write mode manually]\n";
|
||||
log->multi_log = 1;
|
||||
write(log->fd, msg, strlen(msg));
|
||||
unused = write(log->fd, msg, strlen(msg));
|
||||
}
|
||||
close(log->fd);
|
||||
log->fd = -1;
|
||||
@@ -1083,7 +1102,7 @@ static int _tlog_write(struct tlog_log *log, char *buff, int bufflen)
|
||||
return len;
|
||||
}
|
||||
|
||||
int tlog_write(struct tlog_log *log, char *buff, int bufflen)
|
||||
int tlog_write(struct tlog_log *log, const char *buff, int bufflen)
|
||||
{
|
||||
return _tlog_write(log, buff, bufflen);
|
||||
}
|
||||
@@ -1297,7 +1316,7 @@ static void _tlog_work_write(struct tlog_log *log, int log_len, int log_extlen,
|
||||
}
|
||||
}
|
||||
|
||||
static int _tlog_root_write_log(struct tlog_log *log, char *buff, int bufflen)
|
||||
static int _tlog_root_write_log(struct tlog_log *log, const char *buff, int bufflen)
|
||||
{
|
||||
struct tlog_segment_log_head *head = NULL;
|
||||
static struct tlog_segment_log_head empty_info;
|
||||
@@ -1326,7 +1345,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));
|
||||
|
||||
unused = arg;
|
||||
|
||||
while (1) {
|
||||
log_len = 0;
|
||||
log_extlen = 0;
|
||||
@@ -1355,7 +1377,7 @@ static void *_tlog_work(void *arg)
|
||||
log = _tlog_wait_log_locked(log);
|
||||
if (log == NULL) {
|
||||
pthread_mutex_unlock(&tlog.lock);
|
||||
if (errno != ETIMEDOUT) {
|
||||
if (errno != ETIMEDOUT && tlog.run) {
|
||||
sleep(1);
|
||||
}
|
||||
continue;
|
||||
@@ -1491,6 +1513,11 @@ int tlog_setlevel(tlog_level level)
|
||||
return 0;
|
||||
}
|
||||
|
||||
tlog_level tlog_getlevel(void)
|
||||
{
|
||||
return tlog_set_level;
|
||||
}
|
||||
|
||||
tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag)
|
||||
{
|
||||
struct tlog_log *log = NULL;
|
||||
|
||||
83
src/tlog.h
83
src/tlog.h
@@ -9,6 +9,11 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
extern "C" {
|
||||
#endif /*__cplusplus */
|
||||
|
||||
@@ -55,7 +60,7 @@ struct tlog_time {
|
||||
/* enable log to screen */
|
||||
#define TLOG_SCREEN (1 << 4)
|
||||
|
||||
struct tlog_info {
|
||||
struct tlog_loginfo {
|
||||
tlog_level level;
|
||||
const char *file;
|
||||
const char *func;
|
||||
@@ -83,6 +88,9 @@ extern int tlog_write_log(char *buff, int bufflen);
|
||||
/* set log level */
|
||||
extern int tlog_setlevel(tlog_level level);
|
||||
|
||||
/* get log level */
|
||||
extern tlog_level tlog_getlevel(void);
|
||||
|
||||
/* enalbe log to screen */
|
||||
extern void tlog_setlogscreen(int enable);
|
||||
|
||||
@@ -113,13 +121,13 @@ steps:
|
||||
|
||||
read _tlog_format for example.
|
||||
*/
|
||||
typedef int (*tlog_format_func)(char *buff, int maxlen, struct tlog_info *info, void *userptr, const char *format, va_list ap);
|
||||
typedef int (*tlog_format_func)(char *buff, int maxlen, struct tlog_loginfo *info, void *userptr, const char *format, va_list ap);
|
||||
extern int tlog_reg_format_func(tlog_format_func func);
|
||||
|
||||
/* register log output callback
|
||||
Note: info is invalid when flag TLOG_SEGMENT is not set.
|
||||
*/
|
||||
typedef int (*tlog_log_output_func)(struct tlog_info *info, char *buff, int bufflen, void *private_data);
|
||||
typedef int (*tlog_log_output_func)(struct tlog_loginfo *info, const char *buff, int bufflen, void *private_data);
|
||||
extern int tlog_reg_log_output_func(tlog_log_output_func output, void *private_data);
|
||||
|
||||
struct tlog_log;
|
||||
@@ -132,11 +140,11 @@ maxlogcount: Number of archived logs.
|
||||
buffsize: Buffer size, zero for default (128K)
|
||||
flag: read tlog flags
|
||||
return: log stream handler.
|
||||
*/
|
||||
*/
|
||||
extern tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag);
|
||||
|
||||
/* write buff to log file */
|
||||
extern int tlog_write(struct tlog_log *log, char *buff, int bufflen);
|
||||
extern int tlog_write(struct tlog_log *log, const char *buff, int bufflen);
|
||||
|
||||
/* close log stream */
|
||||
extern void tlog_close(tlog_log *log);
|
||||
@@ -160,7 +168,7 @@ extern int tlog_vprintf(tlog_log *log, const char *format, va_list ap);
|
||||
extern void tlog_logscreen(tlog_log *log, int enable);
|
||||
|
||||
/* register output callback */
|
||||
typedef int (*tlog_output_func)(struct tlog_log *log, char *buff, int bufflen);
|
||||
typedef int (*tlog_output_func)(struct tlog_log *log, const char *buff, int bufflen);
|
||||
extern int tlog_reg_output_func(tlog_log *log, tlog_output_func output);
|
||||
|
||||
/* set private data */
|
||||
@@ -173,6 +181,65 @@ extern void *tlog_get_private(tlog_log *log);
|
||||
extern int tlog_localtime(struct tlog_time *tm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__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;
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Buffer Out(tlog_log *log) {
|
||||
return Buffer(new Stream, [=](Stream *st) {
|
||||
tlog_printf(log, "%s", st->str().c_str());
|
||||
delete st;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
#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_debug Tlog_stream(TLOG_DEBUG)
|
||||
#define tlog_info Tlog_stream(TLOG_INFO)
|
||||
#define tlog_notice Tlog_stream(TLOG_NOTICE)
|
||||
#define tlog_warn Tlog_stream(TLOG_WARN)
|
||||
#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))
|
||||
|
||||
} /*__cplusplus */
|
||||
#else
|
||||
#define tlog_debug(...) tlog(TLOG_DEBUG, ##__VA_ARGS__)
|
||||
#define tlog_info(...) tlog(TLOG_INFO, ##__VA_ARGS__)
|
||||
#define tlog_notice(...) tlog(TLOG_NOTICE, ##__VA_ARGS__)
|
||||
#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 // !TLOG_H
|
||||
|
||||
10
src/util.c
10
src/util.c
@@ -947,6 +947,16 @@ void get_compiled_time(struct tm *tm)
|
||||
tm->tm_sec = sec;
|
||||
}
|
||||
|
||||
int is_numeric(const char *str)
|
||||
{
|
||||
while (*str != '\0') {
|
||||
if (*str < '0' || *str > '9')
|
||||
return -1;
|
||||
str++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int has_network_raw_cap(void)
|
||||
{
|
||||
int fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
|
||||
|
||||
@@ -98,6 +98,8 @@ int parse_tls_header(const char *data, size_t data_len, char *hostname, const ch
|
||||
|
||||
void get_compiled_time(struct tm *tm);
|
||||
|
||||
int is_numeric(const char *str);
|
||||
|
||||
int has_network_raw_cap(void);
|
||||
|
||||
int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt);
|
||||
|
||||
Reference in New Issue
Block a user