Home | History | Annotate | Line # | Download | only in util
      1 /*
      2  * util/proxy_protocol.h - PROXY protocol
      3  *
      4  * Copyright (c) 2022, NLnet Labs. All rights reserved.
      5  *
      6  * This software is open source.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * Redistributions of source code must retain the above copyright notice,
     13  * this list of conditions and the following disclaimer.
     14  *
     15  * Redistributions in binary form must reproduce the above copyright notice,
     16  * this list of conditions and the following disclaimer in the documentation
     17  * and/or other materials provided with the distribution.
     18  *
     19  * Neither the name of the NLNET LABS nor the names of its contributors may
     20  * be used to endorse or promote products derived from this software without
     21  * specific prior written permission.
     22  *
     23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
     29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34  */
     35 
     36 /**
     37  * \file
     38  *
     39  * This file contains PROXY protocol structs and functions.
     40  * Only v2 is supported. TLVs are not currently supported.
     41  */
     42 #ifndef PROXY_PROTOCOL_H
     43 #define PROXY_PROTOCOL_H
     44 
     45 #include "config.h"
     46 
     47 /** PROXYv2 minimum header size */
     48 #define PP2_HEADER_SIZE 16
     49 
     50 /** PROXYv2 header signature */
     51 #define PP2_SIG "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
     52 #define PP2_SIG_LEN 12
     53 
     54 /** PROXYv2 version (protocol value) */
     55 #define PP2_VERSION 0x2
     56 
     57 /** PROXYv2 minimum header.len value for TCP/UDP over IPv4 */
     58 #define PP2_HEADER_LEN_INET 12
     59 
     60 /** PROXYv2 minimum header.len value for TCP/UDP over IPv6 */
     61 #define PP2_HEADER_LEN_INET6 36
     62 
     63 /** PROXYv2 minimum header.len value for TCP/UDP over AF_UNIX */
     64 #define PP2_HEADER_LEN_UNIX 216
     65 
     66 /**
     67  * PROXYv2 command (protocol value).
     68  */
     69 enum pp2_command {
     70 	PP2_CMD_LOCAL = 0x0,
     71 	PP2_CMD_PROXY = 0x1
     72 };
     73 
     74 /**
     75  * PROXYv2 address family (protocol value).
     76  */
     77 enum pp2_af {
     78 	PP2_AF_UNSPEC = 0x0,
     79 	PP2_AF_INET = 0x1,
     80 	PP2_AF_INET6 = 0x2,
     81 	PP2_AF_UNIX = 0x3
     82 };
     83 
     84 /**
     85  * PROXYv2 protocol (protocol value).
     86  */
     87 enum pp2_protocol {
     88 	PP2_PROT_UNSPEC = 0x0,
     89 	PP2_PROT_STREAM = 0x1,
     90 	PP2_PROT_DGRAM = 0x2
     91 };
     92 
     93 /**
     94  * Expected combinations of address family and protocol values used in checks.
     95  */
     96 enum pp2_af_protocol_combination {
     97 	PP2_UNSPEC_UNSPEC = (PP2_AF_UNSPEC<<4)|PP2_PROT_UNSPEC,
     98 	PP2_INET_STREAM = (PP2_AF_INET<<4)|PP2_PROT_STREAM,
     99 	PP2_INET_DGRAM = (PP2_AF_INET<<4)|PP2_PROT_DGRAM,
    100 	PP2_INET6_STREAM = (PP2_AF_INET6<<4)|PP2_PROT_STREAM,
    101 	PP2_INET6_DGRAM = (PP2_AF_INET6<<4)|PP2_PROT_DGRAM,
    102 	PP2_UNIX_STREAM = (PP2_AF_UNIX<<4)|PP2_PROT_STREAM,
    103 	PP2_UNIX_DGRAM = (PP2_AF_UNIX<<4)|PP2_PROT_DGRAM
    104 };
    105 
    106 /**
    107  * PROXYv2 header.
    108  */
    109 struct pp2_header {
    110 	uint8_t sig[PP2_SIG_LEN];
    111 	uint8_t ver_cmd;
    112 	uint8_t fam_prot;
    113 	uint16_t len;
    114 	union {
    115 		struct {  /* for TCP/UDP over IPv4, len = 12 */
    116 			uint32_t src_addr;
    117 			uint32_t dst_addr;
    118 			uint16_t src_port;
    119 			uint16_t dst_port;
    120 		} addr4;
    121 		struct {  /* for TCP/UDP over IPv6, len = 36 */
    122 			uint8_t  src_addr[16];
    123 			uint8_t  dst_addr[16];
    124 			uint16_t src_port;
    125 			uint16_t dst_port;
    126 		} addr6;
    127 		struct {  /* for AF_UNIX sockets, len = 216 */
    128 			uint8_t src_addr[108];
    129 			uint8_t dst_addr[108];
    130 		} addru;
    131 	} addr;
    132 };
    133 
    134 /**
    135  * PROXY parse errors.
    136  */
    137 enum pp_parse_errors {
    138 	PP_PARSE_NOERROR = 0,
    139 	PP_PARSE_SIZE,
    140 	PP_PARSE_WRONG_HEADERv2,
    141 	PP_PARSE_UNKNOWN_CMD,
    142 	PP_PARSE_UNKNOWN_FAM_PROT,
    143 };
    144 
    145 /**
    146  * Initialize the internal proxy structure.
    147  * @param write_uint16: pointer to a function that can write uint16.
    148  * @param write_uint32: pointer to a function that can write uint32.
    149  */
    150 void pp_init(void (*write_uint16)(void* buf, uint16_t data),
    151 	void (*write_uint32)(void* buf, uint32_t data));
    152 
    153 /**
    154  * Lookup the parsing error description.
    155  * @param error: parsing error from pp2_read_header.
    156  * @return the description.
    157  */
    158 const char* pp_lookup_error(enum pp_parse_errors error);
    159 
    160 /**
    161  * Write a PROXYv2 header at the current position of the buffer.
    162  * @param buf: pointer to the buffer to write data to.
    163  * @param buflen: available size on the buffer.
    164  * @param src: the source address.
    165  * @param stream: if the protocol is stream or datagram.
    166  * @return 1 on success, 0 on failure.
    167  */
    168 size_t pp2_write_to_buf(uint8_t* buf, size_t buflen,
    169 #ifdef INET6
    170 	struct sockaddr_storage* src,
    171 #else
    172 	struct sockaddr_in* src,
    173 #endif
    174 	int stream);
    175 
    176 /**
    177  * Read a PROXYv2 header from the current position of the buffer.
    178  * It does initial validation and returns a pointer to the buffer position on
    179  * success.
    180  * @param buf: pointer to the buffer data to read from.
    181  * @param buflen: available size on the buffer.
    182  * @return parsing error, 0 on success.
    183  */
    184 int pp2_read_header(uint8_t* buf, size_t buflen);
    185 
    186 #endif /* PROXY_PROTOCOL_H */
    187