Home | History | Annotate | Line # | Download | only in isc
      1 /*	$NetBSD: proxy2.h,v 1.2 2025/01/26 16:25:42 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 #pragma once
     16 
     17 #include <isc/buffer.h>
     18 #include <isc/mem.h>
     19 #include <isc/sockaddr.h>
     20 
     21 /* Definitions taken or derived from the specification */
     22 
     23 #define ISC_PROXY2_HEADER_SIGNATURE \
     24 	("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A")
     25 
     26 #define ISC_PROXY2_HEADER_SIGNATURE_SIZE (12)
     27 
     28 #define ISC_PROXY2_HEADER_SIZE                                            \
     29 	(ISC_PROXY2_HEADER_SIGNATURE_SIZE + 1 /* version and command */ + \
     30 	 1 /* protocol and family */ + 2 /* data size */)
     31 
     32 #define ISC_PROXY2_MAX_SIZE (ISC_PROXY2_HEADER_SIZE + UINT16_MAX)
     33 
     34 #define ISC_PROXY2_MIN_AF_INET_SIZE                                     \
     35 	(ISC_PROXY2_HEADER_SIZE + 4 /* src_addr */ + 4 /* dst_addr */ + \
     36 	 2 /* src port */ + 2 /* dst_port */)
     37 
     38 #define ISC_PROXY2_MIN_AF_INET6_SIZE                                      \
     39 	(ISC_PROXY2_HEADER_SIZE + 16 /* src_addr */ + 16 /* dst_addr */ + \
     40 	 2 /* src port */ + 2 /* dst_port */)
     41 
     42 #define ISC_PROXY2_AF_UNIX_MAX_PATH_LEN (108)
     43 
     44 #define ISC_PROXY2_MIN_AF_UNIX_SIZE                       \
     45 	(ISC_PROXY2_HEADER_SIZE +                         \
     46 	 ISC_PROXY2_AF_UNIX_MAX_PATH_LEN /* src_addr */ + \
     47 	 ISC_PROXY2_AF_UNIX_MAX_PATH_LEN /* dst_addr */)
     48 
     49 #define ISC_PROXY2_TLV_HEADER_SIZE \
     50 	(1 /* type */ + 1 /* length_hi */ + 1 /* length_lo */)
     51 
     52 #define ISC_PROXY2_TLS_SUBHEADER_MIN_SIZE \
     53 	(1 /* client_flags */ + 4 /* verify */)
     54 
     55 ISC_LANG_BEGINDECLS
     56 
     57 typedef enum isc_proxy2_command {
     58 	ISC_PROXY2_CMD_ILLEGAL = -1,
     59 	/*
     60 	 * PROXYv2 header does not contain any addresses and is supposedly
     61 	 * created on behalf of locally running software.
     62 	 */
     63 	ISC_PROXY2_CMD_LOCAL = 0,
     64 	/*
     65 	 * PROXYv2 header contains address-related information and is
     66 	 * created on a behalf of the client.
     67 	 */
     68 	ISC_PROXY2_CMD_PROXY = 1
     69 } isc_proxy2_command_t;
     70 
     71 typedef enum isc_proxy2_addrfamily {
     72 	ISC_PROXY2_AF_UNSPEC = 0,
     73 	ISC_PROXY2_AF_INET = 1,
     74 	ISC_PROXY2_AF_INET6 = 2,
     75 	ISC_PROXY2_AF_UNIX = 3
     76 } isc_proxy2_addrfamily_t;
     77 
     78 typedef enum isc_proxy2_socktype {
     79 	ISC_PROXY2_SOCK_ILLEGAL = -1,
     80 	ISC_PROXY2_SOCK_UNSPEC = 0,
     81 	ISC_PROXY2_SOCK_STREAM = 1,
     82 	ISC_PROXY2_SOCK_DGRAM = 2
     83 } isc_proxy2_socktype_t;
     84 
     85 typedef enum isc_proxy2_tlv_type {
     86 	/*
     87 	 * Application-Layer Protocol Negotiation (ALPN). It is a byte
     88 	 * sequence defining the upper layer protocol in use over the
     89 	 * connection.
     90 	 */
     91 	ISC_PROXY2_TLV_TYPE_ALPN = 0x01,
     92 	/*
     93 	 * Contains the host name value passed by the client, as an
     94 	 * UTF8-encoded string.
     95 	 */
     96 	ISC_PROXY2_TLV_TYPE_AUTHORITY = 0x02,
     97 	/*
     98 	 * The value is a 32-bit number storing the CRC32c checksum of the
     99 	 * PROXY protocol header.
    100 	 */
    101 	ISC_PROXY2_TLV_TYPE_CRC32C = 0x03,
    102 	/*
    103 	 * The TLV of this type should be ignored when parsed. The value
    104 	 * is zero or more bytes. Can be used for data padding or
    105 	 * alignment.
    106 	 */
    107 	ISC_PROXY2_TLV_TYPE_NOOP = 0x04,
    108 	/*
    109 	 * The value is an opaque byte sequence of up to 128 bytes
    110 	 * generated by the upstream proxy that uniquely identifies the
    111 	 * connection.
    112 	 */
    113 	ISC_PROXY2_TLV_TYPE_UNIQUE_ID = 0x05,
    114 	/*
    115 	 * SSL type contains subfields of the given subtypes (see
    116 	 * isc_proxy2_tlv_subtype_tls_t). The header contains:
    117 	 *
    118 	 * - uint8_t client is a bit-field made of
    119 	 *   isc_proxy2_tls_client_flags_t;
    120 	 * - uint32_t verify (0 for a successfully verified certificate);
    121 	 */
    122 	ISC_PROXY2_TLV_TYPE_TLS = 0x20,
    123 	/*
    124 	 * The type PP2_TYPE_NETNS defines the value as the US-ASCII
    125 	 * string representation of the namespace's name.
    126 	 */
    127 	ISC_PROXY2_TLV_TYPE_NETNS = 0x30,
    128 	/*
    129 	 * The following range of 16 type values is reserved for
    130 	 * application-specific data and will be never used by the PROXY
    131 	 * Protocol.
    132 	 */
    133 	ISC_PROXY2_TLV_TYPE_MIN_CUSTOM = 0xE0,
    134 	ISC_PROXY2_TLV_TYPE_MAX_CUSTOM = 0xEF,
    135 	/*
    136 	 * This range of 8 values is reserved for temporary experimental
    137 	 * use by application developers and protocol designers.
    138 	 */
    139 	ISC_PROXY2_TLV_TYPE_MIN_EXPERIMENT = 0xF0,
    140 	ISC_PROXY2_TLV_TYPE_MAX_EXPERIMENT = 0xF7,
    141 	/*
    142 	 * The following range of 8 values is reserved for future use,
    143 	 * potentially to extend the protocol with multibyte type values.
    144 	 */
    145 	ISC_PROXY2_TLV_TYPE_MIN_FUTURE = 0xF8,
    146 	ISC_PROXY2_TLV_TYPE_MAX_FUTURE = 0xFF
    147 } isc_proxy2_tlv_type_t;
    148 
    149 typedef enum isc_proxy2_tls_client_flags {
    150 	/* The flag indicates that the client connected over SSL/TLS. */
    151 	ISC_PROXY2_CLIENT_TLS = 0x01,
    152 	/* The client provided a certificate over the current connection. */
    153 	ISC_PROXY2_CLIENT_CERT_CONN = 0x02,
    154 	/*
    155 	 * The client provided a certificate at least once over the TLS
    156 	 * session this connection belongs to.
    157 	 */
    158 	ISC_PROXY2_CLIENT_CERT_SESS = 0x04
    159 } isc_proxy2_tls_client_flags_t;
    160 
    161 typedef enum isc_proxy2_tlv_subtype_tls {
    162 	/*
    163 	 * The US-ASCII string representation of the TLS version the TLV
    164 	 * format.
    165 	 */
    166 	ISC_PROXY2_TLV_SUBTYPE_TLS_VERSION = 0x21,
    167 	/*
    168 	 * The Common Name field of the client certificate's Distinguished
    169 	 * Name in the TLV format.
    170 	 */
    171 	ISC_PROXY2_TLV_SUBTYPE_TLS_CN = 0x22,
    172 	/*
    173 	 * The US-ASCII string name of the used cipher, for
    174 	 * example "ECDHE-RSA-AES128-GCM-SHA256".
    175 	 */
    176 	ISC_PROXY2_TLV_SUBTYPE_TLS_CIPHER = 0x23,
    177 	/*
    178 	 * The US-ASCII string name of the algorithm used to sign the
    179 	 * certificate presented by the frontend when the incoming
    180 	 * connection was made over an SSL/TLS transport layer, for
    181 	 * example "SHA256".
    182 	 */
    183 	ISC_PROXY2_TLV_SUBTYPE_TLS_SIG_ALG = 0x24,
    184 	/*
    185 	 * The US-ASCII string name of the algorithm used to generate the
    186 	 * key of the certificate presented by the frontend when the
    187 	 * incoming connection was made over an SSL/TLS transport layer,
    188 	 * for example "RSA2048".
    189 	 */
    190 	ISC_PROXY2_TLV_SUBTYPE_TLS_KEY_ALG = 0x25
    191 } isc_proxy2_tlv_subtype_tls_t;
    192 
    193 /*
    194  * Definitions related to processing and verification of existing PROXYv2
    195  * headers
    196  */
    197 
    198 typedef struct isc_proxy2_handler isc_proxy2_handler_t;
    199 /*!<
    200  * 'isc_proxy2_handler_t' is an entity designed for processing of the
    201  * PROXYv2 data received from a network. Despite its purpose, it is
    202  * designed as a state machine which, in fact, has no direct connection
    203  * to the networking code. Interaction with the networking code is done
    204  * via the provided API only.
    205  *
    206  * The entity is designed as a state machine which accepts data on
    207  * input and calls a user-provided data processing callback to notify
    208  * about data processing status and, in the case of successful
    209  * processing, provide the upper level code with the data obtained
    210  * from the PROXYv2 header and associated payload.
    211  *
    212  * The reason for the state machine-based approach is
    213  * many-fold. Firstly, the protocol itself is well suited for
    214  * processing by a state machine with well-defined steps. Secondly,
    215  * such a design allows iterative data processing combined with
    216  * verification, which is more secure than trying to read seemingly
    217  * enough data, process it, and then retrospectively verify
    218  * it. Thirdly, such an approach aligns well with how stream-based
    219  * transports work - PROXYv2 headers might arrive torn into multiple
    220  * parts which need to be assembled (theoretically, it is fine to send
    221  * data over TCP bite-by-bite), and we should handle such
    222  * cases. Additionally to that, we should stop reading data as soon as
    223  * we detect that it is ill-formed. This design allows that and also
    224  * can be used easily with datagram-based networking code.
    225  *
    226  * Another important characteristic of the state machine-based code is
    227  * that it can be unit-tested separately from the rest of the code
    228  * base. Of course, we use that to our advantage.
    229  *
    230  * The implementations closely follows the PROXYv2 protocol
    231  * specification from 2020/03/05
    232  * (https://www.haproxy.org/download/2.9/doc/proxy-protocol.txt),
    233  * however, enough functionality is provided to handle future
    234  * extensions, too. To be fair, our needs are quite modest and we are
    235  * not interested in all the information PROXYv2 protocol could carry
    236  * - we are mostly interested in the basics. However, our protocol
    237  * handling code is fairly complete at the time of writing leaving a
    238  * good foundation for further extensions, as the PROXYv2 protocol is
    239  * itself extensible. The only missing thing is header checksum
    240  * verification - but that functionality is optional. That being said, it is
    241  * easy to add that, should we ever need to.
    242  */
    243 
    244 typedef void (*isc_proxy2_handler_cb_t)(const isc_result_t	   result,
    245 					const isc_proxy2_command_t cmd,
    246 					const int		   socktype,
    247 					const isc_sockaddr_t *restrict src_addr,
    248 					const isc_sockaddr_t *restrict dst_addr,
    249 					const isc_region_t *restrict tlv_data,
    250 					const isc_region_t *restrict extra,
    251 					void *cbarg);
    252 /*!<
    253  * PROXYv2 data processing callback.
    254  *
    255  * Arguments:
    256  *\li	'result' - error status code;
    257  *\li	'cmd' - PROXYv2 command;
    258  *\li	'socktype' - PROXYv2 addresses socket type
    259  *(SOCK_STREAM, SOCK_DGRAM, or '0' for "unspecified" (SOCK_UNSPEC)).
    260  *\li	'src_addr' - original source address extracted from the PROXYv2 header;
    261  *\li	'dst_addr' - original destination address extracted from the PROXYv2
    262  *header;
    263  *\li	'tlv_data' - TLV-data extracted from the header;
    264  *\li	'extra_data' - extra unprocessed data past the PROXYv2 header. It is
    265  *not a part of the header, but it is fine to receive this when reading data
    266  *over TCP-based transports. In general, needs to be passed to the upper
    267  *level as is;
    268  *\li	'cbarg' - opaque pointer to user supplied data.
    269  *
    270  * The user-provided data processing callback function can get the
    271  * following error status codes:
    272  * \li	'ISC_R_SUCCESS' - the header has been processed, and data has been
    273  * extracted from the received header and its payload;
    274  * \li	'ISC_R_NOMORE' - the data passed was processed, and we need more to
    275  * continue processing (=resume reading from the network as we have no more
    276  * data to process);
    277  * \li	'ISC_R_UNEXPECTED' - an unexpected value has been detected;
    278  * \li	'ISC_R_RANGE' - an expected value is not within an expected range.
    279  *
    280  * When processing error status within the callback, in general, we
    281  * are interested in dispatching on the first two values, as anything
    282  * else can be treated as hard-stop errors: their purpose is to give a
    283  * little insight into what has happened without going into gory
    284  * details (as we are not interested in them most of the time anyway).
    285  *
    286  * Any of the argument pointers can be 'NULL', identifying that the
    287  * corresponding data is not present in the PROXYv2 header. Also,
    288  * 'socktype' can be '-1' in a case of processing error.
    289  *
    290  */
    291 
    292 struct isc_proxy2_handler {
    293 	isc_buffer_t hdrbuf; /*!< Internal buffer for assembling PROXYv2 header
    294 			      */
    295 	uint8_t buf[256];    /*!< Internal buffer static storage */
    296 
    297 	int	 state;	      /*!< Current state machine state */
    298 	uint16_t expect_data; /*!< How much data do we need to switch to the
    299 				 next state */
    300 	uint16_t max_size; /*!< Max PROXYv2 header size including its payload */
    301 
    302 	isc_proxy2_handler_cb_t cb;    /*!< Data processing callback. */
    303 	void		       *cbarg; /*!< Callback argument. */
    304 	bool calling_cb; /*<! Callback calling marker. Used to detect recursive
    305 		    object uses (changing the data state from within
    306 		    the callback). */
    307 	isc_result_t result; /*<! The last passed to the callback processing
    308 				status value. */
    309 	isc_mem_t *mctx;
    310 
    311 	uint16_t header_size;	/*!< Total PROXYv2 header size (including the
    312 				   payload. */
    313 	uint16_t tlv_data_size; /*!< The size of TLVs payload size */
    314 
    315 	isc_proxy2_command_t	cmd; /*!< The decoded PROXYv2 command */
    316 	isc_proxy2_addrfamily_t proxy_addr_family; /*!< The decoded PROXYv2
    317 						      address family */
    318 	isc_proxy2_socktype_t proxy_socktype; /*!< The decoded PROXYv2 socket
    319 						 type */
    320 
    321 	isc_region_t tlv_data;	 /*!< TLV data region within the handled PROXYv2
    322 				    header */
    323 	isc_region_t extra_data; /*!< Data past the PROXYv2 header (not
    324 				    belonging to it) */
    325 };
    326 
    327 void
    328 isc_proxy2_handler_init(isc_proxy2_handler_t *restrict handler, isc_mem_t *mctx,
    329 			const uint16_t max_size, isc_proxy2_handler_cb_t cb,
    330 			void *cbarg);
    331 /*!<
    332  * \brief Initialise the given 'isc_proxy2_handler_t' object, attach
    333  * to the memory context.
    334  *
    335  * Arguments:
    336  *\li	'mctx' -  memory context;
    337  *\li	'max_size' - the upper limit for the PROXYv2 header and its payload (0 -
    338  *unlimited);
    339  *\li	'cb' - data processing callback;
    340  *\li	'cbarg' - data processing callback argument.
    341  *
    342  * Requires:
    343  *\li	'handler' is not NULL;
    344  *\li	'mctx' is not NULL;
    345  *\li	'max_size' is >= `ISC_PROXY2_HEADER_SIZE` or is 0;
    346  *\li	'cb' is not NULL.
    347  */
    348 
    349 void
    350 isc_proxy2_handler_uninit(isc_proxy2_handler_t *restrict handler);
    351 /*!<
    352  * \brief Un-initialise the given 'isc_proxy2_handler_t' object, detach
    353  * from the attached memory context. Invalidate any internal unprocessed data.
    354  *
    355  * Requires:
    356  *\li	'handler' is not NULL.
    357  */
    358 
    359 void
    360 isc_proxy2_handler_clear(isc_proxy2_handler_t *restrict handler);
    361 /*!<
    362  * \brief Clear the given 'isc_proxy2_handler_t' object from
    363  * any unprocessed data, clear the last data processing status (set it to
    364  * 'ISC_R_UNSET'). Effectively, the function returns the object to its initial
    365  * state.
    366  *
    367  * Requires:
    368  *\li	'handler' is not NULL.
    369  */
    370 
    371 isc_proxy2_handler_t *
    372 isc_proxy2_handler_new(isc_mem_t *mctx, const uint16_t max_size,
    373 		       isc_proxy2_handler_cb_t cb, void *cbarg);
    374 /*!<
    375  * \brief Allocate and initialise a new 'isc_proxy2_handler_t'
    376  * object, attach to the memory context.
    377  *
    378  * Arguments:
    379  *\li	'mctx' -  memory context;
    380  *\li	'max_size' - the upper limit for the PROXYv2 header and its payload (0 -
    381  *unlimited);
    382  *\li	'cb' - data processing callback;
    383  *\li	'cbarg' - data
    384  *processing callback argument.
    385  *
    386  * Requires:
    387  *\li	'mctx' is not NULL;
    388  *\li	'max_size' is >= `ISC_PROXY2_HEADER_SIZE` or is 0;
    389  *\li	'cb' is not NULL.
    390  */
    391 
    392 void
    393 isc_proxy2_handler_free(isc_proxy2_handler_t **restrict handler);
    394 /*!<
    395  * \brief Un-initialise the given 'isc_proxy2_handler_t' object, detach
    396  * from the attached memory context, free the memory consumed by the object.
    397  *
    398  * Requires:
    399  *\li	'handler' is not NULL;
    400  *\li	'handler' is not pointing to NULL.
    401  */
    402 
    403 void
    404 isc_proxy2_handler_setcb(isc_proxy2_handler_t *restrict handler,
    405 			 isc_proxy2_handler_cb_t cb, void *cbarg);
    406 /*!<
    407  * \brief Change the data processing callback and its argument within the
    408  * given 'isc_proxy2_handler_t' object.
    409  *
    410  * Arguments:
    411  *\li	'handler' - PROXYv2 handler object;
    412  *\li	'cb' - new data processing callback;
    413  *\li	'cbarg' - new data processing callback argument.
    414  *
    415  * Requires:
    416  *\li	'handler' is not NULL;
    417  *\li	'cb' is not NULL.
    418  */
    419 
    420 isc_result_t
    421 isc_proxy2_handler_push_data(isc_proxy2_handler_t *restrict handler,
    422 			     const void *restrict buf,
    423 			     const unsigned int buf_size);
    424 /*!<
    425  * \brief Push new data to the given 'isc_proxy2_handler_t'
    426  * object. Call the callback passing a status and a result of data
    427  * processing to it.
    428  *
    429  * To avoid erroneously recursive usage of the object, it is forbidden to call
    430  * this function from within the callback. Doing so will abort the program.
    431  *
    432  * Requires:
    433  *\li	'handler' is not NULL;
    434  *\li	'buf' is not NULL;
    435  *\li	'buf_size' is not 0.
    436  */
    437 
    438 isc_result_t
    439 isc_proxy2_handler_push(isc_proxy2_handler_t *restrict handler,
    440 			const isc_region_t *restrict region);
    441 /*!<
    442  * \brief The same as 'isc_proxy2_handler_push_data()' but pushes that
    443  * data for processing via an 'isc_region_t' object.
    444  *
    445  * Requires:
    446  *\li	'handler' is not NULL;
    447  *\li	'region' is not NULL.
    448  */
    449 
    450 isc_result_t
    451 isc_proxy2_handler_result(const isc_proxy2_handler_t *restrict handler);
    452 /*!<
    453  * \brief Return the last data processing status passed to the
    454  * callback.
    455  *
    456  * Requires:
    457  *\li	'handler' is not NULL.
    458  *
    459  * Return values:
    460  * \li	'ISC_R_SUCCESS' - the header has been processed, and data has been
    461  * extracted from the received header and its payload;
    462  * \li	'ISC_R_NOMORE' - the data passed was processed, and we need more to
    463  * continue processing (=resume reading from the network as we have no more
    464  * data to process);
    465  * \li	'ISC_R_UNEXPECTED' - an unexpected value has been detected;
    466  * \li	'ISC_R_RANGE' - an expected value is not within an expected range.
    467  */
    468 
    469 size_t
    470 isc_proxy2_handler_header(const isc_proxy2_handler_t *restrict handler,
    471 			  isc_region_t *restrict region);
    472 /*!<
    473  * \brief Get the complete processed PROXYv2 header as is
    474  * (e.g. for forwarding).
    475  *
    476  * Requires:
    477  *\li	'handler' is not NULL;
    478  *\li	'region' is NULL or points to a zeroed 'isc_region_t' object.
    479  *
    480  * Return the size of the header or 0 on error (if it has not been
    481  * processed yet).
    482  */
    483 
    484 size_t
    485 isc_proxy2_handler_tlvs(const isc_proxy2_handler_t *restrict handler,
    486 			isc_region_t *restrict region);
    487 /*!<
    488  * \brief Get the TLV-data within the processed PROXYv2 header.
    489  *
    490  * Requires:
    491  *\li	'handler' is not NULL;
    492  *\li	'region' is NULL or points to a zeroed 'isc_region_t' object.
    493  *
    494  * Return the size of the header or 0 on error (if it has not been
    495  * processed yet).
    496  */
    497 
    498 size_t
    499 isc_proxy2_handler_extra(const isc_proxy2_handler_t *restrict handler,
    500 			 isc_region_t *restrict region);
    501 /*!<
    502  * \brief Get the data past the processed PROXYv2 header. The data
    503  * is not the part of the PROXYv2 header itself. That can happen (and
    504  * does happen) when data is being sent over TCP.
    505  *
    506  * Requires:
    507  *\li	'handler' is not NULL;
    508  *\li	'region' is NULL or points to a zeroed 'isc_region_t' object.
    509  *
    510  * Return the size of the header or 0 on error (if it has not been
    511  * processed yet).
    512  */
    513 
    514 isc_result_t
    515 isc_proxy2_handler_addresses(const isc_proxy2_handler_t *restrict handler,
    516 			     int *restrict psocktype,
    517 			     isc_sockaddr_t *restrict psrc_addr,
    518 			     isc_sockaddr_t *restrict pdst_addr);
    519 /*!<
    520  * \brief Get the addresses directly from the processed PROXYv2
    521  * header. If you are not interested in particular data, you can pass
    522  * NULL as the argument to ignore it.
    523  *
    524  * Requires:
    525  *\li	'handler' is not NULL.
    526  */
    527 
    528 isc_result_t
    529 isc_proxy2_header_handle_directly(const isc_region_t *restrict header_data,
    530 				  const isc_proxy2_handler_cb_t cb,
    531 				  void			       *cbarg);
    532 /*!<
    533  * \brief Process PROXYv2 header in one go directly without memory
    534  * allocation and copying. Specifically designed to work when a
    535  * complete header and associated follow-up data is expected (for
    536  * example, when datagram transports are used, like UDP).
    537  *
    538  * Requires:
    539  *\li	'header_data' is not NULL;
    540  *\li	'cb' is not NULL.
    541  *
    542  * Return values are the same that get passed to the processing
    543  * callback. Given that processing should complete in one go, getting
    544  * anything except `ISC_R_SUCCESS` indicates failure.
    545  */
    546 
    547 typedef bool (*isc_proxy2_tlv_cb_t)(const isc_proxy2_tlv_type_t tlv_type,
    548 				    const isc_region_t *restrict data,
    549 				    void *cbarg);
    550 /*!<
    551  * \brief Callback used for iterating over TLV data extracted from
    552  * PROXYv2 headers.
    553  *
    554  * Arguments:
    555  *\li	'tlv_type' - type value (see the 'isc_proxy2_tlv_type_t' enumeration);
    556  *\li	'data' - pointer to 'isc_region_t' object referring to the data;
    557  *\li	'cbarg' - opaque pointer to user supplied data.
    558  *
    559  * Return values:
    560  *\li	'true' - continue processing the next TLV entry (if any);
    561  *\li	'false' - stop processing TLV-entries.
    562  */
    563 
    564 isc_result_t
    565 isc_proxy2_tlv_iterate(const isc_region_t *restrict tlv_data,
    566 		       const isc_proxy2_tlv_cb_t cb, void *cbarg);
    567 /*!<
    568  * \brief Iterate over the TLV data extracted from PROXYv2 headers.
    569  *
    570  * Arguments:
    571  *\li	'tlv_data' - TLV data extracted from a PROXYv2 header;
    572  *\li	'cb' - user provided iteration callback;
    573  *\li	'cbarg' - user provided iteration callback argument.
    574  *
    575  * Requires:
    576  *\li	'tlv_data' is not NULL;
    577  *\li	'cb' is not NULL.
    578  *
    579  * Return values:
    580  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    581  *\li	'ISC_R_RANGE' - malformed TLV data was detected.
    582  */
    583 
    584 typedef bool (*isc_proxy2_tls_subtlv_cb_t)(
    585 	const uint8_t client_flags, const bool client_cert_verified,
    586 	const isc_proxy2_tlv_subtype_tls_t tls_subtlv_type,
    587 	const isc_region_t *restrict data, void *cbarg);
    588 /*!<
    589  * \brief Callback used for iterating over TLS sub-TLV data extracted from
    590  * PROXYv2 headers.
    591  *
    592  * Arguments:
    593  *\li	'client_flags' - TLS client flags extracted from TLS TLV data
    594  * (see 'isc_proxy2_tls_client_flags_t' enumeration);
    595  *\li	'client_cert_verified' - flag which indicates if the supplied
    596  *TLS client certificate was verified- (if provided by the client);
    597  *\li	'tls_subtlv_type' - TLS sub-TLV type (see the
    598  *'isc_proxy2_tlv_subtype_tls_t' enumeration);
    599  *\li	'cbarg' - opaque pointer to user supplied data.
    600  *
    601  * Return values:
    602  *\li	'true' - continue processing the next TLV entry (if any);
    603  *\li	'false' - stop processing TLV-entries.
    604  */
    605 
    606 isc_result_t
    607 isc_proxy2_subtlv_tls_header_data(const isc_region_t *restrict tls_tlv_data,
    608 				  uint8_t *restrict pclient_flags,
    609 				  bool *restrict pclient_cert_verified);
    610 /*!<
    611  * \brief Get data from a TLS ('ISC_PROXY2_TLV_TYPE_TLS') TLV value.
    612  *
    613  * Arguments:
    614  *\li	'pclient_flags' - a pointer to the variable to receive the TLS client
    615  *flags (see 'isc_proxy2_tls_client_flags_t' enumeration for more details);
    616  *\li	'pclient_cert_verified' - a pointer the value to receive TLS client
    617  *certificate verification status ('true' - verified).
    618  *
    619  * Requires:
    620  *\li	'tls_tlv_data' is not NULL;
    621  *\li	'pclient_flags' is either NULL or a pointer pointing to a
    622  *zeroed variable;
    623  *\li	'pclient_cert_verified' is either NULL or a pointer pointing to a
    624  *zeroed variable.
    625  *
    626  * Return values:
    627  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    628  *\li	'ISC_R_RANGE' - malformed TLV data was detected.
    629  */
    630 
    631 isc_result_t
    632 isc_proxy2_subtlv_tls_iterate(const isc_region_t *restrict tls_tlv_data,
    633 			      const isc_proxy2_tls_subtlv_cb_t cb, void *cbarg);
    634 /*!<
    635  * \brief Iterate over the sub-TLV data extracted from TLS
    636  * ('ISC_PROXY2_TLV_TYPE_TLS') TLV value of a PROXYv2 header.
    637  *
    638  * Arguments:
    639  *\li	'tls_tlv_data' - TLS-realted sub-TLV data extracted from
    640  *a PROXYv2 header;
    641  *\li	'cb' - user provided iteration callback;
    642  *\li	'cbarg' - user provided iteration callback argument.
    643  *
    644  * Requires:
    645  *\li	'tls_tlv_data' is not NULL;
    646  *\li	'cb' is not NULL.
    647  *
    648  * Return values:
    649  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    650  *\li	'ISC_R_RANGE' - malformed TLV data was detected.
    651  */
    652 
    653 isc_result_t
    654 isc_proxy2_tlv_data_verify(const isc_region_t *restrict tlv_data);
    655 /*!<
    656  * \brief Verify TLV-data structure extracted from a PROXYv2 header.
    657  * The function loops over the data verifying that TLVs are structured
    658  * in a correct way.
    659  *
    660  * NOTE: If you are using an 'isc_proxy2_handler_t' object then there
    661  * is no need for you to call this function as it is called during
    662  * the normal operation. It is exposed mostly for unit testing
    663  * purposes or for verifying outgoing data, should it be required.
    664  *
    665  * Arguments:
    666  *\li	'tlv_data' - TLV data extracted from a PROXYv2 header.
    667  *
    668  * Requires:
    669  *\li	'tlv_data' is not NULL.
    670  *
    671  * Return values:
    672  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    673  *\li	'ISC_R_RANGE' - malformed TLV data was detected.
    674  */
    675 
    676 /*
    677  * Definitions related to generation of PROXYv2 headers
    678  */
    679 
    680 isc_result_t
    681 isc_proxy2_make_header(isc_buffer_t *restrict outbuf,
    682 		       const isc_proxy2_command_t cmd, const int socktype,
    683 		       const isc_sockaddr_t *restrict src_addr,
    684 		       const isc_sockaddr_t *restrict dst_addr,
    685 		       const isc_region_t *restrict tlv_data);
    686 /*!<
    687  * \brief Create a PROXYv2 header.
    688  *
    689  * Arguments:
    690  *\li	'outbuf' - the output buffer;
    691  *\li	'cmd' - PROXYv2 command;
    692  *\li	'socktype' - PROXYv2 socket type (possible values are 'SOCK_STREAM',
    693  *'SOCK_DGRAM', or '0' for "unspecified");
    694  *\li	'src_addr' - source address, if any;
    695  *\li	'dst_addr' - destination address, if any;
    696  *\li	'tlv_data' - TLV data, if any.
    697  *
    698  * Requires:
    699  *\li	'outbuf' is not NULL;
    700  *\li	'cmd' is 'ISC_PROXY2_CMD_PROXY' or 'socktype' is equal to '0';
    701  *\li	either both of 'src_addr' and 'dst_addr' are NULL or both are not;
    702  *\li	both of 'src_addr' and 'dst_addr' are of the same type when specified.
    703  *
    704  * Notes:
    705  *
    706  * When 'cmd' equals 'ISC_PROXY2_CMD_LOCAL', then 'socktype' must equal '0'
    707  * (unspecified) and both 'src_addr' and 'dst_addr' must be 'NULL'.
    708  * When 'cmd' equals 'ISC_PROXY2_CMD_PROXY', then having 'socktype' being equal
    709  * to '0' will instruct the function to create PROXYv2 header marked as bearing
    710  * address of "unspecified" ('0') opaque type. In this case both 'src_addr' and
    711  * 'dst_addr' must be 'NULL'. In other cases the address type is determined
    712  * from the 'src_addr' and 'dst_addr' arguments (and might 'AF_INET',
    713  * 'AF_INET6', and 'AF_UNIX' per the protocol spec).
    714  * The socket type, when applicable, is determined from the 'socktype' argument
    715  * and must be any of 'SOCK_STREAM', 'SOCK_DGRAM', when applicable, or '0'
    716  * (unspecified).
    717  *
    718  * Return values:
    719  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    720  *\li	'ISC_R_UNEXPECTED' - an unexpected value has been detected in the input
    721  *data (function arguments);
    722  *\li	'ISC_R_NOSPACE' - not enough data in the output buffer;
    723  *\li	'ISC_R_RANGE' - too much data to fit PROXYv2 header.
    724  */
    725 
    726 isc_result_t
    727 isc_proxy2_header_append(isc_buffer_t *restrict outbuf,
    728 			 const isc_region_t *restrict data);
    729 /*!<
    730  * \brief Append arbitrary data to PROXYv2 header and update the
    731  * length field within the header accordingly. It is used as foundation
    732  * for TLV appending functionality. Also, it can be used to add address
    733  * information in the case when "unspecified" opaque format is used.
    734  *
    735  * Arguments:
    736  *\li	'outbuf' - the output buffer containing a valid PROXYv2 header;
    737  *\li	'data' - use provided arbitrary data.
    738  *
    739  * Requires:
    740  *\li	'outbuf' is not NULL;
    741  *\li	used region within 'outbuf' is more or equal
    742  *to 'ISC_PROXY2_HEADER_SIZE';
    743  *\li	'data' is not NULL.
    744  *
    745  * Return values:
    746  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    747  *\li	'ISC_R_NOSPACE' - not enough data in the output buffer;
    748  *\li	'ISC_R_RANGE' - too much data for PROXYv2 header.
    749  */
    750 
    751 isc_result_t
    752 isc_proxy2_header_append_tlv(isc_buffer_t *restrict outbuf,
    753 			     const isc_proxy2_tlv_type_t tlv_type,
    754 			     const isc_region_t *restrict data);
    755 /*!<
    756  * \brief Append TLV data to PROXYv2 header and update the
    757  * length field within the header accordingly.
    758  *
    759  * Requires:
    760  *\li	'outbuf' is not NULL;
    761  *\li	used region within 'outbuf' is more or equal
    762  *to 'ISC_PROXY2_HEADER_SIZE';
    763  *\li	'data' is not NULL.
    764  *
    765  * Return values:
    766  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    767  *\li	'ISC_R_NOSPACE' - not enough data in the output buffer
    768  *\li	'ISC_R_RANGE' - too much data for PROXYv2 header.
    769  */
    770 
    771 isc_result_t
    772 isc_proxy2_header_append_tlv_string(isc_buffer_t *restrict outbuf,
    773 				    const isc_proxy2_tlv_type_t tlv_type,
    774 				    const char *restrict str);
    775 /*!<
    776  * \brief Append the string as TLV data to PROXYv2 header and update the
    777  * length field within the header accordingly.
    778  *
    779  * Requires:
    780  *\li	'outbuf' is not NULL;
    781  *\li	used region within 'outbuf' is more or equal
    782  *to 'ISC_PROXY2_HEADER_SIZE';
    783  *\li	'data' is not NULL.
    784  *
    785  * Return values:
    786  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    787  *\li	'ISC_R_NOSPACE' - not enough data in the output buffer.
    788  *\li	'ISC_R_RANGE' - too much data for PROXYv2 header.
    789  */
    790 
    791 isc_result_t
    792 isc_proxy2_make_tls_subheader(isc_buffer_t *restrict outbuf,
    793 			      const uint8_t client_flags,
    794 			      const bool    client_cert_verified,
    795 			      const isc_region_t *restrict tls_subtlvs_data);
    796 /*!<
    797  * \brief Create TLS (ISC_PROXY2_TLV_TYPE_TLS) TLV subheader which
    798  * can later be added to the PROXYv2 header TLV data.
    799  *
    800  * Arguments:
    801  *\li	'client_flags' - TLS client flags (see
    802  'isc_proxy2_tls_client_flags_t' enumeration for more details);
    803  *\li	'client_cert_verified' - TLS client certificate verification
    804  *status ('true' - verified).
    805  *\li	'tls_subtlvs_data' - TLS subtlvs data, if any (see
    806  'isc_proxy2_tlv_subtype_tls_t' for more details).
    807  *
    808  * Requires:
    809  *\li	'outbuf' is not NULL;
    810  *
    811  * Return values:
    812  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    813  *\li	'ISC_R_NOSPACE' - not enough data in the output buffer;
    814   *\li	'ISC_R_RANGE' - too much data for a TLV value.
    815  */
    816 
    817 isc_result_t
    818 isc_proxy2_append_tlv(isc_buffer_t *restrict outbuf, const uint8_t type,
    819 		      const isc_region_t *restrict data);
    820 /*!<
    821  * \brief Append TLV data to the end of the buffer. Compared to
    822  * 'isc_proxy2_header_append_tlv()' it does not try to look for a
    823  * correct PROXYv2 header at the beginning of the buffer and update
    824  * its length field. The main purpose of this function is to work with
    825  * sub-TLVs.
    826  *
    827  * Requires:
    828  *\li	'outbuf' is not NULL;
    829  *\li	'data' is not NULL.
    830  *
    831  * Return values:
    832  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    833  *\li	'ISC_R_NOSPACE' - not enough data in the output buffer
    834  *\li	'ISC_R_RANGE' - too much data for PROXYv2 header.
    835  */
    836 
    837 isc_result_t
    838 isc_proxy2_append_tlv_string(isc_buffer_t *restrict outbuf, const uint8_t type,
    839 			     const char *restrict str);
    840 /*!<
    841  * \brief Append the string as TLV data to the end of the
    842  * buffer. Compared to 'isc_proxy2_header_append_tlv_string()' it does not
    843  * try to look for a correct PROXYv2 header at the beginning of the
    844  * buffer and update its length field. The main purpose of this
    845  * function is to work with sub-TLVs.
    846  *
    847  * Requires:
    848  *\li	'outbuf' is not NULL;
    849  *\li	'data' is not NULL.
    850  *
    851  * Return values:
    852  *\li	'ISC_R_SUCCESS' - iteration over the data was successful;
    853  *\li	'ISC_R_NOSPACE' - not enough data in the output buffer
    854  *\li	'ISC_R_RANGE' - too much data for PROXYv2 header.
    855  */
    856 
    857 ISC_LANG_ENDDECLS
    858