私の目的は、ファイアウォールの背後にあるサーバー(ホスト)に接続することです。ネットワーク内の別のサーバー(トンネル)に接続してからこのサーバーにSSHで接続することで、このサーバーにアクセスできます。ただし、JSchを介して同じシナリオを実装することはできません。
この目的のために書いた以下のコードを動作させることができません。ここで何か馬鹿げたことをしているのなら教えてください。
_public class JschExecutor {
public static void main(String[] args){
JschExecutor t=new JschExecutor();
try{
t.go();
} catch(Exception ex){
ex.printStackTrace();
}
}
public void go() throws Exception{
StringBuilder outputBuffer = new StringBuilder();
String Host="xxx.xxx.xxx.xxx"; // The Host to be connected finally
String user="user";
String password="passwrd";
int port=22;
String tunnelRemoteHost="xx.xx.xx.xx"; // The Host from where the tunnel is created
JSch jsch=new JSch();
Session session=jsch.getSession(user, Host, port);
session.setPassword(password);
localUserInfo lui=new localUserInfo();
session.setUserInfo(lui);
session.setConfig("StrictHostKeyChecking", "no");
ProxySOCKS5 proxyTunnel = new ProxySOCKS5(tunnelRemoteHost, 22);
proxyTunnel.setUserPasswd(user, password);
session.setProxy(proxyTunnel);
session.connect(30000);
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand("hostname");
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream in=channel.getInputStream();
BufferedReader ebr = new BufferedReader(new InputStreamReader(in));
channel.connect();
while (true) {
byte[] tmpArray=new byte[1024];
while(in.available()>0){
int i=in.read(tmpArray, 0, 1024);
if(i<0)break;
outputBuffer.append(new String(tmpArray, 0, i)).append("\n");
}
if(channel.isClosed()){
System.out.println("exit-status: "+channel.getExitStatus());
break;
}
}
ebr.close();
channel.disconnect();
session.disconnect();
System.out.println(outputBuffer.toString());
}
class localUserInfo implements UserInfo{
String passwd;
public String getPassword(){ return passwd; }
public boolean promptYesNo(String str){return true;}
public String getPassphrase(){ return null; }
public boolean promptPassphrase(String message){return true; }
public boolean promptPassword(String message){return true;}
public void showMessage(String message){}
}
}
_
上記のコードは、session.connect(30000);
行に以下の例外を与えます。
_com.jcraft.jsch.JSchException: ProxySOCKS5: com.jcraft.jsch.JSchException: fail in SOCKS5 proxy
at com.jcraft.jsch.ProxySOCKS5.connect(ProxySOCKS5.Java:317)
at com.jcraft.jsch.Session.connect(Session.Java:231)
at com.ukris.main.JschExecutor.go(JschExecutor.Java:50)
at com.ukris.main.JschExecutor.main(JschExecutor.Java:19)
Caused by: com.jcraft.jsch.JSchException: fail in SOCKS5 proxy
at com.jcraft.jsch.ProxySOCKS5.connect(ProxySOCKS5.Java:200)
... 3 more
_
jschのSOCKS
プロキシ設定を使用すると、リモート側のrunningプロキシサーバーに接続できます。リモート側のsshd
はnotSOCKS
プロキシと見なされます。トンネリング先のマシンのsshポートに転送するローカルポートを確立してから、APIを使用してこのシステムへのセカンダリssh接続を確立する必要があります。
私はあなたの例を取り上げ、これを達成するために少し書き直しました:
import com.jcraft.jsch.*;
import Java.io.*;
public class JschExecutor2 {
public static void main(String[] args){
JschExecutor2 t=new JschExecutor2();
try{
t.go();
} catch(Exception ex){
ex.printStackTrace();
}
}
public void go() throws Exception{
StringBuilder outputBuffer = new StringBuilder();
String Host="firstsystem"; // First level target
String user="username";
String password="firstlevelpassword";
String tunnelRemoteHost="secondlevelhost"; // The Host of the second target
String secondPassword="targetsystempassword";
int port=22;
JSch jsch=new JSch();
Session session=jsch.getSession(user, Host, port);
session.setPassword(password);
localUserInfo lui=new localUserInfo();
session.setUserInfo(lui);
session.setConfig("StrictHostKeyChecking", "no");
// create port from 2233 on local system to port 22 on tunnelRemoteHost
session.setPortForwardingL(2233, tunnelRemoteHost, 22);
session.connect();
session.openChannel("direct-tcpip");
// create a session connected to port 2233 on the local Host.
Session secondSession = jsch.getSession(user, "localhost", 2233);
secondSession.setPassword(secondPassword);
secondSession.setUserInfo(lui);
secondSession.setConfig("StrictHostKeyChecking", "no");
secondSession.connect(); // now we're connected to the secondary system
Channel channel=secondSession.openChannel("exec");
((ChannelExec)channel).setCommand("hostname");
channel.setInputStream(null);
InputStream stdout=channel.getInputStream();
channel.connect();
while (true) {
byte[] tmpArray=new byte[1024];
while(stdout.available() > 0){
int i=stdout.read(tmpArray, 0, 1024);
if(i<0)break;
outputBuffer.append(new String(tmpArray, 0, i));
}
if(channel.isClosed()){
System.out.println("exit-status: "+channel.getExitStatus());
break;
}
}
stdout.close();
channel.disconnect();
secondSession.disconnect();
session.disconnect();
System.out.print(outputBuffer.toString());
}
class localUserInfo implements UserInfo{
String passwd;
public String getPassword(){ return passwd; }
public boolean promptYesNo(String str){return true;}
public String getPassphrase(){ return null; }
public boolean promptPassphrase(String message){return true; }
public boolean promptPassword(String message){return true;}
public void showMessage(String message){}
}
}
このコードは、ターゲットシステムのsshポートに転送するローカルポートを作成し、それを介して接続します。 hostnameコマンドの実行は、実際に転送先のシステムで実行されていることを示しています。