1209 lines
40 KiB
C
1209 lines
40 KiB
C
/*
|
|
* 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 <sched.h> /* IWYU pragma: keep */
|
|
#include <setjmp.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#define UNIT_TESTING
|
|
#include <cmocka.h>
|
|
|
|
#include <isc/buffer.h>
|
|
#include <isc/mem.h>
|
|
#include <isc/os.h>
|
|
#include <isc/proxy2.h>
|
|
#include <isc/random.h>
|
|
|
|
#include "proxyheader_test_data.h"
|
|
|
|
#include <tests/isc.h>
|
|
|
|
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
|