1865f46b2SCy Schubert /* 2865f46b2SCy Schubert * util/proxy_protocol.c - event notification 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 functions. 40865f46b2SCy Schubert */ 41865f46b2SCy Schubert #include "util/proxy_protocol.h" 42865f46b2SCy Schubert 43*103ba509SCy Schubert /** 44*103ba509SCy Schubert * Internal struct initialized with function pointers for writing uint16 and 45*103ba509SCy Schubert * uint32. 46*103ba509SCy Schubert */ 47*103ba509SCy Schubert struct proxy_protocol_data { 48*103ba509SCy Schubert void (*write_uint16)(void* buf, uint16_t data); 49*103ba509SCy Schubert void (*write_uint32)(void* buf, uint32_t data); 50*103ba509SCy Schubert }; 51*103ba509SCy Schubert struct proxy_protocol_data pp_data; 52*103ba509SCy Schubert 53*103ba509SCy Schubert /** 54*103ba509SCy Schubert * Internal lookup table; could be further generic like sldns_lookup_table 55*103ba509SCy Schubert * for all the future generic stuff. 56*103ba509SCy Schubert */ 57*103ba509SCy Schubert struct proxy_protocol_lookup_table { 58*103ba509SCy Schubert int id; 59*103ba509SCy Schubert const char *text; 60*103ba509SCy Schubert }; 61*103ba509SCy Schubert 62*103ba509SCy Schubert /** 63*103ba509SCy Schubert * Internal parsing error text; could be exposed with pp_lookup_error. 64*103ba509SCy Schubert */ 65*103ba509SCy Schubert static struct proxy_protocol_lookup_table pp_parse_errors_data[] = { 66*103ba509SCy Schubert { PP_PARSE_NOERROR, "no parse error" }, 67*103ba509SCy Schubert { PP_PARSE_SIZE, "not enough space for header" }, 68*103ba509SCy Schubert { PP_PARSE_WRONG_HEADERv2, "could not match PROXYv2 header" }, 69*103ba509SCy Schubert { PP_PARSE_UNKNOWN_CMD, "unknown command" }, 70*103ba509SCy Schubert { PP_PARSE_UNKNOWN_FAM_PROT, "unknown family and protocol" }, 71*103ba509SCy Schubert }; 72*103ba509SCy Schubert 73*103ba509SCy Schubert void 74*103ba509SCy Schubert pp_init(void (*write_uint16)(void* buf, uint16_t data), 75*103ba509SCy Schubert void (*write_uint32)(void* buf, uint32_t data)) { 76*103ba509SCy Schubert pp_data.write_uint16 = write_uint16; 77*103ba509SCy Schubert pp_data.write_uint32 = write_uint32; 78*103ba509SCy Schubert } 79*103ba509SCy Schubert 80*103ba509SCy Schubert const char* 81*103ba509SCy Schubert pp_lookup_error(enum pp_parse_errors error) { 82*103ba509SCy Schubert return pp_parse_errors_data[error].text; 83*103ba509SCy Schubert } 84*103ba509SCy Schubert 85*103ba509SCy Schubert size_t 86*103ba509SCy Schubert pp2_write_to_buf(uint8_t* buf, size_t buflen, 87*103ba509SCy Schubert #ifdef INET6 88*103ba509SCy Schubert struct sockaddr_storage* src, 89*103ba509SCy Schubert #else 90*103ba509SCy Schubert struct sockaddr_in* src, 91*103ba509SCy Schubert #endif 92865f46b2SCy Schubert int stream) 93865f46b2SCy Schubert { 94865f46b2SCy Schubert int af; 95*103ba509SCy Schubert size_t expected_size; 96865f46b2SCy Schubert if(!src) return 0; 97865f46b2SCy Schubert af = (int)((struct sockaddr_in*)src)->sin_family; 98*103ba509SCy Schubert expected_size = PP2_HEADER_SIZE + (af==AF_INET?12:36); 99*103ba509SCy Schubert if(buflen < expected_size) { 100865f46b2SCy Schubert return 0; 101865f46b2SCy Schubert } 102865f46b2SCy Schubert /* sig */ 103*103ba509SCy Schubert memcpy(buf, PP2_SIG, PP2_SIG_LEN); 104*103ba509SCy Schubert buf += PP2_SIG_LEN; 105865f46b2SCy Schubert /* version and command */ 106*103ba509SCy Schubert *buf = (PP2_VERSION << 4) | PP2_CMD_PROXY; 107*103ba509SCy Schubert buf++; 108*103ba509SCy Schubert switch(af) { 109*103ba509SCy Schubert case AF_INET: 110865f46b2SCy Schubert /* family and protocol */ 111*103ba509SCy Schubert *buf = (PP2_AF_INET<<4) | 112*103ba509SCy Schubert (stream?PP2_PROT_STREAM:PP2_PROT_DGRAM); 113*103ba509SCy Schubert buf++; 114865f46b2SCy Schubert /* length */ 115*103ba509SCy Schubert (*pp_data.write_uint16)(buf, 12); 116*103ba509SCy Schubert buf += 2; 117865f46b2SCy Schubert /* src addr */ 118*103ba509SCy Schubert memcpy(buf, 119865f46b2SCy Schubert &((struct sockaddr_in*)src)->sin_addr.s_addr, 4); 120*103ba509SCy Schubert buf += 4; 121865f46b2SCy Schubert /* dst addr */ 122*103ba509SCy Schubert (*pp_data.write_uint32)(buf, 0); 123*103ba509SCy Schubert buf += 4; 124865f46b2SCy Schubert /* src port */ 125*103ba509SCy Schubert memcpy(buf, 126865f46b2SCy Schubert &((struct sockaddr_in*)src)->sin_port, 2); 127*103ba509SCy Schubert buf += 2; 128865f46b2SCy Schubert /* dst addr */ 129865f46b2SCy Schubert /* dst port */ 130*103ba509SCy Schubert (*pp_data.write_uint16)(buf, 12); 131*103ba509SCy Schubert break; 132*103ba509SCy Schubert #ifdef INET6 133*103ba509SCy Schubert case AF_INET6: 134*103ba509SCy Schubert /* family and protocol */ 135*103ba509SCy Schubert *buf = (PP2_AF_INET6<<4) | 136*103ba509SCy Schubert (stream?PP2_PROT_STREAM:PP2_PROT_DGRAM); 137*103ba509SCy Schubert buf++; 138*103ba509SCy Schubert /* length */ 139*103ba509SCy Schubert (*pp_data.write_uint16)(buf, 36); 140*103ba509SCy Schubert buf += 2; 141*103ba509SCy Schubert /* src addr */ 142*103ba509SCy Schubert memcpy(buf, 143*103ba509SCy Schubert &((struct sockaddr_in6*)src)->sin6_addr, 16); 144*103ba509SCy Schubert buf += 16; 145*103ba509SCy Schubert /* dst addr */ 146*103ba509SCy Schubert memset(buf, 0, 16); 147*103ba509SCy Schubert buf += 16; 148*103ba509SCy Schubert /* src port */ 149*103ba509SCy Schubert memcpy(buf, &((struct sockaddr_in6*)src)->sin6_port, 2); 150*103ba509SCy Schubert buf += 2; 151*103ba509SCy Schubert /* dst port */ 152*103ba509SCy Schubert (*pp_data.write_uint16)(buf, 0); 153*103ba509SCy Schubert break; 154*103ba509SCy Schubert #endif /* INET6 */ 155*103ba509SCy Schubert case AF_UNIX: 156*103ba509SCy Schubert /* fallthrough */ 157*103ba509SCy Schubert default: 158*103ba509SCy Schubert return 0; 159865f46b2SCy Schubert } 160*103ba509SCy Schubert return expected_size; 161865f46b2SCy Schubert } 162865f46b2SCy Schubert 163*103ba509SCy Schubert int 164*103ba509SCy Schubert pp2_read_header(uint8_t* buf, size_t buflen) 165865f46b2SCy Schubert { 166865f46b2SCy Schubert size_t size; 167*103ba509SCy Schubert struct pp2_header* header = (struct pp2_header*)buf; 168865f46b2SCy Schubert /* Try to fail all the unsupported cases first. */ 169*103ba509SCy Schubert if(buflen < PP2_HEADER_SIZE) { 170*103ba509SCy Schubert return PP_PARSE_SIZE; 171865f46b2SCy Schubert } 172865f46b2SCy Schubert /* Check for PROXYv2 header */ 173865f46b2SCy Schubert if(memcmp(header, PP2_SIG, PP2_SIG_LEN) != 0 || 174865f46b2SCy Schubert ((header->ver_cmd & 0xF0)>>4) != PP2_VERSION) { 175*103ba509SCy Schubert return PP_PARSE_WRONG_HEADERv2; 176865f46b2SCy Schubert } 177865f46b2SCy Schubert /* Check the length */ 178865f46b2SCy Schubert size = PP2_HEADER_SIZE + ntohs(header->len); 179*103ba509SCy Schubert if(buflen < size) { 180*103ba509SCy Schubert return PP_PARSE_SIZE; 181865f46b2SCy Schubert } 182865f46b2SCy Schubert /* Check for supported commands */ 183865f46b2SCy Schubert if((header->ver_cmd & 0xF) != PP2_CMD_LOCAL && 184865f46b2SCy Schubert (header->ver_cmd & 0xF) != PP2_CMD_PROXY) { 185*103ba509SCy Schubert return PP_PARSE_UNKNOWN_CMD; 186865f46b2SCy Schubert } 187865f46b2SCy Schubert /* Check for supported family and protocol */ 188*103ba509SCy Schubert if(header->fam_prot != PP2_UNSPEC_UNSPEC && 189*103ba509SCy Schubert header->fam_prot != PP2_INET_STREAM && 190*103ba509SCy Schubert header->fam_prot != PP2_INET_DGRAM && 191*103ba509SCy Schubert header->fam_prot != PP2_INET6_STREAM && 192*103ba509SCy Schubert header->fam_prot != PP2_INET6_DGRAM && 193*103ba509SCy Schubert header->fam_prot != PP2_UNIX_STREAM && 194*103ba509SCy Schubert header->fam_prot != PP2_UNIX_DGRAM) { 195*103ba509SCy Schubert return PP_PARSE_UNKNOWN_FAM_PROT; 196865f46b2SCy Schubert } 197865f46b2SCy Schubert /* We have a correct header */ 198*103ba509SCy Schubert return PP_PARSE_NOERROR; 199865f46b2SCy Schubert } 200