[Date Prev][Date Next] [Chronological] [Thread] [Top]

reverse lookups in singlethreaded code (ITS#332)



Full_Name: Christophe Colle
Version: 1.2.3
OS: solaris
URL: ftp://ftp.openldap.org/incoming/
Submission from: (NULL) (195.130.132.49)


The reverse lookup-code for a new connection is in a single-threaded part of
code.
This means that whenever you connect to an ldap-server with a misconfigured 
ip-adres (the reverse takes forever to resolve), then other connections will not
be
serviced properly anymore.

                /* new connection */
                ldap_pvt_thread_mutex_lock( &new_conn_mutex );
                if ( FD_ISSET( tcps, &readfds ) ) {
                        len = sizeof(from);
                        if ( (ns = accept( tcps, (struct sockaddr *) &from,
                            &len )) == -1 ) {
                                Debug( LDAP_DEBUG_ANY,
                                    "accept() failed errno %d (%s)", errno,
                                    errno > -1 && errno < sys_nerr ?
                                    sys_errlist[errno] : "unknown", 0 );
                                ldap_pvt_thread_mutex_unlock( &new_conn_mutex
);
                                continue;
                        }
                        if ( ioctl( ns, FIONBIO, (caddr_t) &on ) == -1 ) {
                                Debug( LDAP_DEBUG_ANY,
                                    "FIONBIO ioctl on %d failed\n", ns, 0, 0 );
                        }

                        Debug( LDAP_DEBUG_CONNS, "new connection on %d\n", ns,
                            0, 0 );

                        len = sizeof(from);

                        if ( getpeername( ns, (struct sockaddr *) &from, &len )
                            == 0 ) {
                                char *s;
                                client_addr = inet_ntoa( from.sin_addr );

#if defined(SLAPD_RLOOKUPS) || defined(HAVE_TCPD)
                                hp = gethostbyaddr( (char *)
                                    &(from.sin_addr.s_addr),
                                    sizeof(from.sin_addr.s_addr), AF_INET );

                                if(hp) {



....


This code extract clearly demonstrates that a lock is created on
new_conn_mutex, while accepting the socket and trying to reverse lookup the
remote side of the socket. This means that whenever your name-services fail,
noone can connect to the directory server (you can, but you will be put in a
backlog queue for a while). Sun's DS clearly makes availibility dependent on
'nameservices' which you don't have under control. I check the man-page to
switch of this behavior, but I couldn't find out how I should do this.

How can you experience/reproduce this DOS-attack:
1) /etc/nsswitch.conf: make sure you use dns
   hosts:      files dns
2) /etc/resolv.conf: use a non existent nameserver
  nameserver 192.168.252.10   
3) (re)start the ds with these reolver settings:
  /etc/init.d/dsserv start

make sure no one conects to your DS and perform:
# time ./ldapsearch uid=colle
Search error: No such object

real    0m0.024s
user    0m0.000s
sys     0m0.030s

Less than a tenth of a seconds...Still looking good

Now from another machine (or a machine which has no ip-addres in your
/etc/hosts) issue:
./ldapsearch -h the_server uid=colle
And in the same time perform on the previous server:
# time ./ldapsearch uid=colle
Search error: No such object

real    0m57.081s
user    0m0.000s
sys     0m0.020s



Just because the reverse lookup cannot be done, a simple search on an
idle server takes up to 1 minute before you get an answer, whereas the
same request can be resolved in less than 1 second when no other
ip-address is connecting. This clearly demonstrates how a DOS-attack
can be setup, because the code is single-threaded in the
'accept'-part.