Browse Source

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
pull/1656/head
Max Lv 7 years ago
committed by GitHub
parent
commit
ede744ae7c
14 changed files with 380 additions and 340 deletions
  1. 10
      README.md
  2. 2
      cmake/configure.cmake
  3. 7
      configure.ac
  4. 10
      src/Makefile.am
  5. 9
      src/local.c
  6. 10
      src/netutils.c
  7. 5
      src/redir.c
  8. 506
      src/resolv.c
  9. 11
      src/resolv.h
  10. 80
      src/server.c
  11. 4
      src/server.h
  12. 5
      src/tunnel.c
  13. 59
      src/udprelay.c
  14. 2
      src/udprelay.h

10
README.md

@ -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

2
cmake/configure.cmake

@ -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)

7
configure.ac

@ -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@:>@.])])

10
src/Makefile.am

@ -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

9
src/local.c

@ -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:

10
src/netutils.c

@ -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));
}

5
src/redir.c

@ -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);
}

506
src/resolv.c

@ -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);
static void dns_query_v4_cb(void *, int, int, struct hostent *);
static void dns_query_v6_cb(void *, int, int, struct hostent *);
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 *);
static void reset_timer();
/*
* DNS UDP socket activity callback
*/
static void
resolv_sock_cb(EV_P_ ev_io *w, int revents)
{
struct resolv_ctx *ctx = (struct resolv_ctx *) w;
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 nameserver_num, int ipv6first)
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;
struct dns_ctx *ctx = &dns_defctx;
if (nameservers == NULL) {
/* Nameservers not specified, use system resolver config */
dns_init(ctx, 0);
} else {
dns_reset(ctx);
default_loop = loop;
for (int i = 0; i < nameserver_num; i++) {
char *server = nameservers[i];
dns_add_serv(ctx, server);
}
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");
}
int sockfd = dns_open(ctx);
if (sockfd < 0) {
FATAL("Failed to open DNS resolver socket");
}
memset(&default_ctx, 0, sizeof(struct resolv_ctx));
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");
}
}
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;
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
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");
}
ev_io_init(&resolv_io_watcher, resolv_sock_cb, sockfd, EV_READ);
resolv_io_watcher.data = ctx;
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
}
ev_io_start(loop, &resolv_io_watcher);
if (status != ARES_SUCCESS) {
FATAL("failed to set nameservers");
}
ev_timer_init(&resolv_timeout_watcher, resolv_timeout_cb, 0.0, 0.0);
resolv_timeout_watcher.data = ctx;
ev_init(&default_ctx.io, resolv_sock_cb);
ev_timer_init(&default_ctx.tw, resolv_timeout_cb, 0.0, 0.0);
dns_set_tmcbck(ctx, dns_timer_setup_cb, loop);
return sockfd;
return 0;
}
void
resolv_shutdown(struct ev_loop *loop)
{
struct dns_ctx *ctx = (struct dns_ctx *)resolv_io_watcher.data;
ares_cancel(default_ctx.channel);
ares_destroy(default_ctx.channel);
ev_io_stop(loop, &resolv_io_watcher);
if (ev_is_active(&resolv_timeout_watcher)) {
ev_timer_stop(loop, &resolv_timeout_watcher);
}
dns_close(ctx);
ares_library_cleanup();
}
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 resolv_query *
resolv_start(const char *hostname, uint16_t port,
void (*client_cb)(struct sockaddr *, void *),
void (*free_cb)(void*), void *data)
{
struct dns_ctx *ctx = (struct dns_ctx *)resolv_io_watcher.data;
/*
* Wrap udns's call back in our own
* Wrap c-ares'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.");
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(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;
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 queries */
/* Submit A and AAAA requests */
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)));
}
ares_gethostbyname(default_ctx.channel, hostname, AF_INET, dns_query_v4_cb, query);
query->requests[0] = AF_INET;
}
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)));
}
ares_gethostbyname(default_ctx.channel, hostname, AF_INET6, dns_query_v6_cb, query);
query->requests[1] = AF_INET6;
}
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);
}
reset_timer();
ss_free(cb_data);
return query;
}
/*
* DNS UDP socket activity callback
* Wrapper for client callback we provide to c-ares
*/
static void
resolv_sock_cb(struct ev_loop *loop, struct ev_io *w, int revents)
dns_query_v4_cb(void *arg, int status, int timeouts, struct hostent *he)
{
struct dns_ctx *ctx = (struct dns_ctx *)w->data;
int i, n;
struct resolv_query *query = (struct resolv_query *)arg;
if (revents & EV_READ) {
dns_ioevent(ctx, ev_now(loop));
if (status == ARES_EDESTRUCTION) {
return;
}
}
/*
* Wrapper for client callback we provide to udns
*/
static void
dns_query_v4_cb(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data)
{
struct ResolvQuery *cb_data = (struct ResolvQuery *)data;
if (result == NULL) {
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 *));
goto CLEANUP;
}
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");
LOGE("failed to allocate memory for additional DNS responses");
} else {
cb_data->responses = new_responses;
query->responses = new_responses;
for (int i = 0; i < result->dnsa4_nrr; i++) {
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];
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");
sa->sin_port = query->port;
memcpy(&sa->sin_addr, he->h_addr_list[i], he->h_length);
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 (status == ARES_EDESTRUCTION) {
return;
}
if (result == NULL) {
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 *));
goto CLEANUP;
}
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");
LOGE("failed to allocate memory for additional DNS responses");
} else {
cb_data->responses = new_responses;
query->responses = new_responses;
for (int i = 0; i < result->dnsa6_nrr; i++) {
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];
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");
sa->sin6_port = query->port;
memcpy(&sa->sin6_addr, he->h_addr_list[i], he->h_length);
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;
}
/*
* DNS timeout callback
*/
static void
resolv_timeout_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
static inline int
all_requests_are_null(struct resolv_query *query)
{
struct dns_ctx *ctx = (struct dns_ctx *)w->data;
int result = 1;
if (revents & EV_TIMER) {
dns_timeouts(ctx, 30, ev_now(loop));
}
for (int i = 0; i < sizeof(query->requests) / sizeof(query->requests[0]);
i++)
result = result && query->requests[i] == 0;
return result;
}
/*
* Callback to setup DNS timeout callback
* DNS timeout callback
*/
static void
dns_timer_setup_cb(struct dns_ctx *ctx, int timeout, void *data)
resolv_timeout_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
{
struct ev_loop *loop = (struct ev_loop *)data;
struct resolv_ctx *ctx= cork_container_of(w, struct resolv_ctx, tw);
if (ev_is_active(&resolv_timeout_watcher)) {
ev_timer_stop(loop, &resolv_timeout_watcher);
}
ares_process_fd(ctx->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
if (ctx != NULL && timeout >= 0) {
ev_timer_set(&resolv_timeout_watcher, timeout, 0.0);
ev_timer_start(loop, &resolv_timeout_watcher);
}
reset_timer();
}
static inline int
all_queries_are_null(struct ResolvQuery *cb_data)
static void
reset_timer()
{
int result = 1;
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);
}
for (int i = 0; i < sizeof(cb_data->queries) / sizeof(cb_data->queries[0]);
i++)
result = result && cb_data->queries[i] == NULL;
/*
* Handle c-ares events
*/
static void
resolv_sock_state_cb(void *data, int s, int read, int write) {
return result;
struct resolv_ctx *ctx = (struct resolv_ctx *) data;
int io_active = ev_is_active(&ctx->io);
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);
}
}

11
src/resolv.h

@ -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

80
src/server.c

@ -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;
}

4
src/server.h

@ -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

5
src/tunnel.c

@ -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;

59
src/udprelay.c

@ -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 *query_ctx = (struct query_ctx *)data;
struct ev_loop *loop = query_ctx->server_ctx->loop;
if (verbose) {
LOGI("[udp] udns resolved");
struct query_ctx *ctx = (struct query_ctx *)data;
if (ctx->buf != NULL) {
bfree(ctx->buf);
ss_free(ctx->buf);
}
ss_free(ctx);
}
query_ctx->query = NULL;
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 (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

2
src/udprelay.h

@ -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;

Loading…
Cancel
Save