view src/net/sourceforge/jsocks/server/Ident.java @ 434:7ea898484623

Added tag stable-1.9.1 for changeset 3e25a713555d
author Carl Byington <carl@five-ten-sg.com>
date Mon, 09 Mar 2015 16:33:11 -0700
parents 72de889ecfe7
children
line wrap: on
line source

package net.sourceforge.jsocks.server;
import net.sourceforge.jsocks.*;
import java.net.*;
import java.io.*;
import java.util.StringTokenizer;

/**
 Class Ident provides means to obtain user name of the owner of the socket 
 on remote machine, providing remote machine runs identd daemon.
 <p>
 To use it:
   <tt><pre>
   Socket s = ss.accept();
   Ident id = new Ident(s);
   if(id.successful) goUseUser(id.userName);
   else handleIdentError(id.errorCode,id.errorMessage)
   </pre></tt>
*/
public class Ident{

    /** Error Message can be null.*/
    public String errorMessage;
    /** Host type as returned by daemon, can be null, if error happened*/
    public String hostType;
    /** User name as returned by the identd daemon, or null, if it failed*/
    public String userName;

    /** If this is true then userName and hostType contain valid values.
        Else errorCode contain the error code, and errorMessage contains
        the corresponding message.
    */
    public boolean successful;
    /** Error code*/
    public int errorCode;
    /** Identd on port 113 can't be contacted*/
    public static final int ERR_NO_CONNECT = 1;
    /** Connection timed out*/
    public static final int ERR_TIMEOUT = 2;
    /** Identd daemon responded with ERROR, in this case errorMessage
        contains the string explanation, as send by the daemon.
    */
    public static final int ERR_PROTOCOL = 3;
    /**
     When parsing server response protocol error happened.
    */
    public static final int ERR_PROTOCOL_INCORRECT = 4;


    /** Maximum amount of time we should wait before dropping the
      connection to identd server.Setting it to 0 implies infinit
      timeout.
    */
    public static final int connectionTimeout = 10000;
    

    /**
     Constructor tries to connect to Identd daemon on the host of the
     given socket, and retrieve user name of the owner of given socket 
     connection on remote machine. After constructor returns public
     fields are initialised to whatever the server returned.
     <p>
     If user name was successfully retrieved successful is set to true,
     and userName and hostType are set to whatever server returned. If
     however for some reason user name was not obtained, successful is set
     to false and errorCode contains the code explaining the reason of
     failure, and errorMessage contains human readable explanation.
     <p>
     Constructor may block, for a while.
     @param s Socket whose ownership on remote end should be obtained.
    */
    public Ident(Socket s ){
      Socket sock = null;
      successful = false; //We are pessimistic

      try{
        sock = new Socket(s.getInetAddress(),113);
        sock.setSoTimeout(connectionTimeout);
        byte[] request = (""+s.getPort()+" , "+
                             s.getLocalPort()+"\r\n").getBytes();

        sock.getOutputStream().write(request);

        BufferedReader in = new BufferedReader(
                            new InputStreamReader(sock.getInputStream()));

        parseResponse(in.readLine());

      }catch(InterruptedIOException iioe){
        errorCode = ERR_TIMEOUT;
        errorMessage = "Connection to identd timed out.";
      }catch(ConnectException ce){
        errorCode = ERR_NO_CONNECT;
        errorMessage = "Connection to identd server failed.";

      }catch(IOException ioe){
        errorCode = ERR_NO_CONNECT;
        errorMessage = ""+ioe;
      }finally{
        try{ if(sock!=null) sock.close();}catch(IOException ioe){};
      }
    }

    private void parseResponse(String response){
      if(response == null){
         errorCode = ERR_PROTOCOL_INCORRECT;
         errorMessage = "Identd server closed connection.";
         return;
      }

      StringTokenizer st = new StringTokenizer(response,":");
      if(st.countTokens() < 3){
         errorCode = ERR_PROTOCOL_INCORRECT;
         errorMessage = "Can't parse server response.";
         return;
      }

      st.nextToken(); //Discard first token, it's basically what we have send
      String command = st.nextToken().trim().toUpperCase();

      if(command.equals("USERID") && st.countTokens() >= 2){
        successful = true;
        hostType = st.nextToken().trim();
        userName = st.nextToken("").substring(1);//Get all that is left
      }else if(command.equals("ERROR")){
        errorCode = ERR_PROTOCOL;
        errorMessage = st.nextToken();
      }else{
        errorCode = ERR_PROTOCOL_INCORRECT;
        System.out.println("Opa!");
        errorMessage = "Can't parse server response.";
      }


    }

///////////////////////////////////////////////
//USED for Testing
/*
    public static void main(String[] args) throws IOException{

       Socket s = null;
       s = new Socket("gp101-16", 1391);

       Ident id = new Ident(s);
       if(id.successful){
         System.out.println("User: "+id.userName);
         System.out.println("HostType: "+id.hostType);
       }else{
         System.out.println("ErrorCode: "+id.errorCode);
         System.out.println("ErrorMessage: "+id.errorMessage);

       }

       if(s!= null) s.close();
    }
//*/

}