]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#9419 Add support for HAProxy proxy protocol v2
authorPaul B. Henson <henson@acm.org>
Sun, 6 Dec 2020 04:56:10 +0000 (20:56 -0800)
committerQuanah Gibson-Mount <quanah@openldap.org>
Wed, 24 Feb 2021 18:11:09 +0000 (18:11 +0000)
14 files changed:
doc/guide/admin/runningslapd.sdf
doc/man/man8/lloadd.8
doc/man/man8/slapd.8
include/ldap_pvt.h
libraries/libldap/ldap-int.h
libraries/libldap/url.c
servers/lloadd/Makefile_server.in
servers/lloadd/daemon.c
servers/lloadd/lload.h
servers/slapd/Makefile.in
servers/slapd/daemon.c
servers/slapd/proto-slap.h
servers/slapd/proxyp.c [new file with mode: 0644]
servers/slapd/slap.h

index 4964b1785a6be89f604c8f3bf62bb65744d4f703..831a12c61eb7772a8aac90c31918374ad39e7a22 100644 (file)
@@ -36,13 +36,23 @@ This option specifies alternative listener configurations.  The
 default is {{EX:ldap:///}} which implies {{TERM:LDAP}} over
 {{TERM:TCP}} on all interfaces on the default LDAP port 389.  You
 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
-URL        Protocol        Transport
-ldap:///   LDAP            TCP port 389
-ldaps:///  LDAP over SSL   TCP port 636
-ldapi:///  LDAP            IPC (Unix-domain socket)
+URL        Protocol                Transport
+ldap:///   LDAP                    TCP port 389
+pldap:///  proxied LDAP            TCP port 389
+ldaps:///  LDAP over SSL           TCP port 636
+pldaps:/// proxied LDAP over SSL   TCP port 636
+ldapi:///  LDAP                    IPC (Unix-domain socket)
 !endblock
 
 For example, {{EX:-h
index d6830749045e00f689e0dea361cce3688473f893..af112b8d391baf297b223380e7cbb8eaea3ed36f 100644 (file)
@@ -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,
 and LDAP over IPC (Unix domain sockets).  Host 0.0.0.0 represents
 INADDR_ANY (any interface).
-A space separated list of URLs is expected.  The URLs should be of
-the LDAP, LDAPS, or LDAPI schemes, and generally
-without a DN or other optional parameters (excepting as discussed below).
-Support for the latter two schemes depends on selected configuration
-options.  Hosts may be specified by name or IPv4 and IPv6 address formats.
-Ports, if specified, must be numeric.  The default ldap:// port is \fB389\fP
-and the default ldaps:// port is \fB636\fP.
+A space separated list of URLs is expected.  The URLs should be of the LDAP,
+PLDAP, LDAPS, PLDAPS, or LDAPI schemes, and generally without a DN or other
+optional parameters (excepting as discussed below).  Support for the latter
+three schemes depends on selected configuration options. Hosts may be specified
+by name or IPv4 and IPv6 address formats.  Ports, if specified, must be
+numeric.  The default ldap:// port is \fB389\fP and the default ldaps:// port
+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,
 .B name
index 14e463cd5ca0d16400c190ab921ac195d016cc50..8504b3736d2b460870f0a1d663339968dc290133 100644 (file)
@@ -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,
 and LDAP over IPC (Unix domain sockets).  Host 0.0.0.0 represents
 INADDR_ANY (any interface).
-A space separated list of URLs is expected.  The URLs should be of
-the LDAP, LDAPS, or LDAPI schemes, and generally
-without a DN or other optional parameters (excepting as discussed below).
-Support for the latter two schemes depends on selected configuration 
-options.  Hosts may be specified by name or IPv4 and IPv6 address formats.
-Ports, if specified, must be numeric.  The default ldap:// port is \fB389\fP
-and the default ldaps:// port is \fB636\fP.
+A space separated list of URLs is expected.  The URLs should be of the LDAP,
+PLDAP, LDAPS, PLDAPS, or LDAPI schemes, and generally without a DN or other
+optional parameters (excepting as discussed below).  Support for the latter
+three schemes depends on selected configuration options. Hosts may be specified
+by name or IPv4 and IPv6 address formats.  Ports, if specified, must be
+numeric.  The default ldap:// port is \fB389\fP and the default ldaps:// port
+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,
 .B name 
index 28cdbbeeb400c6e512f3363132d081cffad1c69e..9d9d697ce7c55ba067377cab9925d611b29cc609 100644 (file)
@@ -32,6 +32,9 @@ ldap_pvt_url_scheme2proto LDAP_P((
 LDAP_F ( int )
 ldap_pvt_url_scheme2tls LDAP_P((
        const char * ));
+LDAP_F ( int )
+ldap_pvt_url_scheme2proxied LDAP_P((
+       const char * ));
 
 LDAP_F ( int )
 ldap_pvt_url_scheme_port LDAP_P((
index fa85b1bb489b5758d87581be4c29f92006910a66..32ef6669221727a2cac9ce2f91c9f80edc5e2b99 100644 (file)
@@ -123,8 +123,12 @@ LDAP_BEGIN_DECL
 
 #define LDAP_URL_PREFIX         "ldap://"
 #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_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_LEN   STRLENOF(LDAPI_URL_PREFIX)
 #ifdef LDAP_CONNECTIONLESS
index c1c022af19e8ac9d7d74fdf75d3b74c0e6afea0e..0328de120136f4cc9dd925829753e910331c9492 100644 (file)
@@ -20,7 +20,7 @@
 
 /*
  *  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:
  *   attributes is a comma separated list
@@ -59,7 +59,7 @@ int ldap_pvt_url_scheme2proto( const char *scheme )
                return -1;
        }
 
-       if( strcmp("ldap", scheme) == 0 ) {
+       if( strcmp("ldap", scheme) == 0 || strcmp("pldap", scheme) == 0 ) {
                return LDAP_PROTO_TCP;
        }
 
@@ -67,7 +67,7 @@ int ldap_pvt_url_scheme2proto( const char *scheme )
                return LDAP_PROTO_IPC;
        }
 
-       if( strcmp("ldaps", scheme) == 0 ) {
+       if( strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0 ) {
                return LDAP_PROTO_TCP;
        }
 #ifdef LDAP_CONNECTIONLESS
@@ -86,7 +86,7 @@ int ldap_pvt_url_scheme_port( const char *scheme, int port )
        if( port ) return port;
        if( scheme == NULL ) return port;
 
-       if( strcmp("ldap", scheme) == 0 ) {
+       if( strcmp("ldap", scheme) == 0 || strcmp("pldap", scheme) == 0 ) {
                return LDAP_PORT;
        }
 
@@ -94,7 +94,7 @@ int ldap_pvt_url_scheme_port( const char *scheme, int port )
                return -1;
        }
 
-       if( strcmp("ldaps", scheme) == 0 ) {
+       if( strcmp("ldaps", scheme) == 0 || strcmp("pldaps", scheme) == 0 ) {
                return LDAPS_PORT;
        }
 
@@ -116,7 +116,19 @@ ldap_pvt_url_scheme2tls( const char *scheme )
                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
@@ -150,7 +162,7 @@ ldap_is_ldaps_url( LDAP_CONST char *url )
                return 0;
        }
 
-       return strcmp(scheme, "ldaps") == 0;
+       return strcmp(scheme, "ldaps") == 0 || strcmp(scheme, "pldaps");
 }
 
 int
@@ -228,6 +240,14 @@ skip_url_prefix(
                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 */
        if ( strncasecmp( p, LDAPS_URL_PREFIX, LDAPS_URL_PREFIX_LEN ) == 0 ) {
                /* skip over "ldaps://" prefix and return success */
@@ -236,6 +256,14 @@ skip_url_prefix(
                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 */
        if ( strncasecmp( p, LDAPI_URL_PREFIX, LDAPI_URL_PREFIX_LEN ) == 0 ) {
                /* skip over "ldapi://" prefix and return success */
index c306b43d9cb6e31e32d3f4f0955eead37a733f95..6964ca5dcc291736096e93b52440b71c70928a98 100644 (file)
@@ -22,7 +22,7 @@ NT_SRCS = ../slapd/nt_svc.c
 NT_OBJS = ../slapd/nt_svc.o ../../libraries/liblutil/slapdmsg.res
 
 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)
 
index c6712c2496a40cf63db598240df17c2206235b1f..110b9c08f5601ef60f7281a80f45b4846616cc2b 100644 (file)
@@ -404,6 +404,8 @@ lload_open_listener(
     l.sl_is_tls = ldap_pvt_url_scheme2tls( lud->lud_scheme );
 #endif /* HAVE_TLS */
 
+    l.sl_is_proxied = ldap_pvt_url_scheme2proxied( lud->lud_scheme );
+
 #ifdef LDAP_TCP_BUFFER
     l.sl_tcp_rmem = 0;
     l.sl_tcp_wmem = 0;
@@ -889,6 +891,16 @@ lload_listener(
     }
 #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;
     switch ( from->sa_addr.sa_family ) {
 #ifdef LDAP_PF_LOCAL
@@ -1118,8 +1130,9 @@ lload_listener_activate( void )
 
         lload_listeners[l]->sl_busy = 1;
         listener = evconnlistener_new( listener_base, lload_listener,
-                lload_listeners[l], LEV_OPT_THREADSAFE, SLAPD_LISTEN_BACKLOG,
-                lload_listeners[l]->sl_sd );
+                lload_listeners[l],
+                LEV_OPT_THREADSAFE|LEV_OPT_DEFERRED_ACCEPT,
+                SLAPD_LISTEN_BACKLOG, lload_listeners[l]->sl_sd );
         if ( !listener ) {
             int err = sock_errno();
 
index 1dc9d1abc0c4f2d521917305ce47240637cc3713..53816b993c10023404a5dd0d6eabb1696f33b317 100644 (file)
@@ -469,6 +469,7 @@ struct LloadListener {
 #ifdef HAVE_TLS
     int sl_is_tls;
 #endif
+    int sl_is_proxied;
     struct event_base *base;
     struct evconnlistener *listener;
     int sl_mute; /* Listener is temporarily disabled due to emfile */
index b6e354595d993df83ba66b12e3d829f80f691e3b..ad2be71c2b77f9beaf8fa7ba5a2730f5a54794ad 100644 (file)
@@ -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 \
                value.c ava.c bind.c unbind.c abandon.c filterentry.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 \
                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 \
@@ -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 \
                value.o ava.o bind.o unbind.o abandon.o filterentry.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 \
                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 \
index 5d99cd187dd4d30d79e50e8f82417ff39055bf05..0416b2b23c8a7b8a94f861eafae40a948acd0ea0 100644 (file)
@@ -1549,6 +1549,8 @@ slap_open_listener(
        }
 #endif /* HAVE_TLS */
 
+       l.sl_is_proxied = ldap_pvt_url_scheme2proxied( lud->lud_scheme );
+
 #ifdef LDAP_TCP_BUFFER
        l.sl_tcp_rmem = 0;
        l.sl_tcp_wmem = 0;
@@ -2270,6 +2272,13 @@ slap_listener(
        case AF_INET6:
 #  endif /* LDAP_PF_INET6 */
        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 );
                break;
 
index 2a356d680483bfcbbb660ee4f581d0f3abab23b5..9a87d4e8f3379a6def32cb51073bb6f8e9495b5d 100644 (file)
@@ -1556,6 +1556,11 @@ LDAP_SLAPD_F (void) slap_passwd_init (void);
  */
 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
  */
diff --git a/servers/slapd/proxyp.c b/servers/slapd/proxyp.c
new file mode 100644 (file)
index 0000000..69359a2
--- /dev/null
@@ -0,0 +1,219 @@
+/* $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;
+
+       default:
+               Debug( LDAP_DEBUG_ANY, "proxyp(%ld): invalid command %x\n",
+                               (long)sfd, pph.ver_cmd & 0x0F );
+               return 0;
+       }
+
+       /* Clear out any options left in proxy packet */
+       if ( pph_len > 0 ) {
+               if (pph_len > sizeof( proxyp_options ) ) {
+                       Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
+                                       "options size %d too big\n",
+                                       (long)sfd, pph_len );
+                       return 0;
+               }
+
+               do {
+                       ret = tcp_read( SLAP_FD2SOCK (sfd), &proxyp_options, pph_len );
+               } while ( ret == -1 && errno == EINTR );
+
+               if ( ret == -1 ) {
+                       char ebuf[128];
+                       int save_errno = errno;
+                       Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
+                                       "options read failed %d (%s)\n",
+                                       (long)sfd, save_errno,
+                                       AC_STRERROR_R( save_errno, ebuf, sizeof(ebuf) ) );
+                       return 0;
+               } else if ( ret != pph_len ) {
+                       Debug( LDAP_DEBUG_ANY, "proxyp(%ld): "
+                                       "options read insufficient data, expecting %d, read %d\n",
+                                       (long)sfd, pph_len, ret );
+                       return 0;
+               }
+       }
+
+       return 1;
+}
index d421786ded7d7d67089a738c5ddd49f8e23e15b7..2a52fe74a6afb54701cbc679ebc5173b7435ea9a 100644 (file)
@@ -3003,6 +3003,7 @@ struct Listener {
 #ifdef LDAP_CONNECTIONLESS
        int     sl_is_udp;              /* UDP listener is also data port */
 #endif
+       int     sl_is_proxied;
        int     sl_mute;        /* Listener is temporarily disabled due to emfile */
        int     sl_busy;        /* Listener is busy (accept thread activated) */
        ber_socket_t sl_sd;