1 /* $NetBSD: proxyp.c,v 1.2 2021/08/14 16:14:58 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 2000-2020 The OpenLDAP Foundation. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17 18 #include <sys/cdefs.h> 19 __RCSID("$NetBSD: proxyp.c,v 1.2 2021/08/14 16:14:58 christos Exp $"); 20 21 #include "portable.h" 22 #include "slap.h" 23 24 #ifdef HAVE_STDINT_H 25 #include <stdint.h> 26 #endif 27 #ifdef HAVE_INTTYPES_H 28 #include <inttypes.h> 29 #endif 30 31 #include <lber_types.h> 32 #include <ac/string.h> 33 #include <ac/errno.h> 34 35 typedef struct { 36 uint8_t sig[12]; /* hex 0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a */ 37 uint8_t ver_cmd; /* protocol version and command */ 38 uint8_t fam; /* protocol family and address */ 39 uint16_t len; /* length of address data */ 40 } proxyp_header; 41 42 typedef union { 43 struct { /* for TCP/UDP over IPv4, len = 12 */ 44 uint32_t src_addr; 45 uint32_t dst_addr; 46 uint16_t src_port; 47 uint16_t dst_port; 48 } ip4; 49 struct { /* for TCP/UDP over IPv6, len = 36 */ 50 uint8_t src_addr[16]; 51 uint8_t dst_addr[16]; 52 uint16_t src_port; 53 uint16_t dst_port; 54 } ip6; 55 struct { /* for AF_UNIX sockets, len = 216 */ 56 uint8_t src_addr[108]; 57 uint8_t dst_addr[108]; 58 } unx; 59 } proxyp_addr; 60 61 static const uint8_t proxyp_sig[12] = { 62 0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x0d, 0x0a, 0x51, 0x55, 0x49, 0x54, 0x0a, 63 }; 64 65 int 66 proxyp( ber_socket_t sfd, Sockaddr *from ) { 67 proxyp_header pph; 68 proxyp_addr ppa; 69 char peername[LDAP_IPADDRLEN]; 70 struct berval peerbv = BER_BVC(peername); 71 /* Maximum size of header minus static component size is max option size */ 72 uint8_t proxyp_options[536 - 16]; 73 int pph_len; 74 int ret; 75 76 peername[0] = '\0'; 77 78 do { 79 ret = tcp_read( SLAP_FD2SOCK( sfd ), &pph, sizeof(pph) ); 80 } while ( ret == -1 && errno == EINTR ); 81 82 if ( ret == -1 ) { 83 char ebuf[128]; 84 int save_errno = errno; 85 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 86 "header read failed %d (%s)\n", 87 (long)sfd, save_errno, 88 AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) ); 89 return 0; 90 } else if ( ret != sizeof(pph) ) { 91 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 92 "header read insufficient data %d\n", 93 (long)sfd, ret ); 94 return 0; 95 } 96 97 if ( memcmp( pph.sig, proxyp_sig, 12 ) != 0 ) { 98 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 99 "invalid header signature\n", (long)sfd ); 100 return 0; 101 } 102 103 if ( ( pph.ver_cmd & 0xF0 ) != 0x20 ) { 104 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 105 "invalid header version %x\n", 106 (long)sfd, pph.ver_cmd & 0xF0 ); 107 return 0; 108 } 109 110 pph_len = ntohs( pph.len ); 111 if ( ( pph.ver_cmd & 0x0F ) == 0x01 ) { /* PROXY command */ 112 int addr_len; 113 switch ( pph.fam ) { 114 case 0x11: /* TCPv4 */ 115 addr_len = sizeof( ppa.ip4 ); 116 break; 117 case 0x21: /* TCPv6 */ 118 addr_len = sizeof( ppa.ip6 ); 119 break; 120 default: 121 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 122 "unsupported protocol %x\n", 123 (long)sfd, pph.fam ); 124 return 0; 125 } 126 127 if ( pph_len < addr_len ) { 128 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 129 "address length %d too small, expecting %d\n", 130 (long)sfd, pph_len, addr_len ); 131 return 0; 132 } 133 134 do { 135 ret = tcp_read( SLAP_FD2SOCK (sfd), &ppa, addr_len ); 136 } while ( ret == -1 && errno == EINTR ); 137 138 if ( ret == -1 ) { 139 char ebuf[128]; 140 int save_errno = errno; 141 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 142 "address read failed %d (%s)\n", 143 (long)sfd, save_errno, 144 AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) ); 145 return 0; 146 } else if ( ret != addr_len ) { 147 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 148 "address read insufficient data, expecting %d, read %d\n", 149 (long)sfd, addr_len, ret ); 150 return 0; 151 } 152 153 pph_len -= addr_len; 154 } 155 156 switch ( pph.ver_cmd & 0x0F ) { 157 case 0x01: /* PROXY command */ 158 switch ( pph.fam ) { 159 case 0x11: /* TCPv4 */ 160 ldap_pvt_sockaddrstr( from, &peerbv ); 161 Debug( LDAP_DEBUG_STATS, "proxyp(%ld): via %s\n", 162 (long)sfd, peername ); 163 164 from->sa_in_addr.sin_family = AF_INET; 165 from->sa_in_addr.sin_addr.s_addr = ppa.ip4.src_addr; 166 from->sa_in_addr.sin_port = ppa.ip4.src_port; 167 break; 168 169 case 0x21: /* TCPv6 */ 170 #ifdef LDAP_PF_INET6 171 ldap_pvt_sockaddrstr( from, &peerbv ); 172 Debug( LDAP_DEBUG_STATS, "proxyp(%ld): via %s\n", 173 (long)sfd, peername ); 174 from->sa_in6_addr.sin6_family = AF_INET6; 175 memcpy( &from->sa_in6_addr.sin6_addr, ppa.ip6.src_addr, 176 sizeof(ppa.ip6.src_addr) ); 177 from->sa_in6_addr.sin6_port = ppa.ip6.src_port; 178 #else 179 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 180 "IPv6 proxied addresses disabled\n", 181 (long)sfd ); 182 return 0; 183 #endif 184 break; 185 } 186 187 break; 188 189 case 0x00: /* LOCAL command */ 190 Debug( LDAP_DEBUG_CONNS, "proxyp(%ld): " 191 "local connection, ignoring proxy data\n", 192 (long)sfd ); 193 break; 194 195 default: 196 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): invalid command %x\n", 197 (long)sfd, pph.ver_cmd & 0x0F ); 198 return 0; 199 } 200 201 /* Clear out any options left in proxy packet */ 202 if ( pph_len > 0 ) { 203 if (pph_len > sizeof( proxyp_options ) ) { 204 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 205 "options size %d too big\n", 206 (long)sfd, pph_len ); 207 return 0; 208 } 209 210 do { 211 ret = tcp_read( SLAP_FD2SOCK (sfd), &proxyp_options, pph_len ); 212 } while ( ret == -1 && errno == EINTR ); 213 214 if ( ret == -1 ) { 215 char ebuf[128]; 216 int save_errno = errno; 217 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 218 "options read failed %d (%s)\n", 219 (long)sfd, save_errno, 220 AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) ); 221 return 0; 222 } else if ( ret != pph_len ) { 223 Debug( LDAP_DEBUG_ANY, "proxyp(%ld): " 224 "options read insufficient data, expecting %d, read %d\n", 225 (long)sfd, pph_len, ret ); 226 return 0; 227 } 228 } 229 230 return 1; 231 } 232