mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
Merge branch 'master' into disable-edns-do
This commit is contained in:
commit
eff3e01ec3
15 changed files with 475 additions and 89 deletions
|
|
@ -66,6 +66,7 @@
|
||||||
#include "util/data/msgencode.h"
|
#include "util/data/msgencode.h"
|
||||||
#include "util/data/dname.h"
|
#include "util/data/dname.h"
|
||||||
#include "util/fptr_wlist.h"
|
#include "util/fptr_wlist.h"
|
||||||
|
#include "util/proxy_protocol.h"
|
||||||
#include "util/tube.h"
|
#include "util/tube.h"
|
||||||
#include "util/edns.h"
|
#include "util/edns.h"
|
||||||
#include "util/timeval_func.h"
|
#include "util/timeval_func.h"
|
||||||
|
|
@ -2317,6 +2318,7 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||||
worker->env.cfg->stat_interval);
|
worker->env.cfg->stat_interval);
|
||||||
worker_restart_timer(worker);
|
worker_restart_timer(worker);
|
||||||
}
|
}
|
||||||
|
pp_init(&sldns_write_uint16, &sldns_write_uint32);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,9 @@
|
||||||
|
3 October 2023: George
|
||||||
|
- Merge #881: Generalise the proxy protocol code.
|
||||||
|
|
||||||
|
2 October 2023: George
|
||||||
|
- Fix misplaced comment.
|
||||||
|
|
||||||
22 September 2023: Wouter
|
22 September 2023: Wouter
|
||||||
- Fix #942: 1.18.0 libunbound DNS regression when built without
|
- Fix #942: 1.18.0 libunbound DNS regression when built without
|
||||||
OpenSSL.
|
OpenSSL.
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@
|
||||||
#include "util/random.h"
|
#include "util/random.h"
|
||||||
#include "util/config_file.h"
|
#include "util/config_file.h"
|
||||||
#include "util/netevent.h"
|
#include "util/netevent.h"
|
||||||
|
#include "util/proxy_protocol.h"
|
||||||
#include "util/storage/lookup3.h"
|
#include "util/storage/lookup3.h"
|
||||||
#include "util/storage/slabhash.h"
|
#include "util/storage/slabhash.h"
|
||||||
#include "util/net_help.h"
|
#include "util/net_help.h"
|
||||||
|
|
@ -265,6 +266,7 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
|
||||||
w->env->kill_sub = &mesh_state_delete;
|
w->env->kill_sub = &mesh_state_delete;
|
||||||
w->env->detect_cycle = &mesh_detect_cycle;
|
w->env->detect_cycle = &mesh_detect_cycle;
|
||||||
comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
|
comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
|
||||||
|
pp_init(&sldns_write_uint16, &sldns_write_uint32);
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -550,7 +550,6 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
|
||||||
log_assert(&key_p.reuse != (struct reuse_tcp*)result);
|
log_assert(&key_p.reuse != (struct reuse_tcp*)result);
|
||||||
log_assert(&key_p != ((struct reuse_tcp*)result)->pending);
|
log_assert(&key_p != ((struct reuse_tcp*)result)->pending);
|
||||||
}
|
}
|
||||||
/* not found, return null */
|
|
||||||
|
|
||||||
/* It is possible that we search for something before the first element
|
/* It is possible that we search for something before the first element
|
||||||
* in the tree. Replace a null pointer with the first element.
|
* in the tree. Replace a null pointer with the first element.
|
||||||
|
|
@ -560,6 +559,7 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
|
||||||
result = rbtree_first(&outnet->tcp_reuse);
|
result = rbtree_first(&outnet->tcp_reuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* not found, return null */
|
||||||
if(!result || result == RBTREE_NULL)
|
if(!result || result == RBTREE_NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,17 @@ Specify the server to send the queries to. If not specified localhost (127.0.0.1
|
||||||
.B \-d \fIsecs
|
.B \-d \fIsecs
|
||||||
Delay after the connection before sending query. This tests the timeout
|
Delay after the connection before sending query. This tests the timeout
|
||||||
on the other side, eg. if shorter the connection is closed.
|
on the other side, eg. if shorter the connection is closed.
|
||||||
|
.TP
|
||||||
|
.B \-p \fIclient
|
||||||
|
Use proxy protocol to send the query. Specify the ipaddr@portnr of the client
|
||||||
|
to include in PROXYv2.
|
||||||
|
.TP
|
||||||
|
.B IXFR=serial
|
||||||
|
Pass the type of the query as IXFR=N to send an IXFR query with serial N.
|
||||||
|
.TP
|
||||||
|
.B NOTIFY[=serial]
|
||||||
|
Pass the type of the query as NOTIFY[=N] to send a notify packet. The serial N
|
||||||
|
of the new zone can be included.
|
||||||
.SH "EXAMPLES"
|
.SH "EXAMPLES"
|
||||||
.LP
|
.LP
|
||||||
Some examples of use.
|
Some examples of use.
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,8 @@ static void usage(char* argv[])
|
||||||
printf("-d secs delay after connection before sending query\n");
|
printf("-d secs delay after connection before sending query\n");
|
||||||
printf("-s use ssl\n");
|
printf("-s use ssl\n");
|
||||||
printf("-h this help text\n");
|
printf("-h this help text\n");
|
||||||
|
printf("IXFR=N for the type, sends ixfr query with serial N.\n");
|
||||||
|
printf("NOTIFY[=N] for the type, sends notify. Can set new zone serial N.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,6 +117,29 @@ open_svr(const char* svr, int udp, struct sockaddr_storage* addr,
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Append a SOA record with serial number */
|
||||||
|
static void
|
||||||
|
write_soa_serial_to_buf(sldns_buffer* buf, struct query_info* qinfo,
|
||||||
|
uint32_t serial)
|
||||||
|
{
|
||||||
|
sldns_buffer_set_position(buf, sldns_buffer_limit(buf));
|
||||||
|
sldns_buffer_set_limit(buf, sldns_buffer_capacity(buf));
|
||||||
|
/* Write compressed reference to the query */
|
||||||
|
sldns_buffer_write_u16(buf, PTR_CREATE(LDNS_HEADER_SIZE));
|
||||||
|
sldns_buffer_write_u16(buf, LDNS_RR_TYPE_SOA);
|
||||||
|
sldns_buffer_write_u16(buf, qinfo->qclass);
|
||||||
|
sldns_buffer_write_u32(buf, 3600); /* TTL */
|
||||||
|
sldns_buffer_write_u16(buf, 1+1+4*5); /* rdatalen */
|
||||||
|
sldns_buffer_write_u8(buf, 0); /* primary "." */
|
||||||
|
sldns_buffer_write_u8(buf, 0); /* email "." */
|
||||||
|
sldns_buffer_write_u32(buf, serial); /* serial */
|
||||||
|
sldns_buffer_write_u32(buf, 0); /* refresh */
|
||||||
|
sldns_buffer_write_u32(buf, 0); /* retry */
|
||||||
|
sldns_buffer_write_u32(buf, 0); /* expire */
|
||||||
|
sldns_buffer_write_u32(buf, 0); /* minimum */
|
||||||
|
sldns_buffer_flip(buf);
|
||||||
|
}
|
||||||
|
|
||||||
/** write a query over the TCP fd */
|
/** write a query over the TCP fd */
|
||||||
static void
|
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,
|
||||||
|
|
@ -123,6 +148,8 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||||
{
|
{
|
||||||
struct query_info qinfo;
|
struct query_info qinfo;
|
||||||
size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf);
|
size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf);
|
||||||
|
int have_serial = 0, is_notify = 0;
|
||||||
|
uint32_t serial = 0;
|
||||||
/* qname */
|
/* qname */
|
||||||
qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len);
|
qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len);
|
||||||
if(!qinfo.qname) {
|
if(!qinfo.qname) {
|
||||||
|
|
@ -130,12 +157,27 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* qtype and qclass */
|
/* qtype */
|
||||||
qinfo.qtype = sldns_get_rr_type_by_name(strtype);
|
if(strncasecmp(strtype, "IXFR=", 5) == 0) {
|
||||||
if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) {
|
serial = (uint32_t)atoi(strtype+5);
|
||||||
printf("cannot parse query type: '%s'\n", strtype);
|
have_serial = 1;
|
||||||
exit(1);
|
qinfo.qtype = LDNS_RR_TYPE_IXFR;
|
||||||
|
} else if(strcasecmp(strtype, "NOTIFY") == 0) {
|
||||||
|
is_notify = 1;
|
||||||
|
qinfo.qtype = LDNS_RR_TYPE_SOA;
|
||||||
|
} else if(strncasecmp(strtype, "NOTIFY=", 7) == 0) {
|
||||||
|
serial = (uint32_t)atoi(strtype+7);
|
||||||
|
have_serial = 1;
|
||||||
|
is_notify = 1;
|
||||||
|
qinfo.qtype = LDNS_RR_TYPE_SOA;
|
||||||
|
} else {
|
||||||
|
qinfo.qtype = sldns_get_rr_type_by_name(strtype);
|
||||||
|
if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) {
|
||||||
|
printf("cannot parse query type: '%s'\n", strtype);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/* qclass */
|
||||||
qinfo.qclass = sldns_get_rr_class_by_name(strclass);
|
qinfo.qclass = sldns_get_rr_class_by_name(strclass);
|
||||||
if(qinfo.qclass == 0 && strcmp(strclass, "CLASS0") != 0) {
|
if(qinfo.qclass == 0 && strcmp(strclass, "CLASS0") != 0) {
|
||||||
printf("cannot parse query class: '%s'\n", strclass);
|
printf("cannot parse query class: '%s'\n", strclass);
|
||||||
|
|
@ -150,6 +192,21 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
|
||||||
sldns_buffer_write_u16_at(buf, 0, id);
|
sldns_buffer_write_u16_at(buf, 0, id);
|
||||||
sldns_buffer_write_u16_at(buf, 2, BIT_RD);
|
sldns_buffer_write_u16_at(buf, 2, BIT_RD);
|
||||||
|
|
||||||
|
if(have_serial && qinfo.qtype == LDNS_RR_TYPE_IXFR) {
|
||||||
|
/* Attach serial to SOA record in the authority section. */
|
||||||
|
write_soa_serial_to_buf(buf, &qinfo, serial);
|
||||||
|
LDNS_NSCOUNT_SET(sldns_buffer_begin(buf), 1);
|
||||||
|
}
|
||||||
|
if(is_notify) {
|
||||||
|
LDNS_OPCODE_SET(sldns_buffer_begin(buf), LDNS_PACKET_NOTIFY);
|
||||||
|
LDNS_RD_CLR(sldns_buffer_begin(buf));
|
||||||
|
LDNS_AA_SET(sldns_buffer_begin(buf));
|
||||||
|
if(have_serial) {
|
||||||
|
write_soa_serial_to_buf(buf, &qinfo, serial);
|
||||||
|
LDNS_ANCOUNT_SET(sldns_buffer_begin(buf), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(1) {
|
if(1) {
|
||||||
/* add EDNS DO */
|
/* add EDNS DO */
|
||||||
struct edns_data edns;
|
struct edns_data edns;
|
||||||
|
|
@ -361,6 +418,7 @@ static int parse_pp2_client(const char* pp2_client, int udp,
|
||||||
sldns_buffer* proxy_buf)
|
sldns_buffer* proxy_buf)
|
||||||
{
|
{
|
||||||
struct sockaddr_storage pp2_addr;
|
struct sockaddr_storage pp2_addr;
|
||||||
|
size_t bytes_written;
|
||||||
socklen_t pp2_addrlen = 0;
|
socklen_t pp2_addrlen = 0;
|
||||||
memset(&pp2_addr, 0, sizeof(pp2_addr));
|
memset(&pp2_addr, 0, sizeof(pp2_addr));
|
||||||
if(*pp2_client == 0) return 0;
|
if(*pp2_client == 0) return 0;
|
||||||
|
|
@ -369,7 +427,9 @@ static int parse_pp2_client(const char* pp2_client, int udp,
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
sldns_buffer_clear(proxy_buf);
|
sldns_buffer_clear(proxy_buf);
|
||||||
pp2_write_to_buf(proxy_buf, &pp2_addr, !udp);
|
bytes_written = pp2_write_to_buf(sldns_buffer_begin(proxy_buf),
|
||||||
|
sldns_buffer_remaining(proxy_buf), &pp2_addr, !udp);
|
||||||
|
sldns_buffer_set_position(proxy_buf, bytes_written);
|
||||||
sldns_buffer_flip(proxy_buf);
|
sldns_buffer_flip(proxy_buf);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -541,6 +601,8 @@ int main(int argc, char** argv)
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
pp2_client = optarg;
|
pp2_client = optarg;
|
||||||
|
pp_init(&sldns_write_uint16,
|
||||||
|
&sldns_write_uint32);
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
onarrival = 1;
|
onarrival = 1;
|
||||||
|
|
|
||||||
34
testdata/root_zonemd.tdir/root_zonemd.conf
vendored
Normal file
34
testdata/root_zonemd.tdir/root_zonemd.conf
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
server:
|
||||||
|
verbosity: 7
|
||||||
|
# num-threads: 1
|
||||||
|
interface: 127.0.0.1
|
||||||
|
port: @PORT@
|
||||||
|
use-syslog: no
|
||||||
|
directory: ""
|
||||||
|
pidfile: "unbound.pid"
|
||||||
|
chroot: ""
|
||||||
|
username: ""
|
||||||
|
do-not-query-localhost: no
|
||||||
|
# for the test, so that DNSSEC verification works.
|
||||||
|
#val-override-date: 20230929090000
|
||||||
|
trust-anchor: ". DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D"
|
||||||
|
|
||||||
|
remote-control:
|
||||||
|
control-enable: yes
|
||||||
|
control-interface: @CONTROL_PATH@/controlpipe.@CONTROL_PID@
|
||||||
|
control-use-cert: no
|
||||||
|
|
||||||
|
# for the test, an upstream server in the test setup.
|
||||||
|
stub-zone:
|
||||||
|
name: "."
|
||||||
|
stub-addr: 127.0.0.1@@TOPORT@
|
||||||
|
|
||||||
|
# hyperlocal root zone
|
||||||
|
auth-zone:
|
||||||
|
name: "."
|
||||||
|
fallback-enabled: yes
|
||||||
|
for-downstream: no
|
||||||
|
for-upstream: yes
|
||||||
|
zonefile: "root.zone"
|
||||||
|
zonemd-check: yes
|
||||||
|
zonemd-reject-absence: yes
|
||||||
16
testdata/root_zonemd.tdir/root_zonemd.dsc
vendored
Normal file
16
testdata/root_zonemd.tdir/root_zonemd.dsc
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
BaseName: root_zonemd
|
||||||
|
Version: 1.0
|
||||||
|
Description: ZONEMD check for root zone
|
||||||
|
CreationDate: Fri 29 Sep 09:00:00 CEST 2023
|
||||||
|
Maintainer: dr. W.C.A. Wijngaards
|
||||||
|
Category:
|
||||||
|
Component:
|
||||||
|
CmdDepends:
|
||||||
|
Depends:
|
||||||
|
Help:
|
||||||
|
Pre: root_zonemd.pre
|
||||||
|
Post: root_zonemd.post
|
||||||
|
Test: root_zonemd.test
|
||||||
|
AuxFiles:
|
||||||
|
Passed:
|
||||||
|
Failure:
|
||||||
14
testdata/root_zonemd.tdir/root_zonemd.post
vendored
Normal file
14
testdata/root_zonemd.tdir/root_zonemd.post
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# #-- root_zonemd.post --#
|
||||||
|
# source the master var file when it's there
|
||||||
|
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||||
|
# source the test var file when it's there
|
||||||
|
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||||
|
#
|
||||||
|
# do your teardown here
|
||||||
|
. ../common.sh
|
||||||
|
echo "> cat logfiles"
|
||||||
|
cat fwd.log
|
||||||
|
cat unbound.log
|
||||||
|
kill_pid $FWD_PID
|
||||||
|
kill_pid $UNBOUND_PID
|
||||||
|
rm -f $CONTROL_PATH/controlpipe.$CONTROL_PID
|
||||||
50
testdata/root_zonemd.tdir/root_zonemd.pre
vendored
Normal file
50
testdata/root_zonemd.tdir/root_zonemd.pre
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
# #-- root_zonemd.pre--#
|
||||||
|
# source the master var file when it's there
|
||||||
|
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||||
|
# use .tpkg.var.test for in test variable passing
|
||||||
|
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||||
|
|
||||||
|
. ../common.sh
|
||||||
|
|
||||||
|
# attempt to download the root zone
|
||||||
|
from=k.root-servers.net
|
||||||
|
dig @$from . AXFR > root.txt
|
||||||
|
if test $? -ne 0; then
|
||||||
|
echo "could not fetch root zone"
|
||||||
|
skip_test "could not fetch root zone"
|
||||||
|
fi
|
||||||
|
grep " SOA " root.txt | head -1 > root.soa
|
||||||
|
cat root.soa >> root.zone
|
||||||
|
grep -v " SOA " root.txt >> root.zone
|
||||||
|
echo "fetched root.zone"
|
||||||
|
ls -l root.zone
|
||||||
|
cat root.soa
|
||||||
|
|
||||||
|
get_random_port 2
|
||||||
|
UNBOUND_PORT=$RND_PORT
|
||||||
|
FWD_PORT=$(($RND_PORT + 1))
|
||||||
|
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
|
||||||
|
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
|
||||||
|
|
||||||
|
# start forwarder
|
||||||
|
get_ldns_testns
|
||||||
|
$LDNS_TESTNS -p $FWD_PORT root_zonemd.testns >fwd.log 2>&1 &
|
||||||
|
FWD_PID=$!
|
||||||
|
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
|
||||||
|
|
||||||
|
# make config file
|
||||||
|
CONTROL_PATH=/tmp
|
||||||
|
CONTROL_PID=$$
|
||||||
|
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' -e 's?@CONTROL_PATH\@?'$CONTROL_PATH'?' -e 's/@CONTROL_PID@/'$CONTROL_PID'/' < root_zonemd.conf > ub.conf
|
||||||
|
# start unbound in the background
|
||||||
|
PRE="../.."
|
||||||
|
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
|
||||||
|
UNBOUND_PID=$!
|
||||||
|
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
|
||||||
|
echo "CONTROL_PATH=$CONTROL_PATH" >> .tpkg.var.test
|
||||||
|
echo "CONTROL_PID=$CONTROL_PID" >> .tpkg.var.test
|
||||||
|
|
||||||
|
cat .tpkg.var.test
|
||||||
|
wait_ldns_testns_up fwd.log
|
||||||
|
wait_unbound_up unbound.log
|
||||||
|
|
||||||
51
testdata/root_zonemd.tdir/root_zonemd.test
vendored
Normal file
51
testdata/root_zonemd.tdir/root_zonemd.test
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# #-- root_zonemd.test --#
|
||||||
|
# source the master var file when it's there
|
||||||
|
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
|
||||||
|
# use .tpkg.var.test for in test variable passing
|
||||||
|
[ -f .tpkg.var.test ] && source .tpkg.var.test
|
||||||
|
|
||||||
|
PRE="../.."
|
||||||
|
# do the test
|
||||||
|
echo "> dig www.example.com."
|
||||||
|
dig @localhost -p $UNBOUND_PORT . SOA | tee outfile
|
||||||
|
echo "> check answer"
|
||||||
|
if grep root-servers outfile | grep "nstld.verisign-grs.com"; then
|
||||||
|
echo "OK"
|
||||||
|
else
|
||||||
|
echo "Not OK"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "> unbound-control status"
|
||||||
|
$PRE/unbound-control -c ub.conf status
|
||||||
|
if test $? -ne 0; then
|
||||||
|
echo "wrong exit value."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "exit value: OK"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# This is the output when an unsupported algorithm is used.
|
||||||
|
if grep "auth zone . ZONEMD unsupported algorithm" unbound.log; then
|
||||||
|
echo "OK"
|
||||||
|
else
|
||||||
|
echo "ZONEMD verification not OK"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "> unbound-control auth_zone_reload ."
|
||||||
|
$PRE/unbound-control -c ub.conf auth_zone_reload . 2>&1 | tee outfile
|
||||||
|
if test $? -ne 0; then
|
||||||
|
echo "wrong exit value."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# The output of the reload can be checked.
|
||||||
|
#echo "> check unbound-control output"
|
||||||
|
#if grep "example.com: ZONEMD verification successful" outfile; then
|
||||||
|
#echo "OK"
|
||||||
|
#else
|
||||||
|
#echo "Not OK"
|
||||||
|
#exit 1
|
||||||
|
#fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
9
testdata/root_zonemd.tdir/root_zonemd.testns
vendored
Normal file
9
testdata/root_zonemd.tdir/root_zonemd.testns
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# reply to everything
|
||||||
|
ENTRY_BEGIN
|
||||||
|
MATCH opcode
|
||||||
|
ADJUST copy_id copy_query
|
||||||
|
REPLY QR SERVFAIL
|
||||||
|
SECTION QUESTION
|
||||||
|
example.com. IN SOA
|
||||||
|
SECTION ANSWER
|
||||||
|
ENTRY_END
|
||||||
|
|
@ -892,15 +892,18 @@ static int udp_recv_needs_log(int err)
|
||||||
static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
|
static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
|
||||||
int stream) {
|
int stream) {
|
||||||
size_t size;
|
size_t size;
|
||||||
struct pp2_header *header = pp2_read_header(buf);
|
struct pp2_header *header;
|
||||||
if(header == NULL) return 0;
|
int err = pp2_read_header(sldns_buffer_begin(buf),
|
||||||
|
sldns_buffer_remaining(buf));
|
||||||
|
if(err) return 0;
|
||||||
|
header = (struct pp2_header*)sldns_buffer_begin(buf);
|
||||||
size = PP2_HEADER_SIZE + ntohs(header->len);
|
size = PP2_HEADER_SIZE + ntohs(header->len);
|
||||||
if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) {
|
if((header->ver_cmd & 0xF) == PP2_CMD_LOCAL) {
|
||||||
/* A connection from the proxy itself.
|
/* A connection from the proxy itself.
|
||||||
* No need to do anything with addresses. */
|
* No need to do anything with addresses. */
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if(header->fam_prot == 0x00) {
|
if(header->fam_prot == PP2_UNSPEC_UNSPEC) {
|
||||||
/* Unspecified family and protocol. This could be used for
|
/* Unspecified family and protocol. This could be used for
|
||||||
* health checks by proxies.
|
* health checks by proxies.
|
||||||
* No need to do anything with addresses. */
|
* No need to do anything with addresses. */
|
||||||
|
|
@ -908,8 +911,8 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
|
||||||
}
|
}
|
||||||
/* Read the proxied address */
|
/* Read the proxied address */
|
||||||
switch(header->fam_prot) {
|
switch(header->fam_prot) {
|
||||||
case 0x11: /* AF_INET|STREAM */
|
case PP2_INET_STREAM:
|
||||||
case 0x12: /* AF_INET|DGRAM */
|
case PP2_INET_DGRAM:
|
||||||
{
|
{
|
||||||
struct sockaddr_in* addr =
|
struct sockaddr_in* addr =
|
||||||
(struct sockaddr_in*)&rep->client_addr;
|
(struct sockaddr_in*)&rep->client_addr;
|
||||||
|
|
@ -920,8 +923,8 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
|
||||||
}
|
}
|
||||||
/* Ignore the destination address; it should be us. */
|
/* Ignore the destination address; it should be us. */
|
||||||
break;
|
break;
|
||||||
case 0x21: /* AF_INET6|STREAM */
|
case PP2_INET6_STREAM:
|
||||||
case 0x22: /* AF_INET6|DGRAM */
|
case PP2_INET6_DGRAM:
|
||||||
{
|
{
|
||||||
struct sockaddr_in6* addr =
|
struct sockaddr_in6* addr =
|
||||||
(struct sockaddr_in6*)&rep->client_addr;
|
(struct sockaddr_in6*)&rep->client_addr;
|
||||||
|
|
@ -934,6 +937,10 @@ static int consume_pp2_header(struct sldns_buffer* buf, struct comm_reply* rep,
|
||||||
}
|
}
|
||||||
/* Ignore the destination address; it should be us. */
|
/* Ignore the destination address; it should be us. */
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
log_err("proxy_protocol: unsupported family and "
|
||||||
|
"protocol 0x%x", (int)header->fam_prot);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
rep->is_proxied = 1;
|
rep->is_proxied = 1;
|
||||||
done:
|
done:
|
||||||
|
|
@ -1813,19 +1820,25 @@ ssl_handle_read(struct comm_point* c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
c->tcp_byte_count += r;
|
c->tcp_byte_count += r;
|
||||||
|
sldns_buffer_skip(c->buffer, r);
|
||||||
if(c->tcp_byte_count != current_read_size) return 1;
|
if(c->tcp_byte_count != current_read_size) return 1;
|
||||||
c->pp2_header_state = pp2_header_init;
|
c->pp2_header_state = pp2_header_init;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(c->pp2_header_state == pp2_header_init) {
|
if(c->pp2_header_state == pp2_header_init) {
|
||||||
header = pp2_read_header(c->buffer);
|
int err;
|
||||||
if(!header) {
|
err = pp2_read_header(
|
||||||
|
sldns_buffer_begin(c->buffer),
|
||||||
|
sldns_buffer_limit(c->buffer));
|
||||||
|
if(err) {
|
||||||
log_err("proxy_protocol: could not parse "
|
log_err("proxy_protocol: could not parse "
|
||||||
"PROXYv2 header");
|
"PROXYv2 header (%s)",
|
||||||
|
pp_lookup_error(err));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
header = (struct pp2_header*)sldns_buffer_begin(c->buffer);
|
||||||
want_read_size = ntohs(header->len);
|
want_read_size = ntohs(header->len);
|
||||||
if(sldns_buffer_remaining(c->buffer) <
|
if(sldns_buffer_limit(c->buffer) <
|
||||||
PP2_HEADER_SIZE + want_read_size) {
|
PP2_HEADER_SIZE + want_read_size) {
|
||||||
log_err_addr("proxy_protocol: not enough "
|
log_err_addr("proxy_protocol: not enough "
|
||||||
"buffer size to read PROXYv2 header", "",
|
"buffer size to read PROXYv2 header", "",
|
||||||
|
|
@ -1874,6 +1887,7 @@ ssl_handle_read(struct comm_point* c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
c->tcp_byte_count += r;
|
c->tcp_byte_count += r;
|
||||||
|
sldns_buffer_skip(c->buffer, r);
|
||||||
if(c->tcp_byte_count != current_read_size) return 1;
|
if(c->tcp_byte_count != current_read_size) return 1;
|
||||||
c->pp2_header_state = pp2_header_done;
|
c->pp2_header_state = pp2_header_done;
|
||||||
}
|
}
|
||||||
|
|
@ -1884,6 +1898,7 @@ ssl_handle_read(struct comm_point* c)
|
||||||
c->repinfo.remote_addrlen);
|
c->repinfo.remote_addrlen);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
sldns_buffer_flip(c->buffer);
|
||||||
if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
|
if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
|
||||||
log_err_addr("proxy_protocol: could not consume "
|
log_err_addr("proxy_protocol: could not consume "
|
||||||
"PROXYv2 header", "", &c->repinfo.remote_addr,
|
"PROXYv2 header", "", &c->repinfo.remote_addr,
|
||||||
|
|
@ -2205,19 +2220,25 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
|
||||||
goto recv_error_initial;
|
goto recv_error_initial;
|
||||||
}
|
}
|
||||||
c->tcp_byte_count += r;
|
c->tcp_byte_count += r;
|
||||||
|
sldns_buffer_skip(c->buffer, r);
|
||||||
if(c->tcp_byte_count != current_read_size) return 1;
|
if(c->tcp_byte_count != current_read_size) return 1;
|
||||||
c->pp2_header_state = pp2_header_init;
|
c->pp2_header_state = pp2_header_init;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(c->pp2_header_state == pp2_header_init) {
|
if(c->pp2_header_state == pp2_header_init) {
|
||||||
header = pp2_read_header(c->buffer);
|
int err;
|
||||||
if(!header) {
|
err = pp2_read_header(
|
||||||
|
sldns_buffer_begin(c->buffer),
|
||||||
|
sldns_buffer_limit(c->buffer));
|
||||||
|
if(err) {
|
||||||
log_err("proxy_protocol: could not parse "
|
log_err("proxy_protocol: could not parse "
|
||||||
"PROXYv2 header");
|
"PROXYv2 header (%s)",
|
||||||
|
pp_lookup_error(err));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
header = (struct pp2_header*)sldns_buffer_begin(c->buffer);
|
||||||
want_read_size = ntohs(header->len);
|
want_read_size = ntohs(header->len);
|
||||||
if(sldns_buffer_remaining(c->buffer) <
|
if(sldns_buffer_limit(c->buffer) <
|
||||||
PP2_HEADER_SIZE + want_read_size) {
|
PP2_HEADER_SIZE + want_read_size) {
|
||||||
log_err_addr("proxy_protocol: not enough "
|
log_err_addr("proxy_protocol: not enough "
|
||||||
"buffer size to read PROXYv2 header", "",
|
"buffer size to read PROXYv2 header", "",
|
||||||
|
|
@ -2244,6 +2265,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
|
||||||
goto recv_error;
|
goto recv_error;
|
||||||
}
|
}
|
||||||
c->tcp_byte_count += r;
|
c->tcp_byte_count += r;
|
||||||
|
sldns_buffer_skip(c->buffer, r);
|
||||||
if(c->tcp_byte_count != current_read_size) return 1;
|
if(c->tcp_byte_count != current_read_size) return 1;
|
||||||
c->pp2_header_state = pp2_header_done;
|
c->pp2_header_state = pp2_header_done;
|
||||||
}
|
}
|
||||||
|
|
@ -2254,6 +2276,7 @@ comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
|
||||||
c->repinfo.remote_addrlen);
|
c->repinfo.remote_addrlen);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
sldns_buffer_flip(c->buffer);
|
||||||
if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
|
if(!consume_pp2_header(c->buffer, &c->repinfo, 1)) {
|
||||||
log_err_addr("proxy_protocol: could not consume "
|
log_err_addr("proxy_protocol: could not consume "
|
||||||
"PROXYv2 header", "", &c->repinfo.remote_addr,
|
"PROXYv2 header", "", &c->repinfo.remote_addr,
|
||||||
|
|
|
||||||
|
|
@ -38,102 +38,162 @@
|
||||||
*
|
*
|
||||||
* This file contains PROXY protocol functions.
|
* This file contains PROXY protocol functions.
|
||||||
*/
|
*/
|
||||||
#include "config.h"
|
|
||||||
#include "util/log.h"
|
|
||||||
#include "util/proxy_protocol.h"
|
#include "util/proxy_protocol.h"
|
||||||
|
|
||||||
int
|
/**
|
||||||
pp2_write_to_buf(struct sldns_buffer* buf, struct sockaddr_storage* src,
|
* Internal struct initialized with function pointers for writing uint16 and
|
||||||
|
* uint32.
|
||||||
|
*/
|
||||||
|
struct proxy_protocol_data {
|
||||||
|
void (*write_uint16)(void* buf, uint16_t data);
|
||||||
|
void (*write_uint32)(void* buf, uint32_t data);
|
||||||
|
};
|
||||||
|
struct proxy_protocol_data pp_data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal lookup table; could be further generic like sldns_lookup_table
|
||||||
|
* for all the future generic stuff.
|
||||||
|
*/
|
||||||
|
struct proxy_protocol_lookup_table {
|
||||||
|
int id;
|
||||||
|
const char *text;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal parsing error text; could be exposed with pp_lookup_error.
|
||||||
|
*/
|
||||||
|
static struct proxy_protocol_lookup_table pp_parse_errors_data[] = {
|
||||||
|
{ PP_PARSE_NOERROR, "no parse error" },
|
||||||
|
{ PP_PARSE_SIZE, "not enough space for header" },
|
||||||
|
{ PP_PARSE_WRONG_HEADERv2, "could not match PROXYv2 header" },
|
||||||
|
{ PP_PARSE_UNKNOWN_CMD, "unknown command" },
|
||||||
|
{ PP_PARSE_UNKNOWN_FAM_PROT, "unknown family and protocol" },
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
pp_init(void (*write_uint16)(void* buf, uint16_t data),
|
||||||
|
void (*write_uint32)(void* buf, uint32_t data)) {
|
||||||
|
pp_data.write_uint16 = write_uint16;
|
||||||
|
pp_data.write_uint32 = write_uint32;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
pp_lookup_error(enum pp_parse_errors error) {
|
||||||
|
return pp_parse_errors_data[error].text;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
pp2_write_to_buf(uint8_t* buf, size_t buflen,
|
||||||
|
#ifdef INET6
|
||||||
|
struct sockaddr_storage* src,
|
||||||
|
#else
|
||||||
|
struct sockaddr_in* src,
|
||||||
|
#endif
|
||||||
int stream)
|
int stream)
|
||||||
{
|
{
|
||||||
int af;
|
int af;
|
||||||
|
size_t expected_size;
|
||||||
if(!src) return 0;
|
if(!src) return 0;
|
||||||
af = (int)((struct sockaddr_in*)src)->sin_family;
|
af = (int)((struct sockaddr_in*)src)->sin_family;
|
||||||
if(sldns_buffer_remaining(buf) <
|
expected_size = PP2_HEADER_SIZE + (af==AF_INET?12:36);
|
||||||
PP2_HEADER_SIZE + (af==AF_INET?12:36)) {
|
if(buflen < expected_size) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* sig */
|
/* sig */
|
||||||
sldns_buffer_write(buf, PP2_SIG, PP2_SIG_LEN);
|
memcpy(buf, PP2_SIG, PP2_SIG_LEN);
|
||||||
|
buf += PP2_SIG_LEN;
|
||||||
/* version and command */
|
/* version and command */
|
||||||
sldns_buffer_write_u8(buf, (PP2_VERSION << 4) | PP2_CMD_PROXY);
|
*buf = (PP2_VERSION << 4) | PP2_CMD_PROXY;
|
||||||
if(af==AF_INET) {
|
buf++;
|
||||||
|
switch(af) {
|
||||||
|
case AF_INET:
|
||||||
/* family and protocol */
|
/* family and protocol */
|
||||||
sldns_buffer_write_u8(buf,
|
*buf = (PP2_AF_INET<<4) |
|
||||||
(PP2_AF_INET<<4) |
|
(stream?PP2_PROT_STREAM:PP2_PROT_DGRAM);
|
||||||
(stream?PP2_PROT_STREAM:PP2_PROT_DGRAM));
|
buf++;
|
||||||
/* length */
|
/* length */
|
||||||
sldns_buffer_write_u16(buf, 12);
|
(*pp_data.write_uint16)(buf, 12);
|
||||||
|
buf += 2;
|
||||||
/* src addr */
|
/* src addr */
|
||||||
sldns_buffer_write(buf,
|
memcpy(buf,
|
||||||
&((struct sockaddr_in*)src)->sin_addr.s_addr, 4);
|
&((struct sockaddr_in*)src)->sin_addr.s_addr, 4);
|
||||||
|
buf += 4;
|
||||||
/* dst addr */
|
/* dst addr */
|
||||||
sldns_buffer_write_u32(buf, 0);
|
(*pp_data.write_uint32)(buf, 0);
|
||||||
|
buf += 4;
|
||||||
/* src port */
|
/* src port */
|
||||||
sldns_buffer_write(buf,
|
memcpy(buf,
|
||||||
&((struct sockaddr_in*)src)->sin_port, 2);
|
&((struct sockaddr_in*)src)->sin_port, 2);
|
||||||
/* dst port */
|
buf += 2;
|
||||||
sldns_buffer_write_u16(buf, 0);
|
|
||||||
} else {
|
|
||||||
/* family and protocol */
|
|
||||||
sldns_buffer_write_u8(buf,
|
|
||||||
(PP2_AF_INET6<<4) |
|
|
||||||
(stream?PP2_PROT_STREAM:PP2_PROT_DGRAM));
|
|
||||||
/* length */
|
|
||||||
sldns_buffer_write_u16(buf, 36);
|
|
||||||
/* src addr */
|
|
||||||
sldns_buffer_write(buf,
|
|
||||||
&((struct sockaddr_in6*)src)->sin6_addr, 16);
|
|
||||||
/* dst addr */
|
/* dst addr */
|
||||||
sldns_buffer_set_at(buf,
|
|
||||||
sldns_buffer_position(buf), 0, 16);
|
|
||||||
sldns_buffer_skip(buf, 16);
|
|
||||||
/* src port */
|
|
||||||
sldns_buffer_write(buf,
|
|
||||||
&((struct sockaddr_in6*)src)->sin6_port, 2);
|
|
||||||
/* dst port */
|
/* dst port */
|
||||||
sldns_buffer_write_u16(buf, 0);
|
(*pp_data.write_uint16)(buf, 12);
|
||||||
|
break;
|
||||||
|
#ifdef INET6
|
||||||
|
case AF_INET6:
|
||||||
|
/* family and protocol */
|
||||||
|
*buf = (PP2_AF_INET6<<4) |
|
||||||
|
(stream?PP2_PROT_STREAM:PP2_PROT_DGRAM);
|
||||||
|
buf++;
|
||||||
|
/* length */
|
||||||
|
(*pp_data.write_uint16)(buf, 36);
|
||||||
|
buf += 2;
|
||||||
|
/* src addr */
|
||||||
|
memcpy(buf,
|
||||||
|
&((struct sockaddr_in6*)src)->sin6_addr, 16);
|
||||||
|
buf += 16;
|
||||||
|
/* dst addr */
|
||||||
|
memset(buf, 0, 16);
|
||||||
|
buf += 16;
|
||||||
|
/* src port */
|
||||||
|
memcpy(buf, &((struct sockaddr_in6*)src)->sin6_port, 2);
|
||||||
|
buf += 2;
|
||||||
|
/* dst port */
|
||||||
|
(*pp_data.write_uint16)(buf, 0);
|
||||||
|
break;
|
||||||
|
#endif /* INET6 */
|
||||||
|
case AF_UNIX:
|
||||||
|
/* fallthrough */
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return expected_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pp2_header*
|
int
|
||||||
pp2_read_header(struct sldns_buffer* buf)
|
pp2_read_header(uint8_t* buf, size_t buflen)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
struct pp2_header* header = (struct pp2_header*)sldns_buffer_begin(buf);
|
struct pp2_header* header = (struct pp2_header*)buf;
|
||||||
/* Try to fail all the unsupported cases first. */
|
/* Try to fail all the unsupported cases first. */
|
||||||
if(sldns_buffer_remaining(buf) < PP2_HEADER_SIZE) {
|
if(buflen < PP2_HEADER_SIZE) {
|
||||||
log_err("proxy_protocol: not enough space for header");
|
return PP_PARSE_SIZE;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
/* Check for PROXYv2 header */
|
/* Check for PROXYv2 header */
|
||||||
if(memcmp(header, PP2_SIG, PP2_SIG_LEN) != 0 ||
|
if(memcmp(header, PP2_SIG, PP2_SIG_LEN) != 0 ||
|
||||||
((header->ver_cmd & 0xF0)>>4) != PP2_VERSION) {
|
((header->ver_cmd & 0xF0)>>4) != PP2_VERSION) {
|
||||||
log_err("proxy_protocol: could not match PROXYv2 header");
|
return PP_PARSE_WRONG_HEADERv2;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
/* Check the length */
|
/* Check the length */
|
||||||
size = PP2_HEADER_SIZE + ntohs(header->len);
|
size = PP2_HEADER_SIZE + ntohs(header->len);
|
||||||
if(sldns_buffer_remaining(buf) < size) {
|
if(buflen < size) {
|
||||||
log_err("proxy_protocol: not enough space for header");
|
return PP_PARSE_SIZE;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
/* Check for supported commands */
|
/* Check for supported commands */
|
||||||
if((header->ver_cmd & 0xF) != PP2_CMD_LOCAL &&
|
if((header->ver_cmd & 0xF) != PP2_CMD_LOCAL &&
|
||||||
(header->ver_cmd & 0xF) != PP2_CMD_PROXY) {
|
(header->ver_cmd & 0xF) != PP2_CMD_PROXY) {
|
||||||
log_err("proxy_protocol: unsupported command");
|
return PP_PARSE_UNKNOWN_CMD;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
/* Check for supported family and protocol */
|
/* Check for supported family and protocol */
|
||||||
if(header->fam_prot != 0x00 /* AF_UNSPEC|UNSPEC */ &&
|
if(header->fam_prot != PP2_UNSPEC_UNSPEC &&
|
||||||
header->fam_prot != 0x11 /* AF_INET|STREAM */ &&
|
header->fam_prot != PP2_INET_STREAM &&
|
||||||
header->fam_prot != 0x12 /* AF_INET|DGRAM */ &&
|
header->fam_prot != PP2_INET_DGRAM &&
|
||||||
header->fam_prot != 0x21 /* AF_INET6|STREAM */ &&
|
header->fam_prot != PP2_INET6_STREAM &&
|
||||||
header->fam_prot != 0x22 /* AF_INET6|DGRAM */) {
|
header->fam_prot != PP2_INET6_DGRAM &&
|
||||||
log_err("proxy_protocol: unsupported family and protocol");
|
header->fam_prot != PP2_UNIX_STREAM &&
|
||||||
return NULL;
|
header->fam_prot != PP2_UNIX_DGRAM) {
|
||||||
|
return PP_PARSE_UNKNOWN_FAM_PROT;
|
||||||
}
|
}
|
||||||
/* We have a correct header */
|
/* We have a correct header */
|
||||||
return header;
|
return PP_PARSE_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
#ifndef PROXY_PROTOCOL_H
|
#ifndef PROXY_PROTOCOL_H
|
||||||
#define PROXY_PROTOCOL_H
|
#define PROXY_PROTOCOL_H
|
||||||
|
|
||||||
#include "sldns/sbuffer.h"
|
#include "config.h"
|
||||||
|
|
||||||
/** PROXYv2 minimum header size */
|
/** PROXYv2 minimum header size */
|
||||||
#define PP2_HEADER_SIZE 16
|
#define PP2_HEADER_SIZE 16
|
||||||
|
|
@ -51,11 +51,11 @@
|
||||||
#define PP2_SIG "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
|
#define PP2_SIG "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
|
||||||
#define PP2_SIG_LEN 12
|
#define PP2_SIG_LEN 12
|
||||||
|
|
||||||
/** PROXYv2 version */
|
/** PROXYv2 version (protocol value) */
|
||||||
#define PP2_VERSION 0x2
|
#define PP2_VERSION 0x2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PROXYv2 command.
|
* PROXYv2 command (protocol value).
|
||||||
*/
|
*/
|
||||||
enum pp2_command {
|
enum pp2_command {
|
||||||
PP2_CMD_LOCAL = 0x0,
|
PP2_CMD_LOCAL = 0x0,
|
||||||
|
|
@ -63,7 +63,7 @@ enum pp2_command {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PROXYv2 address family.
|
* PROXYv2 address family (protocol value).
|
||||||
*/
|
*/
|
||||||
enum pp2_af {
|
enum pp2_af {
|
||||||
PP2_AF_UNSPEC = 0x0,
|
PP2_AF_UNSPEC = 0x0,
|
||||||
|
|
@ -73,7 +73,7 @@ enum pp2_af {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PROXYv2 protocol.
|
* PROXYv2 protocol (protocol value).
|
||||||
*/
|
*/
|
||||||
enum pp2_protocol {
|
enum pp2_protocol {
|
||||||
PP2_PROT_UNSPEC = 0x0,
|
PP2_PROT_UNSPEC = 0x0,
|
||||||
|
|
@ -81,6 +81,19 @@ enum pp2_protocol {
|
||||||
PP2_PROT_DGRAM = 0x2
|
PP2_PROT_DGRAM = 0x2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expected combinations of address family and protocol values used in checks.
|
||||||
|
*/
|
||||||
|
enum pp2_af_protocol_combination {
|
||||||
|
PP2_UNSPEC_UNSPEC = (PP2_AF_UNSPEC<<4)|PP2_PROT_UNSPEC,
|
||||||
|
PP2_INET_STREAM = (PP2_AF_INET<<4)|PP2_PROT_STREAM,
|
||||||
|
PP2_INET_DGRAM = (PP2_AF_INET<<4)|PP2_PROT_DGRAM,
|
||||||
|
PP2_INET6_STREAM = (PP2_AF_INET6<<4)|PP2_PROT_STREAM,
|
||||||
|
PP2_INET6_DGRAM = (PP2_AF_INET6<<4)|PP2_PROT_DGRAM,
|
||||||
|
PP2_UNIX_STREAM = (PP2_AF_UNIX<<4)|PP2_PROT_STREAM,
|
||||||
|
PP2_UNIX_DGRAM = (PP2_AF_UNIX<<4)|PP2_PROT_DGRAM
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PROXYv2 header.
|
* PROXYv2 header.
|
||||||
*/
|
*/
|
||||||
|
|
@ -109,23 +122,56 @@ struct pp2_header {
|
||||||
} addr;
|
} addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PROXY parse errors.
|
||||||
|
*/
|
||||||
|
enum pp_parse_errors {
|
||||||
|
PP_PARSE_NOERROR = 0,
|
||||||
|
PP_PARSE_SIZE,
|
||||||
|
PP_PARSE_WRONG_HEADERv2,
|
||||||
|
PP_PARSE_UNKNOWN_CMD,
|
||||||
|
PP_PARSE_UNKNOWN_FAM_PROT,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the internal proxy structure.
|
||||||
|
* @param write_uint16: pointer to a function that can write uint16.
|
||||||
|
* @param write_uint32: pointer to a function that can write uint32.
|
||||||
|
*/
|
||||||
|
void pp_init(void (*write_uint16)(void* buf, uint16_t data),
|
||||||
|
void (*write_uint32)(void* buf, uint32_t data));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup the parsing error description.
|
||||||
|
* @param error: parsing error from pp2_read_header.
|
||||||
|
* @return the description.
|
||||||
|
*/
|
||||||
|
const char* pp_lookup_error(enum pp_parse_errors error);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a PROXYv2 header at the current position of the buffer.
|
* Write a PROXYv2 header at the current position of the buffer.
|
||||||
* @param buf: the buffer to write to.
|
* @param buf: pointer to the buffer to write data to.
|
||||||
|
* @param buflen: available size on the buffer.
|
||||||
* @param src: the source address.
|
* @param src: the source address.
|
||||||
* @param stream: if the protocol is stream or datagram.
|
* @param stream: if the protocol is stream or datagram.
|
||||||
* @return 1 on success, 0 on failure.
|
* @return 1 on success, 0 on failure.
|
||||||
*/
|
*/
|
||||||
int pp2_write_to_buf(struct sldns_buffer* buf, struct sockaddr_storage* src,
|
size_t pp2_write_to_buf(uint8_t* buf, size_t buflen,
|
||||||
|
#ifdef INET6
|
||||||
|
struct sockaddr_storage* src,
|
||||||
|
#else
|
||||||
|
struct sockaddr_in* src,
|
||||||
|
#endif
|
||||||
int stream);
|
int stream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a PROXYv2 header from the current position of the buffer.
|
* Read a PROXYv2 header from the current position of the buffer.
|
||||||
* It does initial validation and returns a pointer to the buffer position on
|
* It does initial validation and returns a pointer to the buffer position on
|
||||||
* success.
|
* success.
|
||||||
* @param buf: the buffer to read from.
|
* @param buf: pointer to the buffer data to read from.
|
||||||
* @return the pointer to the buffer position on success, NULL on error.
|
* @param buflen: available size on the buffer.
|
||||||
|
* @return parsing error, 0 on success.
|
||||||
*/
|
*/
|
||||||
struct pp2_header* pp2_read_header(struct sldns_buffer* buf);
|
int pp2_read_header(uint8_t* buf, size_t buflen);
|
||||||
|
|
||||||
#endif /* PROXY_PROTOCOL_H */
|
#endif /* PROXY_PROTOCOL_H */
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue