Virtual hosting FTP services

FTP is an example of a 'server-first' protocol. The back-end server sends a greeting message before the client sends its first request. This means that the traffic manager must establish the connection to the back-end node before it can inspect the client's request.

Fortunately, it's possible to implement a full protocol proxy in ZXTM's TrafficScript language. This article explains how!

We're going to manage the following scenario:

A service provider is hosting FTP services for organizations - ferrarif1.com, sauberf1.com and minardif1.com. Each organization has their own cluster of FTP servers:

  • Ferrari have 3 Sun E15Ks in a pool named 'ferrari ftp'
  • Sauber have a couple of old, ex-Ferrari servers in Switzerland, in a pool named 'sauber ftp'
  • Minardi have a capable and cost-effective pair of pizza-box servers in a pool named 'minardi ftp'

The service provider hosts the FTP services through ZXTM, and requires that users log in with their email address. If a user logs in as 'rbraun@ferrarif1.com', ZXTM will connect the user to the 'ferrari ftp' pool and log in with username 'rbraun'.

This is made complicated because an FTP connection begins with a 'server hello' message as follows:

220 ftp.zeus.com FTP server (Version wu-2.6.1-0.6x.21) ready.

... before reading the data from the client.

Configuration

  1. Create the virtual server (FTP, listening on port 21) and the three pools ('ferrari ftp' etc).

    Configure the default pool for the virtual server to be the discard pool.

  2. Configure the virtual server connection management settings, setting the FTP serverfirst_banner to:
    220 F1 FTP server ready.
    
  3. Add the following trafficscript request rule to the virtual server, setting it to run every time:
    $req = string.trim( request.endswith( "\n" ) );
    
    if( !string.regexmatch( $req, "USER (.*)", "i" ) ) {
       # if we're connected, forward the message; otherwise
       # return a login prompt
       if( connection.getNode() ) { 
          break;
       } else {
          request.sendresponse( "530 Please log in!!\r\n" );
          break;
       }
    }
    
    $loginname = $1;
    
    # The login name should look like 'user@host'
    
    if( ! string.regexmatch( $loginname, "(.*)@(.*)" ) ) {
       request.sendresponse( "530 Incorrect user or password!!\r\n" );
       break;
    }
    
    $user = $1; 
    $domain = string.lowercase( $2 );
    
    request.set( "USER ".$user."\r\n" );
    
    # select the pool we want... 
    
    if( $domain == "ferrarif1.com" ) { 
       pool.use( "ferrari ftp" );
    } else if( $domain == "sauberf1.com" ) { 
       pool.use( "sauber ftp" );
    } else if( $domain == "minardif1.com" ) { 
       pool.use( "minardi ftp" );
    } else {
       request.sendresponse( "530 Incorrect user or password!!\r\n" );
    }
    

And that's it! ZXTM automatically slurps and discards the serverfirst banner message from the back-end ftp servers when it connects on the first request.

More...

Here's a more sophisticated example which reads the username and password from the client before attempting to connect. You could add your own authentication at this stage (for example, using http.request.get to query an external server) before initiating the connect to the back-end ftp server:

  1. TrafficScript request rule:
    $req = string.trim( request.endswith( "\n" ) );
    
    if( string.regexmatch( $req, "USER (.*)" ) ) {
       connection.data.set( "user", $1 );
       $msg = "331 Password required for ".$1."!!\r\n";
       request.sendresponse( $msg );
       break;
    }
    
    if( !string.regexmatch( $req, "PASS (.*)" ) ) { 
       # if we're connected, forward the message; otherwise
       # return a login prompt
       if( connection.getNode() ) { 
          break;
       } else {
          request.sendresponse( "530 Please log in!!\r\n" );
          break;
       }
    } 
    
    $loginname = connection.data.get( "user" );
    $pass = $1;
    
    # The login name should look like 'user@host'
    
    if( ! string.regexmatch( $loginname, "(.*)@(.*)" ) ) {
       request.sendresponse( "530 Incorrect user or password!!\r\n" );
       break;
    }
    
    $user = $1; 
    $domain = string.lowercase( $2 );
    
    # You could add your own authentication at this stage.
    # If the username and password is invalid, do the following:
    #
    # if( $badpassword ) { 
    #    request.sendresponse( "530 Incorrect user or password!!\r\n" );
    #    break;
    # } 
    
    # now, replay the correct request against a new 
    # server instance
    
    connection.data.set( "state", "connecting" );
    request.set( "USER ".$user."\r\nPASS ".$pass."\r\n" );
    
    # select the pool we want... 
    if( $domain == "ferrarif1.com" ) { 
       pool.use( "ferrari ftp" );
    } else if( $domain == "sauberf1.com" ) { 
       pool.use( "sauber ftp" );
    } else if( $domain == "minardif1.com" ) { 
       pool.use( "minardi ftp" );
    } else {
       request.sendresponse( "530 Incorrect user or password!!\r\n" );
    }
    
  2. TrafficScript response rule
    if( connection.data.get("state") == "connecting" ) {
       # We've just connected, but ZXTM doesn't slurp the serverfirst
       # banner until after this rule has run.
       # Slurp the first line (the serverfirst banner), the second line 
       # (the 331 need password) and then replace the serverfirst banner
       $first = response.getLine();
       $second = response.getLine( "\n", $1 );
       $remainder = string.skip( response.get(), $1 );
       response.set( $first.$remainder );
       connection.data.set( "state", "" );
    }
    

Remember that both rules must be set to 'run every time'.

Owen Garrett [Zeus Dev Team] 01 July 2005  Permalink  
Leave a comment ...
Your email address will not be displayed.
Your URL will be displayed.
This public messageboard is not a forum for technical support. To report technical support problems, please contact our dedicated Support team using the instructions at the bottom of this page.
Options:
 
(Line breaks become <br />)
(Set cookies for name, email & url)
Download Free ZXTM Desktop Edition

Recent Articles

Other Resources



www.zeus.com