[jcifs] Endless loop while contacting WINS if none of the servers

Michael B Allen mba2000 at ioplex.com
Sun Nov 12 04:52:12 GMT 2006


Actually that fix has a concurrency flaw. Consider that two requests
could go to the server and both fail. Then switchWINS would be called
too aggressively and name service lookups could fail even though a good
WINS server was found.

I believe the proper solution is to only switchWINS if the current WINS
address is the one tried.

And of course the max limit will prevent uncontrolled looping.

This has been applied and will appear in the next release.

Mike

    void send( NameServicePacket request, NameServicePacket response,
                                            int timeout ) throws IOException {
        Integer nid = null; 
        int max = NbtAddress.NBNS.length;
    
        synchronized( response ) {
            while (max-- > 0) {
                try {   
                    synchronized( LOCK ) {
                        request.nameTrnId = getNextNameTrnId();
                        nid = new Integer( request.nameTrnId );
    
                        out.setAddress( request.addr );
                        out.setLength( request.writeWireFormat( snd_buf, 0 ));
                        response.received = false;
    
                        responseTable.put( nid, response );
                        ensureOpen( timeout + 1000 ); 
                        socket.send( out );
    
                        if( log.level > 3 ) { 
                            log.println( request );
                            Hexdump.hexdump( log, snd_buf, 0, out.getLength() );
                        }   
                    }       
    
                    response.wait( timeout );
    
                    if (response.received)
                        return; 
    
                } catch( InterruptedException ie ) {
                } finally {
                    responseTable.remove( nid );
                }
    
                if (NbtAddress.isWINS( request.addr ) == false)
                    break;  
    
                                /* Message was sent to WINS but
                                 * failed to receive response.
                                 * Try a different WINS server. 
                                 */      
                if (request.addr == NbtAddress.getWINSAddress())
                    NbtAddress.switchWINS();
                request.addr = NbtAddress.getWINSAddress();
            }       
        }       
    }


On Tue, 31 Oct 2006 22:05:03 -0500
Michael B Allen <mba2000 at ioplex.com> wrote:

> On Mon, 30 Oct 2006 17:01:44 +0100
> "Dominique Laurent" <lauredo at gmail.com> wrote:
> 
> > Hello Stefan,
> > 
> > We observed the same behaviour. Actually it caused a Denial of
> > Services on our production servers, because we had two WINS servers
> > configured and they were not available at that time => all threads
> > became endlessly looping => no more thread and file handles available
> > => DoS
> > 
> > Could one of the jcifs committers add the patch into the repository?
> 
> There is no repository. But this is a serious flaw so I'll put it at
> the top of The List.
> 
> Mike
> 
> > Also there seems to be something strange in the condition
> > NbtAddress.isWINS( request.addr ) which in the loop is always true
> > unless NBNS is empty.
> > 
> > Thanks in advance,
> > Dominique.
> > 
> > P.S. Hereunder is a slightly modified version of the method (same
> > logic but less lines):
> > 
> > 
> >     void send( NameServicePacket request, NameServicePacket response,
> >                int timeout ) throws IOException {
> >         Integer nid = null;
> >         int count = NbtAddress.NBNS.length;
> > 
> >         synchronized( response ) {
> >             do {
> >                 try {
> >                     synchronized( LOCK ) {
> >                         request.nameTrnId = getNextNameTrnId();
> >                         nid = new Integer( request.nameTrnId );
> > 
> >                         out.setAddress( request.addr );
> >                         out.setLength( request.writeWireFormat( snd_buf, 0 ));
> >                         response.received = false;
> > 
> >                         responseTable.put( nid, response );
> >                         ensureOpen( timeout + 1000 );
> >                         socket.send( out );
> > 
> >                         if( log.level > 3 ) {
> >                             log.println( request );
> >                             Hexdump.hexdump( log, snd_buf, 0, out.getLength() );
> >                         }
> >                     }
> > 
> >                     response.wait( timeout );
> > 
> >                 } catch( InterruptedException ie ) {
> >                 } finally {
> >                     responseTable.remove( nid );
> >                 }
> >                 if( !response.received &&
> >                         --count > 0 &&
> >                         NbtAddress.isWINS( request.addr )) {
> >                     /* Message was sent to WINS but
> >                     * failed to receive response.
> >                     * Try a different WINS server.
> >                     */
> >                     request.addr = NbtAddress.switchWINS();
> >                 } else {
> >                     break;
> >                 }
> >             } while( true );
> >         }
> >     }
> > 
> > 
> > 
> > 
> > 
> > -------------------------------------------------
> > > Hi,
> > >
> > > we configured two WINS servers for jcifs (version 1.2.9) HTTP NTLM authentication. We discovered that jcifs hangs in an endless loop if none of the servers is reachable, i.e. the IP-addresses point to non-existing servers.
> > > I supposed that jcifs would return an error or throw an exception after the configured timeout, but apparently it didn't return at all.
> > >
> > > So I investigated the code and I found a problem in the class    jcifs.netbios.NameServiceClient .
> > > In method
> > >   void send( NameServicePacket request, NameServicePacket response, int timeout)
> > > the loop trying all WINS servers is not correctly terminated. It tries the first server, then the second and then (in case you configured two servers) first again and so on. So as long > as none of the servers gives an answer the method will not be left although the timeouts occur. I suppose that is not desired.
> > >
> > > I fixed it in our local copy of jcifs and I would appreciate if someone could tell me if I misunderstood something.
> > > You will find my version of the method later on.
> > >
> > > Thx for your help,
> > > Stefan
> > >
> > > ----
> > >     void send( NameServicePacket request, NameServicePacket response,
> > >                                             int timeout ) throws IOException {
> > >         Integer nid = null;
> > >         int count = NbtAddress.NBNS.length;
> > >
> > >         synchronized( response ) {
> > >             do {
> > >                 try {
> > >                     synchronized( LOCK ) {
> > >                         request.nameTrnId = getNextNameTrnId();
> > >                         nid = new Integer( request.nameTrnId );
> > >
> > >                         out.setAddress( request.addr );
> > >                         out.setLength( request.writeWireFormat( snd_buf, 0 ));
> > >                         response.received = false;
> > >
> > >                         responseTable.put( nid, response );
> > >                         ensureOpen( timeout + 1000 );
> > >                         socket.send( out );
> > >
> > >                         if( log.level > 3 ) {
> > >                             log.println( request );
> > >                             Hexdump.hexdump( log, snd_buf, 0, out.getLength() );
> > >                         }
> > >                     }
> > >
> > >                     response.wait( timeout );
> > >
> > >                 } catch( InterruptedException ie ) {
> > >                 } finally {
> > >                     responseTable.remove( nid );
> > >                 }
> > >
> > >                 if( !response.received &&
> > >                             NbtAddress.NBNS.length > 1 &&
> > >                             NbtAddress.isWINS( request.addr )) {
> > >                                 /* Message was sent to WINS but
> > >                                  * failed to receive response.
> > >                                  * Try a different WINS server.
> > >                                  */
> > >                     count--;
> > >                     if (count > 0) {
> > >                       request.addr = NbtAddress.switchWINS();
> > >                     } else {
> > >                       break;
> > >                     }
> > >                 } else {
> > >                   break;
> > >                 }
> > >             } while( true );
> > >         }
> > >     }
> > 
> 
> 
> -- 
> Michael B Allen
> PHP Active Directory SSO
> http://www.ioplex.com/
> 


-- 
Michael B Allen
PHP Active Directory SSO
http://www.ioplex.com/


More information about the jcifs mailing list