From 03478debe882a106bd1766ef64b9d2a5ecbe60d8 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Tue, 17 May 2022 20:35:36 +0800 Subject: [PATCH] feature: auto detect ipv6 features. --- src/dns_client.c | 2 +- src/dns_server.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++- src/fast_ping.c | 25 +++++++++------ src/fast_ping.h | 5 +-- 4 files changed, 101 insertions(+), 13 deletions(-) diff --git a/src/dns_client.c b/src/dns_client.c index 912c9ad..8f107d8 100644 --- a/src/dns_client.c +++ b/src/dns_client.c @@ -420,7 +420,7 @@ static int _dns_client_server_exist(const char *server_ip, int port, dns_server_ static void _dns_client_server_update_ttl(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, int ttl, - struct timeval *tv, void *userptr) + struct timeval *tv, int error, void *userptr) { struct dns_server_info *server_info = userptr; if (result != PING_RESULT_RESPONSE || server_info == NULL) { diff --git a/src/dns_server.c b/src/dns_server.c index b43d1f7..d13a160 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -44,6 +44,7 @@ #include #define DNS_MAX_EVENTS 256 +#define IPV6_READY_CHECK_TIME 180 #define DNS_SERVER_TMOUT_TTL (5 * 60) #define DNS_CONN_BUFF_SIZE 4096 #define DNS_REQUEST_MAX_TIMEOUT 850 @@ -248,6 +249,8 @@ static struct dns_server server; static tlog_log *dns_audit; +static int is_ipv6_ready; + 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) @@ -1675,7 +1678,7 @@ errout: static void _dns_server_ping_result(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, int ttl, struct timeval *tv, - void *userptr) + int error, void *userptr) { struct dns_request *request = userptr; int may_complete = 0; @@ -1692,6 +1695,18 @@ static void _dns_server_ping_result(struct ping_host_struct *ping_host, const ch return; } else if (result == PING_RESULT_TIMEOUT) { return; + } else if (result == PING_RESULT_ERROR) { + if (addr->sa_family != AF_INET6) { + return; + } + + if (is_ipv6_ready) { + if (error == EADDRNOTAVAIL || errno == EACCES) { + is_ipv6_ready = 0; + tlog(TLOG_ERROR, "IPV6 is not ready, disable all ipv6 feature, recheck after %ds", IPV6_READY_CHECK_TIME); + } + } + return; } unsigned int rtt = tv->tv_sec * 10000 + tv->tv_usec / 100; @@ -3011,6 +3026,60 @@ out: return ret; } +void _dns_server_check_ipv6_ready(void) +{ + static int do_get_conf = 0; + static int is_icmp_check_set; + static int is_tcp_check_set; + int i = 0; + + if (do_get_conf == 0) { + for (i = 0; i < DOMAIN_CHECK_NUM; i++) { + if (dns_conf_check_order.order[i] == DOMAIN_CHECK_ICMP) { + is_icmp_check_set = 1; + } + + if (dns_conf_check_order.order[i] == DOMAIN_CHECK_TCP) { + is_tcp_check_set = 1; + } + } + + if (is_icmp_check_set == 0) { + tlog(TLOG_INFO, "ICMP ping is disabled, no ipv6 icmp check feature"); + } + + do_get_conf = 1; + } + + if (is_icmp_check_set) { + struct ping_host_struct *check_ping = fast_ping_start(PING_TYPE_ICMP, "2001::", 1, 0, 100, 0, 0); + if (check_ping) { + fast_ping_stop(check_ping); + is_ipv6_ready = 1; + return; + } + + if (errno == EADDRNOTAVAIL) { + is_ipv6_ready = 0; + return; + } + } + + if (is_tcp_check_set) { + struct ping_host_struct *check_ping = fast_ping_start(PING_TYPE_TCP, "2001::", 1, 0, 100, 0, 0); + if (check_ping) { + fast_ping_stop(check_ping); + is_ipv6_ready = 1; + return; + } + + if (errno == EADDRNOTAVAIL) { + is_ipv6_ready = 0; + return; + } + } +} + static void _dns_server_request_set_client(struct dns_request *request, struct dns_server_conn_head *conn) { request->conn = conn; @@ -3116,6 +3185,10 @@ static void _dns_server_check_set_passthrough(struct dns_request *request) request->passthrough = 1; } + if (is_ipv6_ready == 0 && request->qtype == DNS_T_AAAA) { + request->passthrough = 1; + } + if (request->passthrough == 1) { request->dualstack_selection = 0; } @@ -3791,6 +3864,10 @@ static void _dns_server_period_run_second(void) } _dns_server_tcp_idle_check(); + + if (sec % IPV6_READY_CHECK_TIME == 0 && is_ipv6_ready == 0) { + _dns_server_check_ipv6_ready(); + } } static void _dns_server_period_run(void) @@ -4240,6 +4317,9 @@ int dns_server_init(void) goto errout; } + _dns_server_check_ipv6_ready(); + tlog(TLOG_INFO, "%s", (is_ipv6_ready) ? "IPV6 is ready, enable IPV6 features" : "IPV6 is not ready, disable IPV6 features"); + return 0; errout: server.run = 0; diff --git a/src/fast_ping.c b/src/fast_ping.c index 0f2781e..6393499 100644 --- a/src/fast_ping.c +++ b/src/fast_ping.c @@ -97,6 +97,7 @@ struct ping_host_struct { FAST_PING_TYPE type; void *userptr; + int error; fast_ping_result ping_callback; char host[PING_MAX_HOSTLEN]; @@ -386,7 +387,7 @@ static void _fast_ping_host_put(struct ping_host_struct *ping_host) tv.tv_usec = 0; ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len, - ping_host->seq, ping_host->ttl, &tv, ping_host->userptr); + ping_host->seq, ping_host->ttl, &tv, ping_host->error, ping_host->userptr); } tlog(TLOG_DEBUG, "ping end, id %d", ping_host->sid); @@ -414,7 +415,7 @@ static void _fast_ping_host_remove(struct ping_host_struct *ping_host) tv.tv_usec = 0; ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_END, &ping_host->addr, ping_host->addr_len, - ping_host->seq, ping_host->ttl, &tv, ping_host->userptr); + ping_host->seq, ping_host->ttl, &tv, ping_host->error, ping_host->userptr); } _fast_ping_host_put(ping_host); @@ -445,7 +446,7 @@ static int _fast_ping_sendping_v6(struct ping_host_struct *ping_host) (struct sockaddr *)&ping_host->addr, ping_host->addr_len); if (len < 0 || len != sizeof(struct fast_ping_packet)) { int err = errno; - if (errno == ENETUNREACH || errno == EINVAL) { + if (errno == ENETUNREACH || errno == EINVAL || errno == EADDRNOTAVAIL) { goto errout; } @@ -644,6 +645,7 @@ static int _fast_ping_sendping(struct ping_host_struct *ping_host) ping_host->send = 1; if (ret != 0) { + ping_host->error = errno; return ret; } @@ -848,13 +850,15 @@ errout: static void _fast_ping_print_result(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, int ttl, struct timeval *tv, - void *userptr) + int error, void *userptr) { if (result == PING_RESULT_RESPONSE) { double rtt = tv->tv_sec * 1000.0 + tv->tv_usec / 1000.0; tlog(TLOG_INFO, "from %15s: seq=%d ttl=%d time=%.3f\n", host, seqno, ttl, rtt); } else if (result == PING_RESULT_TIMEOUT) { tlog(TLOG_INFO, "from %15s: seq=%d timeout\n", host, seqno); + } else if (result == PING_RESULT_ERROR) { + tlog(TLOG_DEBUG, "from %15s: error is %s\n", host, strerror(error)); } else if (result == PING_RESULT_END) { fast_ping_stop(ping_host); } @@ -1041,7 +1045,6 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c ret = _fast_ping_get_addr_by_type(type, ip_str, port, &gai, &ping_type); if (ret != 0) { - tlog(TLOG_ERROR, "get addr by type failed, host: %s", host); goto errout; } @@ -1097,6 +1100,9 @@ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int c _fast_ping_host_put(ping_host); return ping_host; errout_remove: + ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_ERROR, &ping_host->addr, + ping_host->addr_len, ping_host->seq, ping_host->ttl, 0, + ping_host->error, ping_host->userptr); fast_ping_stop(ping_host); _fast_ping_host_put(ping_host); ping_host = NULL; @@ -1315,7 +1321,7 @@ static int _fast_ping_process_icmp(struct ping_host_struct *ping_host, struct ti if (recv_ping_host->ping_callback) { recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr, recv_ping_host->addr_len, recv_ping_host->seq, recv_ping_host->ttl, &tvresult, - recv_ping_host->userptr); + ping_host->error, recv_ping_host->userptr); } recv_ping_host->send = 0; @@ -1349,7 +1355,8 @@ static int _fast_ping_process_tcp(struct ping_host_struct *ping_host, struct epo tv_sub(&tvresult, tvsend); if (ping_host->ping_callback) { ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_RESPONSE, &ping_host->addr, - ping_host->addr_len, ping_host->seq, ping_host->ttl, &tvresult, ping_host->userptr); + ping_host->addr_len, ping_host->seq, ping_host->ttl, &tvresult, ping_host->error, + ping_host->userptr); } ping_host->send = 0; @@ -1445,7 +1452,7 @@ static int _fast_ping_process_udp(struct ping_host_struct *ping_host, struct tim if (recv_ping_host->ping_callback) { recv_ping_host->ping_callback(recv_ping_host, recv_ping_host->host, PING_RESULT_RESPONSE, &recv_ping_host->addr, recv_ping_host->addr_len, recv_ping_host->seq, recv_ping_host->ttl, &tvresult, - recv_ping_host->userptr); + ping_host->error, recv_ping_host->userptr); } recv_ping_host->send = 0; @@ -1554,7 +1561,7 @@ static void _fast_ping_period_run(void) if (millisecond >= ping_host->timeout && ping_host->send == 1) { ping_host->ping_callback(ping_host, ping_host->host, PING_RESULT_TIMEOUT, &ping_host->addr, ping_host->addr_len, ping_host->seq, ping_host->ttl, &interval, - ping_host->userptr); + ping_host->error, ping_host->userptr); ping_host->send = 0; } diff --git a/src/fast_ping.h b/src/fast_ping.h index b9124c3..61e4ac8 100644 --- a/src/fast_ping.h +++ b/src/fast_ping.h @@ -34,13 +34,14 @@ typedef enum { typedef enum { PING_RESULT_RESPONSE = 1, PING_RESULT_TIMEOUT = 2, - PING_RESULT_END = 3, + PING_RESULT_ERROR = 3, + PING_RESULT_END = 4, } FAST_PING_RESULT; struct ping_host_struct; typedef void (*fast_ping_result)(struct ping_host_struct *ping_host, const char *host, FAST_PING_RESULT result, struct sockaddr *addr, socklen_t addr_len, int seqno, int ttl, struct timeval *tv, - void *userptr); + int error, void *userptr); /* start ping */ struct ping_host_struct *fast_ping_start(PING_TYPE type, const char *host, int count, int interval, int timeout,