/* $NetBSD: proxyheader_test.c,v 1.2 2025/01/26 16:25:50 christos Exp $ */ /* * Copyright (C) Internet Systems Consortium, Inc. ("ISC") * * SPDX-License-Identifier: MPL-2.0 * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, you can obtain one at https://mozilla.org/MPL/2.0/. * * See the COPYRIGHT file distributed with this work for additional * information regarding copyright ownership. */ #include /* IWYU pragma: keep */ #include #include #include #include #define UNIT_TESTING #include #include #include #include #include #include #include "proxyheader_test_data.h" #include typedef struct dummy_handler_cbarg { isc_proxy2_command_t cmd; int socktype; isc_sockaddr_t src_addr; isc_sockaddr_t dst_addr; size_t no_more_calls; size_t tlvs; size_t tls_subtlvs; uint8_t tls_client_flags; bool client_cert_verified; isc_region_t tlv_data; isc_region_t extra; isc_region_t tls_version; isc_region_t tls_common_name; } dummy_handler_cbarg_t; static bool dummy_subtlv_iter_cb(const uint8_t client, const bool client_cert_verified, const isc_proxy2_tlv_subtype_tls_t tls_subtlv_type, const isc_region_t *restrict data, void *cbarg) { dummy_handler_cbarg_t *arg = (dummy_handler_cbarg_t *)cbarg; UNUSED(client); UNUSED(client_cert_verified); arg->tls_subtlvs++; switch (tls_subtlv_type) { case ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION: arg->tls_version = *data; break; case ISC_PROXY2_TLV_SUBTYPE_TLS_CN: arg->tls_common_name = *data; break; default: break; }; return true; } static bool dummy_tlv_iter_cb(const isc_proxy2_tlv_type_t tlv_type, const isc_region_t *restrict data, void *cbarg) { dummy_handler_cbarg_t *arg = (dummy_handler_cbarg_t *)cbarg; if (arg != NULL) { arg->tlvs++; } if (tlv_type == ISC_PROXY2_TLV_TYPE_TLS) { isc_result_t result = isc_proxy2_subtlv_tls_header_data( data, &arg->tls_client_flags, &arg->client_cert_verified); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_subtlv_tls_iterate( data, dummy_subtlv_iter_cb, cbarg); assert_true(result == ISC_R_SUCCESS); } return true; } static void proxy2_handler_dummy(const isc_result_t result, const isc_proxy2_command_t cmd, const int socktype, const isc_sockaddr_t *restrict src_addr, const isc_sockaddr_t *restrict dst_addr, const isc_region_t *restrict tlv_blob, const isc_region_t *restrict extra, void *cbarg) { dummy_handler_cbarg_t *arg = (dummy_handler_cbarg_t *)cbarg; UNUSED(extra); if (result == ISC_R_NOMORE && arg != NULL) { arg->no_more_calls++; return; } else if (result != ISC_R_SUCCESS) { return; } if (cmd == ISC_PROXY2_CMD_PROXY && socktype != 0 /* unspec */) { INSIST(src_addr != NULL); INSIST(dst_addr != NULL); } else if (cmd == ISC_PROXY2_CMD_LOCAL) { INSIST(tlv_blob == NULL); INSIST(src_addr == NULL); INSIST(dst_addr == NULL); } if (arg != NULL) { arg->cmd = cmd; arg->socktype = socktype; if (src_addr != NULL) { INSIST(dst_addr != NULL); arg->src_addr = *src_addr; arg->dst_addr = *dst_addr; } } if (tlv_blob) { assert_true(isc_proxy2_tlv_data_verify(tlv_blob) == ISC_R_SUCCESS); if (cbarg != NULL) { isc_proxy2_tlv_iterate(tlv_blob, dummy_tlv_iter_cb, cbarg); } } } static int setup_test_proxy(void **state) { isc_proxy2_handler_t **handler = (isc_proxy2_handler_t **)state; *handler = isc_proxy2_handler_new(mctx, 0, proxy2_handler_dummy, NULL); return 0; } static int teardown_test_proxy(void **state) { isc_proxy2_handler_free((isc_proxy2_handler_t **)state); return 0; } static void test_header_data(isc_proxy2_handler_t *handler, const void *data, const size_t size, const bool tear_apart, const bool tear_randomly) { isc_region_t region = { 0 }; isc_result_t result; if (tear_apart) { isc_buffer_t databuf = { 0 }; isc_buffer_init(&databuf, (void *)data, size); isc_buffer_add(&databuf, size); for (; isc_buffer_remaininglength(&databuf) > 0;) { isc_region_t remaining = { 0 }; size_t sz = 1; if (tear_randomly) { sz = 1 + isc_random_uniform( isc_buffer_remaininglength( &databuf)); } isc_buffer_remainingregion(&databuf, &remaining); remaining.length = sz; result = isc_proxy2_handler_push(handler, &remaining); assert_true(isc_proxy2_handler_result(handler) == result); isc_buffer_forward(&databuf, sz); if (result == ISC_R_SUCCESS) { break; } } } else { result = isc_proxy2_handler_push_data(handler, data, size); assert_true(isc_proxy2_handler_result(handler) == result); } assert_true(isc_proxy2_handler_result(handler) == ISC_R_SUCCESS); isc_proxy2_handler_header(handler, ®ion); assert_true(region.length == size); assert_true(memcmp(region.base, data, region.length) == 0); } static void verify_proxy_v2_header(isc_proxy2_handler_t *handler, dummy_handler_cbarg_t *cbarg) { char sabuf[ISC_SOCKADDR_FORMATSIZE] = { 0 }; isc_sockaddr_t src_addr = { 0 }, dst_addr = { 0 }; isc_result_t result; int socktype = -1; assert_true(cbarg->cmd == ISC_PROXY2_CMD_PROXY); assert_true(cbarg->socktype == SOCK_STREAM); assert_true(isc_sockaddr_pf(&cbarg->dst_addr) == AF_INET); assert_true(isc_sockaddr_pf(&cbarg->src_addr) == AF_INET); isc_sockaddr_format(&cbarg->dst_addr, sabuf, sizeof(sabuf)); assert_true(strcmp(sabuf, "127.0.0.66#11883") == 0); isc_sockaddr_format(&cbarg->src_addr, sabuf, sizeof(sabuf)); assert_true(strcmp(sabuf, "127.0.0.1#56784") == 0); if (handler != NULL) { result = isc_proxy2_handler_addresses(handler, &socktype, &src_addr, &dst_addr); assert_true(result == ISC_R_SUCCESS); assert_true(isc_sockaddr_equal(&src_addr, &cbarg->src_addr)); assert_true(isc_sockaddr_equal(&dst_addr, &cbarg->dst_addr)); assert_true(socktype == cbarg->socktype); } assert_true(cbarg->tlvs == 0); assert_true(cbarg->tls_subtlvs == 0); assert_true(cbarg->tls_client_flags == 0); assert_true(cbarg->client_cert_verified == false); } static void verify_proxy_v2_header_with_TLS(isc_proxy2_handler_t *handler, dummy_handler_cbarg_t *cbarg) { char sabuf[ISC_SOCKADDR_FORMATSIZE] = { 0 }; isc_sockaddr_t src_addr = { 0 }, dst_addr = { 0 }; isc_result_t result; int socktype = -1; assert_true(cbarg->cmd == ISC_PROXY2_CMD_PROXY); assert_true(cbarg->socktype == SOCK_STREAM); assert_true(isc_sockaddr_pf(&cbarg->dst_addr) == AF_INET); assert_true(isc_sockaddr_pf(&cbarg->src_addr) == AF_INET); isc_sockaddr_format(&cbarg->dst_addr, sabuf, sizeof(sabuf)); assert_true(strcmp(sabuf, "127.0.0.67#11883") == 0); isc_sockaddr_format(&cbarg->src_addr, sabuf, sizeof(sabuf)); assert_true(strcmp(sabuf, "127.0.0.1#39754") == 0); if (handler != NULL) { result = isc_proxy2_handler_addresses(handler, &socktype, &src_addr, &dst_addr); assert_true(result == ISC_R_SUCCESS); assert_true(isc_sockaddr_equal(&src_addr, &cbarg->src_addr)); assert_true(isc_sockaddr_equal(&dst_addr, &cbarg->dst_addr)); assert_true(socktype == cbarg->socktype); } assert_true(cbarg->tlvs == 1); assert_true(cbarg->tls_subtlvs == 1); assert_true(cbarg->tls_client_flags == ISC_PROXY2_CLIENT_TLS); assert_true(cbarg->client_cert_verified == true); /* "TLSv1.2" (w/o trailing '\0') */ assert_true(cbarg->tls_version.length == 7); assert_true(memcmp(cbarg->tls_version.base, "TLSv1.2", 7) == 0); } static void verify_proxy_v2_header_with_TLS_CN(isc_proxy2_handler_t *handler, dummy_handler_cbarg_t *cbarg) { char sabuf[ISC_SOCKADDR_FORMATSIZE] = { 0 }; isc_sockaddr_t src_addr = { 0 }, dst_addr = { 0 }; isc_result_t result; int socktype = -1; assert_true(cbarg->cmd == ISC_PROXY2_CMD_PROXY); assert_true(cbarg->socktype == SOCK_STREAM); assert_true(isc_sockaddr_pf(&cbarg->dst_addr) == AF_INET); assert_true(isc_sockaddr_pf(&cbarg->src_addr) == AF_INET); isc_sockaddr_format(&cbarg->dst_addr, sabuf, sizeof(sabuf)); assert_true(strcmp(sabuf, "127.0.0.67#11883") == 0); isc_sockaddr_format(&cbarg->src_addr, sabuf, sizeof(sabuf)); assert_true(strcmp(sabuf, "127.0.0.1#40402") == 0); if (handler != NULL) { result = isc_proxy2_handler_addresses(handler, &socktype, &src_addr, &dst_addr); assert_true(result == ISC_R_SUCCESS); assert_true(isc_sockaddr_equal(&src_addr, &cbarg->src_addr)); assert_true(isc_sockaddr_equal(&dst_addr, &cbarg->dst_addr)); assert_true(socktype == cbarg->socktype); } assert_true(cbarg->tlvs == 1); assert_true(cbarg->tls_subtlvs == 2); /* version and common name */ assert_true(cbarg->tls_client_flags == (ISC_PROXY2_CLIENT_TLS | ISC_PROXY2_CLIENT_CERT_SESS | ISC_PROXY2_CLIENT_CERT_CONN)); assert_true(cbarg->client_cert_verified == true); /* "TLSv1.2" (w/o trailing '\0') */ assert_true(cbarg->tls_version.length == 7); assert_true(memcmp(cbarg->tls_version.base, "TLSv1.2", 7) == 0); /* "mqttuser1" (w/o trailing '\0') */ assert_true(cbarg->tls_common_name.length == 9); assert_true(memcmp(cbarg->tls_common_name.base, "mqttuser1", 9) == 0); } static void verify_proxy_v2_header_with_AF_UNIX(isc_proxy2_handler_t *handler, dummy_handler_cbarg_t *cbarg) { assert_true(cbarg->cmd == ISC_PROXY2_CMD_PROXY); assert_true(cbarg->socktype == 0); if (handler != NULL) { int socktype = -1; isc_result_t result; result = isc_proxy2_handler_addresses(handler, &socktype, NULL, NULL); assert_int_equal(result, ISC_R_SUCCESS); assert_int_equal(socktype, 0); } } ISC_RUN_TEST_IMPL(proxyheader_generic_test) { isc_proxy2_handler_t *handler = (isc_proxy2_handler_t *)*state; dummy_handler_cbarg_t cbarg = { 0 }; isc_proxy2_handler_setcb(handler, proxy2_handler_dummy, &cbarg); test_header_data(handler, proxy_v2_header, sizeof(proxy_v2_header), false, false); verify_proxy_v2_header(handler, &cbarg); cbarg = (dummy_handler_cbarg_t){ 0 }; test_header_data(handler, (void *)proxy_v2_header_with_TLS, sizeof(proxy_v2_header_with_TLS), false, false); verify_proxy_v2_header_with_TLS(handler, &cbarg); cbarg = (dummy_handler_cbarg_t){ 0 }; test_header_data(handler, (void *)proxy_v2_header_with_TLS_CN, sizeof(proxy_v2_header_with_TLS_CN), false, false); verify_proxy_v2_header_with_TLS_CN(handler, &cbarg); cbarg = (dummy_handler_cbarg_t){ 0 }; test_header_data(handler, (void *)proxy_v2_header_with_AF_UNIX, sizeof(proxy_v2_header_with_AF_UNIX), false, false); verify_proxy_v2_header_with_AF_UNIX(handler, &cbarg); } ISC_RUN_TEST_IMPL(proxyheader_generic_byte_by_byte_test) { isc_proxy2_handler_t *handler = (isc_proxy2_handler_t *)*state; dummy_handler_cbarg_t cbarg = { 0 }; isc_proxy2_handler_setcb(handler, proxy2_handler_dummy, &cbarg); test_header_data(handler, proxy_v2_header, sizeof(proxy_v2_header), true, false); verify_proxy_v2_header(handler, &cbarg); assert_true(cbarg.no_more_calls == sizeof(proxy_v2_header) - 1); cbarg = (dummy_handler_cbarg_t){ 0 }; test_header_data(handler, (void *)proxy_v2_header_with_TLS, sizeof(proxy_v2_header_with_TLS), true, false); verify_proxy_v2_header_with_TLS(handler, &cbarg); assert_true(cbarg.no_more_calls == sizeof(proxy_v2_header_with_TLS) - 1); cbarg = (dummy_handler_cbarg_t){ 0 }; test_header_data(handler, (void *)proxy_v2_header_with_TLS_CN, sizeof(proxy_v2_header_with_TLS_CN), true, false); verify_proxy_v2_header_with_TLS_CN(handler, &cbarg); assert_true(cbarg.no_more_calls == sizeof(proxy_v2_header_with_TLS_CN) - 1); cbarg = (dummy_handler_cbarg_t){ 0 }; test_header_data(handler, (void *)proxy_v2_header_with_AF_UNIX, sizeof(proxy_v2_header_with_AF_UNIX), true, false); verify_proxy_v2_header_with_AF_UNIX(handler, &cbarg); assert_true(cbarg.no_more_calls == sizeof(proxy_v2_header_with_AF_UNIX) - 1); } ISC_RUN_TEST_IMPL(proxyheader_generic_torn_apart_randomly_test) { isc_proxy2_handler_t *handler = (isc_proxy2_handler_t *)*state; dummy_handler_cbarg_t cbarg = { 0 }; isc_proxy2_handler_setcb(handler, proxy2_handler_dummy, &cbarg); test_header_data(handler, proxy_v2_header, sizeof(proxy_v2_header), true, true); verify_proxy_v2_header(handler, &cbarg); cbarg = (dummy_handler_cbarg_t){ 0 }; test_header_data(handler, (void *)proxy_v2_header_with_TLS, sizeof(proxy_v2_header_with_TLS), true, true); verify_proxy_v2_header_with_TLS(handler, &cbarg); cbarg = (dummy_handler_cbarg_t){ 0 }; test_header_data(handler, (void *)proxy_v2_header_with_TLS_CN, sizeof(proxy_v2_header_with_TLS_CN), true, true); verify_proxy_v2_header_with_TLS_CN(handler, &cbarg); cbarg = (dummy_handler_cbarg_t){ 0 }; test_header_data(handler, (void *)proxy_v2_header_with_AF_UNIX, sizeof(proxy_v2_header_with_AF_UNIX), true, true); verify_proxy_v2_header_with_AF_UNIX(handler, &cbarg); } ISC_RUN_TEST_IMPL(proxyheader_direct_test) { isc_result_t result; isc_region_t region = { 0 }; dummy_handler_cbarg_t cbarg = { 0 }; cbarg = (dummy_handler_cbarg_t){ 0 }; region.base = (uint8_t *)proxy_v2_header; region.length = sizeof(proxy_v2_header); result = isc_proxy2_header_handle_directly( ®ion, proxy2_handler_dummy, &cbarg); assert_true(result == ISC_R_SUCCESS); assert_true(cbarg.no_more_calls == 0); verify_proxy_v2_header(NULL, &cbarg); cbarg = (dummy_handler_cbarg_t){ 0 }; region.base = (uint8_t *)proxy_v2_header_with_TLS; region.length = sizeof(proxy_v2_header_with_TLS); result = isc_proxy2_header_handle_directly( ®ion, proxy2_handler_dummy, &cbarg); assert_true(result == ISC_R_SUCCESS); assert_true(cbarg.no_more_calls == 0); isc_proxy2_tlv_iterate(&cbarg.tlv_data, dummy_tlv_iter_cb, &cbarg); verify_proxy_v2_header_with_TLS(NULL, &cbarg); cbarg = (dummy_handler_cbarg_t){ 0 }; region.base = (uint8_t *)proxy_v2_header_with_TLS_CN; region.length = sizeof(proxy_v2_header_with_TLS_CN); result = isc_proxy2_header_handle_directly( ®ion, proxy2_handler_dummy, &cbarg); assert_true(result == ISC_R_SUCCESS); assert_true(cbarg.no_more_calls == 0); isc_proxy2_tlv_iterate(&cbarg.tlv_data, dummy_tlv_iter_cb, &cbarg); verify_proxy_v2_header_with_TLS_CN(NULL, &cbarg); cbarg = (dummy_handler_cbarg_t){ 0 }; region.base = (uint8_t *)proxy_v2_header_with_AF_UNIX; region.length = sizeof(proxy_v2_header_with_AF_UNIX); result = isc_proxy2_header_handle_directly( ®ion, proxy2_handler_dummy, &cbarg); assert_true(result == ISC_R_SUCCESS); assert_true(cbarg.no_more_calls == 0); verify_proxy_v2_header_with_AF_UNIX(NULL, &cbarg); } ISC_RUN_TEST_IMPL(proxyheader_detect_bad_signature_test) { isc_proxy2_handler_t *handler = (isc_proxy2_handler_t *)*state; for (size_t i = 0; i < ISC_PROXY2_HEADER_SIGNATURE_SIZE; i++) { isc_result_t result; uint8_t sig[ISC_PROXY2_HEADER_SIGNATURE_SIZE]; memmove(sig, ISC_PROXY2_HEADER_SIGNATURE, ISC_PROXY2_HEADER_SIGNATURE_SIZE); sig[i] = 0x0C; /* it is not present in the valid signature */ /* * We are expected to detect bad signature as early as possible, * so we are passing only a part of the header. */ result = isc_proxy2_handler_push_data(handler, sig, i + 1); assert_true(result == ISC_R_UNEXPECTED); } } ISC_RUN_TEST_IMPL(proxyheader_extra_data_test) { isc_result_t result; isc_buffer_t databuf; isc_region_t region = { 0 }; size_t sz; isc_proxy2_handler_t *handler = (isc_proxy2_handler_t *)*state; uint8_t header[] = { 0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x0d, 0x0a, 0x51, 0x55, 0x49, 0x54, 0x0a, 0x21, 0x11, 0x00, 0x1e, 0x7f, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x43, 0x9b, 0x4a, 0x2e, 0x6b, 0x20, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x07, 0x54, 0x4c, 0x53, 0x76, 0x31, 0x2e, 0x32 }; uint8_t extra_data[] = { 0x10, 0x1a, 0x00, 0x04, 0x4d, 0x51, 0x54, 0x54, 0x04, 0x02, 0x00, 0x3c, 0x00, 0x0e, 0x4d, 0x51, 0x54, 0x54, 0x5f, 0x46, 0x58, 0x5f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74 }; uint8_t data[sizeof(header) + sizeof(extra_data)]; isc_buffer_init(&databuf, (void *)data, sizeof(data)); isc_buffer_putmem(&databuf, header, sizeof(header)); isc_buffer_putmem(&databuf, extra_data, sizeof(extra_data)); isc_buffer_remainingregion(&databuf, ®ion); result = isc_proxy2_handler_push(handler, ®ion); assert_true(result == ISC_R_SUCCESS); region = (isc_region_t){ 0 }; sz = isc_proxy2_handler_header(handler, ®ion); assert_true(sz == sizeof(header)); assert_true(sz == region.length); assert_true(memcmp(header, region.base, sz) == 0); region = (isc_region_t){ 0 }; sz = isc_proxy2_handler_extra(handler, ®ion); assert_true(sz == sizeof(extra_data)); assert_true(sz == region.length); assert_true(memcmp(extra_data, region.base, sz) == 0); } ISC_RUN_TEST_IMPL(proxyheader_max_size_test) { isc_result_t result; isc_proxy2_handler_t handler; UNUSED(state); isc_proxy2_handler_init(&handler, mctx, sizeof(proxy_v2_header), proxy2_handler_dummy, NULL); result = isc_proxy2_handler_push_data(&handler, proxy_v2_header, sizeof(proxy_v2_header)); assert_true(result == ISC_R_SUCCESS); isc_proxy2_handler_uninit(&handler); isc_proxy2_handler_init(&handler, mctx, sizeof(proxy_v2_header) - 1, proxy2_handler_dummy, NULL); result = isc_proxy2_handler_push_data(&handler, proxy_v2_header, sizeof(proxy_v2_header)); assert_true(result == ISC_R_RANGE); isc_proxy2_handler_uninit(&handler); } ISC_RUN_TEST_IMPL(proxyheader_make_header_test) { isc_result_t result; isc_proxy2_handler_t *handler = (isc_proxy2_handler_t *)*state; isc_buffer_t databuf; uint8_t data[ISC_PROXY2_MAX_SIZE]; isc_buffer_t sslbuf; uint8_t ssldata[ISC_PROXY2_MAX_SIZE]; isc_region_t region = { 0 }; uint8_t extra[256] = { 0 }; const char *tls_version = "TLSv1.3"; const char *tls_cn = "name.test"; dummy_handler_cbarg_t cbarg = { 0 }; struct in_addr localhost4 = { 0 }; isc_sockaddr_t src_addrv4 = { 0 }, dst_addrv4 = { 0 }, src_addrv6 = { 0 }, dst_addrv6 = { 0 }; const uint16_t src_port = 1236; const uint16_t dst_port = 9582; localhost4.s_addr = htonl(INADDR_LOOPBACK); isc_sockaddr_fromin(&src_addrv4, &localhost4, src_port); isc_sockaddr_fromin(&dst_addrv4, &localhost4, dst_port); isc_sockaddr_fromin6(&src_addrv6, &in6addr_loopback, src_port); isc_sockaddr_fromin6(&dst_addrv6, &in6addr_loopback, dst_port); isc_proxy2_handler_setcb(handler, proxy2_handler_dummy, &cbarg); isc_buffer_init(&databuf, (void *)data, sizeof(data)); isc_buffer_init(&sslbuf, (void *)ssldata, sizeof(ssldata)); /* unspec */ result = isc_proxy2_make_header(&databuf, ISC_PROXY2_CMD_LOCAL, 0, NULL, NULL, NULL); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); assert_true(region.length == ISC_PROXY2_HEADER_SIZE); region = (isc_region_t){ .base = extra, .length = sizeof(extra) }; result = isc_proxy2_header_append_tlv( &databuf, ISC_PROXY2_TLV_TYPE_NOOP, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); assert_true(region.length == ISC_PROXY2_HEADER_SIZE + sizeof(extra) + ISC_PROXY2_TLV_HEADER_SIZE); result = isc_proxy2_handler_push(handler, ®ion); assert_true(result == ISC_R_SUCCESS); assert_true(cbarg.tlvs == 0); /* in unspec mode we ignore TLVs */ /* AF_INET, SOCK_STREAM */ cbarg = (dummy_handler_cbarg_t){ 0 }; isc_buffer_clear(&databuf); result = isc_proxy2_make_header(&databuf, ISC_PROXY2_CMD_PROXY, SOCK_STREAM, &src_addrv4, &dst_addrv4, NULL); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); assert_true(region.length == ISC_PROXY2_MIN_AF_INET_SIZE); region = (isc_region_t){ .base = extra, .length = sizeof(extra) }; result = isc_proxy2_header_append_tlv( &databuf, ISC_PROXY2_TLV_TYPE_NOOP, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); assert_true(region.length == ISC_PROXY2_MIN_AF_INET_SIZE + sizeof(extra) + ISC_PROXY2_TLV_HEADER_SIZE); result = isc_proxy2_handler_push(handler, ®ion); assert_true(result == ISC_R_SUCCESS); assert_true(cbarg.tlvs == 1); /* ISC_PROXY2_TLV_TYPE_NOOP */ assert_true(cbarg.socktype == SOCK_STREAM); assert_true(isc_sockaddr_pf(&cbarg.src_addr) == AF_INET); assert_true(isc_sockaddr_pf(&cbarg.dst_addr) == AF_INET); assert_true(isc_sockaddr_equal(&cbarg.src_addr, &src_addrv4)); assert_true(isc_sockaddr_equal(&cbarg.dst_addr, &dst_addrv4)); /* AF_INET6, SOCK_STREAM (+ TLS version and CN) */ cbarg = (dummy_handler_cbarg_t){ 0 }; isc_buffer_clear(&databuf); result = isc_proxy2_make_header(&databuf, ISC_PROXY2_CMD_PROXY, SOCK_STREAM, &src_addrv6, &dst_addrv6, NULL); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); assert_true(region.length == ISC_PROXY2_MIN_AF_INET6_SIZE); region = (isc_region_t){ .base = extra, .length = sizeof(extra) }; result = isc_proxy2_header_append_tlv( &databuf, ISC_PROXY2_TLV_TYPE_NOOP, ®ion); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_make_tls_subheader( &sslbuf, ISC_PROXY2_CLIENT_TLS | ISC_PROXY2_CLIENT_CERT_CONN, true, NULL); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_append_tlv_string( &sslbuf, ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION, tls_version); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_append_tlv_string( &sslbuf, ISC_PROXY2_TLV_SUBTYPE_TLS_CN, tls_cn); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&sslbuf, ®ion); result = isc_proxy2_header_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_TLS, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); size_t expected = ISC_PROXY2_MIN_AF_INET6_SIZE + sizeof(extra) + (4 * ISC_PROXY2_TLV_HEADER_SIZE) + ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE + strlen(tls_version) + strlen(tls_cn); assert_true(region.length == expected); result = isc_proxy2_handler_push(handler, ®ion); assert_true(result == ISC_R_SUCCESS); assert_true(cbarg.socktype == SOCK_STREAM); assert_true(isc_sockaddr_pf(&cbarg.src_addr) == AF_INET6); assert_true(isc_sockaddr_pf(&cbarg.dst_addr) == AF_INET6); assert_true(isc_sockaddr_equal(&cbarg.src_addr, &src_addrv6)); assert_true(isc_sockaddr_equal(&cbarg.dst_addr, &dst_addrv6)); region = (isc_region_t){ 0 }; (void)isc_proxy2_handler_tlvs(handler, ®ion); assert_true(isc_proxy2_tlv_data_verify(®ion) == ISC_R_SUCCESS); /* ISC_PROXY2_TLV_TYPE_NOOP+ISC_PROXY2_TLV_TYPE_TLS */ assert_true(cbarg.tlvs == 2); /* ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION+ISC_PROXY2_TLV_SUBTYPE_TLS_CN */ assert_true(cbarg.tls_subtlvs == 2); assert_true(cbarg.tls_version.length == strlen(tls_version)); assert_true(memcmp(cbarg.tls_version.base, tls_version, strlen(tls_version)) == 0); assert_true(cbarg.tls_common_name.length == strlen(tls_cn)); assert_true(memcmp(cbarg.tls_common_name.base, tls_cn, strlen(tls_cn)) == 0); } static bool rebuild_subtlv_iter_cb(const uint8_t client, const bool client_cert_verified, const isc_proxy2_tlv_subtype_tls_t tls_subtlv_type, const isc_region_t *restrict data, void *cbarg) { isc_result_t result; isc_buffer_t *outbuf = (isc_buffer_t *)cbarg; UNUSED(client); UNUSED(client_cert_verified); result = isc_proxy2_append_tlv(outbuf, tls_subtlv_type, data); assert_true(result == ISC_R_SUCCESS); return true; } static bool rebuild_tlv_iter_cb(const isc_proxy2_tlv_type_t tlv_type, const isc_region_t *restrict data, void *cbarg) { isc_result_t result; isc_buffer_t *outbuf = (isc_buffer_t *)cbarg; if (tlv_type == ISC_PROXY2_TLV_TYPE_TLS) { uint8_t client_flags = 0; bool client_cert_verified = false; isc_buffer_t databuf = { 0 }; isc_region_t region = { 0 }; uint8_t storage[ISC_PROXY2_MAX_SIZE]; isc_buffer_init(&databuf, (void *)storage, sizeof(storage)); /* get flags values */ result = isc_proxy2_subtlv_tls_header_data( data, &client_flags, &client_cert_verified); assert_true(result == ISC_R_SUCCESS); /* create header */ result = isc_proxy2_make_tls_subheader( &databuf, client_flags, client_cert_verified, NULL); assert_true(result == ISC_R_SUCCESS); /* process and append values */ result = isc_proxy2_subtlv_tls_iterate( data, rebuild_subtlv_iter_cb, &databuf); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_header_append_tlv(outbuf, tlv_type, ®ion); assert_true(result == ISC_R_SUCCESS); } else { result = isc_proxy2_header_append_tlv(outbuf, tlv_type, data); assert_true(result == ISC_R_SUCCESS); } return true; } static void proxy2_handler_rebuild_cb(const isc_result_t header_result, const isc_proxy2_command_t cmd, const int socktype, const isc_sockaddr_t *restrict src_addr, const isc_sockaddr_t *restrict dst_addr, const isc_region_t *restrict tlv_blob, const isc_region_t *restrict extra, void *cbarg) { isc_result_t result; isc_buffer_t *outbuf = (isc_buffer_t *)cbarg; if (header_result != ISC_R_SUCCESS) { return; } result = isc_proxy2_make_header(outbuf, cmd, socktype, src_addr, dst_addr, NULL); assert_true(result == ISC_R_SUCCESS); if (tlv_blob != NULL) { isc_proxy2_tlv_iterate(tlv_blob, rebuild_tlv_iter_cb, outbuf); } if (extra != NULL) { result = isc_proxy2_tlv_data_verify(tlv_blob); assert_true(result == ISC_R_SUCCESS); isc_buffer_putmem(outbuf, extra->base, extra->length); } } static void proxy2_handler_rebuild(isc_buffer_t *restrict outbuf, const void *data, const size_t size) { isc_proxy2_handler_t handler = { 0 }; isc_proxy2_handler_init(&handler, mctx, 0, proxy2_handler_rebuild_cb, outbuf); isc_proxy2_handler_push_data(&handler, data, size); isc_proxy2_handler_uninit(&handler); } static void try_rebuild_header(const void *data, size_t size) { isc_buffer_t databuf = { 0 }; isc_region_t region = { 0 }; uint8_t storage[ISC_PROXY2_MAX_SIZE]; isc_buffer_init(&databuf, (void *)storage, sizeof(storage)); proxy2_handler_rebuild(&databuf, data, size); isc_buffer_usedregion(&databuf, ®ion); assert_true(region.length == size); assert_true(memcmp(region.base, data, size) == 0); } ISC_RUN_TEST_IMPL(proxyheader_rebuild_header_test) { try_rebuild_header(proxy_v2_header, sizeof(proxy_v2_header)); try_rebuild_header(proxy_v2_header_with_TLS, sizeof(proxy_v2_header_with_TLS)); try_rebuild_header(proxy_v2_header_with_TLS_CN, sizeof(proxy_v2_header_with_TLS_CN)); } ISC_RUN_TEST_IMPL(proxyheader_bad_header_signature_test) { size_t i; isc_result_t result; isc_proxy2_handler_t *handler = (isc_proxy2_handler_t *)*state; for (i = 0; i < ISC_PROXY2_HEADER_SIGNATURE_SIZE; i++) { uint8_t sig[ISC_PROXY2_HEADER_SIGNATURE_SIZE]; memmove(sig, ISC_PROXY2_HEADER_SIGNATURE, ISC_PROXY2_HEADER_SIGNATURE_SIZE); sig[i] = 0x0C; /* 0x0C cannot be found in the signature */ result = isc_proxy2_handler_push_data(handler, sig, sizeof(sig)); assert_true(result == ISC_R_UNEXPECTED); isc_proxy2_handler_clear(handler); } result = isc_proxy2_handler_push_data(handler, ISC_PROXY2_HEADER_SIGNATURE, ISC_PROXY2_HEADER_SIGNATURE_SIZE); assert_true(result == ISC_R_NOMORE); } ISC_RUN_TEST_IMPL(proxyheader_bad_proto_version_command_test) { isc_proxy2_handler_t *handler = (isc_proxy2_handler_t *)*state; isc_result_t result; uint8_t *pver_cmd = NULL; uint8_t botched_header[sizeof(proxy_v2_header)] = { 0 }; memmove(botched_header, proxy_v2_header, sizeof(proxy_v2_header)); pver_cmd = &botched_header[ISC_PROXY2_HEADER_SIGNATURE_SIZE]; assert_true(*pver_cmd == 0x21); *pver_cmd = 0x31; /* unexpected version (3) followed by PROXY command */ result = isc_proxy2_handler_push_data(handler, botched_header, sizeof(botched_header)); assert_true(result == ISC_R_NOTIMPLEMENTED); *pver_cmd = 0x22; /* version two followed by unexpected command (2) */ result = isc_proxy2_handler_push_data(handler, botched_header, sizeof(botched_header)); assert_true(result == ISC_R_UNEXPECTED); } ISC_RUN_TEST_IMPL(proxyheader_bad_family_socktype_test) { isc_proxy2_handler_t *handler = (isc_proxy2_handler_t *)*state; isc_result_t result; uint8_t *pfam = NULL; uint8_t botched_header[sizeof(proxy_v2_header)] = { 0 }; memmove(botched_header, proxy_v2_header, sizeof(proxy_v2_header)); pfam = &botched_header[ISC_PROXY2_HEADER_SIGNATURE_SIZE + 1]; assert_true(*pfam == 0x11); *pfam = 0x41; /* unexpected family (4) followed by SOCK_STREAM (1)*/ result = isc_proxy2_handler_push_data(handler, botched_header, sizeof(botched_header)); assert_true(result == ISC_R_UNEXPECTED); *pfam = 0x13; /* AF_INET (1) followed by unexpected sock type (3) */ result = isc_proxy2_handler_push_data(handler, botched_header, sizeof(botched_header)); assert_true(result == ISC_R_UNEXPECTED); } static inline void update_header_length(uint8_t *botched_header, uint16_t newlen) { newlen = htons(newlen); memmove(&botched_header[ISC_PROXY2_HEADER_SIGNATURE_SIZE + 2], &newlen, sizeof(newlen)); } ISC_RUN_TEST_IMPL(proxyheader_bad_unexpected_not_enough_length_test) { isc_proxy2_handler_t *handler = (isc_proxy2_handler_t *)*state; isc_result_t result; uint8_t botched_header[sizeof(proxy_v2_header)] = { 0 }; memmove(botched_header, proxy_v2_header, sizeof(proxy_v2_header)); update_header_length(botched_header, 0); result = isc_proxy2_handler_push_data(handler, botched_header, sizeof(botched_header)); assert_true(result == ISC_R_RANGE); update_header_length(botched_header, 4); /* not enough */ result = isc_proxy2_handler_push_data(handler, botched_header, sizeof(botched_header)); assert_true(result == ISC_R_RANGE); update_header_length(botched_header, UINT16_MAX); /* no more */ result = isc_proxy2_handler_push_data(handler, botched_header, sizeof(botched_header)); assert_true(result == ISC_R_NOMORE); isc_proxy2_handler_clear(handler); } ISC_RUN_TEST_IMPL(proxyheader_tlv_data_test) { isc_result_t result; isc_buffer_t databuf = { 0 }; isc_buffer_t tlsbuf = { 0 }; uint8_t data[ISC_PROXY2_MAX_SIZE] = { 0 }; uint8_t tlsdata[ISC_PROXY2_MAX_SIZE] = { 0 }; uint8_t zerodata[0xff] = { 0 }; isc_region_t region = { 0 }; const char *alpn = "dot"; const char *tls_version = "TLSv1.3"; const char *tls_cn = "name.test"; isc_buffer_init(&databuf, (void *)data, sizeof(data)); isc_buffer_init(&tlsbuf, (void *)tlsdata, sizeof(tlsdata)); /* zero filled data is not fine */ region.base = zerodata; region.length = sizeof(zerodata); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_UNEXPECTED); /* crc32c must be 4 bytes long */ isc_buffer_clear(&databuf); region.base = (uint8_t *)zerodata; region.length = sizeof(zerodata); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_CRC32C, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_RANGE); isc_buffer_clear(&databuf); region.base = (uint8_t *)zerodata; region.length = 4; result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_CRC32C, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_SUCCESS); /* unique id must be <= 128 bytes long */ isc_buffer_clear(&databuf); region.base = (uint8_t *)zerodata; region.length = sizeof(zerodata); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_UNIQUE_ID, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_RANGE); isc_buffer_clear(&databuf); region.base = (uint8_t *)zerodata; region.length = 128; result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_UNIQUE_ID, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_SUCCESS); /* two noops is fine */ isc_buffer_clear(&databuf); region = (isc_region_t){ 0 }; result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_NOOP, ®ion); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_NOOP, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_SUCCESS); /* one ALPN tag is fine */ isc_buffer_clear(&databuf); result = isc_proxy2_append_tlv_string(&databuf, ISC_PROXY2_TLV_TYPE_ALPN, alpn); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_SUCCESS); /* two ALPN tags is not fine */ result = isc_proxy2_append_tlv_string(&databuf, ISC_PROXY2_TLV_TYPE_ALPN, alpn); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_UNEXPECTED); /* empty TLS subheader is tolerable */ isc_buffer_clear(&databuf); isc_buffer_clear(&tlsbuf); result = isc_proxy2_make_tls_subheader(&tlsbuf, 0, false, NULL); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&tlsbuf, ®ion); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_TLS, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_SUCCESS); /* empty TLS subheader with no TLS version while one is expected */ isc_buffer_clear(&databuf); isc_buffer_clear(&tlsbuf); result = isc_proxy2_make_tls_subheader(&tlsbuf, ISC_PROXY2_CLIENT_TLS, false, NULL); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&tlsbuf, ®ion); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_TLS, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_UNEXPECTED); /* TLS subheader with TLS version */ isc_buffer_clear(&databuf); isc_buffer_clear(&tlsbuf); result = isc_proxy2_make_tls_subheader(&tlsbuf, ISC_PROXY2_CLIENT_TLS, false, NULL); assert_true(result == ISC_R_SUCCESS); region.length = sizeof(tls_version); result = isc_proxy2_append_tlv_string( &tlsbuf, ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION, tls_version); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&tlsbuf, ®ion); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_TLS, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_SUCCESS); /* TLS subheader with multiple TLS versions is not fine */ isc_buffer_clear(&databuf); isc_buffer_clear(&tlsbuf); result = isc_proxy2_make_tls_subheader(&tlsbuf, ISC_PROXY2_CLIENT_TLS, false, NULL); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_append_tlv_string( &tlsbuf, ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION, tls_version); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_append_tlv( &tlsbuf, ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&tlsbuf, ®ion); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_TLS, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_UNEXPECTED); /* TLS subheader with unexpected TLS version */ isc_buffer_clear(&databuf); isc_buffer_clear(&tlsbuf); result = isc_proxy2_make_tls_subheader(&tlsbuf, 0, false, NULL); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_append_tlv_string( &tlsbuf, ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION, tls_version); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&tlsbuf, ®ion); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_TLS, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_UNEXPECTED); /* TLS subheader with no CN while expected */ isc_buffer_clear(&databuf); isc_buffer_clear(&tlsbuf); result = isc_proxy2_make_tls_subheader( &tlsbuf, ISC_PROXY2_CLIENT_TLS | ISC_PROXY2_CLIENT_CERT_CONN, false, NULL); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_append_tlv_string( &tlsbuf, ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION, tls_version); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&tlsbuf, ®ion); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_TLS, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_UNEXPECTED); /* TLS subheader with unexpected CN */ isc_buffer_clear(&databuf); isc_buffer_clear(&tlsbuf); result = isc_proxy2_make_tls_subheader(&tlsbuf, ISC_PROXY2_CLIENT_TLS, false, NULL); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_append_tlv_string( &tlsbuf, ISC_PROXY2_TLV_SUBTYPE_TLS_CN, tls_cn); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&tlsbuf, ®ion); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_TLS, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_UNEXPECTED); /* TLS subheader with CN unexpected (because TLS flag is not set) */ isc_buffer_clear(&databuf); isc_buffer_clear(&tlsbuf); result = isc_proxy2_make_tls_subheader( &tlsbuf, ISC_PROXY2_CLIENT_CERT_CONN | ISC_PROXY2_CLIENT_CERT_SESS, false, NULL); assert_true(result == ISC_R_SUCCESS); result = isc_proxy2_append_tlv_string( &tlsbuf, ISC_PROXY2_TLV_SUBTYPE_TLS_CN, tls_cn); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&tlsbuf, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&tlsbuf, ®ion); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_TLS, ®ion); assert_true(result == ISC_R_SUCCESS); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_UNEXPECTED); /* botched TLV header */ isc_buffer_clear(&databuf); region.base = (uint8_t *)zerodata; region.length = sizeof(zerodata); result = isc_proxy2_append_tlv(&databuf, ISC_PROXY2_TLV_TYPE_NOOP, ®ion); isc_buffer_subtract(&databuf, region.length / 2); isc_buffer_usedregion(&databuf, ®ion); result = isc_proxy2_tlv_data_verify(®ion); assert_true(result == ISC_R_RANGE); } ISC_TEST_LIST_START ISC_TEST_ENTRY_CUSTOM(proxyheader_generic_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_generic_byte_by_byte_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_generic_torn_apart_randomly_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_direct_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_detect_bad_signature_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_extra_data_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_max_size_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_make_header_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_rebuild_header_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_bad_header_signature_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_bad_proto_version_command_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_bad_family_socktype_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_bad_unexpected_not_enough_length_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_ENTRY_CUSTOM(proxyheader_tlv_data_test, setup_test_proxy, teardown_test_proxy) ISC_TEST_LIST_END ISC_TEST_MAIN