xref: /netbsd-src/external/mpl/bind/dist/lib/isc/proxy2.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
1 /*	$NetBSD: proxy2.c,v 1.2 2025/01/26 16:25:38 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