mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-02-23 14:09:39 +08:00
ITS#8847 Add SOCKET_BIND_ADDRESSES Option
This commit is contained in:
parent
8ebd065048
commit
9d594a118e
@ -376,6 +376,21 @@ must be a
|
||||
This is a read-only, handle-specific option.
|
||||
This option is OpenLDAP specific.
|
||||
.TP
|
||||
.B LDAP_OPT_SOCKET_BIND_ADDRESSES
|
||||
Sets/gets a space-separated list of IP Addresses used as binding interface
|
||||
to remote server when trying to establish a connection. Only one valid IPv4
|
||||
address and/or one valid IPv6 address are allowed in the list.
|
||||
.BR outvalue
|
||||
must be a
|
||||
.BR "char **",
|
||||
and the caller is responsible of freeing the returned string by calling
|
||||
.BR ldap_memfree (3),
|
||||
while
|
||||
.BR invalue
|
||||
must be a
|
||||
.BR "const char *" ;
|
||||
the library duplicates the corresponding string.
|
||||
.TP
|
||||
.B LDAP_OPT_TIMELIMIT
|
||||
Sets/gets the value that defines the time limit after which
|
||||
a search operation should be terminated by the server.
|
||||
|
@ -213,6 +213,11 @@ specifies a request for unlimited search size. Please note that the server
|
||||
may still apply any server-side limit on the amount of entries that can be
|
||||
returned by a search operation.
|
||||
.TP
|
||||
.B SOCKET_BIND_ADDRESSES <IP>
|
||||
Specifies the source bind IP to be used for connecting to target LDAP server.
|
||||
Multiple IP addresses must be space separated. Only one valid IPv4
|
||||
address and/or one valid IPv6 address are allowed in the list.
|
||||
.TP
|
||||
.B TIMELIMIT <integer>
|
||||
Specifies a time limit (in seconds) to use when performing searches.
|
||||
The number should be a non-negative integer. \fITIMELIMIT\fP of zero (0)
|
||||
|
@ -132,6 +132,7 @@ LDAP_BEGIN_DECL
|
||||
#define LDAP_OPT_CONNECT_CB 0x5011 /* connection callbacks */
|
||||
#define LDAP_OPT_SESSION_REFCNT 0x5012 /* session reference count */
|
||||
#define LDAP_OPT_KEEPCONN 0x5013 /* keep the connection on read error or NoD */
|
||||
#define LDAP_OPT_SOCKET_BIND_ADDRESSES 0x5014 /* user configured bind IPs */
|
||||
|
||||
/* OpenLDAP TLS options */
|
||||
#define LDAP_OPT_X_TLS 0x6000
|
||||
|
@ -38,6 +38,7 @@
|
||||
struct ldapoptions ldap_int_global_options =
|
||||
{ LDAP_UNINITIALIZED, LDAP_DEBUG_NONE
|
||||
LDAP_LDO_NULLARG
|
||||
LDAP_LDO_SOURCEIP_NULLARG
|
||||
LDAP_LDO_CONNECTIONLESS_NULLARG
|
||||
LDAP_LDO_TLS_NULLARG
|
||||
LDAP_LDO_SASL_NULLARG
|
||||
@ -93,6 +94,7 @@ static const struct ol_attribute {
|
||||
offsetof(struct ldapoptions, ldo_defport)},
|
||||
{0, ATTR_OPTION, "HOST", NULL, LDAP_OPT_HOST_NAME}, /* deprecated */
|
||||
{0, ATTR_OPTION, "URI", NULL, LDAP_OPT_URI}, /* replaces HOST/PORT */
|
||||
{0, ATTR_OPTION, "SOCKET_BIND_ADDRESSES", NULL, LDAP_OPT_SOCKET_BIND_ADDRESSES},
|
||||
{0, ATTR_BOOL, "REFERRALS", NULL, LDAP_BOOL_REFERRALS},
|
||||
{0, ATTR_INT, "KEEPALIVE_IDLE", NULL, LDAP_OPT_X_KEEPALIVE_IDLE},
|
||||
{0, ATTR_INT, "KEEPALIVE_PROBES", NULL, LDAP_OPT_X_KEEPALIVE_PROBES},
|
||||
@ -142,7 +144,7 @@ static const struct ol_attribute {
|
||||
{0, ATTR_NONE, NULL, NULL, 0}
|
||||
};
|
||||
|
||||
#define MAX_LDAP_ATTR_LEN sizeof("TLS_CIPHER_SUITE")
|
||||
#define MAX_LDAP_ATTR_LEN sizeof("SOCKET_BIND_ADDRESSES")
|
||||
#define MAX_LDAP_ENV_PREFIX_LEN 8
|
||||
|
||||
static int
|
||||
@ -519,6 +521,12 @@ ldap_int_destroy_global_options(void)
|
||||
ldap_free_urllist( gopts->ldo_defludp );
|
||||
gopts->ldo_defludp = NULL;
|
||||
}
|
||||
|
||||
if ( gopts->ldo_local_ip_addrs.local_ip_addrs ) {
|
||||
LDAP_FREE( gopts->ldo_local_ip_addrs.local_ip_addrs );
|
||||
gopts->ldo_local_ip_addrs.local_ip_addrs = NULL;
|
||||
}
|
||||
|
||||
#if defined(HAVE_WINSOCK) || defined(HAVE_WINSOCK2)
|
||||
WSACleanup( );
|
||||
#endif
|
||||
@ -558,6 +566,9 @@ void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl
|
||||
gopts->ldo_tm_api.tv_sec = -1;
|
||||
gopts->ldo_tm_net.tv_sec = -1;
|
||||
|
||||
memset( &gopts->ldo_local_ip_addrs, 0,
|
||||
sizeof( gopts->ldo_local_ip_addrs ) );
|
||||
|
||||
/* ldo_defludp will be freed by the termination handler
|
||||
*/
|
||||
ldap_url_parselist(&gopts->ldo_defludp, "ldap://localhost/");
|
||||
|
@ -45,9 +45,7 @@
|
||||
|
||||
/* for struct timeval */
|
||||
#include <ac/time.h>
|
||||
#ifdef _WIN32
|
||||
#include <ac/socket.h>
|
||||
#endif
|
||||
|
||||
#undef TV2MILLISEC
|
||||
#define TV2MILLISEC(tv) (((tv)->tv_sec * 1000) + ((tv)->tv_usec/1000))
|
||||
@ -199,6 +197,19 @@ typedef struct ldaplist {
|
||||
void *ll_data;
|
||||
} ldaplist;
|
||||
|
||||
/*
|
||||
* LDAP Client Source IP structure
|
||||
*/
|
||||
typedef struct ldapsourceip {
|
||||
char *local_ip_addrs;
|
||||
struct in_addr ip4_addr;
|
||||
unsigned short has_ipv4;
|
||||
#ifdef LDAP_PF_INET6
|
||||
struct in6_addr ip6_addr;
|
||||
unsigned short has_ipv6;
|
||||
#endif
|
||||
} ldapsourceip;
|
||||
|
||||
/*
|
||||
* structure representing get/set'able options
|
||||
* which have global defaults.
|
||||
@ -256,6 +267,15 @@ struct ldapoptions {
|
||||
|
||||
#define LDAP_LDO_NULLARG ,0,0,0,0 ,{0},{0} ,0,0,0,0, 0,0,0,0, 0,0, 0,0,0,0,0,0, 0, 0
|
||||
|
||||
/* LDAP user configured bind IPs */
|
||||
struct ldapsourceip ldo_local_ip_addrs;
|
||||
|
||||
#ifdef LDAP_PF_INET6
|
||||
#define LDAP_LDO_SOURCEIP_NULLARG ,{0,0,0,0,0}
|
||||
#else
|
||||
#define LDAP_LDO_SOURCEIP_NULLARG ,{0,0,0}
|
||||
#endif
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
#define LDAP_IS_UDP(ld) ((ld)->ld_options.ldo_is_udp)
|
||||
void* ldo_peer; /* struct sockaddr* */
|
||||
@ -727,6 +747,9 @@ LDAP_F (void) ldap_clear_select_write( LDAP *ld, Sockbuf *sb );
|
||||
LDAP_F (int) ldap_is_read_ready( LDAP *ld, Sockbuf *sb );
|
||||
LDAP_F (int) ldap_is_write_ready( LDAP *ld, Sockbuf *sb );
|
||||
|
||||
LDAP_F (int) ldap_validate_and_fill_sourceip ( char** source_ip_lst,
|
||||
ldapsourceip* temp_source_ip );
|
||||
|
||||
LDAP_F (int) ldap_int_connect_cbs( LDAP *ld, Sockbuf *sb,
|
||||
ber_socket_t *s, LDAPURLDesc *srv, struct sockaddr *addr );
|
||||
|
||||
|
@ -207,6 +207,14 @@ ldap_create( LDAP **ldp )
|
||||
|
||||
if (( ld->ld_selectinfo = ldap_new_select_info()) == NULL ) goto nomem;
|
||||
|
||||
ld->ld_options.ldo_local_ip_addrs.local_ip_addrs = NULL;
|
||||
if( gopts->ldo_local_ip_addrs.local_ip_addrs ) {
|
||||
ld->ld_options.ldo_local_ip_addrs.local_ip_addrs =
|
||||
LDAP_STRDUP( gopts->ldo_local_ip_addrs.local_ip_addrs );
|
||||
if ( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs == NULL )
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
ld->ld_lberoptions = LBER_USE_DER;
|
||||
|
||||
ld->ld_sb = ber_sockbuf_alloc( );
|
||||
|
@ -258,6 +258,17 @@ ldap_get_option(
|
||||
rc = LDAP_OPT_SUCCESS;
|
||||
break;
|
||||
|
||||
case LDAP_OPT_SOCKET_BIND_ADDRESSES:
|
||||
if ( lo->ldo_local_ip_addrs.local_ip_addrs == NULL ) {
|
||||
* (void **) outvalue = NULL;
|
||||
}
|
||||
else {
|
||||
* (char **) outvalue =
|
||||
LDAP_STRDUP( lo->ldo_local_ip_addrs.local_ip_addrs );
|
||||
}
|
||||
rc = LDAP_OPT_SUCCESS;
|
||||
break;
|
||||
|
||||
case LDAP_OPT_URI:
|
||||
* (char **) outvalue = ldap_url_list2urls(lo->ldo_defludp);
|
||||
rc = LDAP_OPT_SUCCESS;
|
||||
@ -594,6 +605,43 @@ ldap_set_option(
|
||||
break;
|
||||
}
|
||||
|
||||
case LDAP_OPT_SOCKET_BIND_ADDRESSES: {
|
||||
const char *source_ip = (const char *) invalue;
|
||||
char **source_ip_lst = NULL;
|
||||
|
||||
ldapsourceip temp_source_ip;
|
||||
memset( &temp_source_ip, 0, sizeof( ldapsourceip ) );
|
||||
rc = LDAP_OPT_SUCCESS;
|
||||
if( source_ip == NULL ) {
|
||||
if ( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs ) {
|
||||
LDAP_FREE( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs );
|
||||
memset( &ld->ld_options.ldo_local_ip_addrs, 0,
|
||||
sizeof( ldapsourceip ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
source_ip_lst = ldap_str2charray( source_ip, " " );
|
||||
|
||||
if ( source_ip_lst == NULL )
|
||||
rc = LDAP_NO_MEMORY;
|
||||
|
||||
if( rc == LDAP_OPT_SUCCESS ) {
|
||||
rc = ldap_validate_and_fill_sourceip ( source_ip_lst,
|
||||
&temp_source_ip );
|
||||
ldap_charray_free( source_ip_lst );
|
||||
}
|
||||
if ( rc == LDAP_OPT_SUCCESS ) {
|
||||
if ( lo->ldo_local_ip_addrs.local_ip_addrs != NULL ) {
|
||||
LDAP_FREE( lo->ldo_local_ip_addrs.local_ip_addrs );
|
||||
lo->ldo_local_ip_addrs.local_ip_addrs = NULL;
|
||||
}
|
||||
lo->ldo_local_ip_addrs = temp_source_ip;
|
||||
lo->ldo_local_ip_addrs.local_ip_addrs = LDAP_STRDUP( source_ip );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case LDAP_OPT_URI: {
|
||||
const char *urls = (const char *) invalue;
|
||||
LDAPURLDesc *ludlist = NULL;
|
||||
|
@ -475,6 +475,43 @@ ldap_pvt_inet_aton( const char *host, struct in_addr *in)
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
ldap_validate_and_fill_sourceip (char** source_ip_lst, ldapsourceip* temp_source_ip )
|
||||
{
|
||||
int i = 0;
|
||||
int rc = LDAP_PARAM_ERROR;
|
||||
|
||||
for ( i = 0; source_ip_lst[i] != NULL; i++ ) {
|
||||
Debug1( LDAP_DEBUG_TRACE,
|
||||
"ldap_validate_and_fill_sourceip(%s)\n",
|
||||
source_ip_lst[i] );
|
||||
|
||||
if ( !temp_source_ip->has_ipv4 ) {
|
||||
if ( inet_aton( source_ip_lst[i], &temp_source_ip->ip4_addr ) ) {
|
||||
temp_source_ip->has_ipv4 = 1;
|
||||
rc = LDAP_OPT_SUCCESS;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#ifdef LDAP_PF_INET6
|
||||
if ( !temp_source_ip->has_ipv6 ) {
|
||||
if ( inet_pton( AF_INET6, source_ip_lst[i],
|
||||
& temp_source_ip->ip6_addr ) ) {
|
||||
temp_source_ip->has_ipv6 = 1;
|
||||
rc = LDAP_OPT_SUCCESS;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
memset( temp_source_ip, 0, sizeof( * (temp_source_ip ) ) );
|
||||
Debug1( LDAP_DEBUG_TRACE,
|
||||
"ldap_validate_and_fill_sourceip: validation failed for (%s)\n",
|
||||
source_ip_lst[i] );
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
ldap_int_connect_cbs(LDAP *ld, Sockbuf *sb, ber_socket_t *s, LDAPURLDesc *srv, struct sockaddr *addr)
|
||||
{
|
||||
@ -607,6 +644,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
|
||||
rc = -1;
|
||||
|
||||
for( sai=res; sai != NULL; sai=sai->ai_next) {
|
||||
unsigned short bind_success = 1;
|
||||
if( sai->ai_addr == NULL ) {
|
||||
Debug0(LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: getaddrinfo "
|
||||
@ -638,6 +676,24 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
|
||||
Debug2(LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: Trying %s %s\n",
|
||||
addr, serv );
|
||||
if( ld->ld_options.ldo_local_ip_addrs.has_ipv6 ) {
|
||||
struct sockaddr_in6 ip6addr;
|
||||
char bind_addr[INET6_ADDRSTRLEN];
|
||||
ip6addr.sin6_family = AF_INET6;
|
||||
ip6addr.sin6_addr = ld->ld_options.ldo_local_ip_addrs.ip6_addr;
|
||||
inet_ntop( AF_INET6,
|
||||
&(ip6addr.sin6_addr),
|
||||
bind_addr, sizeof bind_addr );
|
||||
Debug1( LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: From source address %s\n",
|
||||
bind_addr );
|
||||
if ( bind( s, ( struct sockaddr* ) &ip6addr, sizeof ip6addr ) != 0 ) {
|
||||
Debug1( LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: Failed to bind source address %s\n",
|
||||
bind_addr );
|
||||
bind_success = 0;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
case AF_INET: {
|
||||
@ -648,17 +704,36 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
|
||||
Debug2(LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: Trying %s:%s\n",
|
||||
addr, serv );
|
||||
if( ld->ld_options.ldo_local_ip_addrs.has_ipv4 ) {
|
||||
struct sockaddr_in ip4addr;
|
||||
char bind_addr[INET_ADDRSTRLEN];
|
||||
ip4addr.sin_family = AF_INET;
|
||||
ip4addr.sin_addr = ld->ld_options.ldo_local_ip_addrs.ip4_addr;
|
||||
inet_ntop( AF_INET,
|
||||
&(ip4addr.sin_addr),
|
||||
bind_addr, sizeof bind_addr );
|
||||
Debug1( LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: From source address %s\n",
|
||||
bind_addr );
|
||||
if ( bind(s, ( struct sockaddr* )&ip4addr, sizeof ip4addr ) != 0 ) {
|
||||
Debug1( LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: Failed to bind source address %s\n",
|
||||
bind_addr );
|
||||
bind_success = 0;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
rc = ldap_pvt_connect( ld, s,
|
||||
sai->ai_addr, sai->ai_addrlen, async );
|
||||
if ( rc == 0 || rc == -2 ) {
|
||||
err = ldap_int_connect_cbs( ld, sb, &s, srv, sai->ai_addr );
|
||||
if ( err )
|
||||
rc = err;
|
||||
else
|
||||
break;
|
||||
if ( bind_success ) {
|
||||
rc = ldap_pvt_connect( ld, s,
|
||||
sai->ai_addr, sai->ai_addrlen, async );
|
||||
if ( rc == 0 || rc == -2 ) {
|
||||
err = ldap_int_connect_cbs( ld, sb, &s, srv, sai->ai_addr );
|
||||
if ( err )
|
||||
rc = err;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
ldap_pvt_close_socket(ld, s);
|
||||
}
|
||||
@ -687,7 +762,14 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
|
||||
rc = s = -1;
|
||||
for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) {
|
||||
struct sockaddr_in sin;
|
||||
|
||||
unsigned short bind_success = 1;
|
||||
#ifdef HAVE_INET_NTOA_B
|
||||
char address[INET_ADDR_LEN];
|
||||
char bind_addr[INET_ADDR_LEN];
|
||||
#else
|
||||
char *address;
|
||||
char *bind_addr;
|
||||
#endif
|
||||
s = ldap_int_socket( ld, PF_INET, socktype );
|
||||
if ( s == AC_SOCKET_INVALID ) {
|
||||
/* use_hp ? continue : break; */
|
||||
@ -712,30 +794,45 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
|
||||
}
|
||||
|
||||
#ifdef HAVE_INET_NTOA_B
|
||||
{
|
||||
/* for VxWorks */
|
||||
char address[INET_ADDR_LEN];
|
||||
inet_ntoa_b(sin.sin_address, address);
|
||||
Debug2(LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: Trying %s:%d\n",
|
||||
address, port );
|
||||
}
|
||||
/* for VxWorks */
|
||||
inet_ntoa_b( sin.sin_address, address );
|
||||
#else
|
||||
Debug2(LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: Trying %s:%d\n",
|
||||
inet_ntoa(sin.sin_addr), port );
|
||||
address = inet_ntoa( sin.sin_addr );
|
||||
#endif
|
||||
Debug2( LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: Trying %s:%d\n",
|
||||
address, port );
|
||||
if( ld->ld_options.ldo_local_ip_addrs.has_ipv4 ) {
|
||||
struct sockaddr_in ip4addr;
|
||||
ip4addr.sin_family = AF_INET;
|
||||
ip4addr.sin_addr = ld->ld_options.ldo_local_ip_addrs.ip4_addr;
|
||||
#ifdef HAVE_INET_NTOA_B
|
||||
inet_ntoa_b( ip4addr.sin_address, bind_addr );
|
||||
#else
|
||||
bind_addr = inet_ntoa( ip4addr.sin_addr );
|
||||
#endif
|
||||
Debug1( LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: From source address %s\n",
|
||||
bind_addr );
|
||||
if ( bind( s, (struct sockaddr*)&ip4addr, sizeof ip4addr ) != 0 ) {
|
||||
Debug1( LDAP_DEBUG_TRACE,
|
||||
"ldap_connect_to_host: Failed to bind source address %s\n",
|
||||
bind_addr );
|
||||
bind_success = 0;
|
||||
}
|
||||
}
|
||||
if ( bind_success ) {
|
||||
rc = ldap_pvt_connect(ld, s,
|
||||
(struct sockaddr *)&sin, sizeof(sin),
|
||||
async);
|
||||
|
||||
rc = ldap_pvt_connect(ld, s,
|
||||
(struct sockaddr *)&sin, sizeof(sin),
|
||||
async);
|
||||
|
||||
if ( (rc == 0) || (rc == -2) ) {
|
||||
int err = ldap_int_connect_cbs( ld, sb, &s, srv, (struct sockaddr *)&sin );
|
||||
if ( err )
|
||||
rc = err;
|
||||
else
|
||||
break;
|
||||
if ( (rc == 0) || (rc == -2) ) {
|
||||
int err = ldap_int_connect_cbs( ld, sb, &s, srv, (struct sockaddr *)&sin );
|
||||
if ( err )
|
||||
rc = err;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ldap_pvt_close_socket(ld, s);
|
||||
|
@ -175,6 +175,12 @@ ldap_ld_free(
|
||||
ld->ld_options.ldo_defludp = NULL;
|
||||
}
|
||||
|
||||
if ( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs ) {
|
||||
LDAP_FREE( ld->ld_options.ldo_local_ip_addrs.local_ip_addrs );
|
||||
memset( & ld->ld_options.ldo_local_ip_addrs, 0,
|
||||
sizeof( ldapsourceip ) );
|
||||
}
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if ( ld->ld_options.ldo_peer != NULL ) {
|
||||
LDAP_FREE( ld->ld_options.ldo_peer );
|
||||
|
@ -57,7 +57,7 @@ slapd-bind: slapd-bind.o $(OBJS) $(XLIBS)
|
||||
$(LTLINK) -o $@ slapd-bind.o $(OBJS) $(LIBS)
|
||||
|
||||
ldif-filter: ldif-filter.o $(XLIBS)
|
||||
$(LTLINK) -o $@ ldif-filter.o $(LIBS)
|
||||
$(LTLINK) -o $@ ldif-filter.o $(OBJS) $(LIBS)
|
||||
|
||||
slapd-mtread: slapd-mtread.o $(OBJS) $(XLIBS)
|
||||
$(LTLINK) -o $@ slapd-mtread.o $(OBJS) $(LIBS)
|
||||
|
Loading…
Reference in New Issue
Block a user