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.
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)
#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
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
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},
{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
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
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/");
/* 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))
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.
#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* */
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 );
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( );
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;
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;
}
#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)
{
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 "
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: {
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);
}
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; */
}
#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
-
- 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;
+ 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);
+
+ 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);
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 );
$(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)