mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-27 03:03:43 +00:00
Add c-ares support (#1655)
* Replace udns with c-ares * Get IO loop work * Clean up * Avoid initializing nameservers each query * Add ARES_OPT_SERVERS * Refine resolv_cancel * Fix a memory leak * Replace udns.h with ares.h * Fix all inet_* fucntions * Clean up * Enable servers_ports when VERSION_MINOR >= 11 * Avoid ares_inet_XtoX * Handle multipe nameservers correctly * Use ares_set_servers for IPv4 and IPv6 mixed list * Refine c-ares for udprelay * Refine ares_set_servers() * Refine the timer based on ares_timeout * Avoid resolv_cancel * Fix an issue of null pointer * Fix another null pointer issue * Refine the order of resolv_shutdown * Fix the corrupted ev io
This commit is contained in:
@@ -185,7 +185,7 @@ If you are using CentOS 7, you need to install these prequirement to build from
|
||||
|
||||
```bash
|
||||
yum install epel-release -y
|
||||
yum install gcc gettext autoconf libtool automake make pcre-devel asciidoc xmlto udns-devel libev-devel libsodium-devel mbedtls-devel -y
|
||||
yum install gcc gettext autoconf libtool automake make pcre-devel asciidoc xmlto c-ares-devel libev-devel libsodium-devel mbedtls-devel -y
|
||||
```
|
||||
|
||||
#### Install from repository
|
||||
@@ -245,7 +245,7 @@ In general, you need the following build dependencies:
|
||||
* libsodium
|
||||
* libpcre3 (old pcre library)
|
||||
* libev
|
||||
* libudns
|
||||
* libc-ares
|
||||
* asciidoc (for documentation only)
|
||||
* xmlto (for documentation only)
|
||||
|
||||
@@ -260,11 +260,11 @@ For some of the distributions, you might install build dependencies like this:
|
||||
```bash
|
||||
# Installation of basic build dependencies
|
||||
## Debian / Ubuntu
|
||||
sudo apt-get install --no-install-recommends gettext build-essential autoconf libtool libpcre3-dev asciidoc xmlto libev-dev libudns-dev automake libmbedtls-dev libsodium-dev
|
||||
sudo apt-get install --no-install-recommends gettext build-essential autoconf libtool libpcre3-dev asciidoc xmlto libev-dev libc-ares-dev automake libmbedtls-dev libsodium-dev
|
||||
## CentOS / Fedora / RHEL
|
||||
sudo yum install gettext gcc autoconf libtool automake make asciidoc xmlto udns-devel libev-devel
|
||||
sudo yum install gettext gcc autoconf libtool automake make asciidoc xmlto c-ares-devel libev-devel
|
||||
## Arch
|
||||
sudo pacman -S gettext gcc autoconf libtool automake make asciidoc xmlto udns libev
|
||||
sudo pacman -S gettext gcc autoconf libtool automake make asciidoc xmlto c-ares libev
|
||||
|
||||
# Installation of Libsodium
|
||||
export LIBSODIUM_VER=1.0.13
|
||||
|
||||
@@ -67,7 +67,7 @@ check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
check_include_files(sys/stat.h HAVE_SYS_STAT_H)
|
||||
check_include_files(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_files(sys/wait.h HAVE_SYS_WAIT_H)
|
||||
check_include_files(udns.h HAVE_UDNS_H)
|
||||
check_include_files(ares.h HAVE_ARES_H)
|
||||
check_include_files(unistd.h HAVE_UNISTD_H)
|
||||
|
||||
check_function_exists(fork HAVE_FORK)
|
||||
|
||||
+2
-5
@@ -218,12 +218,9 @@ AC_CHECK_LIB(socket, connect)
|
||||
dnl Checks for library functions.
|
||||
AC_CHECK_FUNCS([malloc memset posix_memalign socket])
|
||||
|
||||
dnl Add define for libudns to enable IPv6 support
|
||||
dnl This is an option defined in the origin configure script
|
||||
AC_DEFINE([HAVE_IPv6], [1], [Enable IPv6 support in libudns])
|
||||
AC_CHECK_HEADERS([ares.h], [], [AC_MSG_ERROR([Couldn't find libcares. Try installing libc-ares-dev or c-ares-devel.])])
|
||||
|
||||
AC_CHECK_HEADERS([udns.h], [], [AC_MSG_ERROR([Couldn't find libudns. Try installing libudns-dev or udns-devel.])])
|
||||
AC_CHECK_LIB([udns], [dns_dnlen], [LIBS="-ludns $LIBS"], [AC_MSG_ERROR([Couldn't find libudns. Try installing libudns-dev or udns-devel.])])
|
||||
AC_CHECK_LIB([cares], [ares_library_init], [LIBS="-lcares $LIBS"], [AC_MSG_ERROR([Couldn't find libc-ares. Try installing libc-ares-dev or c-ares-devel.])])
|
||||
|
||||
AC_CHECK_HEADERS([ev.h libev/ev.h], [], [])
|
||||
AC_CHECK_LIB([ev], [ev_loop_destroy], [LIBS="-lev $LIBS"], [AC_MSG_ERROR([Couldn't find libev. Try installing libev-dev@<:@el@:>@.])])
|
||||
|
||||
+5
-5
@@ -78,10 +78,10 @@ ss_local_LDADD = $(SS_COMMON_LIBS)
|
||||
ss_tunnel_LDADD = $(SS_COMMON_LIBS)
|
||||
ss_server_LDADD = $(SS_COMMON_LIBS)
|
||||
ss_manager_LDADD = $(SS_COMMON_LIBS)
|
||||
ss_local_LDADD += -ludns
|
||||
ss_tunnel_LDADD += -ludns
|
||||
ss_server_LDADD += -ludns
|
||||
ss_manager_LDADD += -ludns
|
||||
ss_local_LDADD += -lcares
|
||||
ss_tunnel_LDADD += -lcares
|
||||
ss_server_LDADD += -lcares
|
||||
ss_manager_LDADD += -lcares
|
||||
|
||||
ss_local_CFLAGS = $(AM_CFLAGS) -DMODULE_LOCAL
|
||||
ss_tunnel_CFLAGS = $(AM_CFLAGS) -DMODULE_TUNNEL
|
||||
@@ -104,7 +104,7 @@ ss_redir_SOURCES = utils.c \
|
||||
|
||||
ss_redir_CFLAGS = $(AM_CFLAGS) -DMODULE_REDIR
|
||||
ss_redir_LDADD = $(SS_COMMON_LIBS)
|
||||
ss_redir_LDADD += -ludns
|
||||
ss_redir_LDADD += -lcares
|
||||
endif
|
||||
|
||||
lib_LTLIBRARIES = libshadowsocks-libev.la
|
||||
|
||||
+4
-5
@@ -52,7 +52,6 @@
|
||||
#endif
|
||||
|
||||
#include <libcork/core.h>
|
||||
#include <udns.h>
|
||||
|
||||
#include "netutils.h"
|
||||
#include "utils.h"
|
||||
@@ -582,7 +581,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
if (acl || verbose) {
|
||||
uint16_t p = ntohs(*(uint16_t *)(buf->data + request_len + in_addr_len));
|
||||
dns_ntop(AF_INET, (const void *)(buf->data + request_len),
|
||||
inet_ntop(AF_INET, (const void *)(buf->data + request_len),
|
||||
ip, INET_ADDRSTRLEN);
|
||||
sprintf(port, "%d", p);
|
||||
}
|
||||
@@ -615,7 +614,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
if (acl || verbose) {
|
||||
uint16_t p = ntohs(*(uint16_t *)(buf->data + request_len + in6_addr_len));
|
||||
dns_ntop(AF_INET6, (const void *)(buf->data + request_len),
|
||||
inet_ntop(AF_INET6, (const void *)(buf->data + request_len),
|
||||
ip, INET6_ADDRSTRLEN);
|
||||
sprintf(port, "%d", p);
|
||||
}
|
||||
@@ -705,12 +704,12 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
switch(((struct sockaddr*)&storage)->sa_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *addr_in = (struct sockaddr_in *)&storage;
|
||||
dns_ntop(AF_INET, &(addr_in->sin_addr), ip, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &(addr_in->sin_addr), ip, INET_ADDRSTRLEN);
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)&storage;
|
||||
dns_ntop(AF_INET6, &(addr_in6->sin6_addr), ip, INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &(addr_in6->sin6_addr), ip, INET6_ADDRSTRLEN);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
+5
-5
@@ -23,12 +23,12 @@
|
||||
#include <math.h>
|
||||
|
||||
#include <libcork/core.h>
|
||||
#include <udns.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
@@ -97,12 +97,12 @@ bind_to_address(int socket_fd, const char *host)
|
||||
if (cork_ip_init(&ip, host) != -1) {
|
||||
if (ip.version == 4) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
|
||||
dns_pton(AF_INET, host, &addr->sin_addr);
|
||||
inet_pton(AF_INET, host, &addr->sin_addr);
|
||||
addr->sin_family = AF_INET;
|
||||
return bind(socket_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in));
|
||||
} else if (ip.version == 6) {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
|
||||
dns_pton(AF_INET6, host, &addr->sin6_addr);
|
||||
inet_pton(AF_INET6, host, &addr->sin6_addr);
|
||||
addr->sin6_family = AF_INET6;
|
||||
return bind(socket_fd, (struct sockaddr *)addr, sizeof(struct sockaddr_in6));
|
||||
}
|
||||
@@ -121,14 +121,14 @@ get_sockaddr(char *host, char *port,
|
||||
if (ip.version == 4) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)storage;
|
||||
addr->sin_family = AF_INET;
|
||||
dns_pton(AF_INET, host, &(addr->sin_addr));
|
||||
inet_pton(AF_INET, host, &(addr->sin_addr));
|
||||
if (port != NULL) {
|
||||
addr->sin_port = htons(atoi(port));
|
||||
}
|
||||
} else if (ip.version == 6) {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage;
|
||||
addr->sin6_family = AF_INET6;
|
||||
dns_pton(AF_INET6, host, &(addr->sin6_addr));
|
||||
inet_pton(AF_INET6, host, &(addr->sin6_addr));
|
||||
if (port != NULL) {
|
||||
addr->sin6_port = htons(atoi(port));
|
||||
}
|
||||
|
||||
+2
-3
@@ -41,7 +41,6 @@
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
|
||||
#include <udns.h>
|
||||
#include <libcork/core.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -228,11 +227,11 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
if (AF_INET == server->destaddr.ss_family) {
|
||||
struct sockaddr_in *sa = (struct sockaddr_in *)&(server->destaddr);
|
||||
dns_ntop(AF_INET, &(sa->sin_addr), ipstr, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &(sa->sin_addr), ipstr, INET_ADDRSTRLEN);
|
||||
port = ntohs(sa->sin_port);
|
||||
} else {
|
||||
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(server->destaddr);
|
||||
dns_ntop(AF_INET6, &(sa->sin6_addr), ipstr, INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &(sa->sin6_addr), ipstr, INET6_ADDRSTRLEN);
|
||||
port = ntohs(sa->sin6_port);
|
||||
}
|
||||
|
||||
|
||||
+304
-268
@@ -33,12 +33,13 @@
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <udns.h>
|
||||
#include <ares.h>
|
||||
|
||||
#ifdef HAVE_LIBEV_EV_H
|
||||
#include <libev/ev.h>
|
||||
@@ -46,28 +47,44 @@
|
||||
#include <ev.h>
|
||||
#endif
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "resolv.h"
|
||||
#include "utils.h"
|
||||
#include "netutils.h"
|
||||
|
||||
/*
|
||||
* Implement DNS resolution interface using libudns
|
||||
* Implement DNS resolution interface using libc-ares
|
||||
*/
|
||||
|
||||
struct ResolvQuery {
|
||||
void (*client_cb)(struct sockaddr *, void *);
|
||||
void (*client_free_cb)(void *);
|
||||
void *client_cb_data;
|
||||
struct dns_query *queries[2];
|
||||
struct resolv_ctx {
|
||||
struct ev_io io;
|
||||
struct ev_timer tw;
|
||||
|
||||
ares_channel channel;
|
||||
struct ares_options options;
|
||||
};
|
||||
|
||||
struct resolv_query {
|
||||
int requests[2];
|
||||
size_t response_count;
|
||||
struct sockaddr **responses;
|
||||
|
||||
void (*client_cb)(struct sockaddr *, void *);
|
||||
void (*free_cb)(void*);
|
||||
|
||||
uint16_t port;
|
||||
|
||||
void *data;
|
||||
|
||||
int is_closed;
|
||||
};
|
||||
|
||||
extern int verbose;
|
||||
|
||||
static struct ev_io resolv_io_watcher;
|
||||
static struct ev_timer resolv_timeout_watcher;
|
||||
struct resolv_ctx default_ctx;
|
||||
static struct ev_loop* default_loop;
|
||||
|
||||
static const int MODE_IPV4_ONLY = 0;
|
||||
static const int MODE_IPV6_ONLY = 1;
|
||||
static const int MODE_IPV4_FIRST = 2;
|
||||
@@ -76,367 +93,386 @@ static int resolv_mode = 0;
|
||||
|
||||
static void resolv_sock_cb(struct ev_loop *, struct ev_io *, int);
|
||||
static void resolv_timeout_cb(struct ev_loop *, struct ev_timer *, int);
|
||||
static void dns_query_v4_cb(struct dns_ctx *, struct dns_rr_a4 *, void *);
|
||||
static void dns_query_v6_cb(struct dns_ctx *, struct dns_rr_a6 *, void *);
|
||||
static void dns_timer_setup_cb(struct dns_ctx *, int, void *);
|
||||
static void process_client_callback(struct ResolvQuery *);
|
||||
static inline int all_queries_are_null(struct ResolvQuery *);
|
||||
static struct sockaddr *choose_ipv4_first(struct ResolvQuery *);
|
||||
static struct sockaddr *choose_ipv6_first(struct ResolvQuery *);
|
||||
static struct sockaddr *choose_any(struct ResolvQuery *);
|
||||
static void resolv_sock_state_cb(void *, int, int, int);
|
||||
|
||||
int
|
||||
resolv_init(struct ev_loop *loop, char **nameservers, int nameserver_num, int ipv6first)
|
||||
{
|
||||
if (ipv6first)
|
||||
resolv_mode = MODE_IPV6_FIRST;
|
||||
else
|
||||
resolv_mode = MODE_IPV4_FIRST;
|
||||
static void dns_query_v4_cb(void *, int, int, struct hostent *);
|
||||
static void dns_query_v6_cb(void *, int, int, struct hostent *);
|
||||
|
||||
struct dns_ctx *ctx = &dns_defctx;
|
||||
if (nameservers == NULL) {
|
||||
/* Nameservers not specified, use system resolver config */
|
||||
dns_init(ctx, 0);
|
||||
} else {
|
||||
dns_reset(ctx);
|
||||
static void process_client_callback(struct resolv_query *);
|
||||
static inline int all_requests_are_null(struct resolv_query *);
|
||||
static struct sockaddr *choose_ipv4_first(struct resolv_query *);
|
||||
static struct sockaddr *choose_ipv6_first(struct resolv_query *);
|
||||
static struct sockaddr *choose_any(struct resolv_query *);
|
||||
|
||||
for (int i = 0; i < nameserver_num; i++) {
|
||||
char *server = nameservers[i];
|
||||
dns_add_serv(ctx, server);
|
||||
}
|
||||
}
|
||||
|
||||
int sockfd = dns_open(ctx);
|
||||
if (sockfd < 0) {
|
||||
FATAL("Failed to open DNS resolver socket");
|
||||
}
|
||||
|
||||
if (nameserver_num == 1 && nameservers != NULL) {
|
||||
if (strncmp("127.0.0.1", nameservers[0], 9) == 0
|
||||
|| strncmp("::1", nameservers[0], 3) == 0) {
|
||||
if (verbose) {
|
||||
LOGI("bind UDP resolver to %s", nameservers[0]);
|
||||
}
|
||||
if (bind_to_address(sockfd, nameservers[0]) == -1)
|
||||
ERROR("bind_to_address");
|
||||
}
|
||||
}
|
||||
|
||||
int flags = fcntl(sockfd, F_GETFL, 0);
|
||||
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
ev_io_init(&resolv_io_watcher, resolv_sock_cb, sockfd, EV_READ);
|
||||
resolv_io_watcher.data = ctx;
|
||||
|
||||
ev_io_start(loop, &resolv_io_watcher);
|
||||
|
||||
ev_timer_init(&resolv_timeout_watcher, resolv_timeout_cb, 0.0, 0.0);
|
||||
resolv_timeout_watcher.data = ctx;
|
||||
|
||||
dns_set_tmcbck(ctx, dns_timer_setup_cb, loop);
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
void
|
||||
resolv_shutdown(struct ev_loop *loop)
|
||||
{
|
||||
struct dns_ctx *ctx = (struct dns_ctx *)resolv_io_watcher.data;
|
||||
|
||||
ev_io_stop(loop, &resolv_io_watcher);
|
||||
|
||||
if (ev_is_active(&resolv_timeout_watcher)) {
|
||||
ev_timer_stop(loop, &resolv_timeout_watcher);
|
||||
}
|
||||
|
||||
dns_close(ctx);
|
||||
}
|
||||
|
||||
struct ResolvQuery *
|
||||
resolv_query(const char *hostname, void (*client_cb)(struct sockaddr *, void *),
|
||||
void (*client_free_cb)(void *), void *client_cb_data,
|
||||
uint16_t port)
|
||||
{
|
||||
struct dns_ctx *ctx = (struct dns_ctx *)resolv_io_watcher.data;
|
||||
|
||||
/*
|
||||
* Wrap udns's call back in our own
|
||||
*/
|
||||
struct ResolvQuery *cb_data = ss_malloc(sizeof(struct ResolvQuery));
|
||||
if (cb_data == NULL) {
|
||||
LOGE("Failed to allocate memory for DNS query callback data.");
|
||||
return NULL;
|
||||
}
|
||||
memset(cb_data, 0, sizeof(struct ResolvQuery));
|
||||
|
||||
cb_data->client_cb = client_cb;
|
||||
cb_data->client_free_cb = client_free_cb;
|
||||
cb_data->client_cb_data = client_cb_data;
|
||||
memset(cb_data->queries, 0, sizeof(cb_data->queries));
|
||||
cb_data->response_count = 0;
|
||||
cb_data->responses = NULL;
|
||||
cb_data->port = port;
|
||||
|
||||
/* Submit A and AAAA queries */
|
||||
if (resolv_mode != MODE_IPV6_ONLY) {
|
||||
cb_data->queries[0] = dns_submit_a4(ctx,
|
||||
hostname, 0,
|
||||
dns_query_v4_cb, cb_data);
|
||||
if (cb_data->queries[0] == NULL) {
|
||||
LOGE("Failed to submit DNS query: %s",
|
||||
dns_strerror(dns_status(ctx)));
|
||||
}
|
||||
}
|
||||
|
||||
if (resolv_mode != MODE_IPV4_ONLY) {
|
||||
cb_data->queries[1] = dns_submit_a6(ctx,
|
||||
hostname, 0,
|
||||
dns_query_v6_cb, cb_data);
|
||||
if (cb_data->queries[1] == NULL) {
|
||||
LOGE("Failed to submit DNS query: %s",
|
||||
dns_strerror(dns_status(ctx)));
|
||||
}
|
||||
}
|
||||
|
||||
if (all_queries_are_null(cb_data)) {
|
||||
if (cb_data->client_free_cb != NULL) {
|
||||
cb_data->client_free_cb(cb_data->client_cb_data);
|
||||
}
|
||||
ss_free(cb_data);
|
||||
}
|
||||
|
||||
return cb_data;
|
||||
}
|
||||
|
||||
void
|
||||
resolv_cancel(struct ResolvQuery *query_handle)
|
||||
{
|
||||
struct ResolvQuery *cb_data = (struct ResolvQuery *)query_handle;
|
||||
struct dns_ctx *ctx = (struct dns_ctx *)resolv_io_watcher.data;
|
||||
|
||||
for (int i = 0; i < sizeof(cb_data->queries) / sizeof(cb_data->queries[0]);
|
||||
i++)
|
||||
if (cb_data->queries[i] != NULL) {
|
||||
dns_cancel(ctx, cb_data->queries[i]);
|
||||
ss_free(cb_data->queries[i]);
|
||||
}
|
||||
|
||||
if (cb_data->client_free_cb != NULL) {
|
||||
cb_data->client_free_cb(cb_data->client_cb_data);
|
||||
}
|
||||
|
||||
ss_free(cb_data);
|
||||
}
|
||||
static void reset_timer();
|
||||
|
||||
/*
|
||||
* DNS UDP socket activity callback
|
||||
*/
|
||||
static void
|
||||
resolv_sock_cb(struct ev_loop *loop, struct ev_io *w, int revents)
|
||||
resolv_sock_cb(EV_P_ ev_io *w, int revents)
|
||||
{
|
||||
struct dns_ctx *ctx = (struct dns_ctx *)w->data;
|
||||
struct resolv_ctx *ctx = (struct resolv_ctx *) w;
|
||||
|
||||
if (revents & EV_READ) {
|
||||
dns_ioevent(ctx, ev_now(loop));
|
||||
ares_socket_t rfd = ARES_SOCKET_BAD, wfd = ARES_SOCKET_BAD;
|
||||
|
||||
if (revents & EV_READ)
|
||||
rfd = w->fd;
|
||||
if (revents & EV_WRITE)
|
||||
wfd = w->fd;
|
||||
|
||||
ares_process_fd(ctx->channel, rfd, wfd);
|
||||
|
||||
reset_timer();
|
||||
}
|
||||
|
||||
int
|
||||
resolv_init(struct ev_loop *loop, char *nameservers, int ipv6first)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (ipv6first)
|
||||
resolv_mode = MODE_IPV6_FIRST;
|
||||
else
|
||||
resolv_mode = MODE_IPV4_FIRST;
|
||||
|
||||
default_loop = loop;
|
||||
|
||||
if ((status = ares_library_init(ARES_LIB_INIT_ALL) )!= ARES_SUCCESS) {
|
||||
LOGE("c-ares error: %s", ares_strerror(status));
|
||||
FATAL("failed to initialize c-ares");
|
||||
}
|
||||
|
||||
memset(&default_ctx, 0, sizeof(struct resolv_ctx));
|
||||
|
||||
default_ctx.options.sock_state_cb_data = &default_ctx;
|
||||
default_ctx.options.sock_state_cb = resolv_sock_state_cb;
|
||||
default_ctx.options.timeout = 3000;
|
||||
default_ctx.options.tries = 2;
|
||||
|
||||
status = ares_init_options(&default_ctx.channel, &default_ctx.options,
|
||||
ARES_OPT_TIMEOUTMS | ARES_OPT_TRIES | ARES_OPT_SOCK_STATE_CB);
|
||||
|
||||
if (status != ARES_SUCCESS) {
|
||||
FATAL("failed to initialize c-ares");
|
||||
}
|
||||
|
||||
if (nameservers != NULL) {
|
||||
#if ARES_VERSION_MINOR >= 11
|
||||
status = ares_set_servers_ports_csv(default_ctx.channel, nameservers);
|
||||
#else
|
||||
status = ares_set_servers_csv(default_ctx.channel, nameservers);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (status != ARES_SUCCESS) {
|
||||
FATAL("failed to set nameservers");
|
||||
}
|
||||
|
||||
ev_init(&default_ctx.io, resolv_sock_cb);
|
||||
ev_timer_init(&default_ctx.tw, resolv_timeout_cb, 0.0, 0.0);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
resolv_shutdown(struct ev_loop *loop)
|
||||
{
|
||||
ares_cancel(default_ctx.channel);
|
||||
ares_destroy(default_ctx.channel);
|
||||
|
||||
ares_library_cleanup();
|
||||
}
|
||||
|
||||
struct resolv_query *
|
||||
resolv_start(const char *hostname, uint16_t port,
|
||||
void (*client_cb)(struct sockaddr *, void *),
|
||||
void (*free_cb)(void*), void *data)
|
||||
{
|
||||
/*
|
||||
* Wrap c-ares's call back in our own
|
||||
*/
|
||||
|
||||
struct resolv_query *query = ss_malloc(sizeof(struct resolv_query));
|
||||
|
||||
if (query == NULL) {
|
||||
LOGE("failed to allocate memory for DNS query callback data.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(query, 0, sizeof(struct resolv_query));
|
||||
|
||||
query->port = port;
|
||||
query->client_cb = client_cb;
|
||||
query->response_count = 0;
|
||||
query->responses = NULL;
|
||||
query->data = data;
|
||||
query->free_cb = free_cb;
|
||||
|
||||
/* Submit A and AAAA requests */
|
||||
if (resolv_mode != MODE_IPV6_ONLY) {
|
||||
ares_gethostbyname(default_ctx.channel, hostname, AF_INET, dns_query_v4_cb, query);
|
||||
query->requests[0] = AF_INET;
|
||||
}
|
||||
|
||||
if (resolv_mode != MODE_IPV4_ONLY) {
|
||||
ares_gethostbyname(default_ctx.channel, hostname, AF_INET6, dns_query_v6_cb, query);
|
||||
query->requests[1] = AF_INET6;
|
||||
}
|
||||
|
||||
reset_timer();
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for client callback we provide to udns
|
||||
* Wrapper for client callback we provide to c-ares
|
||||
*/
|
||||
static void
|
||||
dns_query_v4_cb(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data)
|
||||
dns_query_v4_cb(void *arg, int status, int timeouts, struct hostent *he)
|
||||
{
|
||||
struct ResolvQuery *cb_data = (struct ResolvQuery *)data;
|
||||
int i, n;
|
||||
struct resolv_query *query = (struct resolv_query *)arg;
|
||||
|
||||
if (result == NULL) {
|
||||
if (status == ARES_EDESTRUCTION) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!he || status != ARES_SUCCESS){
|
||||
if (verbose) {
|
||||
LOGI("IPv4 resolv: %s", dns_strerror(dns_status(ctx)));
|
||||
LOGI("failed to lookup v4 address %s", ares_strerror(status));
|
||||
}
|
||||
} else if (result->dnsa4_nrr > 0) {
|
||||
struct sockaddr **new_responses = ss_realloc(cb_data->responses,
|
||||
(cb_data->response_count +
|
||||
result->dnsa4_nrr) *
|
||||
sizeof(struct sockaddr *));
|
||||
if (new_responses == NULL) {
|
||||
LOGE("Failed to allocate memory for additional DNS responses");
|
||||
} else {
|
||||
cb_data->responses = new_responses;
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
for (int i = 0; i < result->dnsa4_nrr; i++) {
|
||||
if (verbose) {
|
||||
LOGI("found address name v4 address %s", he->h_name);
|
||||
}
|
||||
|
||||
n = 0;
|
||||
while (he->h_addr_list[n]) {
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
struct sockaddr **new_responses = ss_realloc(query->responses,
|
||||
(query->response_count + n)
|
||||
* sizeof(struct sockaddr *));
|
||||
|
||||
if (new_responses == NULL) {
|
||||
LOGE("failed to allocate memory for additional DNS responses");
|
||||
} else {
|
||||
query->responses = new_responses;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
struct sockaddr_in *sa = ss_malloc(sizeof(struct sockaddr_in));
|
||||
memset(sa, 0, sizeof(struct sockaddr_in));
|
||||
sa->sin_family = AF_INET;
|
||||
sa->sin_port = cb_data->port;
|
||||
sa->sin_addr = result->dnsa4_addr[i];
|
||||
sa->sin_port = query->port;
|
||||
memcpy(&sa->sin_addr, he->h_addr_list[i], he->h_length);
|
||||
|
||||
cb_data->responses[cb_data->response_count] =
|
||||
(struct sockaddr *)sa;
|
||||
if (cb_data->responses[cb_data->response_count] == NULL) {
|
||||
LOGE(
|
||||
"Failed to allocate memory for DNS query result address");
|
||||
query->responses[query->response_count] = (struct sockaddr*)sa;
|
||||
if (query->responses[query->response_count] == NULL) {
|
||||
LOGE("failed to allocate memory for DNS query result address");
|
||||
} else {
|
||||
cb_data->response_count++;
|
||||
query->response_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ss_free(result);
|
||||
cb_data->queries[0] = NULL; /* mark A query as being completed */
|
||||
CLEANUP:
|
||||
|
||||
/* Once all queries have completed, call client callback */
|
||||
if (all_queries_are_null(cb_data)) {
|
||||
return process_client_callback(cb_data);
|
||||
query->requests[0] = 0; /* mark A query as being completed */
|
||||
|
||||
/* Once all requests have completed, call client callback */
|
||||
if (all_requests_are_null(query)) {
|
||||
return process_client_callback(query);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dns_query_v6_cb(struct dns_ctx *ctx, struct dns_rr_a6 *result, void *data)
|
||||
dns_query_v6_cb(void *arg, int status, int timeouts, struct hostent *he)
|
||||
{
|
||||
struct ResolvQuery *cb_data = (struct ResolvQuery *)data;
|
||||
int i, n;
|
||||
struct resolv_query *query = (struct resolv_query *)arg;
|
||||
|
||||
if (result == NULL) {
|
||||
if (status == ARES_EDESTRUCTION) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!he || status != ARES_SUCCESS){
|
||||
if (verbose) {
|
||||
LOGI("IPv6 resolv: %s", dns_strerror(dns_status(ctx)));
|
||||
LOGI("failed to lookup v6 address %s", ares_strerror(status));
|
||||
}
|
||||
} else if (result->dnsa6_nrr > 0) {
|
||||
struct sockaddr **new_responses = ss_realloc(cb_data->responses,
|
||||
(cb_data->response_count +
|
||||
result->dnsa6_nrr) *
|
||||
sizeof(struct sockaddr *));
|
||||
if (new_responses == NULL) {
|
||||
LOGE("Failed to allocate memory for additional DNS responses");
|
||||
} else {
|
||||
cb_data->responses = new_responses;
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
for (int i = 0; i < result->dnsa6_nrr; i++) {
|
||||
if (verbose) {
|
||||
LOGI("found address name v6 address %s", he->h_name);
|
||||
}
|
||||
|
||||
n = 0;
|
||||
while (he->h_addr_list[n]) {
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
struct sockaddr **new_responses = ss_realloc(query->responses,
|
||||
(query->response_count + n)
|
||||
* sizeof(struct sockaddr *));
|
||||
|
||||
if (new_responses == NULL) {
|
||||
LOGE("failed to allocate memory for additional DNS responses");
|
||||
} else {
|
||||
query->responses = new_responses;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
struct sockaddr_in6 *sa = ss_malloc(sizeof(struct sockaddr_in6));
|
||||
memset(sa, 0, sizeof(struct sockaddr_in6));
|
||||
sa->sin6_family = AF_INET6;
|
||||
sa->sin6_port = cb_data->port;
|
||||
sa->sin6_addr = result->dnsa6_addr[i];
|
||||
sa->sin6_port = query->port;
|
||||
memcpy(&sa->sin6_addr, he->h_addr_list[i], he->h_length);
|
||||
|
||||
cb_data->responses[cb_data->response_count] =
|
||||
(struct sockaddr *)sa;
|
||||
if (cb_data->responses[cb_data->response_count] == NULL) {
|
||||
LOGE(
|
||||
"Failed to allocate memory for DNS query result address");
|
||||
query->responses[query->response_count] = (struct sockaddr*)sa;
|
||||
if (query->responses[query->response_count] == NULL) {
|
||||
LOGE("failed to allocate memory for DNS query result address");
|
||||
} else {
|
||||
cb_data->response_count++;
|
||||
query->response_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ss_free(result);
|
||||
cb_data->queries[1] = NULL; /* mark AAAA query as being completed */
|
||||
CLEANUP:
|
||||
|
||||
/* Once all queries have completed, call client callback */
|
||||
if (all_queries_are_null(cb_data)) {
|
||||
return process_client_callback(cb_data);
|
||||
query->requests[1] = 0; /* mark A query as being completed */
|
||||
|
||||
/* Once all requests have completed, call client callback */
|
||||
if (all_requests_are_null(query)) {
|
||||
return process_client_callback(query);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called once all queries have been completed
|
||||
* Called once all requests have been completed
|
||||
*/
|
||||
static void
|
||||
process_client_callback(struct ResolvQuery *cb_data)
|
||||
process_client_callback(struct resolv_query *query)
|
||||
{
|
||||
struct sockaddr *best_address = NULL;
|
||||
|
||||
if (resolv_mode == MODE_IPV4_FIRST) {
|
||||
best_address = choose_ipv4_first(cb_data);
|
||||
best_address = choose_ipv4_first(query);
|
||||
} else if (resolv_mode == MODE_IPV6_FIRST) {
|
||||
best_address = choose_ipv6_first(cb_data);
|
||||
best_address = choose_ipv6_first(query);
|
||||
} else {
|
||||
best_address = choose_any(cb_data);
|
||||
best_address = choose_any(query);
|
||||
}
|
||||
|
||||
cb_data->client_cb(best_address, cb_data->client_cb_data);
|
||||
query->client_cb(best_address, query->data);
|
||||
|
||||
for (int i = 0; i < cb_data->response_count; i++)
|
||||
ss_free(cb_data->responses[i]);
|
||||
for (int i = 0; i < query->response_count; i++)
|
||||
ss_free(query->responses[i]);
|
||||
|
||||
ss_free(cb_data->responses);
|
||||
if (cb_data->client_free_cb != NULL) {
|
||||
cb_data->client_free_cb(cb_data->client_cb_data);
|
||||
}
|
||||
ss_free(cb_data);
|
||||
ss_free(query->responses);
|
||||
|
||||
if (query->free_cb != NULL)
|
||||
query->free_cb(query->data);
|
||||
else
|
||||
ss_free(query->data);
|
||||
|
||||
ss_free(query);
|
||||
}
|
||||
|
||||
static struct sockaddr *
|
||||
choose_ipv4_first(struct ResolvQuery *cb_data)
|
||||
choose_ipv4_first(struct resolv_query *query)
|
||||
{
|
||||
for (int i = 0; i < cb_data->response_count; i++)
|
||||
if (cb_data->responses[i]->sa_family == AF_INET) {
|
||||
return cb_data->responses[i];
|
||||
for (int i = 0; i < query->response_count; i++)
|
||||
if (query->responses[i]->sa_family == AF_INET) {
|
||||
return query->responses[i];
|
||||
}
|
||||
|
||||
return choose_any(cb_data);
|
||||
return choose_any(query);
|
||||
}
|
||||
|
||||
static struct sockaddr *
|
||||
choose_ipv6_first(struct ResolvQuery *cb_data)
|
||||
choose_ipv6_first(struct resolv_query *query)
|
||||
{
|
||||
for (int i = 0; i < cb_data->response_count; i++)
|
||||
if (cb_data->responses[i]->sa_family == AF_INET6) {
|
||||
return cb_data->responses[i];
|
||||
for (int i = 0; i < query->response_count; i++)
|
||||
if (query->responses[i]->sa_family == AF_INET6) {
|
||||
return query->responses[i];
|
||||
}
|
||||
|
||||
return choose_any(cb_data);
|
||||
return choose_any(query);
|
||||
}
|
||||
|
||||
static struct sockaddr *
|
||||
choose_any(struct ResolvQuery *cb_data)
|
||||
choose_any(struct resolv_query *query)
|
||||
{
|
||||
if (cb_data->response_count >= 1) {
|
||||
return cb_data->responses[0];
|
||||
if (query->response_count >= 1) {
|
||||
return query->responses[0];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int
|
||||
all_requests_are_null(struct resolv_query *query)
|
||||
{
|
||||
int result = 1;
|
||||
|
||||
for (int i = 0; i < sizeof(query->requests) / sizeof(query->requests[0]);
|
||||
i++)
|
||||
result = result && query->requests[i] == 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* DNS timeout callback
|
||||
* DNS timeout callback
|
||||
*/
|
||||
static void
|
||||
resolv_timeout_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
|
||||
{
|
||||
struct dns_ctx *ctx = (struct dns_ctx *)w->data;
|
||||
struct resolv_ctx *ctx= cork_container_of(w, struct resolv_ctx, tw);
|
||||
|
||||
if (revents & EV_TIMER) {
|
||||
dns_timeouts(ctx, 30, ev_now(loop));
|
||||
ares_process_fd(ctx->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
|
||||
|
||||
reset_timer();
|
||||
}
|
||||
|
||||
static void
|
||||
reset_timer()
|
||||
{
|
||||
struct timeval tvout;
|
||||
struct timeval *tv = ares_timeout(default_ctx.channel, NULL, &tvout);
|
||||
if (tv == NULL) {
|
||||
return;
|
||||
}
|
||||
float repeat = tv->tv_sec + tv->tv_usec / 1000000. + 1e-9;
|
||||
ev_timer_set(&default_ctx.tw, repeat, repeat);
|
||||
ev_timer_again(default_loop, &default_ctx.tw);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback to setup DNS timeout callback
|
||||
* Handle c-ares events
|
||||
*/
|
||||
static void
|
||||
dns_timer_setup_cb(struct dns_ctx *ctx, int timeout, void *data)
|
||||
{
|
||||
struct ev_loop *loop = (struct ev_loop *)data;
|
||||
resolv_sock_state_cb(void *data, int s, int read, int write) {
|
||||
|
||||
if (ev_is_active(&resolv_timeout_watcher)) {
|
||||
ev_timer_stop(loop, &resolv_timeout_watcher);
|
||||
}
|
||||
struct resolv_ctx *ctx = (struct resolv_ctx *) data;
|
||||
int io_active = ev_is_active(&ctx->io);
|
||||
|
||||
if (ctx != NULL && timeout >= 0) {
|
||||
ev_timer_set(&resolv_timeout_watcher, timeout, 0.0);
|
||||
ev_timer_start(loop, &resolv_timeout_watcher);
|
||||
if (read || write) {
|
||||
if (io_active && ctx->io.fd != s) {
|
||||
ev_io_stop(default_loop, &ctx->io);
|
||||
}
|
||||
ev_io_set(&ctx->io, s, (read ? EV_READ : 0) | (write ? EV_WRITE : 0));
|
||||
ev_io_start(default_loop, &ctx->io);
|
||||
} else {
|
||||
ev_io_stop(default_loop, &ctx->io);
|
||||
ev_io_set(&ctx->io, -1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
all_queries_are_null(struct ResolvQuery *cb_data)
|
||||
{
|
||||
int result = 1;
|
||||
|
||||
for (int i = 0; i < sizeof(cb_data->queries) / sizeof(cb_data->queries[0]);
|
||||
i++)
|
||||
result = result && cb_data->queries[i] == NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
+5
-6
@@ -33,13 +33,12 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
struct ResolvQuery;
|
||||
struct resolv_query;
|
||||
|
||||
int resolv_init(struct ev_loop *, char **, int, int);
|
||||
struct ResolvQuery *resolv_query(const char *, void (*)(struct sockaddr *,
|
||||
void *), void (*)(
|
||||
void *), void *, uint16_t);
|
||||
void resolv_cancel(struct ResolvQuery *);
|
||||
int resolv_init(struct ev_loop *, char *, int);
|
||||
struct resolv_query *resolv_start(const char *hostname, uint16_t port,
|
||||
void (*client_cb)(struct sockaddr *, void *),
|
||||
void (*free_cb)(void*), void *data);
|
||||
void resolv_shutdown(struct ev_loop *);
|
||||
|
||||
#endif
|
||||
|
||||
+43
-37
@@ -44,7 +44,6 @@
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <libcork/core.h>
|
||||
#include <udns.h>
|
||||
|
||||
#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__)
|
||||
#include <net/if.h>
|
||||
@@ -108,8 +107,8 @@ static void free_remote(remote_t *remote);
|
||||
static void close_and_free_remote(EV_P_ remote_t *remote);
|
||||
static void free_server(server_t *server);
|
||||
static void close_and_free_server(EV_P_ server_t *server);
|
||||
static void server_resolve_cb(struct sockaddr *addr, void *data);
|
||||
static void query_free_cb(void *data);
|
||||
static void resolv_cb(struct sockaddr *addr, void *data);
|
||||
static void resolv_free_cb(void *data);
|
||||
|
||||
int verbose = 0;
|
||||
int reuse_port = 0;
|
||||
@@ -242,10 +241,10 @@ get_peer_name(int fd)
|
||||
if (err == 0) {
|
||||
if (addr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)&addr;
|
||||
dns_ntop(AF_INET, &s->sin_addr, peer_name, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &s->sin_addr, peer_name, INET_ADDRSTRLEN);
|
||||
} else if (addr.ss_family == AF_INET6) {
|
||||
struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr;
|
||||
dns_ntop(AF_INET6, &s->sin6_addr, peer_name, INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &s->sin6_addr, peer_name, INET6_ADDRSTRLEN);
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
@@ -454,10 +453,10 @@ connect_to_remote(EV_P_ struct addrinfo *res,
|
||||
|
||||
if (res->ai_addr->sa_family == AF_INET) {
|
||||
struct sockaddr_in *s = (struct sockaddr_in *)res->ai_addr;
|
||||
dns_ntop(AF_INET, &s->sin_addr, ipstr, INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET, &s->sin_addr, ipstr, INET_ADDRSTRLEN);
|
||||
} else if (res->ai_addr->sa_family == AF_INET6) {
|
||||
struct sockaddr_in6 *s = (struct sockaddr_in6 *)res->ai_addr;
|
||||
dns_ntop(AF_INET6, &s->sin6_addr, ipstr, INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, INET6_ADDRSTRLEN);
|
||||
}
|
||||
|
||||
if (outbound_block_match_host(ipstr) == 1) {
|
||||
@@ -759,7 +758,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
addr->sin_family = AF_INET;
|
||||
if (server->buf->len >= in_addr_len + 3) {
|
||||
addr->sin_addr = *(struct in_addr *)(server->buf->data + offset);
|
||||
dns_ntop(AF_INET, (const void *)(server->buf->data + offset),
|
||||
inet_ntop(AF_INET, (const void *)(server->buf->data + offset),
|
||||
host, INET_ADDRSTRLEN);
|
||||
offset += in_addr_len;
|
||||
} else {
|
||||
@@ -796,7 +795,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
info.ai_protocol = IPPROTO_TCP;
|
||||
if (ip.version == 4) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
|
||||
dns_pton(AF_INET, host, &(addr->sin_addr));
|
||||
inet_pton(AF_INET, host, &(addr->sin_addr));
|
||||
addr->sin_port = *(uint16_t *)(server->buf->data + offset);
|
||||
addr->sin_family = AF_INET;
|
||||
info.ai_family = AF_INET;
|
||||
@@ -804,7 +803,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
info.ai_addr = (struct sockaddr *)addr;
|
||||
} else if (ip.version == 6) {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
|
||||
dns_pton(AF_INET6, host, &(addr->sin6_addr));
|
||||
inet_pton(AF_INET6, host, &(addr->sin6_addr));
|
||||
addr->sin6_port = *(uint16_t *)(server->buf->data + offset);
|
||||
addr->sin6_family = AF_INET6;
|
||||
info.ai_family = AF_INET6;
|
||||
@@ -826,7 +825,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
addr->sin6_family = AF_INET6;
|
||||
if (server->buf->len >= in6_addr_len + 3) {
|
||||
addr->sin6_addr = *(struct in6_addr *)(server->buf->data + offset);
|
||||
dns_ntop(AF_INET6, (const void *)(server->buf->data + offset),
|
||||
inet_ntop(AF_INET6, (const void *)(server->buf->data + offset),
|
||||
host, INET6_ADDRSTRLEN);
|
||||
offset += in6_addr_len;
|
||||
} else {
|
||||
@@ -899,11 +898,19 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
query_t *query = ss_malloc(sizeof(query_t));
|
||||
memset(query, 0, sizeof(query_t));
|
||||
query->server = server;
|
||||
server->query = query;
|
||||
snprintf(query->hostname, 256, "%s", host);
|
||||
|
||||
server->stage = STAGE_RESOLVE;
|
||||
server->query = resolv_query(host, server_resolve_cb,
|
||||
query_free_cb, query, port);
|
||||
struct resolv_query *q = resolv_start(host, port,
|
||||
resolv_cb, resolv_free_cb, query);
|
||||
|
||||
if (q == NULL) {
|
||||
if (query != NULL) ss_free(query);
|
||||
server->query = NULL;
|
||||
close_and_free_server(EV_A_ server);
|
||||
return;
|
||||
}
|
||||
|
||||
ev_io_stop(EV_A_ & server_recv_ctx->io);
|
||||
}
|
||||
@@ -992,21 +999,26 @@ server_timeout_cb(EV_P_ ev_timer *watcher, int revents)
|
||||
}
|
||||
|
||||
static void
|
||||
query_free_cb(void *data)
|
||||
resolv_free_cb(void *data)
|
||||
{
|
||||
if (data != NULL) {
|
||||
ss_free(data);
|
||||
query_t *query = (query_t *)data;
|
||||
|
||||
if (query != NULL) {
|
||||
if (query->server != NULL)
|
||||
query->server->query = NULL;
|
||||
ss_free(query);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
server_resolve_cb(struct sockaddr *addr, void *data)
|
||||
resolv_cb(struct sockaddr *addr, void *data)
|
||||
{
|
||||
query_t *query = (query_t *)data;
|
||||
server_t *server = query->server;
|
||||
struct ev_loop *loop = server->listen_ctx->loop;
|
||||
|
||||
server->query = NULL;
|
||||
if (server == NULL) return;
|
||||
|
||||
struct ev_loop *loop = server->listen_ctx->loop;
|
||||
|
||||
if (addr == NULL) {
|
||||
LOGE("unable to resolve %s", query->hostname);
|
||||
@@ -1375,7 +1387,7 @@ close_and_free_server(EV_P_ server_t *server)
|
||||
{
|
||||
if (server != NULL) {
|
||||
if (server->query != NULL) {
|
||||
resolv_cancel(server->query);
|
||||
server->query->server = NULL;
|
||||
server->query = NULL;
|
||||
}
|
||||
ev_io_stop(EV_A_ & server->send_ctx->io);
|
||||
@@ -1484,8 +1496,7 @@ main(int argc, char **argv)
|
||||
int server_num = 0;
|
||||
const char *server_host[MAX_REMOTE_NUM];
|
||||
|
||||
char *nameservers[MAX_DNS_NUM + 1];
|
||||
int nameserver_num = 0;
|
||||
char *nameservers = NULL;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{ "fast-open", no_argument, NULL, GETOPT_VAL_FAST_OPEN },
|
||||
@@ -1574,9 +1585,7 @@ main(int argc, char **argv)
|
||||
iface = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
if (nameserver_num < MAX_DNS_NUM) {
|
||||
nameservers[nameserver_num++] = optarg;
|
||||
}
|
||||
nameservers = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
user = optarg;
|
||||
@@ -1675,8 +1684,8 @@ main(int argc, char **argv)
|
||||
nofile = conf->nofile;
|
||||
}
|
||||
#endif
|
||||
if (conf->nameserver != NULL) {
|
||||
nameservers[nameserver_num++] = conf->nameserver;
|
||||
if (nameservers == NULL) {
|
||||
nameservers = conf->nameserver;
|
||||
}
|
||||
if (ipv6first == 0) {
|
||||
ipv6first = conf->ipv6_first;
|
||||
@@ -1776,15 +1785,11 @@ main(int argc, char **argv)
|
||||
// initialize ev loop
|
||||
struct ev_loop *loop = EV_DEFAULT;
|
||||
|
||||
// setup udns
|
||||
if (nameserver_num == 0) {
|
||||
resolv_init(loop, NULL, 0, ipv6first);
|
||||
} else {
|
||||
resolv_init(loop, nameservers, nameserver_num, ipv6first);
|
||||
}
|
||||
// setup dns
|
||||
resolv_init(loop, nameservers, ipv6first);
|
||||
|
||||
for (int i = 0; i < nameserver_num; i++)
|
||||
LOGI("using nameserver: %s", nameservers[i]);
|
||||
if (nameservers != NULL)
|
||||
LOGI("using nameserver: %s", nameservers);
|
||||
|
||||
// Start plugin server
|
||||
if (plugin != NULL) {
|
||||
@@ -1909,6 +1914,9 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
// Clean up
|
||||
|
||||
resolv_shutdown(loop);
|
||||
|
||||
for (int i = 0; i < server_num; i++) {
|
||||
listen_ctx_t *listen_ctx = &listen_ctx_list[i];
|
||||
if (mode != UDP_ONLY) {
|
||||
@@ -1926,7 +1934,5 @@ main(int argc, char **argv)
|
||||
free_udprelay();
|
||||
}
|
||||
|
||||
resolv_shutdown(loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+3
-1
@@ -67,6 +67,8 @@ struct dscptracker {
|
||||
|
||||
#endif
|
||||
|
||||
struct query;
|
||||
|
||||
typedef struct server {
|
||||
int fd;
|
||||
int stage;
|
||||
@@ -81,7 +83,7 @@ typedef struct server {
|
||||
struct listen_ctx *listen_ctx;
|
||||
struct remote *remote;
|
||||
|
||||
struct ResolvQuery *query;
|
||||
struct query *query;
|
||||
|
||||
struct cork_dllist_item entries;
|
||||
#ifdef USE_NFCONNTRACK_TOS
|
||||
|
||||
+2
-3
@@ -47,7 +47,6 @@
|
||||
#endif
|
||||
|
||||
#include <libcork/core.h>
|
||||
#include <udns.h>
|
||||
|
||||
#include "netutils.h"
|
||||
#include "utils.h"
|
||||
@@ -416,7 +415,7 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
|
||||
memset(&host, 0, sizeof(struct in_addr));
|
||||
int host_len = sizeof(struct in_addr);
|
||||
|
||||
if (dns_pton(AF_INET, sa->host, &host) == -1) {
|
||||
if (inet_pton(AF_INET, sa->host, &host) == -1) {
|
||||
FATAL("IP parser error");
|
||||
}
|
||||
abuf->data[abuf->len++] = 1;
|
||||
@@ -428,7 +427,7 @@ remote_send_cb(EV_P_ ev_io *w, int revents)
|
||||
memset(&host, 0, sizeof(struct in6_addr));
|
||||
int host_len = sizeof(struct in6_addr);
|
||||
|
||||
if (dns_pton(AF_INET6, sa->host, &host) == -1) {
|
||||
if (inet_pton(AF_INET6, sa->host, &host) == -1) {
|
||||
FATAL("IP parser error");
|
||||
}
|
||||
abuf->data[abuf->len++] = 4;
|
||||
|
||||
+31
-28
@@ -47,7 +47,6 @@
|
||||
#endif
|
||||
|
||||
#include <libcork/core.h>
|
||||
#include <udns.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "netutils.h"
|
||||
@@ -80,7 +79,8 @@ static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents);
|
||||
|
||||
static char *hash_key(const int af, const struct sockaddr_storage *addr);
|
||||
#ifdef MODULE_REMOTE
|
||||
static void query_resolve_cb(struct sockaddr *addr, void *data);
|
||||
static void resolv_free_cb(void *data);
|
||||
static void resolv_cb(struct sockaddr *addr, void *data);
|
||||
#endif
|
||||
static void close_and_free_remote(EV_P_ remote_ctx_t *ctx);
|
||||
static remote_ctx_t *new_remote(int fd, server_ctx_t *server_ctx);
|
||||
@@ -241,7 +241,7 @@ parse_udprelay_header(const char *buf, const size_t buf_len,
|
||||
addr->sin_port = *(uint16_t *)(buf + offset + in_addr_len);
|
||||
}
|
||||
if (host != NULL) {
|
||||
dns_ntop(AF_INET, (const void *)(buf + offset),
|
||||
inet_ntop(AF_INET, (const void *)(buf + offset),
|
||||
host, INET_ADDRSTRLEN);
|
||||
}
|
||||
offset += in_addr_len;
|
||||
@@ -257,12 +257,12 @@ parse_udprelay_header(const char *buf, const size_t buf_len,
|
||||
if (cork_ip_init(&ip, tmp) != -1) {
|
||||
if (ip.version == 4) {
|
||||
struct sockaddr_in *addr = (struct sockaddr_in *)storage;
|
||||
dns_pton(AF_INET, tmp, &(addr->sin_addr));
|
||||
inet_pton(AF_INET, tmp, &(addr->sin_addr));
|
||||
addr->sin_port = *(uint16_t *)(buf + offset + 1 + name_len);
|
||||
addr->sin_family = AF_INET;
|
||||
} else if (ip.version == 6) {
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)storage;
|
||||
dns_pton(AF_INET, tmp, &(addr->sin6_addr));
|
||||
inet_pton(AF_INET, tmp, &(addr->sin6_addr));
|
||||
addr->sin6_port = *(uint16_t *)(buf + offset + 1 + name_len);
|
||||
addr->sin6_family = AF_INET6;
|
||||
}
|
||||
@@ -284,7 +284,7 @@ parse_udprelay_header(const char *buf, const size_t buf_len,
|
||||
addr->sin6_port = *(uint16_t *)(buf + offset + in6_addr_len);
|
||||
}
|
||||
if (host != NULL) {
|
||||
dns_ntop(AF_INET6, (const void *)(buf + offset),
|
||||
inet_ntop(AF_INET6, (const void *)(buf + offset),
|
||||
host, INET6_ADDRSTRLEN);
|
||||
}
|
||||
offset += in6_addr_len;
|
||||
@@ -315,14 +315,14 @@ get_addr_str(const struct sockaddr *sa)
|
||||
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
dns_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
|
||||
inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
|
||||
addr, INET_ADDRSTRLEN);
|
||||
p = ntohs(((struct sockaddr_in *)sa)->sin_port);
|
||||
sprintf(port, "%d", p);
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
dns_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
|
||||
inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
|
||||
addr, INET6_ADDRSTRLEN);
|
||||
p = ntohs(((struct sockaddr_in *)sa)->sin_port);
|
||||
sprintf(port, "%d", p);
|
||||
@@ -535,10 +535,6 @@ void
|
||||
close_and_free_query(EV_P_ struct query_ctx *ctx)
|
||||
{
|
||||
if (ctx != NULL) {
|
||||
if (ctx->query != NULL) {
|
||||
resolv_cancel(ctx->query);
|
||||
ctx->query = NULL;
|
||||
}
|
||||
if (ctx->buf != NULL) {
|
||||
bfree(ctx->buf);
|
||||
ss_free(ctx->buf);
|
||||
@@ -576,19 +572,24 @@ remote_timeout_cb(EV_P_ ev_timer *watcher, int revents)
|
||||
|
||||
#ifdef MODULE_REMOTE
|
||||
static void
|
||||
query_resolve_cb(struct sockaddr *addr, void *data)
|
||||
resolv_free_cb(void *data)
|
||||
{
|
||||
struct query_ctx *ctx = (struct query_ctx *)data;
|
||||
if (ctx->buf != NULL) {
|
||||
bfree(ctx->buf);
|
||||
ss_free(ctx->buf);
|
||||
}
|
||||
ss_free(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
resolv_cb(struct sockaddr *addr, void *data)
|
||||
{
|
||||
struct query_ctx *query_ctx = (struct query_ctx *)data;
|
||||
struct ev_loop *loop = query_ctx->server_ctx->loop;
|
||||
|
||||
if (verbose) {
|
||||
LOGI("[udp] udns resolved");
|
||||
}
|
||||
|
||||
query_ctx->query = NULL;
|
||||
|
||||
if (addr == NULL) {
|
||||
LOGE("[udp] udns returned an error");
|
||||
LOGE("[udp] unable to resolve");
|
||||
} else {
|
||||
remote_ctx_t *remote_ctx = query_ctx->remote_ctx;
|
||||
int cache_hit = 0;
|
||||
@@ -634,7 +635,10 @@ query_resolve_cb(struct sockaddr *addr, void *data)
|
||||
}
|
||||
|
||||
if (remote_ctx != NULL) {
|
||||
memcpy(&remote_ctx->dst_addr, addr, sizeof(struct sockaddr_storage));
|
||||
if (addr->sa_family == AF_INET)
|
||||
memcpy(&remote_ctx->dst_addr, addr, sizeof(struct sockaddr_in));
|
||||
else
|
||||
memcpy(&remote_ctx->dst_addr, addr, sizeof(struct sockaddr_in6));
|
||||
|
||||
size_t addr_len = get_sockaddr_len(addr);
|
||||
int s = sendto(remote_ctx->fd, query_ctx->buf->data, query_ctx->buf->len,
|
||||
@@ -656,9 +660,6 @@ query_resolve_cb(struct sockaddr *addr, void *data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
close_and_free_query(EV_A_ query_ctx);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1007,7 +1008,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
memset(&host_addr, 0, sizeof(struct in_addr));
|
||||
int host_len = sizeof(struct in_addr);
|
||||
|
||||
if (dns_pton(AF_INET, host, &host_addr) == -1) {
|
||||
if (inet_pton(AF_INET, host, &host_addr) == -1) {
|
||||
FATAL("IP parser error");
|
||||
}
|
||||
addr_header[addr_header_len++] = 1;
|
||||
@@ -1019,7 +1020,7 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
memset(&host_addr, 0, sizeof(struct in6_addr));
|
||||
int host_len = sizeof(struct in6_addr);
|
||||
|
||||
if (dns_pton(AF_INET6, host, &host_addr) == -1) {
|
||||
if (inet_pton(AF_INET6, host, &host_addr) == -1) {
|
||||
FATAL("IP parser error");
|
||||
}
|
||||
addr_header[addr_header_len++] = 4;
|
||||
@@ -1295,13 +1296,15 @@ server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
query_ctx->remote_ctx = remote_ctx;
|
||||
}
|
||||
|
||||
struct ResolvQuery *query = resolv_query(host, query_resolve_cb,
|
||||
NULL, query_ctx, htons(atoi(port)));
|
||||
struct resolv_query *query = resolv_start(host, htons(atoi(port)),
|
||||
resolv_cb, resolv_free_cb, query_ctx);
|
||||
|
||||
if (query == NULL) {
|
||||
ERROR("[udp] unable to create DNS query");
|
||||
close_and_free_query(EV_A_ query_ctx);
|
||||
goto CLEAN_UP;
|
||||
}
|
||||
|
||||
query_ctx->query = query;
|
||||
}
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ typedef struct server_ctx {
|
||||
|
||||
#ifdef MODULE_REMOTE
|
||||
typedef struct query_ctx {
|
||||
struct ResolvQuery *query;
|
||||
struct resolv_query *query;
|
||||
struct sockaddr_storage src_addr;
|
||||
buffer_t *buf;
|
||||
int addr_header_len;
|
||||
|
||||
Reference in New Issue
Block a user