Commit 146889f2 authored by Paul Henson's avatar Paul Henson Committed by Quanah Gibson-Mount
Browse files

ITS#9419 Add support for HAProxy proxy protocol v2

parent dcca7337
...@@ -36,13 +36,23 @@ This option specifies alternative listener configurations. The ...@@ -36,13 +36,23 @@ This option specifies alternative listener configurations. The
default is {{EX:ldap:///}} which implies {{TERM:LDAP}} over default is {{EX:ldap:///}} which implies {{TERM:LDAP}} over
{{TERM:TCP}} on all interfaces on the default LDAP port 389. You {{TERM:TCP}} on all interfaces on the default LDAP port 389. You
can specify specific host-port pairs or other protocol schemes (such can specify specific host-port pairs or other protocol schemes (such
as {{EX:ldaps://}} or {{EX:ldapi://}}). as {{EX:ldaps://}} or {{EX:ldapi://}}). slapd supports the HAProxy
proxy protocol version 2, which allows a load balancer or proxy
server to provide the remote client IP address to slapd to be used
for access control or logging. Listeners configured using either
{{EX:pldap:///}} or {{EX:pldaps:///}} URLS will only accept
connections that include the necessary proxy protocol header.
Connections to the ports used by these listeners should be restricted
at the network level to only trusted load balancers or proxies to
avoid spoofing of client IP addresses by third parties.
!block table !block table
URL Protocol Transport URL Protocol Transport
ldap:/// LDAP TCP port 389 ldap:/// LDAP TCP port 389
ldaps:/// LDAP over SSL TCP port 636 pldap:/// proxied LDAP TCP port 389
ldapi:/// LDAP IPC (Unix-domain socket) ldaps:/// LDAP over SSL TCP port 636
pldaps:/// proxied LDAP over SSL TCP port 636
ldapi:/// LDAP IPC (Unix-domain socket)
!endblock !endblock
For example, {{EX:-h For example, {{EX:-h
......
...@@ -142,13 +142,24 @@ For example, if lloadd is given ...@@ -142,13 +142,24 @@ For example, if lloadd is given
it will listen on 127.0.0.1:9009 for LDAP, 0.0.0.0:636 for LDAP over TLS, it will listen on 127.0.0.1:9009 for LDAP, 0.0.0.0:636 for LDAP over TLS,
and LDAP over IPC (Unix domain sockets). Host 0.0.0.0 represents and LDAP over IPC (Unix domain sockets). Host 0.0.0.0 represents
INADDR_ANY (any interface). INADDR_ANY (any interface).
A space separated list of URLs is expected. The URLs should be of A space separated list of URLs is expected. The URLs should be of the LDAP,
the LDAP, LDAPS, or LDAPI schemes, and generally PLDAP, LDAPS, PLDAPS, or LDAPI schemes, and generally without a DN or other
without a DN or other optional parameters (excepting as discussed below). optional parameters (excepting as discussed below). Support for the latter
Support for the latter two schemes depends on selected configuration three schemes depends on selected configuration options. Hosts may be specified
options. Hosts may be specified by name or IPv4 and IPv6 address formats. by name or IPv4 and IPv6 address formats. Ports, if specified, must be
Ports, if specified, must be numeric. The default ldap:// port is \fB389\fP numeric. The default ldap:// port is \fB389\fP and the default ldaps:// port
and the default ldaps:// port is \fB636\fP. is \fB636\fP, same for the proxy enabled variants.
The PLDAP and PLDAPS URL schemes provide support for the HAProxy proxy protocol
version 2, which allows a load balancer or proxy server to provide the remote
client IP address to slapd to be used for access control or logging. Ports
configured for PLDAP or PLDAPS will only accept connections that include the
necessary proxy protocol header. Connections to these ports should be
restricted at the network level to only trusted load balancers or proxies to
avoid spoofing of client IP addresses by third parties.
At the moment, the load balancer does not act on the recorded address in any
way.
For LDAP over IPC, For LDAP over IPC,
.B name .B name
......
...@@ -192,13 +192,21 @@ For example, if slapd is given ...@@ -192,13 +192,21 @@ For example, if slapd is given
it will listen on 127.0.0.1:9009 for LDAP, 0.0.0.0:636 for LDAP over TLS, it will listen on 127.0.0.1:9009 for LDAP, 0.0.0.0:636 for LDAP over TLS,
and LDAP over IPC (Unix domain sockets). Host 0.0.0.0 represents and LDAP over IPC (Unix domain sockets). Host 0.0.0.0 represents
INADDR_ANY (any interface). INADDR_ANY (any interface).
A space separated list of URLs is expected. The URLs should be of A space separated list of URLs is expected. The URLs should be of the LDAP,
the LDAP, LDAPS, or LDAPI schemes, and generally PLDAP, LDAPS, PLDAPS, or LDAPI schemes, and generally without a DN or other
without a DN or other optional parameters (excepting as discussed below). optional parameters (excepting as discussed below). Support for the latter
Support for the latter two schemes depends on selected configuration three schemes depends on selected configuration options. Hosts may be specified
options. Hosts may be specified by name or IPv4 and IPv6 address formats. by name or IPv4 and IPv6 address formats. Ports, if specified, must be
Ports, if specified, must be numeric. The default ldap:// port is \fB389\fP numeric. The default ldap:// port is \fB389\fP and the default ldaps:// port
and the default ldaps:// port is \fB636\fP. is \fB636\fP, same for the proxy enabled variants.
The PLDAP and PLDAPS URL schemes provide support for the HAProxy proxy protocol
version 2, which allows a load balancer or proxy server to provide the remote
client IP address to slapd to be used for access control or logging. Ports
configured for PLDAP or PLDAPS will only accept connections that include the
necessary proxy protocol header. Connections to these ports should be
restricted at the network level to only trusted load balancers or proxies to
avoid spoofing of client IP addresses by third parties.
For LDAP over IPC, For LDAP over IPC,
.B name .B name
......
...@@ -32,6 +32,9 @@ ldap_pvt_url_scheme2proto LDAP_P(( ...@@ -32,6 +32,9 @@ ldap_pvt_url_scheme2proto LDAP_P((
LDAP_F ( int ) LDAP_F ( int )
ldap_pvt_url_scheme2tls LDAP_P(( ldap_pvt_url_scheme2tls LDAP_P((
const char * )); const char * ));
LDAP_F ( int )
ldap_pvt_url_scheme2proxied LDAP_P((
const char * ));
LDAP_F ( int ) LDAP_F ( int )
ldap_pvt_url_scheme_port LDAP_P(( ldap_pvt_url_scheme_port LDAP_P((
......
...@@ -123,8 +123,12 @@ LDAP_BEGIN_DECL ...@@ -123,8 +123,12 @@ LDAP_BEGIN_DECL
#define LDAP_URL_PREFIX "ldap://" #define LDAP_URL_PREFIX "ldap://"
#define LDAP_URL_PREFIX_LEN STRLENOF(LDAP_URL_PREFIX) #define LDAP_URL_PREFIX_LEN STRLENOF(LDAP_URL_PREFIX)
#define PLDAP_URL_PREFIX "pldap://"
#define PLDAP_URL_PREFIX_LEN STRLENOF(PLDAP_URL_PREFIX)
#define LDAPS_URL_PREFIX "ldaps://" #define LDAPS_URL_PREFIX "ldaps://"
#define LDAPS_URL_PREFIX_LEN STRLENOF(LDAPS_URL_PREFIX) #define LDAPS_URL_PREFIX_LEN STRLENOF(LDAPS_URL_PREFIX)
#define PLDAPS_URL_PREFIX "pldaps://"
#define PLDAPS_URL_PREFIX_LEN STRLENOF(PLDAPS_URL_PREFIX)
#define LDAPI_URL_PREFIX "ldapi://" #define LDAPI_URL_PREFIX "ldapi://"
#define LDAPI_URL_PREFIX_LEN STRLENOF(LDAPI_URL_PREFIX) #define LDAPI_URL_PREFIX_LEN STRLENOF(LDAPI_URL_PREFIX)
#ifdef LDAP_CONNECTIONLESS #ifdef LDAP_CONNECTIONLESS
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
/* /*
* LDAP URLs look like this: * LDAP URLs look like this:
* ldap[is]://host[:port][/[dn[?[attributes][?[scope][?[filter][?exts]]]]]] * [p]ldap[is]://host[:port][/[dn[?[attributes][?[scope][?[filter][?exts]]]]]]
* *
* where: * where:
* attributes is a comma separated list * attributes is a comma separated list
...@@ -59,7 +59,7 @@ int ldap_pvt_url_scheme2proto( const char *scheme ) ...@@ -59,7 +59,7 @@ int ldap_pvt_url_scheme2proto( const char *scheme )
return -1; return -1;
} }
if( strcmp("ldap", scheme) == 0 ) { if( strcmp("ldap", scheme) == 0 || strcmp("pldap", scheme) == 0 ) {
return LDAP_PROTO_TCP; return LDAP_PROTO_TCP;
} }
...@@ -67,7 +67,7 @@ int ldap_pvt_url_scheme2proto( const char *scheme ) ...@@ -67,7 +67,7 @@ int ldap_pvt_url_scheme2proto( const char *scheme )
return LDAP_PROTO_IPC; return LDAP_PROTO_IPC;
} }
if( strcmp("ldaps", scheme) == 0 ) { if( strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0 ) {
return LDAP_PROTO_TCP; return LDAP_PROTO_TCP;
} }
#ifdef LDAP_CONNECTIONLESS #ifdef LDAP_CONNECTIONLESS
...@@ -86,7 +86,7 @@ int ldap_pvt_url_scheme_port( const char *scheme, int port ) ...@@ -86,7 +86,7 @@ int ldap_pvt_url_scheme_port( const char *scheme, int port )
if( port ) return port; if( port ) return port;
if( scheme == NULL ) return port; if( scheme == NULL ) return port;
if( strcmp("ldap", scheme) == 0 ) { if( strcmp("ldap", scheme) == 0 || strcmp("pldap", scheme) == 0 ) {
return LDAP_PORT; return LDAP_PORT;
} }
...@@ -94,7 +94,7 @@ int ldap_pvt_url_scheme_port( const char *scheme, int port ) ...@@ -94,7 +94,7 @@ int ldap_pvt_url_scheme_port( const char *scheme, int port )
return -1; return -1;
} }
if( strcmp("ldaps", scheme) == 0 ) { if( strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0 ) {
return LDAPS_PORT; return LDAPS_PORT;
} }
...@@ -116,7 +116,19 @@ ldap_pvt_url_scheme2tls( const char *scheme ) ...@@ -116,7 +116,19 @@ ldap_pvt_url_scheme2tls( const char *scheme )
return -1; return -1;
} }
return strcmp("ldaps", scheme) == 0; return strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0;
}
int
ldap_pvt_url_scheme2proxied( const char *scheme )
{
assert( scheme != NULL );
if( scheme == NULL ) {
return -1;
}
return strcmp("pldap", scheme) == 0 || strcmp("pldaps", scheme) == 0;
} }
int int
...@@ -150,7 +162,7 @@ ldap_is_ldaps_url( LDAP_CONST char *url ) ...@@ -150,7 +162,7 @@ ldap_is_ldaps_url( LDAP_CONST char *url )
return 0; return 0;
} }
return strcmp(scheme, "ldaps") == 0; return strcmp(scheme, "ldaps") == 0 || strcmp(scheme, "pldaps");
} }
int int
...@@ -228,6 +240,14 @@ skip_url_prefix( ...@@ -228,6 +240,14 @@ skip_url_prefix(
return( p ); return( p );
} }
/* check for "pldap://" prefix */
if ( strncasecmp( p, PLDAP_URL_PREFIX, PLDAP_URL_PREFIX_LEN ) == 0 ) {
/* skip over "pldap://" prefix and return success */
p += PLDAP_URL_PREFIX_LEN;
*scheme = "pldap";
return( p );
}
/* check for "ldaps://" prefix */ /* check for "ldaps://" prefix */
if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) { if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
/* skip over "ldaps://" prefix and return success */ /* skip over "ldaps://" prefix and return success */
...@@ -236,6 +256,14 @@ skip_url_prefix( ...@@ -236,6 +256,14 @@ skip_url_prefix(
return( p ); return( p );
} }
/* check for "pldaps://" prefix */
if ( strncasecmp( p, PLDAPS_URL_PREFIX, PLDAPS_URL_PREFIX_LEN ) == 0 ) {
/* skip over "pldaps://" prefix and return success */
p += PLDAPS_URL_PREFIX_LEN;
*scheme = "pldaps";
return( p );
}
/* check for "ldapi://" prefix */ /* check for "ldapi://" prefix */
if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) { if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) {
/* skip over "ldapi://" prefix and return success */ /* skip over "ldapi://" prefix and return success */
......
...@@ -22,7 +22,7 @@ NT_SRCS = ../slapd/nt_svc.c ...@@ -22,7 +22,7 @@ NT_SRCS = ../slapd/nt_svc.c
NT_OBJS = ../slapd/nt_svc.o ../../libraries/liblutil/slapdmsg.res NT_OBJS = ../slapd/nt_svc.o ../../libraries/liblutil/slapdmsg.res
SRCS += main.c value.c \ SRCS += main.c value.c \
../slapd/ch_malloc.c ../slapd/sl_malloc.c ../slapd/user.c ../slapd/ch_malloc.c ../slapd/proxyp.c ../slapd/sl_malloc.c ../slapd/user.c
OBJS = $(patsubst %.c,%.o,$(SRCS)) $(@PLAT@_OBJS) OBJS = $(patsubst %.c,%.o,$(SRCS)) $(@PLAT@_OBJS)
......
...@@ -404,6 +404,8 @@ lload_open_listener( ...@@ -404,6 +404,8 @@ lload_open_listener(
l.sl_is_tls = ldap_pvt_url_scheme2tls( lud->lud_scheme ); l.sl_is_tls = ldap_pvt_url_scheme2tls( lud->lud_scheme );
#endif /* HAVE_TLS */ #endif /* HAVE_TLS */
l.sl_is_proxied = ldap_pvt_url_scheme2proxied( lud->lud_scheme );
#ifdef LDAP_TCP_BUFFER #ifdef LDAP_TCP_BUFFER
l.sl_tcp_rmem = 0; l.sl_tcp_rmem = 0;
l.sl_tcp_wmem = 0; l.sl_tcp_wmem = 0;
...@@ -889,6 +891,16 @@ lload_listener( ...@@ -889,6 +891,16 @@ lload_listener(
} }
#endif /* SO_KEEPALIVE || TCP_NODELAY */ #endif /* SO_KEEPALIVE || TCP_NODELAY */
if ( sl->sl_is_proxied ) {
if ( !proxyp( s, from ) ) {
Debug( LDAP_DEBUG_ANY, "lload_listener: "
"proxyp(%ld) failed\n",
(long)s );
lloadd_close( s );
return;
}
}
cflag = 0; cflag = 0;
switch ( from->sa_addr.sa_family ) { switch ( from->sa_addr.sa_family ) {
#ifdef LDAP_PF_LOCAL #ifdef LDAP_PF_LOCAL
...@@ -1118,8 +1130,9 @@ lload_listener_activate( void ) ...@@ -1118,8 +1130,9 @@ lload_listener_activate( void )
lload_listeners[l]->sl_busy = 1; lload_listeners[l]->sl_busy = 1;
listener = evconnlistener_new( listener_base, lload_listener, listener = evconnlistener_new( listener_base, lload_listener,
lload_listeners[l], LEV_OPT_THREADSAFE, SLAPD_LISTEN_BACKLOG, lload_listeners[l],
lload_listeners[l]->sl_sd ); LEV_OPT_THREADSAFE|LEV_OPT_DEFERRED_ACCEPT,
SLAPD_LISTEN_BACKLOG, lload_listeners[l]->sl_sd );
if ( !listener ) { if ( !listener ) {
int err = sock_errno(); int err = sock_errno();
......
...@@ -469,6 +469,7 @@ struct LloadListener { ...@@ -469,6 +469,7 @@ struct LloadListener {
#ifdef HAVE_TLS #ifdef HAVE_TLS
int sl_is_tls; int sl_is_tls;
#endif #endif
int sl_is_proxied;
struct event_base *base; struct event_base *base;
struct evconnlistener *listener; struct evconnlistener *listener;
int sl_mute; /* Listener is temporarily disabled due to emfile */ int sl_mute; /* Listener is temporarily disabled due to emfile */
......
...@@ -29,7 +29,7 @@ SRCS = main.c globals.c bconfig.c config.c daemon.c \ ...@@ -29,7 +29,7 @@ SRCS = main.c globals.c bconfig.c config.c daemon.c \
dn.c compare.c modify.c delete.c modrdn.c ch_malloc.c \ dn.c compare.c modify.c delete.c modrdn.c ch_malloc.c \
value.c ava.c bind.c unbind.c abandon.c filterentry.c \ value.c ava.c bind.c unbind.c abandon.c filterentry.c \
phonetic.c acl.c str2filter.c aclparse.c init.c user.c \ phonetic.c acl.c str2filter.c aclparse.c init.c user.c \
lock.c controls.c extended.c passwd.c \ lock.c controls.c extended.c passwd.c proxyp.c \
schema.c schema_check.c schema_init.c schema_prep.c \ schema.c schema_check.c schema_init.c schema_prep.c \
schemaparse.c ad.c at.c mr.c syntax.c oc.c saslauthz.c \ schemaparse.c ad.c at.c mr.c syntax.c oc.c saslauthz.c \
oidm.c starttls.c index.c sets.c referral.c root_dse.c \ oidm.c starttls.c index.c sets.c referral.c root_dse.c \
...@@ -47,7 +47,7 @@ OBJS = main.o globals.o bconfig.o config.o daemon.o \ ...@@ -47,7 +47,7 @@ OBJS = main.o globals.o bconfig.o config.o daemon.o \
dn.o compare.o modify.o delete.o modrdn.o ch_malloc.o \ dn.o compare.o modify.o delete.o modrdn.o ch_malloc.o \
value.o ava.o bind.o unbind.o abandon.o filterentry.o \ value.o ava.o bind.o unbind.o abandon.o filterentry.o \
phonetic.o acl.o str2filter.o aclparse.o init.o user.o \ phonetic.o acl.o str2filter.o aclparse.o init.o user.o \
lock.o controls.o extended.o passwd.o \ lock.o controls.o extended.o passwd.o proxyp.o \
schema.o schema_check.o schema_init.o schema_prep.o \ schema.o schema_check.o schema_init.o schema_prep.o \
schemaparse.o ad.o at.o mr.o syntax.o oc.o saslauthz.o \ schemaparse.o ad.o at.o mr.o syntax.o oc.o saslauthz.o \
oidm.o starttls.o index.o sets.o referral.o root_dse.o \ oidm.o starttls.o index.o sets.o referral.o root_dse.o \
......
...@@ -1549,6 +1549,8 @@ slap_open_listener( ...@@ -1549,6 +1549,8 @@ slap_open_listener(
} }
#endif /* HAVE_TLS */ #endif /* HAVE_TLS */
l.sl_is_proxied = ldap_pvt_url_scheme2proxied( lud->lud_scheme );
#ifdef LDAP_TCP_BUFFER #ifdef LDAP_TCP_BUFFER
l.sl_tcp_rmem = 0; l.sl_tcp_rmem = 0;
l.sl_tcp_wmem = 0; l.sl_tcp_wmem = 0;
...@@ -2270,6 +2272,13 @@ slap_listener( ...@@ -2270,6 +2272,13 @@ slap_listener(
case AF_INET6: case AF_INET6:
# endif /* LDAP_PF_INET6 */ # endif /* LDAP_PF_INET6 */
case AF_INET: case AF_INET:
if ( sl->sl_is_proxied ) {
if ( !proxyp( sfd, &from ) ) {
Debug( LDAP_DEBUG_ANY, "slapd(%ld): proxyp failed\n", (long)sfd );
slapd_close( sfd );
return 0;
}
}
lutil_sockaddrstr( &from, &peerbv ); lutil_sockaddrstr( &from, &peerbv );
break; break;
......
...@@ -1556,6 +1556,11 @@ LDAP_SLAPD_F (void) slap_passwd_init (void); ...@@ -1556,6 +1556,11 @@ LDAP_SLAPD_F (void) slap_passwd_init (void);
*/ */
LDAP_SLAPD_F (char *) phonetic LDAP_P(( char *s )); LDAP_SLAPD_F (char *) phonetic LDAP_P(( char *s ));
/*
* proxyp.c
*/
LDAP_SLAPD_F (int) proxyp LDAP_P((ber_socket_t sfd, Sockaddr *from));
/* /*
* referral.c * referral.c
*/ */
......
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 2000-2020 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include "portable.h"
#include "slap.h"
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
#include <lber_types.h>
#include <ac/string.h>
#include <ac/errno.h>
typedef struct {
uint8_t sig[12]; /* hex 0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a */
uint8_t ver_cmd; /* protocol version and command */
uint8_t fam; /* protocol family and address */
uint16_t len; /* length of address data */
} proxyp_header;
typedef union {
struct { /* for TCP/UDP over IPv4, len = 12 */
uint32_t src_addr;
uint32_t dst_addr;
uint16_t src_port;
uint16_t dst_port;
} ip4;
struct { /* for TCP/UDP over IPv6, len = 36 */
uint8_t src_addr[16];
uint8_t dst_addr[16];
uint16_t src_port;
uint16_t dst_port;
} ip6;
struct { /* for AF_UNIX sockets, len = 216 */
uint8_t src_addr[108];
uint8_t dst_addr[108];
} unx;
} proxyp_addr;
static const uint8_t proxyp_sig[12] = {
0x0d, 0x0a, 0x0d, 0x0a, 0x00, 0x0d, 0x0a, 0x51, 0x55, 0x49, 0x54, 0x0a,
};
int
proxyp( ber_socket_t sfd, Sockaddr *from ) {
proxyp_header pph;
proxyp_addr ppa;
char peername[LUTIL_ADDRLEN];
struct berval peerbv = BER_BVC(peername);
/* Maximum size of header minus static component size is max option size */
uint8_t proxyp_options[536 - 16];
int pph_len;
int ret;
peername[0] = '\0';
do {
ret = tcp_read( SLAP_FD2SOCK( sfd ), &pph, sizeof(pph) );
} while ( ret == -1 && errno == EINTR );
if ( ret == -1 ) {
char ebuf[128];
int save_errno = errno;
Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
"header read failed %d (%s)\n",
(long)sfd, save_errno,
AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
return 0;
} else if ( ret != sizeof(pph) ) {
Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
"header read insufficient data %d\n",
(long)sfd, ret );
return 0;
}
if ( memcmp( pph.sig, proxyp_sig, 12 ) != 0 ) {
Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
"invalid header signature\n", (long)sfd );
return 0;
}
if ( ( pph.ver_cmd & 0xF0 ) != 0x20 ) {
Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
"invalid header version %x\n",
(long)sfd, pph.ver_cmd & 0xF0 );
return 0;
}
pph_len = ntohs( pph.len );
if ( ( pph.ver_cmd & 0x0F ) == 0x01 ) { /* PROXY command */
int addr_len;
switch ( pph.fam ) {
case 0x11: /* TCPv4 */
addr_len = sizeof( ppa.ip4 );
break;
case 0x21: /* TCPv6 */
addr_len = sizeof( ppa.ip6 );
break;
default:
Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
"unsupported protocol %x\n",
(long)sfd, pph.fam );
return 0;
}
if ( pph_len < addr_len ) {
Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
"address length %d too small, expecting %d\n",
(long)sfd, pph_len, addr_len );
return 0;
}
do {
ret = tcp_read( SLAP_FD2SOCK (sfd), &ppa, addr_len );
} while ( ret == -1 && errno == EINTR );
if ( ret == -1 ) {
char ebuf[128];
int save_errno = errno;
Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
"address read failed %d (%s)\n",
(long)sfd, save_errno,
AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
return 0;
} else if ( ret != addr_len ) {
Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
"address read insufficient data, expecting %d, read %d\n",
(long)sfd, addr_len, ret );
return 0;
}
pph_len -= addr_len;
}
switch ( pph.ver_cmd & 0x0F ) {
case 0x01: /* PROXY command */
switch ( pph.fam ) {
case 0x11: /* TCPv4 */
lutil_sockaddrstr( from, &peerbv );
Debug( LDAP_DEBUG_STATS, "proxyp(%ld): via %s\n",
(long)sfd, peername );
from->sa_in_addr.sin_family = AF_INET;
from->sa_in_addr.sin_addr.s_addr = ppa.ip4.src_addr;
from->sa_in_addr.sin_port = ppa.ip4.src_port;
break;
case 0x21: /* TCPv6 */
lutil_sockaddrstr( from, &peerbv );
Debug( LDAP_DEBUG_STATS, "proxyp(%ld): via %s\n",
(long)sfd, peername );
from->sa_in6_addr.sin6_family = AF_INET6;
memcpy( &from->sa_in6_addr.sin6_addr, ppa.ip6.src_addr,
sizeof(ppa.ip6.src_addr) );
from->sa_in6_addr.sin6_port = ppa.ip6.src_port;
break;
}
break;
case 0x00: /* LOCAL command */
Debug( LDAP_DEBUG_CONNS, "proxyp(%ld): "
"local connection, ignoring proxy data\n",
(long)sfd );
break;