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