Home | History | Annotate | Line # | Download | only in isc
      1 /*	$NetBSD: proxy2.c,v 1.3 2025/07/17 19:01:46 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 #include <isc/proxy2.h>
     17 
     18 enum isc_proxy2_states {
     19 	ISC_PROXY2_STATE_WAITING_SIGNATURE,
     20 	ISC_PROXY2_STATE_WAITING_HEADER,
     21 	ISC_PROXY2_STATE_WAITING_PAYLOAD, /* Addresses and TLVs */
     22 	ISC_PROXY2_STATE_END
     23 };
     24 
     25 static inline void
     26 isc__proxy2_handler_init_direct(isc_proxy2_handler_t *restrict handler,
     27 				const uint16_t max_size,
     28 				const isc_region_t *restrict data,
     29 				isc_proxy2_handler_cb_t cb, void *cbarg) {
     30 	*handler = (isc_proxy2_handler_t){ .result = ISC_R_UNSET,
     31 					   .max_size = max_size };
     32 	isc_proxy2_handler_setcb(handler, cb, cbarg);
     33 
     34 	if (data == NULL) {
     35 		isc_buffer_init(&handler->hdrbuf, handler->buf,
     36 				sizeof(handler->buf));
     37 	} else {
     38 		isc_buffer_init(&handler->hdrbuf, data->base, data->length);
     39 		isc_buffer_add(&handler->hdrbuf, data->length);
     40 	}
     41 }
     42 
     43 void
     44 isc_proxy2_handler_init(isc_proxy2_handler_t *restrict handler, isc_mem_t *mctx,
     45 			const uint16_t max_size, isc_proxy2_handler_cb_t cb,
     46 			void *cbarg) {
     47 	REQUIRE(handler != NULL);
     48 	REQUIRE(mctx != NULL);
     49 	REQUIRE(max_size == 0 || max_size >= ISC_PROXY2_HEADER_SIZE);
     50 	REQUIRE(cb != NULL);
     51 
     52 	isc__proxy2_handler_init_direct(handler, max_size, NULL, cb, cbarg);
     53 
     54 	isc_mem_attach(mctx, &handler->mctx);
     55 	isc_buffer_setmctx(&handler->hdrbuf, handler->mctx);
     56 }
     57 
     58 void
     59 isc_proxy2_handler_uninit(isc_proxy2_handler_t *restrict handler) {
     60 	REQUIRE(handler != NULL);
     61 
     62 	/*
     63 	 * Uninitialising the object from withing the callback does not
     64 	 * make any sense.
     65 	 */
     66 	INSIST(handler->calling_cb == false);
     67 	if (handler->mctx != NULL) {
     68 		isc_buffer_clearmctx(&handler->hdrbuf);
     69 		isc_mem_detach(&handler->mctx);
     70 	}
     71 	isc_buffer_invalidate(&handler->hdrbuf);
     72 }
     73 
     74 void
     75 isc_proxy2_handler_clear(isc_proxy2_handler_t *restrict handler) {
     76 	REQUIRE(handler != NULL);
     77 
     78 	*handler = (isc_proxy2_handler_t){ .result = ISC_R_UNSET,
     79 					   .mctx = handler->mctx,
     80 					   .cb = handler->cb,
     81 					   .cbarg = handler->cbarg,
     82 					   .hdrbuf = handler->hdrbuf,
     83 					   .max_size = handler->max_size };
     84 
     85 	isc_buffer_clear(&handler->hdrbuf);
     86 	isc_buffer_trycompact(&handler->hdrbuf);
     87 }
     88 
     89 isc_proxy2_handler_t *
     90 isc_proxy2_handler_new(isc_mem_t *mctx, const uint16_t max_size,
     91 		       isc_proxy2_handler_cb_t cb, void *cbarg) {
     92 	isc_proxy2_handler_t *newhandler;
     93 
     94 	REQUIRE(mctx != NULL);
     95 	REQUIRE(cb != NULL);
     96 
     97 	newhandler = isc_mem_get(mctx, sizeof(*newhandler));
     98 	isc_proxy2_handler_init(newhandler, mctx, max_size, cb, cbarg);
     99 
    100 	return newhandler;
    101 }
    102 
    103 void
    104 isc_proxy2_handler_free(isc_proxy2_handler_t **restrict phandler) {
    105 	isc_proxy2_handler_t *restrict handler = NULL;
    106 	isc_mem_t *mctx = NULL;
    107 	REQUIRE(phandler != NULL && *phandler != NULL);
    108 
    109 	handler = *phandler;
    110 
    111 	isc_mem_attach(handler->mctx, &mctx);
    112 	isc_proxy2_handler_uninit(handler);
    113 	isc_mem_putanddetach(&mctx, handler, sizeof(*handler));
    114 
    115 	*phandler = NULL;
    116 }
    117 
    118 void
    119 isc_proxy2_handler_setcb(isc_proxy2_handler_t *restrict handler,
    120 			 isc_proxy2_handler_cb_t cb, void *cbarg) {
    121 	REQUIRE(handler != NULL);
    122 	REQUIRE(cb != NULL);
    123 	handler->cb = cb;
    124 	handler->cbarg = cbarg;
    125 }
    126 
    127 static inline int
    128 proxy2_socktype_to_socktype(const isc_proxy2_socktype_t proxy_socktype) {
    129 	int socktype = 0;
    130 
    131 	switch (proxy_socktype) {
    132 	case ISC_PROXY2_SOCK_UNSPEC:
    133 		socktype = 0;
    134 		break;
    135 	case ISC_PROXY2_SOCK_STREAM:
    136 		socktype = SOCK_STREAM;
    137 		break;
    138 	case ISC_PROXY2_SOCK_DGRAM:
    139 		socktype = SOCK_DGRAM;
    140 		break;
    141 	default:
    142 		ISC_UNREACHABLE();
    143 	};
    144 
    145 	return socktype;
    146 }
    147 
    148 static inline void
    149 isc__proxy2_handler_callcb(isc_proxy2_handler_t *restrict handler,
    150 			   const isc_result_t result,
    151 			   const isc_proxy2_command_t cmd,
    152 			   const isc_proxy2_socktype_t proxy_socktype,
    153 			   const isc_sockaddr_t *src_addr,
    154 			   const isc_sockaddr_t *dst_addr,
    155 			   const isc_region_t *restrict tlv_data,
    156 			   const isc_region_t *restrict extra_data) {
    157 	int socktype = 0;
    158 
    159 	handler->result = result;
    160 	handler->calling_cb = true;
    161 
    162 	if (result != ISC_R_SUCCESS) {
    163 		handler->cb(result, cmd, -1, NULL, NULL, NULL, NULL,
    164 			    handler->cbarg);
    165 	} else {
    166 		socktype = proxy2_socktype_to_socktype(proxy_socktype);
    167 		handler->cb(result, cmd, socktype,
    168 			    proxy_socktype == ISC_PROXY2_SOCK_UNSPEC ? NULL
    169 								     : src_addr,
    170 			    proxy_socktype == ISC_PROXY2_SOCK_UNSPEC ? NULL
    171 								     : dst_addr,
    172 			    tlv_data->length == 0 ? NULL : tlv_data,
    173 			    extra_data->length == 0 ? NULL : extra_data,
    174 			    handler->cbarg);
    175 	}
    176 
    177 	handler->calling_cb = false;
    178 }
    179 
    180 static inline void
    181 isc__proxy2_handler_error(isc_proxy2_handler_t *restrict handler,
    182 			  const isc_result_t result) {
    183 	INSIST(result != ISC_R_SUCCESS);
    184 	isc__proxy2_handler_callcb(handler, result, ISC_PROXY2_CMD_ILLEGAL,
    185 				   ISC_PROXY2_SOCK_ILLEGAL, NULL, NULL, NULL,
    186 				   NULL);
    187 	if (result != ISC_R_NOMORE) {
    188 		handler->state = ISC_PROXY2_STATE_END;
    189 	}
    190 }
    191 
    192 static inline bool
    193 isc__proxy2_handler_handle_signature(isc_proxy2_handler_t *restrict handler) {
    194 	isc_region_t remaining = { 0, 0 };
    195 	size_t len;
    196 
    197 	isc_buffer_remainingregion(&handler->hdrbuf, &remaining);
    198 	len = ISC_MIN(remaining.length, ISC_PROXY2_HEADER_SIGNATURE_SIZE);
    199 
    200 	if (memcmp(ISC_PROXY2_HEADER_SIGNATURE, remaining.base, len) != 0) {
    201 		isc__proxy2_handler_error(handler, ISC_R_UNEXPECTED);
    202 		return false;
    203 	} else if (len == ISC_PROXY2_HEADER_SIGNATURE_SIZE) {
    204 		isc_buffer_forward(&handler->hdrbuf,
    205 				   ISC_PROXY2_HEADER_SIGNATURE_SIZE);
    206 		handler->expect_data = ISC_PROXY2_HEADER_SIZE -
    207 				       ISC_PROXY2_HEADER_SIGNATURE_SIZE;
    208 		handler->state++;
    209 	} else {
    210 		INSIST(len < ISC_PROXY2_HEADER_SIGNATURE_SIZE);
    211 		isc__proxy2_handler_error(handler, ISC_R_NOMORE);
    212 		return false;
    213 	}
    214 	return true;
    215 }
    216 
    217 static inline bool
    218 isc__proxy2_handler_handle_header(isc_proxy2_handler_t *restrict handler) {
    219 	/*
    220 	 * The PROXYv2 header can be described as (signature 'sig' has been
    221 	 * processed and verified already as a separate step):
    222 	 *
    223 	 *  struct proxy_hdr_v2 {
    224 	 *     uint8_t sig[12];  // hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A
    225 	 *     uint8_t ver_cmd;  // protocol version and command
    226 	 *     uint8_t fam;      // protocol family and address
    227 	 *     uint16_t len;     // number of following bytes part of the header
    228 	 *  };
    229 	 */
    230 	uint8_t ver_cmd = 0;
    231 	uint8_t cmd = 0;
    232 	uint8_t fam = 0;
    233 	uint16_t len = 0;
    234 	int addrfamily = 0;
    235 	int socktype = 0;
    236 	size_t min_addr_payload_size = 0;
    237 
    238 	ver_cmd = isc_buffer_getuint8(&handler->hdrbuf);
    239 
    240 	/* extract version and check it */
    241 	if ((ver_cmd & 0xF0U) >> 4 != 2) {
    242 		/* only support for version 2 is implemented */
    243 		isc__proxy2_handler_error(handler, ISC_R_NOTIMPLEMENTED);
    244 		return false;
    245 	}
    246 
    247 	/* extract command */
    248 	cmd = ver_cmd & 0xFU;
    249 
    250 	fam = isc_buffer_getuint8(&handler->hdrbuf);
    251 	len = isc_buffer_getuint16(&handler->hdrbuf);
    252 
    253 	if (handler->max_size > 0 &&
    254 	    (len + ISC_PROXY2_HEADER_SIZE) > handler->max_size)
    255 	{
    256 		goto error_range;
    257 	}
    258 
    259 	handler->expect_data = len;
    260 
    261 	/* extract address family and socket type */
    262 	addrfamily = (fam & 0xF0U) >> 4;
    263 	socktype = fam & 0xFU;
    264 
    265 	/* dispatch on the command value */
    266 	switch (cmd) {
    267 	case ISC_PROXY2_CMD_LOCAL:
    268 		/* LOCAL implies "unspec" mode */
    269 		handler->cmd = ISC_PROXY2_CMD_LOCAL;
    270 		if (addrfamily != ISC_PROXY2_AF_UNSPEC ||
    271 		    socktype != ISC_PROXY2_SOCK_UNSPEC)
    272 		{
    273 			goto error_unexpected;
    274 		}
    275 		handler->proxy_addr_family = ISC_PROXY2_AF_UNSPEC;
    276 		handler->proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
    277 		break;
    278 	case ISC_PROXY2_CMD_PROXY:
    279 		handler->cmd = ISC_PROXY2_CMD_PROXY;
    280 		switch (addrfamily) {
    281 		case ISC_PROXY2_AF_UNSPEC:
    282 			if (socktype != ISC_PROXY2_SOCK_UNSPEC) {
    283 				goto error_unexpected;
    284 			}
    285 			handler->proxy_addr_family = ISC_PROXY2_AF_UNSPEC;
    286 			handler->proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
    287 			break;
    288 		case ISC_PROXY2_AF_INET:
    289 		case ISC_PROXY2_AF_INET6:
    290 		case ISC_PROXY2_AF_UNIX:
    291 			handler->proxy_addr_family =
    292 				(isc_proxy2_addrfamily_t)addrfamily;
    293 			switch (socktype) {
    294 			case ISC_PROXY2_SOCK_DGRAM:
    295 			case ISC_PROXY2_SOCK_STREAM:
    296 				handler->proxy_socktype =
    297 					(isc_proxy2_socktype_t)socktype;
    298 				break;
    299 			default:
    300 				goto error_unexpected;
    301 			}
    302 			break;
    303 		default:
    304 			goto error_unexpected;
    305 		}
    306 		break;
    307 	default:
    308 		goto error_unexpected;
    309 	};
    310 
    311 	/* verify if enough data will be available in the payload */
    312 	switch (handler->proxy_addr_family) {
    313 	case ISC_PROXY2_AF_INET:
    314 		min_addr_payload_size = ISC_PROXY2_MIN_AF_INET_SIZE -
    315 					ISC_PROXY2_HEADER_SIZE;
    316 		break;
    317 	case ISC_PROXY2_AF_INET6:
    318 		min_addr_payload_size = ISC_PROXY2_MIN_AF_INET6_SIZE -
    319 					ISC_PROXY2_HEADER_SIZE;
    320 		break;
    321 	case ISC_PROXY2_AF_UNIX:
    322 		min_addr_payload_size = ISC_PROXY2_MIN_AF_UNIX_SIZE -
    323 					ISC_PROXY2_HEADER_SIZE;
    324 		break;
    325 	default:
    326 		break;
    327 	}
    328 
    329 	if (min_addr_payload_size > 0) {
    330 		if (len < min_addr_payload_size) {
    331 			goto error_range;
    332 		}
    333 		handler->tlv_data_size = len - min_addr_payload_size;
    334 	}
    335 
    336 	if (handler->tlv_data_size > 0 &&
    337 	    handler->tlv_data_size < ISC_PROXY2_TLV_HEADER_SIZE)
    338 	{
    339 		goto error_range;
    340 	}
    341 
    342 	handler->header_size = ISC_PROXY2_HEADER_SIZE + len;
    343 
    344 	handler->state++;
    345 
    346 	return true;
    347 
    348 error_unexpected:
    349 	isc__proxy2_handler_error(handler, ISC_R_UNEXPECTED);
    350 	return false;
    351 error_range:
    352 	isc__proxy2_handler_error(handler, ISC_R_RANGE);
    353 	return false;
    354 }
    355 
    356 static inline isc_result_t
    357 isc__proxy2_handler_get_addresses(isc_proxy2_handler_t *restrict handler,
    358 				  isc_buffer_t *restrict hdrbuf,
    359 				  isc_sockaddr_t *restrict src_addr,
    360 				  isc_sockaddr_t *restrict dst_addr) {
    361 	size_t addr_size = 0;
    362 	void *psrc_addr = NULL, *pdst_addr = NULL;
    363 	uint16_t src_port = 0, dst_port = 0;
    364 
    365 	switch (handler->proxy_addr_family) {
    366 	case ISC_PROXY2_AF_UNSPEC:
    367 		/* in this case we are instructed to skip over the data */
    368 		INSIST(handler->tlv_data_size == 0);
    369 		isc_buffer_forward(hdrbuf, handler->expect_data);
    370 		break;
    371 	case ISC_PROXY2_AF_INET:
    372 		addr_size = sizeof(src_addr->type.sin.sin_addr.s_addr);
    373 		/*
    374 		 * IPv4 source and destination endpoint addresses can be
    375 		 * described as follows:
    376 		 *
    377 		 * struct {        // for TCP/UDP over IPv4, len = 12
    378 		 *   uint32_t src_addr;
    379 		 *   uint32_t dst_addr;
    380 		 *   uint16_t src_port;
    381 		 *   uint16_t dst_port;
    382 		 * } ipv4_addr;
    383 		 */
    384 		psrc_addr = isc_buffer_current(hdrbuf);
    385 		isc_buffer_forward(hdrbuf, addr_size);
    386 
    387 		pdst_addr = isc_buffer_current(hdrbuf);
    388 		isc_buffer_forward(hdrbuf, addr_size);
    389 
    390 		src_port = isc_buffer_getuint16(hdrbuf);
    391 		dst_port = isc_buffer_getuint16(hdrbuf);
    392 
    393 		if (src_addr != NULL) {
    394 			isc_sockaddr_fromin(src_addr, psrc_addr, src_port);
    395 		}
    396 		if (dst_addr != NULL) {
    397 			isc_sockaddr_fromin(dst_addr, pdst_addr, dst_port);
    398 		}
    399 		break;
    400 	case ISC_PROXY2_AF_INET6:
    401 		addr_size = sizeof(src_addr->type.sin6.sin6_addr);
    402 		/*
    403 		 * IPv4 source and destination endpoint addresses can be
    404 		 * described as follows:
    405 		 *
    406 		 * struct {        // for TCP/UDP over IPv6, len = 36
    407 		 *    uint8_t  src_addr[16];
    408 		 *    uint8_t  dst_addr[16];
    409 		 *    uint16_t src_port;
    410 		 *    uint16_t dst_port;
    411 		 * } ipv6_addr;
    412 		 */
    413 		psrc_addr = isc_buffer_current(hdrbuf);
    414 		isc_buffer_forward(hdrbuf, addr_size);
    415 
    416 		pdst_addr = isc_buffer_current(hdrbuf);
    417 		isc_buffer_forward(hdrbuf, addr_size);
    418 
    419 		src_port = isc_buffer_getuint16(hdrbuf);
    420 		dst_port = isc_buffer_getuint16(hdrbuf);
    421 
    422 		if (src_addr != NULL) {
    423 			isc_sockaddr_fromin6(src_addr, psrc_addr, src_port);
    424 		}
    425 
    426 		if (dst_addr != NULL) {
    427 			isc_sockaddr_fromin6(dst_addr, pdst_addr, dst_port);
    428 		}
    429 		break;
    430 	case ISC_PROXY2_AF_UNIX: {
    431 		/*
    432 		 * UNIX domain sockets source and destination endpoint
    433 		 * addresses can be described as follows:
    434 		 *
    435 		 * struct {        // for AF_UNIX sockets, len = 216
    436 		 *    uint8_t src_addr[108];
    437 		 *    uint8_t dst_addr[108];
    438 		 * } unix_addr;
    439 		 *
    440 		 * We currently have no use for this address type, but we can
    441 		 * validate the data.
    442 		 */
    443 		unsigned char *ret = NULL;
    444 
    445 		addr_size = ISC_PROXY2_AF_UNIX_MAX_PATH_LEN;
    446 
    447 		ret = memchr(isc_buffer_current(hdrbuf), '\0', addr_size);
    448 		if (ret == NULL) {
    449 			/*
    450 			 * Someone has attempted to send us a path string
    451 			 * without a terminating '\0' byte - not a friend
    452 			 * knocking at the door.
    453 			 */
    454 			return ISC_R_RANGE;
    455 		}
    456 		isc_buffer_forward(hdrbuf, addr_size);
    457 
    458 		ret = memchr(isc_buffer_current(hdrbuf), '\0', addr_size);
    459 		if (ret == NULL) {
    460 			return ISC_R_RANGE;
    461 		}
    462 		isc_buffer_forward(hdrbuf, addr_size);
    463 	} break;
    464 	default:
    465 		UNREACHABLE();
    466 	}
    467 
    468 	return ISC_R_SUCCESS;
    469 }
    470 
    471 static inline void
    472 isc__proxy2_handler_handle_payload(isc_proxy2_handler_t *restrict handler) {
    473 	isc_result_t result;
    474 	isc_sockaddr_t src_addr = { 0 }, dst_addr = { 0 };
    475 
    476 	result = isc__proxy2_handler_get_addresses(handler, &handler->hdrbuf,
    477 						   &src_addr, &dst_addr);
    478 
    479 	if (result != ISC_R_SUCCESS) {
    480 		isc__proxy2_handler_error(handler, result);
    481 		return;
    482 	}
    483 
    484 	if (handler->tlv_data_size > 0) {
    485 		isc_buffer_remainingregion(&handler->hdrbuf,
    486 					   &handler->tlv_data);
    487 		handler->tlv_data.length = handler->tlv_data_size;
    488 		isc_buffer_forward(&handler->hdrbuf, handler->tlv_data_size);
    489 		result = isc_proxy2_tlv_data_verify(&handler->tlv_data);
    490 		if (result != ISC_R_SUCCESS) {
    491 			isc__proxy2_handler_error(handler, result);
    492 			return;
    493 		}
    494 	}
    495 
    496 	isc_buffer_remainingregion(&handler->hdrbuf, &handler->extra_data);
    497 	handler->expect_data = 0;
    498 
    499 	handler->state++;
    500 
    501 	/*
    502 	 * Treat AF_UNIX as AF_UNSPEC as we have no use for it, although
    503 	 * at this point we have fully verified the header.
    504 	 */
    505 	if (handler->proxy_addr_family == ISC_PROXY2_AF_UNIX) {
    506 		handler->proxy_addr_family = ISC_PROXY2_AF_UNSPEC;
    507 		handler->proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
    508 		handler->tlv_data = (isc_region_t){ 0 };
    509 	}
    510 
    511 	isc__proxy2_handler_callcb(
    512 		handler, ISC_R_SUCCESS, handler->cmd, handler->proxy_socktype,
    513 		&src_addr, &dst_addr, &handler->tlv_data, &handler->extra_data);
    514 
    515 	return;
    516 }
    517 
    518 static inline bool
    519 isc__proxy2_handler_handle_data(isc_proxy2_handler_t *restrict handler) {
    520 	if (isc_buffer_remaininglength(&handler->hdrbuf) < handler->expect_data)
    521 	{
    522 		isc__proxy2_handler_error(handler, ISC_R_NOMORE);
    523 		return false;
    524 	}
    525 
    526 	switch (handler->state) {
    527 	case ISC_PROXY2_STATE_WAITING_SIGNATURE:
    528 		/*
    529 		 * We check for signature no matter how many bytes of it we
    530 		 * have received. The idea is to not wait for the whole
    531 		 * signature to verify it at once, but to detect, e.g. port
    532 		 * scanners as early as possible. Should we receive data byte
    533 		 * by byte, we would detect the problem when processing the
    534 		 * first unexpected byte.
    535 		 */
    536 		return isc__proxy2_handler_handle_signature(handler);
    537 	case ISC_PROXY2_STATE_WAITING_HEADER:
    538 		/*
    539 		 * Handle the rest of the header (except signature which we
    540 		 * heave verified by now).
    541 		 */
    542 		return isc__proxy2_handler_handle_header(handler);
    543 	case ISC_PROXY2_STATE_WAITING_PAYLOAD:
    544 		/*
    545 		 * Handle the PROXYv2 header payload - addresses and TLVs.
    546 		 */
    547 		isc__proxy2_handler_handle_payload(handler);
    548 		break;
    549 	default:
    550 		UNREACHABLE();
    551 		break;
    552 	};
    553 
    554 	return false;
    555 }
    556 
    557 static inline isc_result_t
    558 isc__proxy2_handler_process_data(isc_proxy2_handler_t *restrict handler) {
    559 	while (isc__proxy2_handler_handle_data(handler)) {
    560 		if (handler->state == ISC_PROXY2_STATE_END) {
    561 			break;
    562 		}
    563 	}
    564 
    565 	return handler->result;
    566 }
    567 
    568 isc_result_t
    569 isc_proxy2_handler_push_data(isc_proxy2_handler_t *restrict handler,
    570 			     const void *restrict buf,
    571 			     const unsigned int buf_size) {
    572 	isc_result_t result;
    573 
    574 	REQUIRE(handler != NULL);
    575 	REQUIRE(buf != NULL && buf_size != 0);
    576 
    577 	INSIST(!handler->calling_cb);
    578 
    579 	if (handler->state == ISC_PROXY2_STATE_END) {
    580 		isc_proxy2_handler_clear(handler);
    581 	}
    582 
    583 	isc_buffer_putmem(&handler->hdrbuf, buf, buf_size);
    584 
    585 	result = isc__proxy2_handler_process_data(handler);
    586 
    587 	return result;
    588 }
    589 
    590 isc_result_t
    591 isc_proxy2_handler_push(isc_proxy2_handler_t *restrict handler,
    592 			const isc_region_t *restrict region) {
    593 	isc_result_t result;
    594 
    595 	REQUIRE(handler != NULL);
    596 	REQUIRE(region != NULL);
    597 
    598 	result = isc_proxy2_handler_push_data(handler, region->base,
    599 					      region->length);
    600 
    601 	return result;
    602 }
    603 
    604 static inline bool
    605 proxy2_payload_is_processed(const isc_proxy2_handler_t *restrict handler) {
    606 	if (handler->state < ISC_PROXY2_STATE_END ||
    607 	    handler->result != ISC_R_SUCCESS)
    608 	{
    609 		return false;
    610 	}
    611 
    612 	return true;
    613 }
    614 
    615 size_t
    616 isc_proxy2_handler_header(const isc_proxy2_handler_t *restrict handler,
    617 			  isc_region_t *restrict region) {
    618 	REQUIRE(handler != NULL);
    619 	REQUIRE(region == NULL ||
    620 		(region->base == NULL && region->length == 0));
    621 
    622 	if (!proxy2_payload_is_processed(handler)) {
    623 		return 0;
    624 	}
    625 
    626 	if (region != NULL) {
    627 		region->base = isc_buffer_base(&handler->hdrbuf);
    628 		region->length = handler->header_size;
    629 	}
    630 
    631 	return handler->header_size;
    632 }
    633 
    634 size_t
    635 isc_proxy2_handler_tlvs(const isc_proxy2_handler_t *restrict handler,
    636 			isc_region_t *restrict region) {
    637 	REQUIRE(handler != NULL);
    638 	REQUIRE(region == NULL ||
    639 		(region->base == NULL && region->length == 0));
    640 
    641 	if (!proxy2_payload_is_processed(handler)) {
    642 		return 0;
    643 	}
    644 
    645 	SET_IF_NOT_NULL(region, handler->tlv_data);
    646 
    647 	return handler->tlv_data.length;
    648 }
    649 
    650 size_t
    651 isc_proxy2_handler_extra(const isc_proxy2_handler_t *restrict handler,
    652 			 isc_region_t *restrict region) {
    653 	REQUIRE(handler != NULL);
    654 	REQUIRE(region == NULL ||
    655 		(region->base == NULL && region->length == 0));
    656 
    657 	if (!proxy2_payload_is_processed(handler)) {
    658 		return 0;
    659 	}
    660 
    661 	SET_IF_NOT_NULL(region, handler->extra_data);
    662 
    663 	return handler->extra_data.length;
    664 }
    665 
    666 isc_result_t
    667 isc_proxy2_handler_result(const isc_proxy2_handler_t *restrict handler) {
    668 	REQUIRE(handler != NULL);
    669 
    670 	return handler->result;
    671 }
    672 
    673 isc_result_t
    674 isc_proxy2_handler_addresses(const isc_proxy2_handler_t *restrict handler,
    675 			     int *restrict psocktype,
    676 			     isc_sockaddr_t *restrict psrc_addr,
    677 			     isc_sockaddr_t *restrict pdst_addr) {
    678 	isc_result_t result;
    679 	size_t ret;
    680 	isc_region_t header_region = { 0 };
    681 	isc_buffer_t buf = { 0 };
    682 
    683 	REQUIRE(handler != NULL);
    684 
    685 	if (!proxy2_payload_is_processed(handler)) {
    686 		return ISC_R_UNEXPECTED;
    687 	}
    688 
    689 	ret = isc_proxy2_handler_header(handler, &header_region);
    690 	RUNTIME_CHECK(ret > 0);
    691 
    692 	isc_buffer_init(&buf, header_region.base, header_region.length);
    693 	isc_buffer_add(&buf, header_region.length);
    694 	isc_buffer_forward(&buf, ISC_PROXY2_HEADER_SIZE);
    695 
    696 	INSIST(handler->expect_data == 0);
    697 
    698 	result = isc__proxy2_handler_get_addresses(
    699 		(isc_proxy2_handler_t *)handler, &buf, psrc_addr, pdst_addr);
    700 
    701 	if (result != ISC_R_SUCCESS) {
    702 		return result;
    703 	}
    704 
    705 	SET_IF_NOT_NULL(psocktype,
    706 			proxy2_socktype_to_socktype(handler->proxy_socktype));
    707 
    708 	return ISC_R_SUCCESS;
    709 }
    710 
    711 isc_result_t
    712 isc_proxy2_tlv_iterate(const isc_region_t *restrict tlv_data,
    713 		       const isc_proxy2_tlv_cb_t cb, void *cbarg) {
    714 	isc_result_t result = ISC_R_SUCCESS;
    715 	isc_buffer_t tlvs = { 0 };
    716 	size_t remaining;
    717 
    718 	/*
    719 	 * TLV header can be described as follows:
    720 	 *
    721 	 *   struct {
    722 	 *       uint8_t type;
    723 	 *       uint8_t length_hi;
    724 	 *       uint8_t length_lo;
    725 	 *   };
    726 	 *
    727 	 */
    728 
    729 	REQUIRE(tlv_data != NULL);
    730 	REQUIRE(cb != NULL);
    731 
    732 	isc_buffer_init(&tlvs, tlv_data->base, tlv_data->length);
    733 	isc_buffer_add(&tlvs, tlv_data->length);
    734 
    735 	while ((remaining = isc_buffer_remaininglength(&tlvs)) > 0) {
    736 		uint8_t type = 0;
    737 		uint16_t len = 0;
    738 		isc_region_t current_tlv_data = { 0 };
    739 		bool ret = false;
    740 
    741 		/* not enough data for a TLV header */
    742 		if (remaining < ISC_PROXY2_TLV_HEADER_SIZE) {
    743 			result = ISC_R_RANGE;
    744 			break;
    745 		}
    746 
    747 		type = isc_buffer_getuint8(&tlvs);
    748 		len = isc_buffer_getuint16(&tlvs);
    749 
    750 		if ((remaining - ISC_PROXY2_TLV_HEADER_SIZE) < len) {
    751 			result = ISC_R_RANGE;
    752 			break;
    753 		}
    754 
    755 		current_tlv_data.base = isc_buffer_current(&tlvs);
    756 		current_tlv_data.length = len;
    757 		isc_buffer_forward(&tlvs, len);
    758 
    759 		ret = cb((isc_proxy2_tlv_type_t)type, &current_tlv_data, cbarg);
    760 		if (!ret) {
    761 			break;
    762 		}
    763 	}
    764 
    765 	return result;
    766 }
    767 
    768 typedef struct proxy2_tls_cbarg {
    769 	uint8_t client;
    770 	bool client_cert_verified;
    771 	isc_proxy2_tls_subtlv_cb_t cb;
    772 	void *cbarg;
    773 } tls_cbarg_t;
    774 
    775 static bool
    776 proxy2_tls_iter_cb(const isc_proxy2_tlv_type_t tlv_type,
    777 		   const isc_region_t *restrict data, void *cbarg) {
    778 	bool ret = false;
    779 	tls_cbarg_t *tls_cbarg = (tls_cbarg_t *)cbarg;
    780 
    781 	ret = tls_cbarg->cb(tls_cbarg->client, tls_cbarg->client_cert_verified,
    782 			    (isc_proxy2_tlv_subtype_tls_t)tlv_type, data,
    783 			    tls_cbarg->cbarg);
    784 
    785 	return ret;
    786 }
    787 
    788 isc_result_t
    789 isc_proxy2_subtlv_tls_header_data(const isc_region_t *restrict tls_tlv_data,
    790 				  uint8_t *restrict pclient_flags,
    791 				  bool *restrict pclient_cert_verified) {
    792 	/*
    793 	 * SSL/TLS TLV header can be described as follows:
    794 	 *
    795 	 *   struct {
    796 	 *       uint8_t  client_flags;
    797 	 *       uint32_t client_cert_not_verified;
    798 	 *   }
    799 	 */
    800 	uint8_t *p = NULL;
    801 	uint8_t client_flags = 0;
    802 	bool client_cert_verified = false;
    803 	uint32_t client_cert_verified_data = 0;
    804 
    805 	REQUIRE(tls_tlv_data != NULL);
    806 	REQUIRE(pclient_flags == NULL || *pclient_flags == 0);
    807 	REQUIRE(pclient_cert_verified == NULL ||
    808 		*pclient_cert_verified == false);
    809 
    810 	if (tls_tlv_data->length < ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE) {
    811 		return ISC_R_RANGE;
    812 	}
    813 
    814 	p = tls_tlv_data->base;
    815 
    816 	client_flags = *p;
    817 	p++;
    818 	/* We need this to avoid ASAN complain about unaligned access */
    819 	memmove(&client_cert_verified_data, p, sizeof(uint32_t));
    820 	client_cert_verified = ntohl(client_cert_verified_data) == 0;
    821 
    822 	SET_IF_NOT_NULL(pclient_flags, client_flags);
    823 	SET_IF_NOT_NULL(pclient_cert_verified, client_cert_verified);
    824 
    825 	return ISC_R_SUCCESS;
    826 }
    827 
    828 isc_result_t
    829 isc_proxy2_subtlv_tls_iterate(const isc_region_t *restrict tls_tlv_data,
    830 			      const isc_proxy2_tls_subtlv_cb_t cb,
    831 			      void *cbarg) {
    832 	tls_cbarg_t tls_cbarg;
    833 	isc_result_t result = ISC_R_SUCCESS;
    834 	uint8_t *p = NULL;
    835 	uint8_t client_flags = 0;
    836 	bool client_cert_verified = false;
    837 
    838 	REQUIRE(tls_tlv_data != NULL);
    839 	REQUIRE(cb != NULL);
    840 
    841 	if (tls_tlv_data->length < ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE) {
    842 		return ISC_R_RANGE;
    843 	}
    844 
    845 	result = isc_proxy2_subtlv_tls_header_data(tls_tlv_data, &client_flags,
    846 						   &client_cert_verified);
    847 
    848 	if (result != ISC_R_SUCCESS) {
    849 		return result;
    850 	}
    851 
    852 	p = tls_tlv_data->base;
    853 	p += ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE;
    854 
    855 	if (cb != NULL) {
    856 		isc_region_t data = {
    857 			.base = p,
    858 			.length = tls_tlv_data->length -
    859 				  ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE
    860 		};
    861 		tls_cbarg = (tls_cbarg_t){ .client = client_flags,
    862 					   .client_cert_verified =
    863 						   client_cert_verified,
    864 					   .cb = cb,
    865 					   .cbarg = cbarg };
    866 		result = isc_proxy2_tlv_iterate(&data, proxy2_tls_iter_cb,
    867 						&tls_cbarg);
    868 	}
    869 
    870 	return result;
    871 }
    872 
    873 typedef struct tls_subtlv_verify_cbarg {
    874 	uint16_t *count;
    875 	isc_result_t verif_result;
    876 } tls_subtlv_verify_cbarg_t;
    877 
    878 static bool
    879 proxy2_subtlv_verify_iter_cb(const uint8_t client,
    880 			     const bool client_cert_verified,
    881 			     const isc_proxy2_tlv_subtype_tls_t tls_subtlv_type,
    882 			     const isc_region_t *restrict data, void *cbarg) {
    883 	bool verify_count = false;
    884 	tls_subtlv_verify_cbarg_t *restrict arg =
    885 		(tls_subtlv_verify_cbarg_t *)cbarg;
    886 	uint8_t type = tls_subtlv_type;
    887 
    888 	UNUSED(client);
    889 	UNUSED(client_cert_verified);
    890 
    891 	if (type <= ISC_PROXY2_TLV_TYPE_TLS ||
    892 	    type == ISC_PROXY2_TLV_TYPE_NETNS)
    893 	{
    894 		arg->verif_result = ISC_R_UNEXPECTED;
    895 		return false;
    896 	}
    897 
    898 	switch (tls_subtlv_type) {
    899 	case ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION:
    900 	case ISC_PROXY2_TLV_SUBTYPE_TLS_CN:
    901 	case ISC_PROXY2_TLV_SUBTYPE_TLS_SIG_ALG:
    902 	case ISC_PROXY2_TLV_SUBTYPE_TLS_KEY_ALG:
    903 		if (data->length == 0) {
    904 			arg->verif_result = ISC_R_RANGE;
    905 			return false;
    906 		}
    907 		arg->count[tls_subtlv_type]++;
    908 		verify_count = true;
    909 		break;
    910 	default:
    911 		break;
    912 	};
    913 
    914 	if (verify_count && arg->count[tls_subtlv_type] > 1) {
    915 		arg->verif_result = ISC_R_UNEXPECTED;
    916 		return false;
    917 	}
    918 
    919 	return true;
    920 }
    921 
    922 typedef struct tlv_verify_cbarg {
    923 	uint16_t count[256];
    924 	isc_result_t verify_result;
    925 } tlv_verify_cbarg_t;
    926 
    927 static bool
    928 isc_proxy2_tlv_verify_cb(const isc_proxy2_tlv_type_t tlv_type,
    929 			 const isc_region_t *restrict data, void *cbarg) {
    930 	bool verify_count = false;
    931 	uint8_t client = 0;
    932 	tlv_verify_cbarg_t *arg = (tlv_verify_cbarg_t *)cbarg;
    933 
    934 	if (tlv_type == 0) {
    935 		/* the TLV values start from 1 */
    936 		goto error_unexpected;
    937 	}
    938 
    939 	switch (tlv_type) {
    940 	case ISC_PROXY2_TLV_TYPE_ALPN:
    941 	case ISC_PROXY2_TLV_TYPE_AUTHORITY:
    942 	case ISC_PROXY2_TLV_TYPE_NETNS:
    943 		/* these values need to be more than 0 bytes long */
    944 		if (data->length == 0) {
    945 			goto error_range;
    946 		}
    947 		arg->count[tlv_type]++;
    948 		verify_count = true;
    949 		break;
    950 	case ISC_PROXY2_TLV_TYPE_CRC32C:
    951 		if (data->length != sizeof(uint32_t)) {
    952 			goto error_range;
    953 		}
    954 		arg->count[tlv_type]++;
    955 		verify_count = true;
    956 		break;
    957 	case ISC_PROXY2_TLV_TYPE_UNIQUE_ID:
    958 		if (data->length > 128) {
    959 			goto error_range;
    960 		}
    961 		arg->count[tlv_type]++;
    962 		verify_count = true;
    963 		break;
    964 	case ISC_PROXY2_TLV_TYPE_TLS: {
    965 		tls_subtlv_verify_cbarg_t tls_cbarg = {
    966 			.verif_result = ISC_R_SUCCESS, .count = arg->count
    967 		};
    968 		size_t tls_version_count, tls_cn_count;
    969 
    970 		arg->verify_result =
    971 			isc_proxy2_subtlv_tls_header_data(data, &client, NULL);
    972 
    973 		if (arg->verify_result != ISC_R_SUCCESS) {
    974 			return false;
    975 		}
    976 
    977 		arg->verify_result = isc_proxy2_subtlv_tls_iterate(
    978 			data, proxy2_subtlv_verify_iter_cb, &tls_cbarg);
    979 
    980 		if (arg->verify_result != ISC_R_SUCCESS) {
    981 			return false;
    982 		} else if (tls_cbarg.verif_result != ISC_R_SUCCESS) {
    983 			arg->verify_result = tls_cbarg.verif_result;
    984 			return false;
    985 		}
    986 
    987 		/*
    988 		 * if CLIENT_TLS flag is set - TLS version TLV must be present
    989 		 */
    990 		tls_version_count =
    991 			arg->count[ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION];
    992 
    993 		if ((client & ISC_PROXY2_CLIENT_TLS) != 0) {
    994 			if (tls_version_count != 1) {
    995 				goto error_unexpected;
    996 			}
    997 		} else if (tls_version_count > 0) {
    998 			/* unexpected TLS version TLV */
    999 			goto error_unexpected;
   1000 		}
   1001 
   1002 		/*
   1003 		 * If client cert was submitted, CLIENT_CERT_CONN or
   1004 		 * CLIENT_CERT_SESS flags must be present alongside the
   1005 		 * CLIENT_TLS flag.
   1006 		 */
   1007 		tls_cn_count = arg->count[ISC_PROXY2_TLV_SUBTYPE_TLS_CN];
   1008 
   1009 		if ((client & (ISC_PROXY2_CLIENT_CERT_CONN |
   1010 			       ISC_PROXY2_CLIENT_CERT_SESS)) != 0)
   1011 		{
   1012 			if (tls_cn_count != 1 ||
   1013 			    (client & ISC_PROXY2_CLIENT_TLS) == 0)
   1014 			{
   1015 				goto error_unexpected;
   1016 			}
   1017 		} else if (tls_cn_count > 0) {
   1018 			/* unexpected Common Name TLV */
   1019 			goto error_unexpected;
   1020 		}
   1021 
   1022 		arg->count[tlv_type]++;
   1023 		verify_count = true;
   1024 	} break;
   1025 	default:
   1026 		break;
   1027 	};
   1028 
   1029 	if (verify_count && arg->count[tlv_type] > 1) {
   1030 		goto error_unexpected;
   1031 	}
   1032 
   1033 	return true;
   1034 
   1035 error_unexpected:
   1036 	arg->verify_result = ISC_R_UNEXPECTED;
   1037 	return false;
   1038 
   1039 error_range:
   1040 	arg->verify_result = ISC_R_RANGE;
   1041 	return false;
   1042 }
   1043 
   1044 isc_result_t
   1045 isc_proxy2_tlv_data_verify(const isc_region_t *restrict tlv_data) {
   1046 	isc_result_t result;
   1047 	tlv_verify_cbarg_t cbarg = { .verify_result = ISC_R_SUCCESS };
   1048 
   1049 	result = isc_proxy2_tlv_iterate(tlv_data, isc_proxy2_tlv_verify_cb,
   1050 					&cbarg);
   1051 	if (result != ISC_R_SUCCESS) {
   1052 		return result;
   1053 	}
   1054 
   1055 	return cbarg.verify_result;
   1056 }
   1057 
   1058 isc_result_t
   1059 isc_proxy2_header_handle_directly(const isc_region_t *restrict header_data,
   1060 				  const isc_proxy2_handler_cb_t cb,
   1061 				  void *cbarg) {
   1062 	isc_result_t result;
   1063 	isc_proxy2_handler_t handler = { 0 };
   1064 
   1065 	REQUIRE(header_data != NULL);
   1066 	REQUIRE(cb != NULL);
   1067 
   1068 	isc__proxy2_handler_init_direct(&handler, 0, header_data, cb, cbarg);
   1069 
   1070 	result = isc__proxy2_handler_process_data(&handler);
   1071 
   1072 	return result;
   1073 }
   1074 
   1075 isc_result_t
   1076 isc_proxy2_make_header(isc_buffer_t *restrict outbuf,
   1077 		       const isc_proxy2_command_t cmd, const int socktype,
   1078 		       const isc_sockaddr_t *restrict src_addr,
   1079 		       const isc_sockaddr_t *restrict dst_addr,
   1080 		       const isc_region_t *restrict tlv_data) {
   1081 	size_t total_size = ISC_PROXY2_HEADER_SIZE;
   1082 	uint8_t family = ISC_PROXY2_AF_UNSPEC;
   1083 	isc_proxy2_socktype_t proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
   1084 
   1085 	uint8_t ver_cmd = 0;
   1086 	uint8_t fam_socktype = 0;
   1087 	uint16_t len = 0;
   1088 
   1089 	size_t addr_size = 0;
   1090 	void *psrc_addr = NULL, *pdst_addr = NULL;
   1091 	/*
   1092 	 * The complete PROXYv2 header can be described as follows:
   1093 	 *
   1094 	 * 1. Header:
   1095 	 *
   1096 	 * struct proxy_hdr_v2 {
   1097 	 *   uint8_t sig[12];      // hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A
   1098 	 *   uint8_t ver_cmd;      // protocol version and command
   1099 	 *   uint8_t fam_socktype; // protocol family and socket type
   1100 	 *   uint16_t len;         // number of following bytes
   1101 	 * };
   1102 	 *
   1103 	 * 2. Addresses:
   1104 	 *
   1105 	 * union proxy_addr {
   1106 	 *   struct {        // for TCP/UDP over IPv4, len = 12
   1107 	 *       uint32_t src_addr;
   1108 	 *       uint32_t dst_addr;
   1109 	 *       uint16_t src_port;
   1110 	 *       uint16_t dst_port;
   1111 	 *   } ipv4_addr;
   1112 	 *   struct {        // for TCP/UDP over IPv6, len = 36
   1113 	 *        uint8_t  src_addr[16];
   1114 	 *        uint8_t  dst_addr[16];
   1115 	 *        uint16_t src_port;
   1116 	 *        uint16_t dst_port;
   1117 	 *   } ipv6_addr;
   1118 	 *   struct {        // for AF_UNIX sockets, len = 216
   1119 	 *        uint8_t src_addr[108];
   1120 	 *        uint8_t dst_addr[108];
   1121 	 *   } unix_addr;
   1122 	 * };
   1123 	 *
   1124 	 * 3. TLVs (optional)
   1125 	 */
   1126 
   1127 	REQUIRE(outbuf != NULL);
   1128 	REQUIRE(cmd == ISC_PROXY2_CMD_PROXY || socktype == 0);
   1129 	REQUIRE((src_addr == NULL && dst_addr == NULL) ||
   1130 		(src_addr != NULL && dst_addr != NULL));
   1131 	REQUIRE(src_addr == NULL ||
   1132 		(isc_sockaddr_pf(src_addr) == isc_sockaddr_pf(dst_addr)));
   1133 
   1134 	switch (cmd) {
   1135 	case ISC_PROXY2_CMD_LOCAL:
   1136 		family = ISC_PROXY2_AF_UNSPEC;
   1137 		break;
   1138 	case ISC_PROXY2_CMD_PROXY:
   1139 		if (socktype == 0) {
   1140 			family = ISC_PROXY2_AF_UNSPEC;
   1141 		} else {
   1142 			switch (isc_sockaddr_pf(src_addr)) {
   1143 			case AF_INET:
   1144 				family = ISC_PROXY2_AF_INET;
   1145 				addr_size = sizeof(src_addr->type.sin.sin_addr);
   1146 				total_size += addr_size * 2 +
   1147 					      sizeof(uint16_t) * 2;
   1148 				psrc_addr = (void *)&src_addr->type.sin.sin_addr
   1149 						    .s_addr;
   1150 				pdst_addr = (void *)&dst_addr->type.sin.sin_addr
   1151 						    .s_addr;
   1152 				break;
   1153 			case AF_INET6:
   1154 				family = ISC_PROXY2_AF_INET6;
   1155 				addr_size =
   1156 					sizeof(src_addr->type.sin6.sin6_addr);
   1157 				total_size += addr_size * 2 +
   1158 					      sizeof(uint16_t) * 2;
   1159 				psrc_addr =
   1160 					(void *)&src_addr->type.sin6.sin6_addr;
   1161 				pdst_addr =
   1162 					(void *)&dst_addr->type.sin6.sin6_addr;
   1163 				break;
   1164 			default:
   1165 				return ISC_R_UNEXPECTED;
   1166 			}
   1167 		}
   1168 		break;
   1169 	default:
   1170 		return ISC_R_UNEXPECTED;
   1171 	}
   1172 
   1173 	switch (socktype) {
   1174 	case 0:
   1175 		proxy_socktype = ISC_PROXY2_SOCK_UNSPEC;
   1176 		break;
   1177 	case SOCK_STREAM:
   1178 		proxy_socktype = ISC_PROXY2_SOCK_STREAM;
   1179 		break;
   1180 	case SOCK_DGRAM:
   1181 		proxy_socktype = ISC_PROXY2_SOCK_DGRAM;
   1182 		break;
   1183 	default:
   1184 		return ISC_R_UNEXPECTED;
   1185 	}
   1186 
   1187 	if (tlv_data != NULL) {
   1188 		if (tlv_data->length > UINT16_MAX) {
   1189 			return ISC_R_RANGE;
   1190 		}
   1191 		total_size += tlv_data->length;
   1192 	}
   1193 
   1194 	if (isc_buffer_availablelength(outbuf) < total_size) {
   1195 		return ISC_R_NOSPACE;
   1196 	} else if (total_size > UINT16_MAX) {
   1197 		return ISC_R_RANGE;
   1198 	}
   1199 
   1200 	/*
   1201 	 * Combine version 2 (highest four bits) and command (lowest four
   1202 	 * bits).
   1203 	 */
   1204 	ver_cmd = (((2 << 4) & 0xF0U) | cmd);
   1205 
   1206 	/*
   1207 	 * Combine address family (highest four bits) and socket type
   1208 	 * (lowest four bits).
   1209 	 */
   1210 	fam_socktype = (((family << 4) & 0xF0U) | proxy_socktype);
   1211 
   1212 	len = (uint16_t)(total_size - ISC_PROXY2_HEADER_SIZE);
   1213 
   1214 	/* Write signature */
   1215 	isc_buffer_putmem(outbuf, (uint8_t *)ISC_PROXY2_HEADER_SIGNATURE,
   1216 			  ISC_PROXY2_HEADER_SIGNATURE_SIZE);
   1217 	/* Write version and command */
   1218 	isc_buffer_putuint8(outbuf, ver_cmd);
   1219 	/* Write address family and socket type */
   1220 	isc_buffer_putuint8(outbuf, fam_socktype);
   1221 	/* Write header payload size (addresses + TLVs) */
   1222 	isc_buffer_putuint16(outbuf, len);
   1223 
   1224 	/* Write source and destination addresses (if we should) */
   1225 	if (psrc_addr != NULL) {
   1226 		isc_buffer_putmem(outbuf, psrc_addr, addr_size);
   1227 	}
   1228 
   1229 	if (pdst_addr != NULL) {
   1230 		isc_buffer_putmem(outbuf, pdst_addr, addr_size);
   1231 	}
   1232 
   1233 	/* Write source and destination ports (if we should) */
   1234 	if (family == ISC_PROXY2_AF_INET || family == ISC_PROXY2_AF_INET6) {
   1235 		isc_buffer_putuint16(outbuf, isc_sockaddr_getport(src_addr));
   1236 		isc_buffer_putuint16(outbuf, isc_sockaddr_getport(dst_addr));
   1237 	}
   1238 
   1239 	if (tlv_data != NULL) {
   1240 		isc_buffer_putmem(outbuf, tlv_data->base, tlv_data->length);
   1241 	}
   1242 
   1243 	return ISC_R_SUCCESS;
   1244 }
   1245 
   1246 isc_result_t
   1247 isc_proxy2_header_append(isc_buffer_t *restrict outbuf,
   1248 			 const isc_region_t *restrict data) {
   1249 	const size_t len_offset = ISC_PROXY2_HEADER_SIZE - sizeof(uint16_t);
   1250 	isc_region_t header_data = { 0 };
   1251 	uint16_t new_len = 0;
   1252 
   1253 	REQUIRE(outbuf != NULL);
   1254 
   1255 	isc_buffer_usedregion(outbuf, &header_data);
   1256 
   1257 	REQUIRE(header_data.length >= ISC_PROXY2_HEADER_SIZE);
   1258 	REQUIRE(data != NULL);
   1259 
   1260 	if (isc_buffer_availablelength(outbuf) < data->length) {
   1261 		return ISC_R_NOSPACE;
   1262 	} else if ((data->length + header_data.length) > UINT16_MAX) {
   1263 		return ISC_R_RANGE;
   1264 	}
   1265 
   1266 	INSIST(memcmp(header_data.base, ISC_PROXY2_HEADER_SIGNATURE,
   1267 		      ISC_PROXY2_HEADER_SIGNATURE_SIZE) == 0);
   1268 
   1269 	/* fixup length of the header payload */
   1270 	/* load */
   1271 	memmove(&new_len, &header_data.base[len_offset], sizeof(new_len));
   1272 	new_len = ntohs(new_len);
   1273 	/* check */
   1274 	if ((data->length + new_len) > UINT16_MAX) {
   1275 		return ISC_R_RANGE;
   1276 	}
   1277 	/* update */
   1278 	new_len += (uint16_t)data->length;
   1279 	/* store */
   1280 	new_len = htons(new_len);
   1281 	memmove(&header_data.base[len_offset], &new_len, sizeof(new_len));
   1282 
   1283 	isc_buffer_putmem(outbuf, data->base, data->length);
   1284 
   1285 	return ISC_R_SUCCESS;
   1286 }
   1287 
   1288 static inline void
   1289 append_type_and_length(isc_buffer_t *restrict outbuf, const uint8_t type,
   1290 		       const uint16_t tlv_length, const bool update_header) {
   1291 	uint16_t length;
   1292 	isc_region_t type_region = { 0 }, length_region = { 0 };
   1293 
   1294 	type_region = (isc_region_t){ .base = (uint8_t *)&type,
   1295 				      .length = sizeof(type) };
   1296 	length = htons(tlv_length);
   1297 	length_region = (isc_region_t){ .base = (uint8_t *)&length,
   1298 					.length = sizeof(length) };
   1299 
   1300 	if (update_header) {
   1301 		isc_result_t result = isc_proxy2_header_append(outbuf,
   1302 							       &type_region);
   1303 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1304 		result = isc_proxy2_header_append(outbuf, &length_region);
   1305 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1306 	} else {
   1307 		isc_buffer_putmem(outbuf, type_region.base, type_region.length);
   1308 		isc_buffer_putmem(outbuf, length_region.base,
   1309 				  length_region.length);
   1310 	}
   1311 }
   1312 
   1313 isc_result_t
   1314 isc_proxy2_header_append_tlv(isc_buffer_t *restrict outbuf,
   1315 			     const isc_proxy2_tlv_type_t tlv_type,
   1316 			     const isc_region_t *restrict tlv_data) {
   1317 	size_t new_data_len = 0;
   1318 	REQUIRE(outbuf != NULL);
   1319 	REQUIRE(tlv_data != NULL);
   1320 
   1321 	/*
   1322 	 * TLV header can be described as follows:
   1323 	 *
   1324 	 *   struct {
   1325 	 *       uint8_t type;
   1326 	 *       uint8_t length_hi;
   1327 	 *       uint8_t length_lo;
   1328 	 *   };
   1329 	 *
   1330 	 */
   1331 	new_data_len = tlv_data->length + 3;
   1332 
   1333 	if (isc_buffer_availablelength(outbuf) < (new_data_len)) {
   1334 		return ISC_R_NOSPACE;
   1335 	} else if ((isc_buffer_usedlength(outbuf) + new_data_len) > UINT16_MAX)
   1336 	{
   1337 		return ISC_R_RANGE;
   1338 	}
   1339 
   1340 	append_type_and_length(outbuf, (uint8_t)tlv_type,
   1341 			       (uint16_t)tlv_data->length, true);
   1342 
   1343 	if (tlv_data->length > 0) {
   1344 		isc_result_t result = isc_proxy2_header_append(outbuf,
   1345 							       tlv_data);
   1346 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1347 	}
   1348 
   1349 	return ISC_R_SUCCESS;
   1350 }
   1351 
   1352 isc_result_t
   1353 isc_proxy2_header_append_tlv_string(isc_buffer_t *restrict outbuf,
   1354 				    const isc_proxy2_tlv_type_t tlv_type,
   1355 				    const char *restrict str) {
   1356 	isc_result_t result;
   1357 	isc_region_t region = { 0 };
   1358 
   1359 	REQUIRE(str != NULL && *str != '\0');
   1360 
   1361 	region.base = (uint8_t *)str;
   1362 	region.length = strlen(str);
   1363 
   1364 	result = isc_proxy2_header_append_tlv(outbuf, tlv_type, &region);
   1365 
   1366 	return result;
   1367 }
   1368 
   1369 isc_result_t
   1370 isc_proxy2_make_tls_subheader(isc_buffer_t *restrict outbuf,
   1371 			      const uint8_t client_flags,
   1372 			      const bool client_cert_verified,
   1373 			      const isc_region_t *restrict tls_subtlvs_data) {
   1374 	size_t total_size = ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE;
   1375 	uint32_t client_cert_not_verified = 1;
   1376 	REQUIRE(outbuf != NULL);
   1377 
   1378 	if (tls_subtlvs_data != NULL) {
   1379 		total_size += tls_subtlvs_data->length;
   1380 	}
   1381 
   1382 	if (isc_buffer_availablelength(outbuf) < total_size) {
   1383 		return ISC_R_NOSPACE;
   1384 	} else if (total_size > UINT16_MAX) {
   1385 		return ISC_R_RANGE;
   1386 	}
   1387 
   1388 	isc_buffer_putuint8(outbuf, client_flags);
   1389 	client_cert_not_verified = htonl(!client_cert_verified);
   1390 	isc_buffer_putmem(outbuf, (uint8_t *)&client_cert_not_verified,
   1391 			  sizeof(client_cert_not_verified));
   1392 
   1393 	if (tls_subtlvs_data != NULL) {
   1394 		isc_buffer_putmem(outbuf, tls_subtlvs_data->base,
   1395 				  tls_subtlvs_data->length);
   1396 	}
   1397 
   1398 	return ISC_R_SUCCESS;
   1399 }
   1400 
   1401 isc_result_t
   1402 isc_proxy2_append_tlv(isc_buffer_t *restrict outbuf, const uint8_t type,
   1403 		      const isc_region_t *restrict data) {
   1404 	size_t new_data_len = 0;
   1405 	REQUIRE(outbuf != NULL);
   1406 	REQUIRE(data != NULL);
   1407 
   1408 	new_data_len = (data->length + 3);
   1409 
   1410 	if (isc_buffer_availablelength(outbuf) < new_data_len) {
   1411 		return ISC_R_NOSPACE;
   1412 	} else if ((isc_buffer_usedlength(outbuf) + (data->length + 3)) >
   1413 		   UINT16_MAX)
   1414 	{
   1415 		return ISC_R_RANGE;
   1416 	}
   1417 
   1418 	append_type_and_length(outbuf, (uint8_t)type, (uint16_t)data->length,
   1419 			       false);
   1420 
   1421 	if (data->length > 0) {
   1422 		isc_buffer_putmem(outbuf, data->base, data->length);
   1423 	}
   1424 
   1425 	return ISC_R_SUCCESS;
   1426 }
   1427 
   1428 isc_result_t
   1429 isc_proxy2_append_tlv_string(isc_buffer_t *restrict outbuf, const uint8_t type,
   1430 			     const char *restrict str) {
   1431 	isc_result_t result;
   1432 	isc_region_t region = { 0 };
   1433 
   1434 	REQUIRE(str != NULL && *str != '\0');
   1435 
   1436 	region.base = (uint8_t *)str;
   1437 	region.length = strlen(str);
   1438 
   1439 	result = isc_proxy2_append_tlv(outbuf, type, &region);
   1440 
   1441 	return result;
   1442 }
   1443