Compare commits

...

10 Commits

Author SHA1 Message Date
Nick Peng
a9829f6155 dns-server: fix race condition issue 2020-08-09 23:54:23 +08:00
Nick Peng
1923271630 compile: fix comile warnings 2020-08-09 18:01:33 +08:00
Nick Peng
c23ec7ea8f client: suppress log. 2020-08-03 01:07:47 +08:00
rhettor
aad751c1f5 Support docker 2020-08-02 18:10:31 +08:00
Nick Peng
138df2fd5d luci: fix no-check-certificate config not working issue 2020-08-02 17:43:38 +08:00
Nick Peng
297ea29639 Client: Fix ssl crash issue. 2020-08-02 01:00:46 +08:00
Nick Peng
bc0d6b89ca tlog: update tlog 2020-07-30 00:03:20 +08:00
Nick Peng
2148efd262 client: retry upstream when network restart 2020-07-12 11:12:55 +08:00
Nick Peng
ce46ac58a7 dns_client: check ssl before set certificate 2020-05-10 22:04:48 +08:00
Nick Peng
c1f9941427 dualstack: update cache when ipv6 not exists 2020-05-04 02:24:55 +08:00
14 changed files with 354 additions and 160 deletions

18
Dockerfile Normal file
View 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"]

View File

@@ -156,7 +156,7 @@ load_server()
config_get type "$section" "type" "udp" config_get type "$section" "type" "udp"
config_get ip "$section" "ip" "" config_get ip "$section" "ip" ""
config_get tls_host_verify "$section" "tls_host_verify" "" 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 host_name "$section" "host_name" ""
config_get http_host "$section" "http_host" "" config_get http_host "$section" "http_host" ""
config_get server_group "$section" "server_group" "" config_get server_group "$section" "server_group" ""
@@ -187,7 +187,7 @@ load_server()
fi fi
[ -z "$tls_host_verify" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -tls-host-verify $tls_host_verify" [ -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 "$host_name" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -host-name $host_name"
[ -z "$http_host" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -http-host $http_host" [ -z "$http_host" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -http-host $http_host"
[ -z "$server_group" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -group $server_group" [ -z "$server_group" ] || ADDITIONAL_ARGS="$ADDITIONAL_ARGS -group $server_group"

View File

@@ -110,7 +110,7 @@ struct dns_head {
unsigned short ancount; /* number of answer entries */ unsigned short ancount; /* number of answer entries */
unsigned short nscount; /* number of authority entries */ unsigned short nscount; /* number of authority entries */
unsigned short nrcount; /* number of addititional resource entries */ unsigned short nrcount; /* number of addititional resource entries */
} __attribute__((packed)); } __attribute__((packed, aligned(2)));
struct dns_rrs { struct dns_rrs {
unsigned short next; unsigned short next;

View File

@@ -130,7 +130,7 @@ int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_typ
/* lookup existing cache */ /* lookup existing cache */
dns_cache = dns_cache_lookup(domain, qtype); dns_cache = dns_cache_lookup(domain, qtype);
if (dns_cache == NULL) { if (dns_cache == NULL) {
return 0; return dns_cache_insert(domain, cname, cname_ttl, ttl, qtype, addr, addr_len, speed);
} }
if (ttl < DNS_CACHE_TTL_MIN) { if (ttl < DNS_CACHE_TTL_MIN) {

View File

@@ -853,15 +853,19 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
#else #else
server_info->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); server_info->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
#endif #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) { if (server_info->ssl_ctx == NULL) {
tlog(TLOG_ERROR, "init ssl failed."); tlog(TLOG_ERROR, "init ssl failed.");
goto errout; 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);
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 */ /* safe address info */
@@ -901,13 +905,14 @@ static int _dns_client_server_add(char *server_ip, char *server_host, int port,
return 0; return 0;
errout: errout:
if (server_info) { if (server_info) {
if (server_info->ping_host) {
fast_ping_stop(server_info->ping_host);
}
if (server_info->ssl_ctx) { if (server_info->ssl_ctx) {
SSL_CTX_free(server_info->ssl_ctx); SSL_CTX_free(server_info->ssl_ctx);
server_info->ssl_ctx = NULL; server_info->ssl_ctx = NULL;
} }
if (server_info->ping_host) {
fast_ping_stop(server_info->ping_host);
}
free(server_info); free(server_info);
} }
@@ -927,6 +932,7 @@ static void _dns_client_close_socket(struct dns_server_info *server_info)
if (server_info->ssl) { if (server_info->ssl) {
/* Shutdown ssl */ /* Shutdown ssl */
SSL_shutdown(server_info->ssl);
SSL_free(server_info->ssl); SSL_free(server_info->ssl);
server_info->ssl = NULL; server_info->ssl = NULL;
} }
@@ -1507,8 +1513,13 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
set_sock_keepalive(fd, 15, 3, 4); set_sock_keepalive(fd, 15, 3, 4);
if (connect(fd, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen) != 0) { 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) { if (errno != EINPROGRESS) {
tlog(TLOG_ERROR, "connect failed."); tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno));
goto errout; goto errout;
} }
} }
@@ -1517,7 +1528,7 @@ static int _DNS_client_create_socket_tcp(struct dns_server_info *server_info)
event.events = EPOLLIN | EPOLLOUT; event.events = EPOLLIN | EPOLLOUT;
event.data.ptr = server_info; event.data.ptr = server_info;
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) { if (epoll_ctl(client.epoll_fd, EPOLL_CTL_ADD, fd, &event) != 0) {
tlog(TLOG_ERROR, "epoll ctl failed."); tlog(TLOG_ERROR, "epoll ctl failed, %s", strerror(errno));
return -1; return -1;
} }
@@ -1571,20 +1582,26 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
} }
// ? this cause ssl crash ? // ? this cause ssl crash ?
// setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)); 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_DUPACK, &yes, sizeof(yes));
// setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof(yes)); setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof(yes));
// set_sock_keepalive(fd, 15, 3, 4); set_sock_keepalive(fd, 15, 3, 4);
setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)); setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority));
setsockopt(fd, IPPROTO_IP, IP_TOS, &ip_tos, sizeof(ip_tos)); 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 (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) { if (errno != EINPROGRESS) {
tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno)); tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno));
goto errout; goto errout;
} }
} }
SSL_set_connect_state(ssl);
if (SSL_set_fd(ssl, fd) == 0) { if (SSL_set_fd(ssl, fd) == 0) {
tlog(TLOG_ERROR, "ssl set fd failed."); tlog(TLOG_ERROR, "ssl set fd failed.");
goto errout; goto errout;
@@ -1595,7 +1612,7 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info, ch
SSL_set_session(ssl, server_info->ssl_session); 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) { if (hostname[0] != 0) {
SSL_set_tlsext_host_name(ssl, hostname); SSL_set_tlsext_host_name(ssl, hostname);
} }
@@ -1721,20 +1738,18 @@ static int _dns_client_socket_ssl_send(SSL *ssl, const void *buf, int num)
unsigned long ssl_err = 0; unsigned long ssl_err = 0;
if (ssl == NULL) { if (ssl == NULL) {
errno = EINVAL;
return -1; return -1;
} }
ret = SSL_write(ssl, buf, num); ret = SSL_write(ssl, buf, num);
if (ret >= 0) { if (ret > 0) {
return ret; return ret;
} }
ssl_ret = SSL_get_error(ssl, ret); ssl_ret = SSL_get_error(ssl, ret);
switch (ssl_ret) { switch (ssl_ret) {
case SSL_ERROR_NONE: case SSL_ERROR_NONE:
errno = EAGAIN;
return -1;
break;
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
return 0; return 0;
break; break;
@@ -1748,12 +1763,14 @@ static int _dns_client_socket_ssl_send(SSL *ssl, const void *buf, int num)
break; break;
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
ssl_err = ERR_get_error(); 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) {
errno = EAGAIN; errno = EAGAIN;
return -1; 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; errno = EFAULT;
ret = -1; ret = -1;
break; break;
@@ -1788,9 +1805,6 @@ static int _dns_client_socket_ssl_recv(SSL *ssl, void *buf, int num)
ssl_ret = SSL_get_error(ssl, ret); ssl_ret = SSL_get_error(ssl, ret);
switch (ssl_ret) { switch (ssl_ret) {
case SSL_ERROR_NONE: case SSL_ERROR_NONE:
errno = EAGAIN;
return -1;
break;
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
return 0; return 0;
break; break;
@@ -1804,11 +1818,16 @@ static int _dns_client_socket_ssl_recv(SSL *ssl, void *buf, int num)
break; break;
case SSL_ERROR_SSL: case SSL_ERROR_SSL:
ssl_err = ERR_get_error(); 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; errno = EAGAIN;
return -1; return -1;
} }
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(%ld)\n", ERR_reason_error_string(ssl_err), ssl_err); tlog(TLOG_ERROR, "SSL read fail error no: %s(%ld)\n", ERR_reason_error_string(ssl_err), ssl_err);
errno = EFAULT; errno = EFAULT;
ret = -1; ret = -1;
@@ -2096,11 +2115,30 @@ static int _dns_client_tls_matchName(const char *host, const char *pattern, int
return match; 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) static int _dns_client_tls_verify(struct dns_server_info *server_info)
{ {
X509 *cert = NULL; X509 *cert = NULL;
X509_PUBKEY *pubkey = NULL; X509_PUBKEY *pubkey = NULL;
X509_NAME *cert_name = NULL;
char peer_CN[256]; char peer_CN[256];
char cert_fingerprint[256]; char cert_fingerprint[256];
int i = 0; int i = 0;
@@ -2124,24 +2162,20 @@ static int _dns_client_tls_verify(struct dns_server_info *server_info)
if (server_info->skip_check_cert == 0) { if (server_info->skip_check_cert == 0) {
long res = SSL_get_verify_result(server_info->ssl); long res = SSL_get_verify_result(server_info->ssl);
if (res != X509_V_OK) { 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; goto errout;
} }
} }
cert_name = X509_get_subject_name(cert); if (_dns_client_tls_get_cert_CN(cert, peer_CN, sizeof(peer_CN)) != 0) {
if (cert_name == NULL) { tlog(TLOG_ERROR, "get cert CN failed.");
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");
goto errout; goto errout;
} }
tlog(TLOG_DEBUG, "peer CN: %s", peer_CN); tlog(TLOG_DEBUG, "peer CN: %s", peer_CN);
/* check tls host */ /* check tls host */
tls_host_verify = _dns_client_server_get_tls_host_verify(server_info); tls_host_verify = _dns_client_server_get_tls_host_verify(server_info);
if (tls_host_verify) { if (tls_host_verify) {
@@ -2234,7 +2268,7 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
if (server_info->status == DNS_SERVER_STATUS_CONNECTING) { if (server_info->status == DNS_SERVER_STATUS_CONNECTING) {
/* do SSL hand shake */ /* do SSL hand shake */
ret = SSL_connect(server_info->ssl); ret = SSL_do_handshake(server_info->ssl);
if (ret == 0) { if (ret == 0) {
goto errout; goto errout;
} else if (ret < 0) { } else if (ret < 0) {
@@ -2243,8 +2277,17 @@ static int _dns_client_process_tls(struct dns_server_info *server_info, struct e
if (ssl_ret == SSL_ERROR_WANT_READ) { if (ssl_ret == SSL_ERROR_WANT_READ) {
fd_event.events = EPOLLIN; fd_event.events = EPOLLIN;
} else if (ssl_ret == SSL_ERROR_WANT_WRITE) { } 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 { } 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; goto errout;
} }
@@ -2351,7 +2394,7 @@ static int _dns_client_send_data_to_buffer(struct dns_server_info *server_info,
event.events = EPOLLIN | EPOLLOUT; event.events = EPOLLIN | EPOLLOUT;
event.data.ptr = server_info; event.data.ptr = server_info;
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_MOD, server_info->fd, &event) != 0) { 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; return -1;
} }
@@ -2424,11 +2467,12 @@ static int _dns_client_send_tls(struct dns_server_info *server_info, void *packe
} }
if (server_info->ssl == NULL) { if (server_info->ssl == NULL) {
errno = EINVAL;
return -1; return -1;
} }
send_len = _dns_client_socket_ssl_send(server_info->ssl, inpacket, len); 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) { if (errno == EAGAIN || errno == EPIPE || server_info->ssl == NULL) {
/* save data to buffer, and retry when EPOLLOUT is available */ /* save data to buffer, and retry when EPOLLOUT is available */
return _dns_client_send_data_to_buffer(server_info, inpacket, len); return _dns_client_send_data_to_buffer(server_info, inpacket, len);
@@ -2474,11 +2518,12 @@ static int _dns_client_send_https(struct dns_server_info *server_info, void *pac
} }
if (server_info->ssl == NULL) { if (server_info->ssl == NULL) {
errno = EINVAL;
return -1; return -1;
} }
send_len = _dns_client_socket_ssl_send(server_info->ssl, inpacket, http_len); 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) { if (errno == EAGAIN || errno == EPIPE || server_info->ssl == NULL) {
/* save data to buffer, and retry when EPOLLOUT is available */ /* save data to buffer, and retry when EPOLLOUT is available */
return _dns_client_send_data_to_buffer(server_info, inpacket, http_len); return _dns_client_send_data_to_buffer(server_info, inpacket, http_len);
@@ -2501,63 +2546,88 @@ static int _dns_client_send_packet(struct dns_query_struct *query, void *packet,
struct dns_server_group_member *tmp = NULL; struct dns_server_group_member *tmp = NULL;
int ret = 0; int ret = 0;
int send_err = 0; int send_err = 0;
int i = 0;
query->send_tick = get_tick_count(); query->send_tick = get_tick_count();
/* send query to all dns servers */ /* send query to all dns servers */
pthread_mutex_lock(&client.server_list_lock); for (i = 0; i < 2; i++) {
list_for_each_entry_safe(group_member, tmp, &query->server_group->head, list) 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) { server_info = group_member->server;
ret = _dns_client_create_socket(server_info); 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;
}
if (ret != 0) { 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);
} else 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) {
server_info->recv_buff.len = 0;
server_info->send_buff.len = 0;
tlog(TLOG_DEBUG, "server %s not response, retry.", server_info->ip);
_dns_client_close_socket(server_info);
}
}
atomic_dec(&query->dns_request_sent);
continue; continue;
} }
time(&server_info->last_send);
} }
pthread_mutex_unlock(&client.server_list_lock);
atomic_inc(&query->dns_request_sent); if (atomic_read(&query->dns_request_sent) > 0) {
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; break;
} }
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);
}
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) {
tlog(TLOG_ERROR, "Send query to upstream server failed.");
return -1;
}
return 0; return 0;
} }

View File

@@ -262,6 +262,7 @@ static int _config_server(int argc, char *argv[], dns_server_type_t type, int de
return -1; return -1;
} }
ip = argv[1];
if (index >= DNS_MAX_SERVERS) { if (index >= DNS_MAX_SERVERS) {
tlog(TLOG_WARN, "exceeds max server number, %s", ip); tlog(TLOG_WARN, "exceeds max server number, %s", ip);
return 0; 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->httphost[0] = '\0';
server->tls_host_verify[0] = '\0'; server->tls_host_verify[0] = '\0';
ip = argv[1];
if (type == DNS_SERVER_HTTPS) { if (type == DNS_SERVER_HTTPS) {
if (parse_uri(ip, NULL, server->server, &port, server->path) != 0) { if (parse_uri(ip, NULL, server->server, &port, server->path) != 0) {
return -1; return -1;
@@ -871,6 +870,7 @@ static int _config_bind_ip(int argc, char *argv[], DNS_BIND_TYPE type)
goto errout; goto errout;
} }
ip = argv[1];
if (index >= DNS_MAX_SERVERS) { if (index >= DNS_MAX_SERVERS) {
tlog(TLOG_WARN, "exceeds max server number, %s", ip); tlog(TLOG_WARN, "exceeds max server number, %s", ip);
return 0; 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 = &dns_conf_bind_ip[index];
bind_ip->type = type; bind_ip->type = type;
bind_ip->flags = 0; bind_ip->flags = 0;
ip = argv[1];
safe_strncpy(bind_ip->ip, ip, DNS_MAX_IPLEN); safe_strncpy(bind_ip->ip, ip, DNS_MAX_IPLEN);
/* process extra options */ /* process extra options */

View File

@@ -880,6 +880,7 @@ static void _dns_server_select_possible_ipaddress(struct dns_request *request)
/* Return the most likely correct IP address */ /* 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. */ /* 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) hash_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
{ {
if (addr_map->addr_type != request->qtype) { if (addr_map->addr_type != request->qtype) {
@@ -896,6 +897,7 @@ static void _dns_server_select_possible_ipaddress(struct dns_request *request)
maxhit_addr_map = addr_map; maxhit_addr_map = addr_map;
} }
} }
pthread_mutex_unlock(&request->ip_map_lock);
if (maxhit_addr_map && maxhit > 1) { if (maxhit_addr_map && maxhit > 1) {
selected_addr_map = maxhit_addr_map; selected_addr_map = maxhit_addr_map;
@@ -966,11 +968,13 @@ static void _dns_server_request_release_complete(struct dns_request *request, in
_dns_server_request_complete(request); _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_for_each_safe(request->ip_map, bucket, tmp, addr_map, node)
{ {
hash_del(&addr_map->node); hash_del(&addr_map->node);
free(addr_map); free(addr_map);
} }
pthread_mutex_unlock(&request->ip_map_lock);
_dns_server_delete_request(request); _dns_server_delete_request(request);
} }
@@ -2009,7 +2013,7 @@ errout:
return -1; 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; struct dns_domain_check_order *check_order = NULL;
@@ -2026,9 +2030,10 @@ static int _dns_server_process_cache(struct dns_request *request)
{ {
struct dns_cache *dns_cache = NULL; struct dns_cache *dns_cache = NULL;
struct dns_cache *dns_cache_A = NULL; struct dns_cache *dns_cache_A = NULL;
int ret = -1;
if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) == 0) { if (_dns_server_has_bind_flag(request, BIND_FLAG_NO_CACHE) == 0) {
goto errout; goto out;
} }
dns_cache = dns_cache_lookup(request->domain, request->qtype); dns_cache = dns_cache_lookup(request->domain, request->qtype);
@@ -2037,16 +2042,18 @@ static int _dns_server_process_cache(struct dns_request *request)
dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A); dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A);
if (dns_cache_A) { if (dns_cache_A) {
tlog(TLOG_DEBUG, "No IPV6 Found, Force IPV4 perfered."); tlog(TLOG_DEBUG, "No IPV6 Found, Force IPV4 perfered.");
dns_cache_release(dns_cache_A); if (dns_cache_get_ttl(dns_cache_A) == 0) {
dns_cache_release(dns_cache); _dns_server_prefetch_request(request->domain, request->qtype);
return _dns_server_reply_SOA(DNS_RC_NOERROR, request); }
ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request);
goto out;
} }
} }
goto errout; goto out;
} }
if (request->qtype != dns_cache->qtype) { if (request->qtype != dns_cache->qtype) {
goto errout; goto out;
} }
if (request->dualstack_selection && request->qtype == DNS_T_AAAA) { if (request->dualstack_selection && request->qtype == DNS_T_AAAA) {
@@ -2055,9 +2062,8 @@ static int _dns_server_process_cache(struct dns_request *request)
if ((dns_cache_A->speed + (dns_conf_dualstack_ip_selection_threshold * 10)) < dns_cache->speed || if ((dns_cache_A->speed + (dns_conf_dualstack_ip_selection_threshold * 10)) < dns_cache->speed ||
dns_cache->speed < 0) { dns_cache->speed < 0) {
tlog(TLOG_DEBUG, "Force IPV4 perfered."); tlog(TLOG_DEBUG, "Force IPV4 perfered.");
dns_cache_release(dns_cache_A); ret = _dns_server_reply_SOA(DNS_RC_NOERROR, request);
dns_cache_release(dns_cache); goto out_update_cache;
return _dns_server_reply_SOA(DNS_RC_NOERROR, request);
} }
} }
} }
@@ -2075,7 +2081,7 @@ static int _dns_server_process_cache(struct dns_request *request)
request->has_ipv6 = 1; request->has_ipv6 = 1;
break; break;
default: default:
goto errout; goto out;
break; break;
} }
@@ -2093,28 +2099,26 @@ static int _dns_server_process_cache(struct dns_request *request)
_dns_reply(request); _dns_reply(request);
} }
ret = 0;
out_update_cache:
if (dns_cache_get_ttl(dns_cache) == 0) { if (dns_cache_get_ttl(dns_cache) == 0) {
_dns_server_prefetch_request(request->domain, request->qtype); _dns_server_prefetch_request(request->domain, request->qtype);
} else { } else {
dns_cache_update(dns_cache); dns_cache_update(dns_cache);
} }
dns_cache_release(dns_cache);
if (dns_cache_A) { out:
dns_cache_release(dns_cache_A);
dns_cache_A = NULL;
}
return 0;
errout:
if (dns_cache) { if (dns_cache) {
dns_cache_release(dns_cache); dns_cache_release(dns_cache);
} }
if (dns_cache_A) { if (dns_cache_A) {
dns_cache_release(dns_cache_A); dns_cache_release(dns_cache_A);
dns_cache_A = NULL; 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) static void _dns_server_request_set_client(struct dns_request *request, struct dns_server_conn_head *conn)
@@ -2257,7 +2261,7 @@ static int _dns_server_do_query(struct dns_request *request, const char *domain,
} }
/* process speed check rule */ /* process speed check rule */
_dns_server_prolcess_speed_check_rule(request); _dns_server_process_speed_check_rule(request);
/* check and set passthrough */ /* check and set passthrough */
_dns_server_check_set_passthrough(request); _dns_server_check_set_passthrough(request);

View File

@@ -19,6 +19,7 @@
#include "http_parse.h" #include "http_parse.h"
#include "hash.h" #include "hash.h"
#include "hashtable.h" #include "hashtable.h"
#include "util.h"
#include "jhash.h" #include "jhash.h"
#include "list.h" #include "list.h"
#include <stdlib.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 *field_start = NULL;
char *tmp_ptr = NULL; char *tmp_ptr = NULL;
char *result = NULL; char *ret_msg = NULL;
char *ret_code = NULL; char *ret_code = NULL;
if (strstr(key, "HTTP/") == 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; field_start = tmp_ptr;
} }
if (*tmp_ptr == ' ') { if (*tmp_ptr != ' ') {
*tmp_ptr = '\0'; continue;
if (ret_code == NULL) {
ret_code = field_start;
} else if (result == NULL) {
result = field_start;
break;
}
field_start = NULL;
} }
*tmp_ptr = '\0';
ret_code = field_start;
ret_msg = tmp_ptr + 1;
field_start = NULL;
break;
} }
if (field_start && result == NULL) { if (ret_code == NULL || ret_msg == NULL) {
result = field_start; return -1;
} }
if (ret_code == NULL || result == NULL) { if (is_numeric(ret_code) != 0) {
return -1; return -1;
} }
http_head->code = atol(ret_code); http_head->code = atol(ret_code);
http_head->code_msg = result; http_head->code_msg = ret_msg;
http_head->version = key; http_head->version = key;
http_head->head_type = HTTP_HEAD_RESPONSE; http_head->head_type = HTTP_HEAD_RESPONSE;

View File

@@ -20,12 +20,6 @@
#ifndef _GENERIC_ATOMIC_H #ifndef _GENERIC_ATOMIC_H
#define _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. * Atomic type.
*/ */

View File

@@ -339,24 +339,30 @@ static void _sig_error_exit(int signo, siginfo_t *siginfo, void *ct)
{ {
unsigned long PC = 0; unsigned long PC = 0;
ucontext_t *context = ct; ucontext_t *context = ct;
const char *arch = NULL;
#if defined(__i386__) #if defined(__i386__)
int *pgregs = (int *)(&(context->uc_mcontext.gregs)); int *pgregs = (int *)(&(context->uc_mcontext.gregs));
PC = pgregs[REG_EIP]; PC = pgregs[REG_EIP];
arch = "i386";
#elif defined(__x86_64__) #elif defined(__x86_64__)
int *pgregs = (int *)(&(context->uc_mcontext.gregs)); int *pgregs = (int *)(&(context->uc_mcontext.gregs));
PC = pgregs[REG_RIP]; PC = pgregs[REG_RIP];
arch = "x86_64";
#elif defined(__arm__) #elif defined(__arm__)
PC = context->uc_mcontext.arm_pc; PC = context->uc_mcontext.arm_pc;
arch = "arm";
#elif defined(__aarch64__) #elif defined(__aarch64__)
PC = context->uc_mcontext.pc; PC = context->uc_mcontext.pc;
arch = "arm64";
#elif defined(__mips__) #elif defined(__mips__)
PC = context->uc_mcontext.pc; PC = context->uc_mcontext.pc;
arch = "mips";
#endif #endif
tlog(TLOG_FATAL, tlog(TLOG_FATAL,
"process exit with signal %d, code = %d, errno = %d, pid = %d, self = %d, pc = %#lx, addr = %#lx, build(%s " "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, signo, siginfo->si_code, siginfo->si_errno, siginfo->si_pid, getpid(), PC, (unsigned long)siginfo->si_addr,
__DATE__, __TIME__); __DATE__, __TIME__, arch);
sleep(1); sleep(1);
_exit(0); _exit(0);

View File

@@ -1,6 +1,6 @@
/* /*
* tinylog * tinylog
* Copyright (C) 2018-2020 Nick Peng <pymumu@gmail.com> * Copyright (C) 2018-2019 Nick Peng <pymumu@gmail.com>
* https://github.com/pymumu/tinylog * https://github.com/pymumu/tinylog
*/ */
#ifndef _GNU_SOURCE #ifndef _GNU_SOURCE
@@ -94,7 +94,7 @@ struct tlog {
}; };
struct tlog_segment_log_head { struct tlog_segment_log_head {
struct tlog_info info; struct tlog_loginfo info;
unsigned short len; unsigned short len;
char data[0]; char data[0];
} __attribute__((packed)); } __attribute__((packed));
@@ -117,7 +117,7 @@ struct count_log {
}; };
struct tlog_info_inter { struct tlog_info_inter {
struct tlog_info info; struct tlog_loginfo info;
void *userptr; void *userptr;
}; };
@@ -166,6 +166,10 @@ static int _tlog_mkdir(const char *path)
if (access(path, F_OK) == 0) { if (access(path, F_OK) == 0) {
return 0; return 0;
} }
while(*path == ' ' && *path != '\0') {
path++;
}
strncpy(path_c, path, sizeof(path_c) - 1); strncpy(path_c, path, sizeof(path_c) - 1);
path_c[sizeof(path_c) - 1] = '\0'; path_c[sizeof(path_c) - 1] = '\0';
@@ -181,6 +185,11 @@ static int _tlog_mkdir(const char *path)
continue; continue;
} }
if (path_end == path_c) {
path_end++;
continue;
}
str = *path_end; str = *path_end;
*path_end = '\0'; *path_end = '\0';
if (access(path_c, F_OK) == 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 struct tm *_tlog_localtime(time_t *timep, struct tm *tm)
{ {
static time_t last_time = {0}; static time_t last_time;
static struct tm last_tm = {0}; static struct tm last_tm;
/* localtime_r has a global timezone lock, it's about 8 times slower than gmtime /* 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. * 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; 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 len = 0;
int total_len = 0; int total_len = 0;
struct tlog_time *tm = &info->time; struct tlog_time *tm = &info->time;
void* unused __attribute__ ((unused));
unused = userptr;
if (tlog.root->multi_log) { if (tlog.root->multi_log) {
/* format prefix */ /* format prefix */
@@ -388,6 +400,9 @@ static int _tlog_print_buffer(char *buff, int maxlen, void *userptr, const char
{ {
int len; int len;
int total_len = 0; int total_len = 0;
void* unused __attribute__ ((unused));
unused = userptr;
/* format log message */ /* format log message */
len = vsnprintf(buff, maxlen, format, ap); 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) static int _tlog_early_print(const char *format, va_list ap)
{ {
char log_buf[TLOG_MAX_LINE_LEN]; char log_buf[TLOG_MAX_LINE_LEN];
int len = 0; size_t len = 0;
int out_len = 0; size_t out_len = 0;
int unused __attribute__ ((unused));
if (tlog_disable_early_print) { if (tlog_disable_early_print) {
return 0; return 0;
@@ -565,9 +581,9 @@ static int _tlog_early_print(const char *format, va_list ap)
out_len = sizeof(log_buf); 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') { if (log_buf[out_len - 1] != '\n') {
write(STDOUT_FILENO, "\n", 1); unused = write(STDOUT_FILENO, "\n", 1);
} }
return len; return len;
@@ -650,6 +666,7 @@ static int _tlog_list_dir(const char *path, list_callback callback, void *userpt
DIR *dir = NULL; DIR *dir = NULL;
struct dirent *ent; struct dirent *ent;
int ret = 0; int ret = 0;
const char* unused __attribute__ ((unused)) = path;
dir = opendir(path); dir = opendir(path);
if (dir == NULL) { 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 count_log *count_log = (struct count_log *)userptr;
struct tlog_log *log = count_log->log; struct tlog_log *log = count_log->log;
char logname[TLOG_LOG_NAME_LEN * 2]; char logname[TLOG_LOG_NAME_LEN * 2];
const char* unused __attribute__ ((unused)) = path;
if (strstr(entry->d_name, log->suffix) == NULL) { if (strstr(entry->d_name, log->suffix) == NULL) {
return 0; 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 len;
int unused __attribute__ ((unused));
if (bufflen <= 0) { if (bufflen <= 0) {
return 0; return 0;
@@ -1015,7 +1034,7 @@ static int _tlog_write(struct tlog_log *log, char *buff, int bufflen)
/* output log to screen */ /* output log to screen */
if (log->logscreen) { if (log->logscreen) {
write(STDOUT_FILENO, buff, bufflen); unused = write(STDOUT_FILENO, buff, bufflen);
} }
/* if log file size exceeds threshold, start to compress */ /* 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) { 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"; 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; log->multi_log = 1;
write(log->fd, msg, strlen(msg)); unused = write(log->fd, msg, strlen(msg));
} }
close(log->fd); close(log->fd);
log->fd = -1; log->fd = -1;
@@ -1083,7 +1102,7 @@ static int _tlog_write(struct tlog_log *log, char *buff, int bufflen)
return len; 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); 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; struct tlog_segment_log_head *head = NULL;
static struct tlog_segment_log_head empty_info; static struct tlog_segment_log_head empty_info;
@@ -1326,7 +1345,10 @@ static void *_tlog_work(void *arg)
int log_dropped = 0; int log_dropped = 0;
struct tlog_log *log = NULL; struct tlog_log *log = NULL;
struct tlog_log *loop_log = NULL; struct tlog_log *loop_log = NULL;
void* unused __attribute__ ((unused));
unused = arg;
while (1) { while (1) {
log_len = 0; log_len = 0;
log_extlen = 0; log_extlen = 0;
@@ -1491,6 +1513,11 @@ int tlog_setlevel(tlog_level level)
return 0; 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) tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag)
{ {
struct tlog_log *log = NULL; struct tlog_log *log = NULL;

View File

@@ -1,6 +1,6 @@
/* /*
* tinylog * tinylog
* Copyright (C) 2018-2020 Ruilin Peng (Nick) <pymumu@gmail.com> * Copyright (C) 2018-2019 Ruilin Peng (Nick) <pymumu@gmail.com>
* https://github.com/pymumu/tinylog * https://github.com/pymumu/tinylog
*/ */
@@ -9,6 +9,11 @@
#include <stdarg.h> #include <stdarg.h>
#ifdef __cplusplus #ifdef __cplusplus
#include <string>
#include <memory>
#include <sstream>
#include <iostream>
#include <functional>
extern "C" { extern "C" {
#endif /*__cplusplus */ #endif /*__cplusplus */
@@ -55,7 +60,7 @@ struct tlog_time {
/* enable log to screen */ /* enable log to screen */
#define TLOG_SCREEN (1 << 4) #define TLOG_SCREEN (1 << 4)
struct tlog_info { struct tlog_loginfo {
tlog_level level; tlog_level level;
const char *file; const char *file;
const char *func; const char *func;
@@ -83,6 +88,9 @@ extern int tlog_write_log(char *buff, int bufflen);
/* set log level */ /* set log level */
extern int tlog_setlevel(tlog_level level); extern int tlog_setlevel(tlog_level level);
/* get log level */
extern tlog_level tlog_getlevel(void);
/* enalbe log to screen */ /* enalbe log to screen */
extern void tlog_setlogscreen(int enable); extern void tlog_setlogscreen(int enable);
@@ -113,13 +121,13 @@ steps:
read _tlog_format for example. 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); extern int tlog_reg_format_func(tlog_format_func func);
/* register log output callback /* register log output callback
Note: info is invalid when flag TLOG_SEGMENT is not set. 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); extern int tlog_reg_log_output_func(tlog_log_output_func output, void *private_data);
struct tlog_log; struct tlog_log;
@@ -132,11 +140,11 @@ maxlogcount: Number of archived logs.
buffsize: Buffer size, zero for default (128K) buffsize: Buffer size, zero for default (128K)
flag: read tlog flags flag: read tlog flags
return: log stream handler. return: log stream handler.
*/ */
extern tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag); extern tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag);
/* write buff to log file */ /* 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 */ /* close log stream */
extern void tlog_close(tlog_log *log); 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); extern void tlog_logscreen(tlog_log *log, int enable);
/* register output callback */ /* 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); extern int tlog_reg_output_func(tlog_log *log, tlog_output_func output);
/* set private data */ /* set private data */
@@ -173,6 +181,63 @@ extern void *tlog_get_private(tlog_log *log);
extern int tlog_localtime(struct tlog_time *tm); extern int tlog_localtime(struct tlog_time *tm);
#ifdef __cplusplus #ifdef __cplusplus
} class Tlog {
#endif /*__cplusplus */ 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());
});
}
};
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());
});
}
};
#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 #endif // !TLOG_H

View File

@@ -947,6 +947,16 @@ void get_compiled_time(struct tm *tm)
tm->tm_sec = sec; 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 has_network_raw_cap(void)
{ {
int fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); int fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);

View File

@@ -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); void get_compiled_time(struct tm *tm);
int is_numeric(const char *str);
int has_network_raw_cap(void); int has_network_raw_cap(void);
int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt); int set_sock_keepalive(int fd, int keepidle, int keepinterval, int keepcnt);