diff options
-rw-r--r-- | Knot.files | 4 | ||||
-rw-r--r-- | distro/pkg/deb/copyright | 5 | ||||
-rw-r--r-- | doc/man/knot.conf.5in | 16 | ||||
-rw-r--r-- | doc/reference.rst | 16 | ||||
-rw-r--r-- | src/contrib/Makefile.inc | 2 | ||||
-rw-r--r-- | src/contrib/proxyv2/proxyv2.c (renamed from src/knot/query/proxyv2.c) | 124 | ||||
-rw-r--r-- | src/contrib/proxyv2/proxyv2.h | 24 | ||||
-rw-r--r-- | src/knot/Makefile.inc | 8 | ||||
-rw-r--r-- | src/knot/conf/base.c | 3 | ||||
-rw-r--r-- | src/knot/conf/base.h | 1 | ||||
-rw-r--r-- | src/knot/conf/schema.c | 1 | ||||
-rw-r--r-- | src/knot/conf/schema.h | 1 | ||||
-rw-r--r-- | src/knot/include/module.h | 1 | ||||
-rw-r--r-- | src/knot/query/proxyv2.h | 16 | ||||
-rw-r--r-- | src/knot/server/proxyv2.c | 76 | ||||
-rw-r--r-- | src/knot/server/proxyv2.h | 23 | ||||
-rw-r--r-- | src/knot/server/udp-handler.c | 23 | ||||
-rw-r--r-- | src/knot/server/xdp-handler.c | 9 |
18 files changed, 225 insertions, 128 deletions
diff --git a/Knot.files b/Knot.files index c5d001513..3484fc8d5 100644 --- a/Knot.files +++ b/Knot.files @@ -161,6 +161,8 @@ src/contrib/openbsd/strlcat.h src/contrib/openbsd/strlcpy.c src/contrib/openbsd/strlcpy.h src/contrib/os.h +src/contrib/proxyv2/proxyv2.c +src/contrib/proxyv2/proxyv2.h src/contrib/qp-trie/trie.c src/contrib/qp-trie/trie.h src/contrib/semaphore.c @@ -342,6 +344,8 @@ src/knot/query/requestor.c src/knot/query/requestor.h src/knot/server/dthreads.c src/knot/server/dthreads.h +src/knot/server/proxyv2.c +src/knot/server/proxyv2.h src/knot/server/server.c src/knot/server/server.h src/knot/server/tcp-handler.c diff --git a/distro/pkg/deb/copyright b/distro/pkg/deb/copyright index 61ec7e81b..7e0f90f92 100644 --- a/distro/pkg/deb/copyright +++ b/distro/pkg/deb/copyright @@ -60,6 +60,11 @@ Files: src/contrib/openbsd/strl* Copyright: 1998 Todd C. Miller <Todd.Miller@courtesan.com> License: 0BSD +Files: src/contrib/proxyv2/* +Copyright: 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + 2021 Fastly, Inc. +License: GPL-3+ + Files: src/contrib/qp-trie/* Copyright: 2011-2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> 2018 Tony Finch <dot@dotat.at> diff --git a/doc/man/knot.conf.5in b/doc/man/knot.conf.5in index d360292da..b154b4d45 100644 --- a/doc/man/knot.conf.5in +++ b/doc/man/knot.conf.5in @@ -201,6 +201,7 @@ server: edns\-client\-subnet: BOOL answer\-rotation: BOOL automatic\-acl: BOOL + proxy\-allowlist: ADDR[/INT] | ADDR\-ADDR ... dbus\-event: none | running | zone\-updated | ksk\-submission | dnssec\-invalid ... listen: ADDR[@INT] ... .ft P @@ -443,6 +444,21 @@ If enabled, \fI\%automatic ACL\fP setting of configured remotes is considered when evaluating authorized operations. .sp \fIDefault:\fP off +.SS proxy\-allowlist +.sp +An ordered list of IP addresses, network subnets, or network ranges +which are allowed as a source address of proxied DNS traffic over UDP. +The supported proxy protocol is +\fI\%haproxy PROXY v2\fP\&. +.sp +\fBNOTE:\fP +.INDENT 0.0 +.INDENT 3.5 +TCP is not supported. +.UNINDENT +.UNINDENT +.sp +\fIDefault:\fP not set .SS dbus\-event .sp Specification of server or zone states which emit a D\-Bus signal on the system diff --git a/doc/reference.rst b/doc/reference.rst index 9dacdcb60..fdd84717e 100644 --- a/doc/reference.rst +++ b/doc/reference.rst @@ -152,6 +152,7 @@ General options related to the server. edns-client-subnet: BOOL answer-rotation: BOOL automatic-acl: BOOL + proxy-allowlist: ADDR[/INT] | ADDR-ADDR ... dbus-event: none | running | zone-updated | ksk-submission | dnssec-invalid ... listen: ADDR[@INT] ... @@ -476,6 +477,21 @@ configured remotes is considered when evaluating authorized operations. *Default:* off +.. _server_proxy-allowlist: + +proxy-allowlist +--------------- + +An ordered list of IP addresses, network subnets, or network ranges +which are allowed as a source address of proxied DNS traffic over UDP. +The supported proxy protocol is +`haproxy PROXY v2 <https://www.haproxy.org/download/2.5/doc/proxy-protocol.txt>`_. + +.. NOTE:: + TCP is not supported. + +*Default:* not set + .. _server_dbus-event: dbus-event diff --git a/src/contrib/Makefile.inc b/src/contrib/Makefile.inc index c0dc0fc7d..6af6e5c29 100644 --- a/src/contrib/Makefile.inc +++ b/src/contrib/Makefile.inc @@ -66,6 +66,8 @@ libcontrib_la_SOURCES = \ contrib/openbsd/strlcat.h \ contrib/openbsd/strlcpy.c \ contrib/openbsd/strlcpy.h \ + contrib/proxyv2/proxyv2.c \ + contrib/proxyv2/proxyv2.h \ contrib/ucw/array-sort.h \ contrib/ucw/binsearch.h \ contrib/ucw/heap.c \ diff --git a/src/knot/query/proxyv2.c b/src/contrib/proxyv2/proxyv2.c index 7c50df2c9..fb3e925e9 100644 --- a/src/knot/query/proxyv2.c +++ b/src/contrib/proxyv2/proxyv2.c @@ -14,10 +14,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#include "knot/query/proxyv2.h" - #include <arpa/inet.h> #include <stdint.h> +#include <string.h> + +#include "contrib/proxyv2/proxyv2.h" +#include "contrib/sockaddr.h" +#include "libknot/errcode.h" /* * Minimal implementation of the haproxy PROXY v2 protocol. @@ -61,7 +64,7 @@ struct proxyv2_hdr { /* * The number of PROXY v2 payload bytes following this header to skip - * to reach the proxied packet (i.e., start of the original DNS mesage). + * to reach the proxied packet (i.e., start of the original DNS message). */ uint16_t len; }; @@ -99,36 +102,9 @@ _Static_assert(sizeof(struct proxyv2_addr_ipv6) == 36, "struct proxyv2_addr_ipv6 is correct size"); #endif -#define S_ADDR_IS_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) - -int proxyv2_decapsulate(void *base, - size_t len_base, - knot_pkt_t **query, - knotd_qdata_params_t *params, - struct sockaddr_storage *client, - knot_mm_t *mm) +int proxyv2_header_offset(void *base, size_t len_base) { /* - * Check if the query was sent from an IP address authorized to send - * proxied DNS traffic. This is a hardcoded ACL check for queries - * originated from 127.0.0.0/8. - * - * XXX: This should be a real ACL check. - */ - int ret = KNOT_EDENIED; - const struct sockaddr_storage *sock = params->remote; - if (sock != NULL && sock->ss_family == AF_INET) { - const struct sockaddr_in *sock4 = (const struct sockaddr_in *) sock; - if (S_ADDR_IS_LOOPBACK(ntohl(sock4->sin_addr.s_addr))) { - ret = KNOT_EOK; - } - } - if (ret != KNOT_EOK) { - /* Failure. */ - return ret; - } - - /* * Check that 'base' has enough bytes to read the PROXY v2 signature * and header, and if so whether the PROXY v2 signature is present. */ @@ -140,8 +116,7 @@ int proxyv2_decapsulate(void *base, } /* Read the PROXY v2 header. */ - struct proxyv2_hdr hdr; - memcpy(&hdr, base + sizeof(PROXYV2_SIG), sizeof(hdr)); + struct proxyv2_hdr *hdr = base + sizeof(PROXYV2_SIG); /* * Check that this is a version 2, command "PROXY" payload. @@ -149,7 +124,7 @@ int proxyv2_decapsulate(void *base, * XXX: The PROXY v2 spec mandates support for the "LOCAL" command * (byte 0x20). */ - if (hdr.ver_cmd != 0x21) { + if (hdr->ver_cmd != 0x21) { /* Failure. */ return KNOT_EMALF; } @@ -160,49 +135,32 @@ int proxyv2_decapsulate(void *base, * PROXY v2 header, and the bytes of variable length PROXY v2 data * following the PROXY v2 header. */ - const size_t offset_dns = - sizeof(PROXYV2_SIG) + - sizeof(struct proxyv2_hdr) + - ntohs(hdr.len); - - /* - * Check if the calculated offset of the original DNS message is - * actually inside the packet received on the wire, and if so, parse - * the real DNS query message. - */ + const size_t offset_dns = sizeof(PROXYV2_SIG) + + sizeof(struct proxyv2_hdr) + ntohs(hdr->len); if (offset_dns < len_base) { - /* Free the old, misparsed query message object. */ - knot_pkt_free(*query); - - /* - * Re-parse the query message using the data in the - * packet following the PROXY v2 payload. - */ - *query = knot_pkt_new(base + offset_dns, - len_base - offset_dns, - mm); - ret = knot_pkt_parse(*query, 0); - if (ret != KNOT_EOK) { - /* Failure. */ - return ret; - } + return offset_dns; } + return KNOT_EMALF; +} + +int proxyv2_addr_store(void *base, size_t len_base, struct sockaddr_storage *ss) +{ /* * Calculate the offset of the PROXY v2 address block. This is the data * immediately following the PROXY v2 header. */ - const size_t offset_proxy_addr = - sizeof(PROXYV2_SIG) + sizeof(struct proxyv2_hdr); + const size_t offset_proxy_addr = sizeof(PROXYV2_SIG) + + sizeof(struct proxyv2_hdr); + struct proxyv2_hdr *hdr = base + sizeof(PROXYV2_SIG); /* * Handle proxied UDP-over-IPv4 and UDP-over-IPv6 packets. - * - * XXX: What about TCP? */ - if (hdr.fam_addr == 0x12) { + //TODO What about TCP? + if (hdr->fam_addr == 0x12) { /* This is a proxied UDP-over-IPv4 packet. */ - struct proxyv2_addr_ipv4 addr; + struct proxyv2_addr_ipv4 *addr; /* * Check that the packet is large enough to contain the IPv4 @@ -210,29 +168,21 @@ int proxyv2_decapsulate(void *base, */ if (offset_proxy_addr + sizeof(addr) < len_base) { /* Read the PROXY v2 address block. */ - memcpy(&addr, base + offset_proxy_addr, sizeof(addr)); + addr = base + offset_proxy_addr; /* Copy the client's IPv4 address to the caller. */ - sockaddr_set_raw(client, - AF_INET, - &addr.src_addr[0], - sizeof(addr.src_addr)); + sockaddr_set_raw(ss, AF_INET, addr->src_addr, + sizeof(addr->src_addr)); /* Copy the client's port to the caller. */ - sockaddr_port_set(client, ntohs(addr.src_port)); - - /* Save the address of the proxy. */ - params->proxy = params->remote; - - /* Expose the address of the proxied client. */ - params->remote = client; + sockaddr_port_set(ss, ntohs(addr->src_port)); /* Success. */ return KNOT_EOK; } - } else if (hdr.fam_addr == 0x22) { + } else if (hdr->fam_addr == 0x22) { /* This is a proxied UDP-over-IPv6 packet. */ - struct proxyv2_addr_ipv6 addr; + struct proxyv2_addr_ipv6 *addr; /* * Check that the packet is large enough to contain the IPv6 @@ -240,22 +190,14 @@ int proxyv2_decapsulate(void *base, */ if (offset_proxy_addr + sizeof(addr) < len_base) { /* Read the PROXY v2 address block. */ - memcpy(&addr, base + offset_proxy_addr, sizeof(addr)); + addr = base + offset_proxy_addr; /* Copy the client's IPv6 address to the caller. */ - sockaddr_set_raw(client, - AF_INET6, - &addr.src_addr[0], - sizeof(addr.src_addr)); + sockaddr_set_raw(ss, AF_INET6, addr->src_addr, + sizeof(addr->src_addr)); /* Copy the client's port to the caller. */ - sockaddr_port_set(client, ntohs(addr.src_port)); - - /* Save the address of the proxy. */ - params->proxy = params->remote; - - /* Expose the address of the proxied client. */ - params->remote = client; + sockaddr_port_set(ss, ntohs(addr->src_port)); /* Success. */ return KNOT_EOK; diff --git a/src/contrib/proxyv2/proxyv2.h b/src/contrib/proxyv2/proxyv2.h new file mode 100644 index 000000000..677825ec0 --- /dev/null +++ b/src/contrib/proxyv2/proxyv2.h @@ -0,0 +1,24 @@ +/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <stddef.h> +#include <sys/socket.h> + +int proxyv2_header_offset(void *base, size_t len_base); + +int proxyv2_addr_store(void *base, size_t len_base, struct sockaddr_storage *ss); diff --git a/src/knot/Makefile.inc b/src/knot/Makefile.inc index f86d62371..531de466e 100644 --- a/src/knot/Makefile.inc +++ b/src/knot/Makefile.inc @@ -115,8 +115,6 @@ libknotd_la_SOURCES = \ knot/query/capture.c \ knot/query/capture.h \ knot/query/layer.h \ - knot/query/proxyv2.c \ - knot/query/proxyv2.h \ knot/query/query.c \ knot/query/query.h \ knot/query/requestor.c \ @@ -135,8 +133,6 @@ libknotd_la_SOURCES = \ knot/common/systemd.h \ knot/common/unreachable.c \ knot/common/unreachable.h \ - knot/server/dthreads.c \ - knot/server/dthreads.h \ knot/journal/journal_basic.c \ knot/journal/journal_basic.h \ knot/journal/journal_metadata.c \ @@ -149,6 +145,10 @@ libknotd_la_SOURCES = \ knot/journal/knot_lmdb.h \ knot/journal/serialization.c \ knot/journal/serialization.h \ + knot/server/dthreads.c \ + knot/server/dthreads.h \ + knot/server/proxyv2.c \ + knot/server/proxyv2.h \ knot/server/server.c \ knot/server/server.h \ knot/server/tcp-handler.c \ diff --git a/src/knot/conf/base.c b/src/knot/conf/base.c index f46386920..40997d1e1 100644 --- a/src/knot/conf/base.c +++ b/src/knot/conf/base.c @@ -240,6 +240,9 @@ static void init_cache( val = conf_get(conf, C_SRV, C_AUTO_ACL); conf->cache.srv_auto_acl = conf_bool(&val); + + val = conf_get(conf, C_SRV, C_PROXY_ALLOWLIST); + conf->cache.srv_proxy_enabled = (conf_val_count(&val) > 0); } int conf_new( diff --git a/src/knot/conf/base.h b/src/knot/conf/base.h index 81b54a5b1..0d32c1bb2 100644 --- a/src/knot/conf/base.h +++ b/src/knot/conf/base.h @@ -147,6 +147,7 @@ typedef struct { bool srv_ecs; bool srv_ans_rotate; bool srv_auto_acl; + bool srv_proxy_enabled; } cache; /*! List of dynamically loaded modules. */ diff --git a/src/knot/conf/schema.c b/src/knot/conf/schema.c index ae4cf3222..5f309ff27 100644 --- a/src/knot/conf/schema.c +++ b/src/knot/conf/schema.c @@ -236,6 +236,7 @@ static const yp_item_t desc_server[] = { { C_ECS, YP_TBOOL, YP_VNONE }, { C_ANS_ROTATION, YP_TBOOL, YP_VNONE }, { C_AUTO_ACL, YP_TBOOL, YP_VNONE }, + { C_PROXY_ALLOWLIST, YP_TNET, YP_VNONE, YP_FMULTI}, { C_DBUS_EVENT, YP_TOPT, YP_VOPT = { dbus_events, DBUS_EVENT_NONE }, YP_FMULTI }, { C_LISTEN, YP_TADDR, YP_VADDR = { 53 }, YP_FMULTI, { check_listen } }, { C_COMMENT, YP_TSTR, YP_VNONE }, diff --git a/src/knot/conf/schema.h b/src/knot/conf/schema.h index 55fb9ea35..3c40594d0 100644 --- a/src/knot/conf/schema.h +++ b/src/knot/conf/schema.h @@ -97,6 +97,7 @@ #define C_PIDFILE "\x07""pidfile" #define C_POLICY "\x06""policy" #define C_PROPAG_DELAY "\x11""propagation-delay" +#define C_PROXY_ALLOWLIST "\x0F""proxy-allowlist" #define C_REFRESH_MAX_INTERVAL "\x14""refresh-max-interval" #define C_REFRESH_MIN_INTERVAL "\x14""refresh-min-interval" #define C_REPRO_SIGNING "\x14""reproducible-signing" diff --git a/src/knot/include/module.h b/src/knot/include/module.h index 54fd4dab6..423fa7d28 100644 --- a/src/knot/include/module.h +++ b/src/knot/include/module.h @@ -400,7 +400,6 @@ typedef enum { typedef struct { knotd_query_flag_t flags; /*!< Current query flags. */ const struct sockaddr_storage *remote; /*!< Current remote address. */ - const struct sockaddr_storage *proxy; /*!< Current proxy address. */ int socket; /*!< Current network socket. */ unsigned thread_id; /*!< Current thread id. */ void *server; /*!< Server object private item. */ diff --git a/src/knot/query/proxyv2.h b/src/knot/query/proxyv2.h deleted file mode 100644 index 62a5597a9..000000000 --- a/src/knot/query/proxyv2.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include <sys/socket.h> -#include <stddef.h> - -#include "libknot/mm_ctx.h" -#include "libknot/packet/pkt.h" -#include "knot/include/module.h" -#include "contrib/sockaddr.h" - -int proxyv2_decapsulate(void *base, - size_t len_base, - knot_pkt_t **query, - knotd_qdata_params_t *params, - struct sockaddr_storage *client, - knot_mm_t *mm); diff --git a/src/knot/server/proxyv2.c b/src/knot/server/proxyv2.c new file mode 100644 index 000000000..1fc2c5adb --- /dev/null +++ b/src/knot/server/proxyv2.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "knot/server/proxyv2.h" + +#include "contrib/proxyv2/proxyv2.h" +#include "knot/conf/conf.h" + +int proxyv2_header_strip(knot_pkt_t **query, + const struct sockaddr_storage *remote, + struct sockaddr_storage *new_remote) +{ + conf_t *pconf = conf(); + if (!pconf->cache.srv_proxy_enabled) { + return KNOT_EDENIED; + } + + uint8_t *pkt = (*query)->wire; + size_t pkt_len = (*query)->max_size; + + int offset = proxyv2_header_offset(pkt, pkt_len); + if (offset <= 0) { + return KNOT_EMALF; + } + + /* + * Check if the query was sent from an IP address authorized to send + * proxied DNS traffic. + */ + conf_val_t whitelist_val = conf_get(pconf, C_SRV, C_PROXY_ALLOWLIST); + if (!conf_addr_range_match(&whitelist_val, remote)) { + return KNOT_EDENIED; + } + + /* + * Re-parse the query message using the data in the + * packet following the PROXY v2 payload. + */ + knot_pkt_t *q = knot_pkt_new(pkt + offset, pkt_len - offset, &(*query)->mm); + + /* + * Check if the calculated offset of the original DNS message is + * actually inside the packet received on the wire, and if so, parse + * the real DNS query message. + */ + int ret = knot_pkt_parse(q, 0); + if (ret != KNOT_EOK) { + return ret; + } + + /* + * Store the provided remote address. + */ + ret = proxyv2_addr_store(pkt, pkt_len, new_remote); + if (ret != KNOT_EOK && q->parsed > 0) { + return ret; + } + + knot_pkt_free(*query); + *query = q; + + return KNOT_EOK; +} diff --git a/src/knot/server/proxyv2.h b/src/knot/server/proxyv2.h new file mode 100644 index 000000000..5cb12512c --- /dev/null +++ b/src/knot/server/proxyv2.h @@ -0,0 +1,23 @@ +/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "libknot/packet/pkt.h" + +int proxyv2_header_strip(knot_pkt_t **query, + const struct sockaddr_storage *remote, + struct sockaddr_storage *new_remote); diff --git a/src/knot/server/udp-handler.c b/src/knot/server/udp-handler.c index 933064004..f5d8a7e41 100644 --- a/src/knot/server/udp-handler.c +++ b/src/knot/server/udp-handler.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ #include "knot/common/fdset.h" #include "knot/nameserver/process_query.h" #include "knot/query/layer.h" -#include "knot/query/proxyv2.h" +#include "knot/server/proxyv2.h" #include "knot/server/server.h" #include "knot/server/udp-handler.h" #include "knot/server/xdp-handler.h" @@ -85,19 +85,12 @@ static void udp_handle(udp_context_t *udp, int fd, struct sockaddr_storage *ss, /* Input packet. */ int ret = knot_pkt_parse(query, 0); - if (ret != KNOT_EOK && query->parsed > 0) { // parsing failed (e.g. 2x OPT) - /* - * DNS parsing failed, try re-parsing with a PROXY v2 header. - * XXX: This behavior should probably be controlled by a config - * option. - */ - ret = proxyv2_decapsulate(rx->iov_base, rx->iov_len, - &query, ¶ms, &proxied_remote, - udp->layer.mm); - - if (ret != KNOT_EOK && query->parsed > 0) { - // artificially decreasing "parsed" leads to FORMERR - query->parsed--; + if (ret != KNOT_EOK && query->parsed > 0) { + ret = proxyv2_header_strip(&query, params.remote, &proxied_remote); + if (ret == KNOT_EOK) { + params.remote = &proxied_remote; + } else { + query->parsed--; // artificially decreasing "parsed" leads to FORMERR } } knot_layer_consume(&udp->layer, query); diff --git a/src/knot/server/xdp-handler.c b/src/knot/server/xdp-handler.c index 05acbc5b9..29e085373 100644 --- a/src/knot/server/xdp-handler.c +++ b/src/knot/server/xdp-handler.c @@ -22,6 +22,7 @@ #include "knot/server/xdp-handler.h" #include "knot/common/log.h" +#include "knot/server/proxyv2.h" #include "knot/server/server.h" #include "contrib/sockaddr.h" #include "contrib/time.h" @@ -136,13 +137,19 @@ static void handle_init(knotd_qdata_params_t *params, knot_layer_t *layer, KNOTD_QUERY_FLAG_NO_IXFR | KNOTD_QUERY_FLAG_LIMIT_SIZE; } + struct sockaddr_storage proxied_remote; knot_layer_begin(layer, params); knot_pkt_t *query = knot_pkt_new(payload->iov_base, payload->iov_len, layer->mm); int ret = knot_pkt_parse(query, 0); if (ret != KNOT_EOK && query->parsed > 0) { // parsing failed (e.g. 2x OPT) - query->parsed--; // artificially decreasing "parsed" leads to FORMERR + ret = proxyv2_header_strip(&query, params->remote, &proxied_remote); + if (ret == KNOT_EOK) { + params->remote = &proxied_remote; + } else { + query->parsed--; // artificially decreasing "parsed" leads to FORMERR + } } knot_layer_consume(layer, query); } |