mirror of
https://github.com/cofyc/dnscrypt-wrapper.git
synced 2024-10-04 07:07:08 +03:00
support tcp protocol
This commit is contained in:
parent
723a512a2d
commit
1e4c13352e
1
Makefile
1
Makefile
@ -20,6 +20,7 @@ LIB_H = dnscrypt.h udp_request.h edns.h logger.h dnscrypt-proxy/src/libevent/inc
|
||||
|
||||
LIB_OBJS += dnscrypt.o
|
||||
LIB_OBJS += udp_request.o
|
||||
LIB_OBJS += tcp_request.o
|
||||
LIB_OBJS += edns.o
|
||||
LIB_OBJS += logger.o
|
||||
LIB_OBJS += main.o
|
||||
|
@ -11,8 +11,6 @@ This is dnscrypt wrapper (server-side dnscrypt proxy), which helps to add dnscry
|
||||
This software is modified from
|
||||
[dnscrypt-proxy](https://github.com/opendns/dnscrypt-proxy).
|
||||
|
||||
Only udp protocol is supported now, tcp is work in progress.
|
||||
|
||||
INSTALLATION
|
||||
============
|
||||
|
||||
|
2
TODO
2
TODO
@ -1,2 +1,2 @@
|
||||
* support tcp protocol
|
||||
* reconnect to resolver server?
|
||||
* test framework?
|
||||
|
2
compat.h
2
compat.h
@ -37,6 +37,8 @@
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/queue.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[1]))
|
||||
#define COMPILER_ASSERT(X) (void) sizeof(char[(X) ? 1 : -1])
|
||||
|
10
dnscrypt.h
10
dnscrypt.h
@ -2,8 +2,10 @@
|
||||
#define DNSCRYPT_H
|
||||
|
||||
#include "compat.h"
|
||||
#include <sys/queue.h>
|
||||
#include <event2/event.h>
|
||||
#include <event2/listener.h>
|
||||
#include <event2/bufferevent.h>
|
||||
#include <event2/buffer.h>
|
||||
#include <event2/util.h>
|
||||
#include <crypto_box.h>
|
||||
#include <crypto_stream.h>
|
||||
@ -72,6 +74,7 @@
|
||||
|
||||
#include "edns.h"
|
||||
#include "udp_request.h"
|
||||
#include "tcp_request.h"
|
||||
#include "rfc1035.h"
|
||||
#include "logger.h"
|
||||
#include "salsa20_random.h"
|
||||
@ -80,6 +83,8 @@
|
||||
|
||||
#define DNSCRYPT_QUERY_HEADER_SIZE \
|
||||
(DNSCRYPT_MAGIC_HEADER_LEN + crypto_box_PUBLICKEYBYTES + crypto_box_HALF_NONCEBYTES + crypto_box_MACBYTES)
|
||||
#define DNSCRYPT_RESPONSE_HEADER_SIZE \
|
||||
(DNSCRYPT_MAGIC_HEADER_LEN + crypto_box_NONCEBYTES + crypto_box_MACBYTES)
|
||||
|
||||
#define DNSCRYPT_REPLY_HEADER_SIZE \
|
||||
(DNSCRYPT_MAGIC_HEADER_LEN + crypto_box_HALF_NONCEBYTES * 2 + crypto_box_MACBYTES)
|
||||
@ -91,6 +96,8 @@ struct context {
|
||||
ev_socklen_t resolver_sockaddr_len;
|
||||
const char *resolver_address;
|
||||
const char *listen_address;
|
||||
struct evconnlistener *tcp_conn_listener;
|
||||
struct event *tcp_accept_timer;
|
||||
struct event *udp_listener_event;
|
||||
struct event *udp_resolver_event;
|
||||
evutil_socket_t udp_listener_handle;
|
||||
@ -107,7 +114,6 @@ struct context {
|
||||
|
||||
/* Process stuff. */
|
||||
bool daemonize;
|
||||
bool tcp_only;
|
||||
char *user;
|
||||
uid_t user_id;
|
||||
gid_t user_group;
|
||||
|
12
main.c
12
main.c
@ -197,7 +197,6 @@ main(int argc, const char **argv)
|
||||
OPT_STRING('r', "resolver-address", &c.resolver_address, "upstream dns resolver server (<address:port>)"),
|
||||
OPT_STRING('u', "user", &c.user, "run as given user"),
|
||||
OPT_BOOLEAN('d', "daemonize", &c.daemonize, "run as daemon (default: off)"),
|
||||
/*OPT_BOOLEAN('t', "tcp-only", &c.tcp_only, "use tcp only (default: off)"),*/
|
||||
OPT_BOOLEAN('V', "verbose", &verbose, "show verbose logs (specify more -VVV to increase verbosity)"),
|
||||
OPT_STRING('l', "logfile", &c.logfile, "log file path (default: stdout)"),
|
||||
OPT_BOOLEAN(0, "gen-provider-keypair", &gen_provider_keypair, "generate provider key pair"),
|
||||
@ -367,11 +366,13 @@ main(int argc, const char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (udp_listern_bind(&c) != 0) {
|
||||
if (udp_listener_bind(&c) != 0 ||
|
||||
tcp_listener_bind(&c) != 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (udp_listener_start(&c) != 0) {
|
||||
if (udp_listener_start(&c) != 0 ||
|
||||
tcp_listener_start(&c) != 0) {
|
||||
logger(LOG_ERR, "Unable to start udp listener.");
|
||||
exit(1);
|
||||
}
|
||||
@ -380,5 +381,10 @@ main(int argc, const char **argv)
|
||||
|
||||
event_base_dispatch(c.event_loop);
|
||||
|
||||
logger(LOG_INFO, "Stopping proxy");
|
||||
udp_listener_stop(&c);
|
||||
tcp_listener_stop(&c);
|
||||
event_base_free(c.event_loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
441
tcp_request.c
Normal file
441
tcp_request.c
Normal file
@ -0,0 +1,441 @@
|
||||
#include "dnscrypt.h"
|
||||
|
||||
static void
|
||||
tcp_request_kill(TCPRequest * const tcp_request)
|
||||
{
|
||||
if (tcp_request == NULL || tcp_request->status.is_dying) {
|
||||
return;
|
||||
}
|
||||
tcp_request->status.is_dying = 1;
|
||||
struct context *c;
|
||||
|
||||
if (tcp_request->timeout_timer != NULL) {
|
||||
event_free(tcp_request->timeout_timer);
|
||||
tcp_request->timeout_timer = NULL;
|
||||
}
|
||||
if (tcp_request->client_proxy_bev != NULL) {
|
||||
bufferevent_free(tcp_request->client_proxy_bev);
|
||||
tcp_request->client_proxy_bev = NULL;
|
||||
}
|
||||
if (tcp_request->proxy_resolver_bev != NULL) {
|
||||
bufferevent_free(tcp_request->proxy_resolver_bev);
|
||||
tcp_request->proxy_resolver_bev = NULL;
|
||||
}
|
||||
if (tcp_request->proxy_resolver_query_evbuf != NULL) {
|
||||
evbuffer_free(tcp_request->proxy_resolver_query_evbuf);
|
||||
tcp_request->proxy_resolver_query_evbuf = NULL;
|
||||
}
|
||||
c = tcp_request->context;
|
||||
if (tcp_request->status.is_in_queue != 0) {
|
||||
assert(! TAILQ_EMPTY(&c->tcp_request_queue));
|
||||
TAILQ_REMOVE(&c->tcp_request_queue, tcp_request, queue);
|
||||
assert(c->connections > 0U);
|
||||
c->connections--;
|
||||
}
|
||||
tcp_request->context = NULL;
|
||||
free(tcp_request);
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_tune(evutil_socket_t handle)
|
||||
{
|
||||
if (handle == -1) {
|
||||
return;
|
||||
}
|
||||
setsockopt(handle, IPPROTO_TCP, TCP_NODELAY,
|
||||
(void *) (int []) { 1 }, sizeof (int));
|
||||
}
|
||||
|
||||
static void
|
||||
timeout_timer_cb(evutil_socket_t timeout_timer_handle, short ev_flags,
|
||||
void * const tcp_request_)
|
||||
{
|
||||
TCPRequest * const tcp_request = tcp_request_;
|
||||
|
||||
(void) ev_flags;
|
||||
(void) timeout_timer_handle;
|
||||
logger(LOG_WARNING, "resolver timeout (TCP)");
|
||||
tcp_request_kill(tcp_request);
|
||||
}
|
||||
|
||||
int
|
||||
tcp_listener_kill_oldest_request(struct context *c)
|
||||
{
|
||||
if (TAILQ_EMPTY(&c->tcp_request_queue)) {
|
||||
return -1;
|
||||
}
|
||||
tcp_request_kill(TAILQ_FIRST(&c->tcp_request_queue));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
client_proxy_read_cb(struct bufferevent * const client_proxy_bev,
|
||||
void * const tcp_request_)
|
||||
{
|
||||
uint8_t dns_query[DNS_MAX_PACKET_SIZE_TCP - 2U];
|
||||
uint8_t dns_query_len_buf[2];
|
||||
uint8_t dns_curved_query_len_buf[2];
|
||||
TCPRequest *tcp_request = tcp_request_;
|
||||
struct context *c = tcp_request->context;
|
||||
struct evbuffer *input = bufferevent_get_input(client_proxy_bev);
|
||||
size_t available_size;
|
||||
size_t dns_query_len;
|
||||
size_t max_query_size;
|
||||
|
||||
if (tcp_request->status.has_dns_query_len == 0) {
|
||||
assert(evbuffer_get_length(input) >= (size_t) 2U);
|
||||
evbuffer_remove(input, dns_query_len_buf, sizeof dns_query_len_buf);
|
||||
tcp_request->dns_query_len = (size_t)
|
||||
((dns_query_len_buf[0] << 8) | dns_query_len_buf[1]);
|
||||
tcp_request->status.has_dns_query_len = 1;
|
||||
}
|
||||
assert(tcp_request->status.has_dns_query_len != 0);
|
||||
dns_query_len = tcp_request->dns_query_len;
|
||||
if (dns_query_len < (size_t) DNS_HEADER_SIZE) {
|
||||
logger(LOG_WARNING, "Short query received");
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
available_size = evbuffer_get_length(input);
|
||||
if (available_size < dns_query_len) {
|
||||
bufferevent_setwatermark(tcp_request->client_proxy_bev,
|
||||
EV_READ, dns_query_len, dns_query_len);
|
||||
return;
|
||||
}
|
||||
assert(available_size >= dns_query_len);
|
||||
bufferevent_disable(tcp_request->client_proxy_bev, EV_READ);
|
||||
assert(tcp_request->proxy_resolver_query_evbuf == NULL);
|
||||
if ((tcp_request->proxy_resolver_query_evbuf = evbuffer_new()) == NULL) {
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
if ((ssize_t)
|
||||
evbuffer_remove_buffer(input, tcp_request->proxy_resolver_query_evbuf,
|
||||
dns_query_len) != (ssize_t) dns_query_len) {
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
assert(dns_query_len <= sizeof dns_query);
|
||||
if ((ssize_t) evbuffer_remove(tcp_request->proxy_resolver_query_evbuf,
|
||||
dns_query, dns_query_len)
|
||||
!= (ssize_t) dns_query_len) {
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
max_query_size = sizeof dns_query;
|
||||
assert(max_query_size < DNS_MAX_PACKET_SIZE_TCP);
|
||||
assert(SIZE_MAX - DNSCRYPT_MAX_PADDING - DNSCRYPT_QUERY_HEADER_SIZE
|
||||
> dns_query_len);
|
||||
size_t max_len = dns_query_len + DNSCRYPT_MAX_PADDING + DNSCRYPT_QUERY_HEADER_SIZE;
|
||||
if (max_len > max_query_size) {
|
||||
max_len = max_query_size;
|
||||
}
|
||||
if (dns_query_len + DNSCRYPT_QUERY_HEADER_SIZE > max_len) {
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
assert(max_len <= DNS_MAX_PACKET_SIZE_TCP - 2U);
|
||||
assert(max_len <= sizeof dns_query);
|
||||
assert(dns_query_len <= max_len);
|
||||
|
||||
// decrypt if encrypted
|
||||
struct dnscrypt_query_header *dnscrypt_header = (struct dnscrypt_query_header *)dns_query;
|
||||
if (memcmp(dnscrypt_header->magic_query, CERT_MAGIC_HEADER, DNSCRYPT_MAGIC_HEADER_LEN) == 0) {
|
||||
if (dnscrypt_server_uncurve(c, tcp_request->client_nonce, tcp_request->nmkey, dns_query, &dns_query_len) != 0) {
|
||||
logger(LOG_WARNING, "Received a suspicious query from the client");
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
tcp_request->is_dnscrypted = true;
|
||||
} else {
|
||||
tcp_request->is_dnscrypted = false;
|
||||
}
|
||||
|
||||
dns_curved_query_len_buf[0] = (dns_query_len >> 8) & 0xff;
|
||||
dns_curved_query_len_buf[1] = dns_query_len & 0xff;
|
||||
if (bufferevent_write(tcp_request->proxy_resolver_bev,
|
||||
dns_curved_query_len_buf, (size_t) 2U) != 0 ||
|
||||
bufferevent_write(tcp_request->proxy_resolver_bev, dns_query,
|
||||
(size_t) dns_query_len) != 0) {
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
|
||||
bufferevent_enable(tcp_request->proxy_resolver_bev, EV_READ);
|
||||
}
|
||||
|
||||
static void
|
||||
client_proxy_event_cb(struct bufferevent * const client_proxy_bev,
|
||||
const short events, void * const tcp_request_)
|
||||
{
|
||||
TCPRequest * const tcp_request = tcp_request_;
|
||||
|
||||
(void) client_proxy_bev;
|
||||
(void) events;
|
||||
tcp_request_kill(tcp_request);
|
||||
}
|
||||
|
||||
static void
|
||||
client_proxy_write_cb(struct bufferevent * const client_proxy_bev,
|
||||
void * const tcp_request_)
|
||||
{
|
||||
TCPRequest * const tcp_request = tcp_request_;
|
||||
|
||||
(void) client_proxy_bev;
|
||||
tcp_request_kill(tcp_request);
|
||||
}
|
||||
|
||||
static void
|
||||
proxy_resolver_event_cb(struct bufferevent * const proxy_resolver_bev,
|
||||
const short events, void * const tcp_request_)
|
||||
{
|
||||
TCPRequest * const tcp_request = tcp_request_;
|
||||
|
||||
(void) proxy_resolver_bev;
|
||||
if ((events & BEV_EVENT_ERROR) != 0) {
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
if ((events & BEV_EVENT_CONNECTED) == 0) {
|
||||
tcp_tune(bufferevent_getfd(proxy_resolver_bev));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
resolver_proxy_read_cb(struct bufferevent * const proxy_resolver_bev,
|
||||
void * const tcp_request_)
|
||||
{
|
||||
uint8_t dns_reply_len_buf[2];
|
||||
uint8_t dns_uncurved_reply_len_buf[2];
|
||||
uint8_t *dns_reply;
|
||||
TCPRequest *tcp_request = tcp_request_;
|
||||
struct context *c = tcp_request->context;
|
||||
struct evbuffer *input = bufferevent_get_input(proxy_resolver_bev);
|
||||
size_t available_size;
|
||||
size_t dns_reply_len;
|
||||
|
||||
logger(LOG_DEBUG, "Resolver read callback.");
|
||||
if (tcp_request->status.has_dns_reply_len == 0) {
|
||||
assert(evbuffer_get_length(input) >= (size_t) 2U);
|
||||
evbuffer_remove(input, dns_reply_len_buf, sizeof dns_reply_len_buf);
|
||||
tcp_request->dns_reply_len = (size_t)
|
||||
((dns_reply_len_buf[0] << 8) | dns_reply_len_buf[1]);
|
||||
tcp_request->status.has_dns_reply_len = 1;
|
||||
}
|
||||
assert(tcp_request->status.has_dns_reply_len != 0);
|
||||
dns_reply_len = tcp_request->dns_reply_len;
|
||||
if (dns_reply_len <
|
||||
(size_t) DNS_HEADER_SIZE + DNSCRYPT_RESPONSE_HEADER_SIZE) {
|
||||
logger(LOG_WARNING, "Short reply received");
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
available_size = evbuffer_get_length(input);
|
||||
if (available_size < dns_reply_len) {
|
||||
bufferevent_setwatermark(tcp_request->proxy_resolver_bev,
|
||||
EV_READ, dns_reply_len, dns_reply_len);
|
||||
return;
|
||||
}
|
||||
assert(available_size >= dns_reply_len);
|
||||
dns_reply = evbuffer_pullup(input, (ssize_t) dns_reply_len);
|
||||
if (dns_reply == NULL) {
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t max_len = dns_reply_len + DNSCRYPT_MAX_PADDING + DNSCRYPT_REPLY_HEADER_SIZE;
|
||||
|
||||
if (tcp_request->is_dnscrypted) {
|
||||
if (dnscrypt_server_curve(c, tcp_request->client_nonce, tcp_request->nmkey, dns_reply, &dns_reply_len, max_len) != 0) {
|
||||
logger(LOG_ERR, "Curving reply failed.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dns_uncurved_reply_len_buf[0] = (dns_reply_len >> 8) & 0xff;
|
||||
dns_uncurved_reply_len_buf[1] = dns_reply_len & 0xff;
|
||||
if (bufferevent_write(tcp_request->client_proxy_bev,
|
||||
dns_uncurved_reply_len_buf, (size_t) 2U) != 0 ||
|
||||
bufferevent_write(tcp_request->client_proxy_bev, dns_reply,
|
||||
dns_reply_len) != 0) {
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
bufferevent_enable(tcp_request->client_proxy_bev, EV_WRITE);
|
||||
bufferevent_free(tcp_request->proxy_resolver_bev);
|
||||
tcp_request->proxy_resolver_bev = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_connection_cb(struct evconnlistener * const tcp_conn_listener,
|
||||
evutil_socket_t handle,
|
||||
struct sockaddr * const client_sockaddr,
|
||||
const int client_sockaddr_len_int,
|
||||
void * const context)
|
||||
{
|
||||
logger(LOG_DEBUG, "Accepted a connection.");
|
||||
struct context *c = context;
|
||||
TCPRequest *tcp_request;
|
||||
|
||||
(void) tcp_conn_listener;
|
||||
(void) client_sockaddr;
|
||||
(void) client_sockaddr_len_int;
|
||||
if ((tcp_request = calloc((size_t) 1U, sizeof *tcp_request)) == NULL) {
|
||||
return;
|
||||
}
|
||||
tcp_request->context = c;
|
||||
tcp_request->timeout_timer = NULL;
|
||||
tcp_request->proxy_resolver_query_evbuf = NULL;
|
||||
tcp_request->client_proxy_bev = bufferevent_socket_new(c->event_loop,
|
||||
handle, BEV_OPT_CLOSE_ON_FREE);
|
||||
if (tcp_request->client_proxy_bev == NULL) {
|
||||
evutil_closesocket(handle);
|
||||
free(tcp_request);
|
||||
return;
|
||||
}
|
||||
tcp_request->proxy_resolver_bev = bufferevent_socket_new(c->event_loop, -1,
|
||||
BEV_OPT_CLOSE_ON_FREE);
|
||||
if (tcp_request->proxy_resolver_bev == NULL) {
|
||||
bufferevent_free(tcp_request->client_proxy_bev);
|
||||
tcp_request->client_proxy_bev = NULL;
|
||||
free(tcp_request);
|
||||
return;
|
||||
}
|
||||
if (c->connections >=
|
||||
c->connections_max) {
|
||||
if (tcp_listener_kill_oldest_request(c) != 0) {
|
||||
udp_listener_kill_oldest_request(c);
|
||||
}
|
||||
}
|
||||
c->connections++;
|
||||
assert(c->connections
|
||||
<= c->connections_max);
|
||||
TAILQ_INSERT_TAIL(&c->tcp_request_queue,
|
||||
tcp_request, queue);
|
||||
memset(&tcp_request->status, 0, sizeof tcp_request->status);
|
||||
tcp_request->status.is_in_queue = 1;
|
||||
if ((tcp_request->timeout_timer =
|
||||
evtimer_new(tcp_request->context->event_loop,
|
||||
timeout_timer_cb, tcp_request)) == NULL) {
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
const struct timeval tv = {
|
||||
.tv_sec = (time_t) DNS_QUERY_TIMEOUT, .tv_usec = 0
|
||||
};
|
||||
evtimer_add(tcp_request->timeout_timer, &tv);
|
||||
bufferevent_setwatermark(tcp_request->client_proxy_bev,
|
||||
EV_READ, (size_t) 2U,
|
||||
(size_t) DNS_MAX_PACKET_SIZE_TCP);
|
||||
bufferevent_setcb(tcp_request->client_proxy_bev,
|
||||
client_proxy_read_cb, client_proxy_write_cb,
|
||||
client_proxy_event_cb, tcp_request);
|
||||
if (bufferevent_socket_connect
|
||||
(tcp_request->proxy_resolver_bev,
|
||||
(struct sockaddr *) &c->resolver_sockaddr,
|
||||
(int) c->resolver_sockaddr_len) != 0) {
|
||||
tcp_request_kill(tcp_request);
|
||||
return;
|
||||
}
|
||||
bufferevent_setwatermark(tcp_request->proxy_resolver_bev,
|
||||
EV_READ, (size_t) 2U,
|
||||
(size_t) DNS_MAX_PACKET_SIZE_TCP);
|
||||
bufferevent_setcb(tcp_request->proxy_resolver_bev,
|
||||
resolver_proxy_read_cb, NULL, proxy_resolver_event_cb,
|
||||
tcp_request);
|
||||
bufferevent_enable(tcp_request->client_proxy_bev, EV_READ);
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_accept_timer_cb(evutil_socket_t handle, const short event,
|
||||
void * const context)
|
||||
{
|
||||
struct context *c = context;
|
||||
|
||||
(void) handle;
|
||||
(void) event;
|
||||
event_free(c->tcp_accept_timer);
|
||||
c->tcp_accept_timer = NULL;
|
||||
evconnlistener_enable(c->tcp_conn_listener);
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_accept_error_cb(struct evconnlistener * const tcp_conn_listener,
|
||||
void * const context)
|
||||
{
|
||||
struct context *c = context;
|
||||
|
||||
(void)tcp_conn_listener;
|
||||
if (c->tcp_accept_timer == NULL) {
|
||||
c->tcp_accept_timer = evtimer_new
|
||||
(c->event_loop, tcp_accept_timer_cb, c);
|
||||
if (c->tcp_accept_timer == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (evtimer_pending(c->tcp_accept_timer, NULL)) {
|
||||
return;
|
||||
}
|
||||
evconnlistener_disable(c->tcp_conn_listener);
|
||||
|
||||
const struct timeval tv = {
|
||||
.tv_sec = (time_t)1,
|
||||
.tv_usec = 0
|
||||
};
|
||||
evtimer_add(c->tcp_accept_timer, &tv);
|
||||
}
|
||||
|
||||
int
|
||||
tcp_listener_bind(struct context *c)
|
||||
{
|
||||
assert(c->tcp_conn_listener == NULL);
|
||||
#ifndef LEV_OPT_DEFERRED_ACCEPT
|
||||
# define LEV_OPT_DEFERRED_ACCEPT 0
|
||||
#endif
|
||||
c->tcp_conn_listener =
|
||||
evconnlistener_new_bind(c->event_loop,
|
||||
tcp_connection_cb, c,
|
||||
LEV_OPT_CLOSE_ON_FREE |
|
||||
LEV_OPT_CLOSE_ON_EXEC |
|
||||
LEV_OPT_REUSEABLE |
|
||||
LEV_OPT_DEFERRED_ACCEPT,
|
||||
TCP_REQUEST_BACKLOG,
|
||||
(struct sockaddr *)
|
||||
&c->local_sockaddr,
|
||||
(int) c->local_sockaddr_len);
|
||||
if (c->tcp_conn_listener == NULL) {
|
||||
logger(LOG_ERR, "Unable to bind (TCP)");
|
||||
return -1;
|
||||
}
|
||||
if (evconnlistener_disable(c->tcp_conn_listener) != 0) {
|
||||
evconnlistener_free(c->tcp_conn_listener);
|
||||
c->tcp_conn_listener = NULL;
|
||||
return -1;
|
||||
}
|
||||
evconnlistener_set_error_cb(c->tcp_conn_listener,
|
||||
tcp_accept_error_cb);
|
||||
TAILQ_INIT(&c->tcp_request_queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
tcp_listener_start(struct context *c)
|
||||
{
|
||||
assert(c->tcp_conn_listener != NULL);
|
||||
if (evconnlistener_enable(c->tcp_conn_listener) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
tcp_listener_stop(struct context *c)
|
||||
{
|
||||
evconnlistener_free(c->tcp_conn_listener);
|
||||
c->tcp_conn_listener = NULL;
|
||||
while (tcp_listener_kill_oldest_request(c) != 0) { }
|
||||
logger(LOG_INFO, "TCP listener shut down");
|
||||
}
|
40
tcp_request.h
Normal file
40
tcp_request.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef TCP_REQUEST_H
|
||||
#define TCP_REQUEST_H
|
||||
|
||||
#include "dnscrypt.h"
|
||||
|
||||
#define DNS_MAX_PACKET_SIZE_TCP (65535U + 2U)
|
||||
|
||||
#ifndef TCP_REQUEST_BACKLOG
|
||||
# define TCP_REQUEST_BACKLOG 128
|
||||
#endif
|
||||
|
||||
struct context;
|
||||
|
||||
typedef struct TCPRequestStatus_ {
|
||||
bool has_dns_query_len : 1;
|
||||
bool has_dns_reply_len : 1;
|
||||
bool is_in_queue : 1;
|
||||
bool is_dying : 1;
|
||||
} TCPRequestStatus;
|
||||
|
||||
typedef struct TCPRequest_ {
|
||||
uint8_t client_nonce[crypto_box_HALF_NONCEBYTES];
|
||||
uint8_t nmkey[crypto_box_BEFORENMBYTES];
|
||||
TAILQ_ENTRY(TCPRequest_) queue;
|
||||
struct bufferevent *client_proxy_bev;
|
||||
struct bufferevent *proxy_resolver_bev;
|
||||
struct evbuffer *proxy_resolver_query_evbuf;
|
||||
struct context *context;
|
||||
struct event *timeout_timer;
|
||||
TCPRequestStatus status;
|
||||
size_t dns_query_len;
|
||||
size_t dns_reply_len;
|
||||
bool is_dnscrypted;
|
||||
} TCPRequest;
|
||||
|
||||
int tcp_listener_bind(struct context *c);
|
||||
int tcp_listener_start(struct context *c);
|
||||
void tcp_listener_stop(struct context *c);
|
||||
|
||||
#endif
|
9
test.sh
Executable file
9
test.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
# directly to dnscrypt-wrapper
|
||||
dig +short -p 54 twitter.com @127.0.0.1
|
||||
dig +short -p 54 twitter.com @127.0.0.1 +tcp
|
||||
|
||||
# through dnscrypt-proxy
|
||||
dig +short -p 55 twitter.com @127.0.0.1
|
||||
dig +short -p 55 twitter.com @127.0.0.1 +tcp
|
@ -85,7 +85,7 @@ udp_request_kill(UDPRequest * const udp_request)
|
||||
free(udp_request);
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
udp_listener_kill_oldest_request(struct context *c)
|
||||
{
|
||||
if (TAILQ_EMPTY(&c->udp_request_queue))
|
||||
@ -333,10 +333,6 @@ client_to_proxy_cb(evutil_socket_t client_proxy_handle, short ev_flags,
|
||||
dns_query_len = (size_t) nread;
|
||||
assert(dns_query_len <= sizeof(dns_query));
|
||||
|
||||
if (udp_request->context->tcp_only != 0) {
|
||||
proxy_client_send_truncated(udp_request, dns_query, dns_query_len);
|
||||
return;
|
||||
}
|
||||
assert(SIZE_MAX - DNSCRYPT_MAX_PADDING - DNSCRYPT_QUERY_HEADER_SIZE >
|
||||
dns_query_len);
|
||||
|
||||
@ -473,7 +469,7 @@ resolver_to_proxy_cb(evutil_socket_t proxy_resolver_handle, short ev_flags,
|
||||
}
|
||||
|
||||
int
|
||||
udp_listern_bind(struct context *c)
|
||||
udp_listener_bind(struct context *c)
|
||||
{
|
||||
// listen socket & bind
|
||||
assert(c->udp_listener_handle == -1);
|
||||
|
@ -30,8 +30,9 @@ typedef struct UDPRequest_ {
|
||||
typedef TAILQ_HEAD(TCPRequestQueue_, TCPRequest_) TCPRequestQueue;
|
||||
typedef TAILQ_HEAD(UDPRequestQueue_, UDPRequest_) UDPRequestQueue;
|
||||
|
||||
int udp_listern_bind(struct context *c);
|
||||
int udp_listener_bind(struct context *c);
|
||||
int udp_listener_start(struct context *c);
|
||||
void udp_listener_stop(struct context *c);
|
||||
int udp_listener_kill_oldest_request(struct context *c);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user