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