mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-17 21:25:50 +02:00
PROXYv2 downstream support (#760)
This commit is contained in:
@@ -16,7 +16,7 @@ NEED_WHOAMI='07-confroot.tdir'
|
||||
NEED_IPV6='fwd_ancil.tdir fwd_tcp_tc6.tdir stub_udp6.tdir edns_cache.tdir'
|
||||
NEED_NOMINGW='tcp_sigpipe.tdir 07-confroot.tdir 08-host-lib.tdir fwd_ancil.tdir'
|
||||
NEED_DNSCRYPT_PROXY='dnscrypt_queries.tdir dnscrypt_queries_chacha.tdir'
|
||||
NEED_UNSHARE='acl_interface.tdir'
|
||||
NEED_UNSHARE='acl_interface.tdir proxy_protocol.tdir'
|
||||
|
||||
# test if dig and ldns-testns are available.
|
||||
test_tool_avail "dig"
|
||||
|
||||
+11
-8
@@ -384,8 +384,8 @@ answer_callback_from_entry(struct replay_runtime* runtime,
|
||||
fill_buffer_with_reply(c.buffer, entry, pend->pkt, pend->pkt_len,
|
||||
pend->tcp_pkt_counter);
|
||||
repinfo.c = &c;
|
||||
repinfo.addrlen = pend->addrlen;
|
||||
memcpy(&repinfo.addr, &pend->addr, pend->addrlen);
|
||||
repinfo.remote_addrlen = pend->addrlen;
|
||||
memcpy(&repinfo.remote_addr, &pend->addr, pend->addrlen);
|
||||
if(!pend->serviced) {
|
||||
if(entry && entry->reply_list->next &&
|
||||
pend->tcp_pkt_counter < count_reply_packets(entry)) {
|
||||
@@ -415,7 +415,7 @@ answer_check_it(struct replay_runtime* runtime)
|
||||
tr = transport_udp;
|
||||
if((runtime->now->addrlen == 0 || sockaddr_cmp(
|
||||
&runtime->now->addr, runtime->now->addrlen,
|
||||
&ans->repinfo.addr, ans->repinfo.addrlen) == 0) &&
|
||||
&ans->repinfo.remote_addr, ans->repinfo.remote_addrlen) == 0) &&
|
||||
find_match(runtime->now->match, ans->pkt,
|
||||
ans->pkt_len, tr)) {
|
||||
log_info("testbound matched event entry from line %d",
|
||||
@@ -453,10 +453,12 @@ fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo)
|
||||
repinfo.c = (struct comm_point*)calloc(1, sizeof(struct comm_point));
|
||||
if(!repinfo.c)
|
||||
fatal_exit("out of memory in fake_front_query");
|
||||
repinfo.addrlen = (socklen_t)sizeof(struct sockaddr_in);
|
||||
repinfo.remote_addrlen = (socklen_t)sizeof(struct sockaddr_in);
|
||||
if(todo->addrlen != 0) {
|
||||
repinfo.addrlen = todo->addrlen;
|
||||
memcpy(&repinfo.addr, &todo->addr, todo->addrlen);
|
||||
repinfo.remote_addrlen = todo->addrlen;
|
||||
memcpy(&repinfo.remote_addr, &todo->addr, todo->addrlen);
|
||||
repinfo.client_addrlen = todo->addrlen;
|
||||
memcpy(&repinfo.client_addr, &todo->addr, todo->addrlen);
|
||||
}
|
||||
repinfo.c->fd = -1;
|
||||
repinfo.c->ev = (struct internal_event*)runtime;
|
||||
@@ -510,8 +512,8 @@ fake_pending_callback(struct replay_runtime* runtime,
|
||||
p->pkt_len, p->tcp_pkt_counter);
|
||||
}
|
||||
repinfo.c = &c;
|
||||
repinfo.addrlen = p->addrlen;
|
||||
memcpy(&repinfo.addr, &p->addr, p->addrlen);
|
||||
repinfo.remote_addrlen = p->addrlen;
|
||||
memcpy(&repinfo.remote_addr, &p->addr, p->addrlen);
|
||||
if(!p->serviced) {
|
||||
if(todo->match && todo->match->reply_list->next && !error &&
|
||||
p->tcp_pkt_counter < count_reply_packets(todo->match)) {
|
||||
@@ -1663,6 +1665,7 @@ int create_udp_sock(int ATTR_UNUSED(family), int ATTR_UNUSED(socktype),
|
||||
|
||||
struct comm_point* comm_point_create_udp(struct comm_base *ATTR_UNUSED(base),
|
||||
int ATTR_UNUSED(fd), sldns_buffer* ATTR_UNUSED(buffer),
|
||||
int ATTR_UNUSED(pp2_enabled),
|
||||
comm_point_callback_type* ATTR_UNUSED(callback),
|
||||
void* ATTR_UNUSED(callback_arg),
|
||||
struct unbound_socket* ATTR_UNUSED(socket))
|
||||
|
||||
+101
-27
@@ -49,6 +49,7 @@
|
||||
#include "util/locks.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/proxy_protocol.h"
|
||||
#include "util/data/msgencode.h"
|
||||
#include "util/data/msgparse.h"
|
||||
#include "util/data/msgreply.h"
|
||||
@@ -71,6 +72,7 @@ static void usage(char* argv[])
|
||||
printf("usage: %s [options] name type class ...\n", argv[0]);
|
||||
printf(" sends the name-type-class queries over TCP.\n");
|
||||
printf("-f server what ipaddr@portnr to send the queries to\n");
|
||||
printf("-p client what ipaddr@portnr to include in PROXYv2\n");
|
||||
printf("-u use UDP. No retries are attempted.\n");
|
||||
printf("-n do not wait for an answer.\n");
|
||||
printf("-a print answers as they arrive.\n");
|
||||
@@ -82,18 +84,17 @@ static void usage(char* argv[])
|
||||
|
||||
/** open TCP socket to svr */
|
||||
static int
|
||||
open_svr(const char* svr, int udp)
|
||||
open_svr(const char* svr, int udp, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int fd = -1;
|
||||
/* svr can be ip@port */
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
if(!extstrtoaddr(svr, &addr, &addrlen, UNBOUND_DNS_PORT)) {
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
if(!extstrtoaddr(svr, addr, addrlen, UNBOUND_DNS_PORT)) {
|
||||
printf("fatal: bad server specs '%s'\n", svr);
|
||||
exit(1);
|
||||
}
|
||||
fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET,
|
||||
fd = socket(addr_is_ip6(addr, *addrlen)?PF_INET6:PF_INET,
|
||||
udp?SOCK_DGRAM:SOCK_STREAM, 0);
|
||||
if(fd == -1) {
|
||||
#ifndef USE_WINSOCK
|
||||
@@ -103,7 +104,7 @@ open_svr(const char* svr, int udp)
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
|
||||
if(connect(fd, (struct sockaddr*)addr, *addrlen) < 0) {
|
||||
#ifndef USE_WINSOCK
|
||||
perror("connect() error");
|
||||
#else
|
||||
@@ -116,11 +117,12 @@ open_svr(const char* svr, int udp)
|
||||
|
||||
/** write a query over the TCP fd */
|
||||
static void
|
||||
write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||
write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||
sldns_buffer* proxy_buf, int pp2_parsed,
|
||||
const char* strname, const char* strtype, const char* strclass)
|
||||
{
|
||||
struct query_info qinfo;
|
||||
uint16_t len;
|
||||
size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf);
|
||||
/* qname */
|
||||
qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len);
|
||||
if(!qinfo.qname) {
|
||||
@@ -152,9 +154,27 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||
attach_edns_record(buf, &edns);
|
||||
}
|
||||
|
||||
/* we need to send the PROXYv2 information in every UDP message */
|
||||
if(udp && pp2_parsed) {
|
||||
/* append the proxy_buf with the buf's content
|
||||
* and use that for sending */
|
||||
if(sldns_buffer_capacity(proxy_buf) <
|
||||
sldns_buffer_limit(proxy_buf) +
|
||||
sldns_buffer_limit(buf)) {
|
||||
printf("buffer too small for packet + proxy");
|
||||
exit(1);
|
||||
}
|
||||
sldns_buffer_clear(proxy_buf);
|
||||
sldns_buffer_skip(proxy_buf, proxy_buf_limit);
|
||||
sldns_buffer_write(proxy_buf, sldns_buffer_begin(buf),
|
||||
sldns_buffer_limit(buf));
|
||||
sldns_buffer_flip(proxy_buf);
|
||||
buf = proxy_buf;
|
||||
}
|
||||
|
||||
/* send it */
|
||||
if(!udp) {
|
||||
len = (uint16_t)sldns_buffer_limit(buf);
|
||||
uint16_t len = (uint16_t)sldns_buffer_limit(buf);
|
||||
len = htons(len);
|
||||
if(ssl) {
|
||||
if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
|
||||
@@ -167,7 +187,7 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||
#ifndef USE_WINSOCK
|
||||
perror("send() len failed");
|
||||
#else
|
||||
printf("send len: %s\n",
|
||||
printf("send len: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
@@ -182,17 +202,20 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||
}
|
||||
} else {
|
||||
if(send(fd, (void*)sldns_buffer_begin(buf),
|
||||
sldns_buffer_limit(buf), 0) <
|
||||
sldns_buffer_limit(buf), 0) <
|
||||
(ssize_t)sldns_buffer_limit(buf)) {
|
||||
#ifndef USE_WINSOCK
|
||||
perror("send() data failed");
|
||||
#else
|
||||
printf("send data: %s\n", wsa_strerror(WSAGetLastError()));
|
||||
printf("send data: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* reset the proxy_buf for next packet */
|
||||
sldns_buffer_set_limit(proxy_buf, proxy_buf_limit);
|
||||
free(qinfo.qname);
|
||||
}
|
||||
|
||||
@@ -224,7 +247,7 @@ recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
|
||||
#ifndef USE_WINSOCK
|
||||
perror("read() len failed");
|
||||
#else
|
||||
printf("read len: %s\n",
|
||||
printf("read len: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
@@ -243,12 +266,12 @@ recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
|
||||
if(r != (int)len)
|
||||
fatal_exit("ssl_read %d of %d", r, len);
|
||||
} else {
|
||||
if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) <
|
||||
if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) <
|
||||
(ssize_t)len) {
|
||||
#ifndef USE_WINSOCK
|
||||
perror("read() data failed");
|
||||
#else
|
||||
printf("read data: %s\n",
|
||||
printf("read data: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
@@ -257,12 +280,12 @@ recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
|
||||
} else {
|
||||
ssize_t l;
|
||||
sldns_buffer_clear(buf);
|
||||
if((l=recv(fd, (void*)sldns_buffer_begin(buf),
|
||||
if((l=recv(fd, (void*)sldns_buffer_begin(buf),
|
||||
sldns_buffer_capacity(buf), 0)) < 0) {
|
||||
#ifndef USE_WINSOCK
|
||||
perror("read() data failed");
|
||||
#else
|
||||
printf("read data: %s\n",
|
||||
printf("read data: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
@@ -324,17 +347,40 @@ static int get_random(void)
|
||||
return (int)arc4random();
|
||||
}
|
||||
|
||||
/* parse the pp2_client and populate the proxy_buffer
|
||||
* It doesn't populate the destination parts. */
|
||||
static int parse_pp2_client(const char* pp2_client, int udp,
|
||||
sldns_buffer* proxy_buf)
|
||||
{
|
||||
struct sockaddr_storage pp2_addr;
|
||||
socklen_t pp2_addrlen = 0;
|
||||
memset(&pp2_addr, 0, sizeof(pp2_addr));
|
||||
if(*pp2_client == 0) return 0;
|
||||
if(!extstrtoaddr(pp2_client, &pp2_addr, &pp2_addrlen, UNBOUND_DNS_PORT)) {
|
||||
printf("fatal: bad proxy client specs '%s'\n", pp2_client);
|
||||
exit(1);
|
||||
}
|
||||
sldns_buffer_clear(proxy_buf);
|
||||
pp2_write_to_buf(proxy_buf, &pp2_addr, !udp);
|
||||
sldns_buffer_flip(proxy_buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** send the TCP queries and print answers */
|
||||
static void
|
||||
send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
|
||||
int delay, int num, char** qs)
|
||||
send_em(const char* svr, const char* pp2_client, int udp, int usessl,
|
||||
int noanswer, int onarrival, int delay, int num, char** qs)
|
||||
{
|
||||
sldns_buffer* buf = sldns_buffer_new(65553);
|
||||
int fd = open_svr(svr, udp);
|
||||
int i, wait_results = 0;
|
||||
sldns_buffer* proxy_buf = sldns_buffer_new(65553);
|
||||
struct sockaddr_storage svr_addr;
|
||||
socklen_t svr_addrlen;
|
||||
int fd = open_svr(svr, udp, &svr_addr, &svr_addrlen);
|
||||
int i, wait_results = 0, pp2_parsed;
|
||||
SSL_CTX* ctx = NULL;
|
||||
SSL* ssl = NULL;
|
||||
if(!buf) fatal_exit("out of memory");
|
||||
pp2_parsed = parse_pp2_client(pp2_client, udp, proxy_buf);
|
||||
if(usessl) {
|
||||
ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
|
||||
if(!ctx) fatal_exit("cannot create ssl ctx");
|
||||
@@ -361,6 +407,28 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Send the PROXYv2 information once per stream */
|
||||
if(!udp && pp2_parsed) {
|
||||
if(ssl) {
|
||||
if(SSL_write(ssl, (void*)sldns_buffer_begin(proxy_buf),
|
||||
(int)sldns_buffer_limit(proxy_buf)) <= 0) {
|
||||
log_crypto_err("cannot SSL_write");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
if(send(fd, (void*)sldns_buffer_begin(proxy_buf),
|
||||
sldns_buffer_limit(proxy_buf), 0) <
|
||||
(ssize_t)sldns_buffer_limit(proxy_buf)) {
|
||||
#ifndef USE_WINSOCK
|
||||
perror("send() data failed");
|
||||
#else
|
||||
printf("send data: %s\n",
|
||||
wsa_strerror(WSAGetLastError()));
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i=0; i<num; i+=3) {
|
||||
if (delay != 0) {
|
||||
#ifdef HAVE_SLEEP
|
||||
@@ -370,8 +438,9 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
|
||||
#endif
|
||||
}
|
||||
printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
|
||||
write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i],
|
||||
qs[i+1], qs[i+2]);
|
||||
write_q(fd, udp, ssl, buf, (uint16_t)get_random(), proxy_buf,
|
||||
pp2_parsed,
|
||||
qs[i], qs[i+1], qs[i+2]);
|
||||
/* print at least one result */
|
||||
if(onarrival) {
|
||||
wait_results += 1; /* one more answer to fetch */
|
||||
@@ -390,6 +459,7 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
|
||||
}
|
||||
sock_close(fd);
|
||||
sldns_buffer_free(buf);
|
||||
sldns_buffer_free(proxy_buf);
|
||||
printf("orderly exit\n");
|
||||
}
|
||||
|
||||
@@ -418,10 +488,11 @@ extern int optind;
|
||||
extern char* optarg;
|
||||
|
||||
/** main program for streamtcp */
|
||||
int main(int argc, char** argv)
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int c;
|
||||
const char* svr = "127.0.0.1";
|
||||
const char* pp2_client = "";
|
||||
int udp = 0;
|
||||
int noanswer = 0;
|
||||
int onarrival = 0;
|
||||
@@ -451,11 +522,14 @@ int main(int argc, char** argv)
|
||||
if(argc == 1) {
|
||||
usage(argv);
|
||||
}
|
||||
while( (c=getopt(argc, argv, "af:hnsud:")) != -1) {
|
||||
while( (c=getopt(argc, argv, "af:p:hnsud:")) != -1) {
|
||||
switch(c) {
|
||||
case 'f':
|
||||
svr = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
pp2_client = optarg;
|
||||
break;
|
||||
case 'a':
|
||||
onarrival = 1;
|
||||
break;
|
||||
@@ -508,7 +582,7 @@ int main(int argc, char** argv)
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
#endif
|
||||
}
|
||||
send_em(svr, udp, usessl, noanswer, onarrival, delay, argc, argv);
|
||||
send_em(svr, pp2_client, udp, usessl, noanswer, onarrival, delay, argc, argv);
|
||||
checklock_stop();
|
||||
#ifdef USE_WINSOCK
|
||||
WSACleanup();
|
||||
|
||||
Reference in New Issue
Block a user