1865f46b2SCy Schubert /* 2865f46b2SCy Schubert * util/proxy_protocol.h - PROXY protocol 3865f46b2SCy Schubert * 4865f46b2SCy Schubert * Copyright (c) 2022, NLnet Labs. All rights reserved. 5865f46b2SCy Schubert * 6865f46b2SCy Schubert * This software is open source. 7865f46b2SCy Schubert * 8865f46b2SCy Schubert * Redistribution and use in source and binary forms, with or without 9865f46b2SCy Schubert * modification, are permitted provided that the following conditions 10865f46b2SCy Schubert * are met: 11865f46b2SCy Schubert * 12865f46b2SCy Schubert * Redistributions of source code must retain the above copyright notice, 13865f46b2SCy Schubert * this list of conditions and the following disclaimer. 14865f46b2SCy Schubert * 15865f46b2SCy Schubert * Redistributions in binary form must reproduce the above copyright notice, 16865f46b2SCy Schubert * this list of conditions and the following disclaimer in the documentation 17865f46b2SCy Schubert * and/or other materials provided with the distribution. 18865f46b2SCy Schubert * 19865f46b2SCy Schubert * Neither the name of the NLNET LABS nor the names of its contributors may 20865f46b2SCy Schubert * be used to endorse or promote products derived from this software without 21865f46b2SCy Schubert * specific prior written permission. 22865f46b2SCy Schubert * 23865f46b2SCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24865f46b2SCy Schubert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25865f46b2SCy Schubert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26865f46b2SCy Schubert * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27865f46b2SCy Schubert * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28865f46b2SCy Schubert * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29865f46b2SCy Schubert * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30865f46b2SCy Schubert * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31865f46b2SCy Schubert * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32865f46b2SCy Schubert * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33865f46b2SCy Schubert * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34865f46b2SCy Schubert */ 35865f46b2SCy Schubert 36865f46b2SCy Schubert /** 37865f46b2SCy Schubert * \file 38865f46b2SCy Schubert * 39865f46b2SCy Schubert * This file contains PROXY protocol structs and functions. 40865f46b2SCy Schubert * Only v2 is supported. TLVs are not currently supported. 41865f46b2SCy Schubert */ 42865f46b2SCy Schubert #ifndef PROXY_PROTOCOL_H 43865f46b2SCy Schubert #define PROXY_PROTOCOL_H 44865f46b2SCy Schubert 45*103ba509SCy Schubert #include "config.h" 46865f46b2SCy Schubert 47865f46b2SCy Schubert /** PROXYv2 minimum header size */ 48865f46b2SCy Schubert #define PP2_HEADER_SIZE 16 49865f46b2SCy Schubert 50865f46b2SCy Schubert /** PROXYv2 header signature */ 51865f46b2SCy Schubert #define PP2_SIG "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A" 52865f46b2SCy Schubert #define PP2_SIG_LEN 12 53865f46b2SCy Schubert 54*103ba509SCy Schubert /** PROXYv2 version (protocol value) */ 55865f46b2SCy Schubert #define PP2_VERSION 0x2 56865f46b2SCy Schubert 57865f46b2SCy Schubert /** 58*103ba509SCy Schubert * PROXYv2 command (protocol value). 59865f46b2SCy Schubert */ 60865f46b2SCy Schubert enum pp2_command { 61865f46b2SCy Schubert PP2_CMD_LOCAL = 0x0, 62865f46b2SCy Schubert PP2_CMD_PROXY = 0x1 63865f46b2SCy Schubert }; 64865f46b2SCy Schubert 65865f46b2SCy Schubert /** 66*103ba509SCy Schubert * PROXYv2 address family (protocol value). 67865f46b2SCy Schubert */ 68865f46b2SCy Schubert enum pp2_af { 69865f46b2SCy Schubert PP2_AF_UNSPEC = 0x0, 70865f46b2SCy Schubert PP2_AF_INET = 0x1, 71865f46b2SCy Schubert PP2_AF_INET6 = 0x2, 72865f46b2SCy Schubert PP2_AF_UNIX = 0x3 73865f46b2SCy Schubert }; 74865f46b2SCy Schubert 75865f46b2SCy Schubert /** 76*103ba509SCy Schubert * PROXYv2 protocol (protocol value). 77865f46b2SCy Schubert */ 78865f46b2SCy Schubert enum pp2_protocol { 79865f46b2SCy Schubert PP2_PROT_UNSPEC = 0x0, 80865f46b2SCy Schubert PP2_PROT_STREAM = 0x1, 81865f46b2SCy Schubert PP2_PROT_DGRAM = 0x2 82865f46b2SCy Schubert }; 83865f46b2SCy Schubert 84865f46b2SCy Schubert /** 85*103ba509SCy Schubert * Expected combinations of address family and protocol values used in checks. 86*103ba509SCy Schubert */ 87*103ba509SCy Schubert enum pp2_af_protocol_combination { 88*103ba509SCy Schubert PP2_UNSPEC_UNSPEC = (PP2_AF_UNSPEC<<4)|PP2_PROT_UNSPEC, 89*103ba509SCy Schubert PP2_INET_STREAM = (PP2_AF_INET<<4)|PP2_PROT_STREAM, 90*103ba509SCy Schubert PP2_INET_DGRAM = (PP2_AF_INET<<4)|PP2_PROT_DGRAM, 91*103ba509SCy Schubert PP2_INET6_STREAM = (PP2_AF_INET6<<4)|PP2_PROT_STREAM, 92*103ba509SCy Schubert PP2_INET6_DGRAM = (PP2_AF_INET6<<4)|PP2_PROT_DGRAM, 93*103ba509SCy Schubert PP2_UNIX_STREAM = (PP2_AF_UNIX<<4)|PP2_PROT_STREAM, 94*103ba509SCy Schubert PP2_UNIX_DGRAM = (PP2_AF_UNIX<<4)|PP2_PROT_DGRAM 95*103ba509SCy Schubert }; 96*103ba509SCy Schubert 97*103ba509SCy Schubert /** 98865f46b2SCy Schubert * PROXYv2 header. 99865f46b2SCy Schubert */ 100865f46b2SCy Schubert struct pp2_header { 101865f46b2SCy Schubert uint8_t sig[PP2_SIG_LEN]; 102865f46b2SCy Schubert uint8_t ver_cmd; 103865f46b2SCy Schubert uint8_t fam_prot; 104865f46b2SCy Schubert uint16_t len; 105865f46b2SCy Schubert union { 106865f46b2SCy Schubert struct { /* for TCP/UDP over IPv4, len = 12 */ 107865f46b2SCy Schubert uint32_t src_addr; 108865f46b2SCy Schubert uint32_t dst_addr; 109865f46b2SCy Schubert uint16_t src_port; 110865f46b2SCy Schubert uint16_t dst_port; 111865f46b2SCy Schubert } addr4; 112865f46b2SCy Schubert struct { /* for TCP/UDP over IPv6, len = 36 */ 113865f46b2SCy Schubert uint8_t src_addr[16]; 114865f46b2SCy Schubert uint8_t dst_addr[16]; 115865f46b2SCy Schubert uint16_t src_port; 116865f46b2SCy Schubert uint16_t dst_port; 117865f46b2SCy Schubert } addr6; 118865f46b2SCy Schubert struct { /* for AF_UNIX sockets, len = 216 */ 119865f46b2SCy Schubert uint8_t src_addr[108]; 120865f46b2SCy Schubert uint8_t dst_addr[108]; 121865f46b2SCy Schubert } addru; 122865f46b2SCy Schubert } addr; 123865f46b2SCy Schubert }; 124865f46b2SCy Schubert 125865f46b2SCy Schubert /** 126*103ba509SCy Schubert * PROXY parse errors. 127*103ba509SCy Schubert */ 128*103ba509SCy Schubert enum pp_parse_errors { 129*103ba509SCy Schubert PP_PARSE_NOERROR = 0, 130*103ba509SCy Schubert PP_PARSE_SIZE, 131*103ba509SCy Schubert PP_PARSE_WRONG_HEADERv2, 132*103ba509SCy Schubert PP_PARSE_UNKNOWN_CMD, 133*103ba509SCy Schubert PP_PARSE_UNKNOWN_FAM_PROT, 134*103ba509SCy Schubert }; 135*103ba509SCy Schubert 136*103ba509SCy Schubert /** 137*103ba509SCy Schubert * Initialize the internal proxy structure. 138*103ba509SCy Schubert * @param write_uint16: pointer to a function that can write uint16. 139*103ba509SCy Schubert * @param write_uint32: pointer to a function that can write uint32. 140*103ba509SCy Schubert */ 141*103ba509SCy Schubert void pp_init(void (*write_uint16)(void* buf, uint16_t data), 142*103ba509SCy Schubert void (*write_uint32)(void* buf, uint32_t data)); 143*103ba509SCy Schubert 144*103ba509SCy Schubert /** 145*103ba509SCy Schubert * Lookup the parsing error description. 146*103ba509SCy Schubert * @param error: parsing error from pp2_read_header. 147*103ba509SCy Schubert * @return the description. 148*103ba509SCy Schubert */ 149*103ba509SCy Schubert const char* pp_lookup_error(enum pp_parse_errors error); 150*103ba509SCy Schubert 151*103ba509SCy Schubert /** 152865f46b2SCy Schubert * Write a PROXYv2 header at the current position of the buffer. 153*103ba509SCy Schubert * @param buf: pointer to the buffer to write data to. 154*103ba509SCy Schubert * @param buflen: available size on the buffer. 155865f46b2SCy Schubert * @param src: the source address. 156865f46b2SCy Schubert * @param stream: if the protocol is stream or datagram. 157865f46b2SCy Schubert * @return 1 on success, 0 on failure. 158865f46b2SCy Schubert */ 159*103ba509SCy Schubert size_t pp2_write_to_buf(uint8_t* buf, size_t buflen, 160*103ba509SCy Schubert #ifdef INET6 161*103ba509SCy Schubert struct sockaddr_storage* src, 162*103ba509SCy Schubert #else 163*103ba509SCy Schubert struct sockaddr_in* src, 164*103ba509SCy Schubert #endif 165865f46b2SCy Schubert int stream); 166865f46b2SCy Schubert 167865f46b2SCy Schubert /** 168865f46b2SCy Schubert * Read a PROXYv2 header from the current position of the buffer. 169865f46b2SCy Schubert * It does initial validation and returns a pointer to the buffer position on 170865f46b2SCy Schubert * success. 171*103ba509SCy Schubert * @param buf: pointer to the buffer data to read from. 172*103ba509SCy Schubert * @param buflen: available size on the buffer. 173*103ba509SCy Schubert * @return parsing error, 0 on success. 174865f46b2SCy Schubert */ 175*103ba509SCy Schubert int pp2_read_header(uint8_t* buf, size_t buflen); 176865f46b2SCy Schubert 177865f46b2SCy Schubert #endif /* PROXY_PROTOCOL_H */ 178