sshclient.java
来自「一个非常好的ssh客户端实现」· Java 代码 · 共 1,227 行 · 第 1/3 页
JAVA
1,227 行
/****************************************************************************** * * Copyright (c) 1999-2003 AppGate Network Security AB. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code as * defined in and that are subject to the MindTerm Public Source License, * Version 2.0, (the 'License'). You may not use this file except in compliance * with the License. * * You should have received a copy of the MindTerm Public Source License * along with this software; see the file LICENSE. If not, write to * AppGate Network Security AB, Otterhallegatan 2, SE-41118 Goteborg, SWEDEN * *****************************************************************************/package com.mindbright.ssh;import java.net.*;import java.io.*;import java.math.BigInteger;import java.util.Vector;import com.mindbright.jca.security.MessageDigest;import com.mindbright.jca.security.SignatureException;import com.mindbright.jca.security.interfaces.RSAPublicKey;import com.mindbright.jca.security.interfaces.RSAPrivateCrtKey;import com.mindbright.security.publickey.RSAAlgorithm;import com.mindbright.util.SecureRandomAndPad;import com.mindbright.terminal.*;/** * This class contains the main functionality for setting up a connection to a * ssh-server. It can be used both to implement a "full" ssh-client, or it can * be used to fire off a singe command on the server (both in a background * thread and in the current-/foreground-thread). A set of properties can be * used to control different aspects of the connection. These are fetched from * an object implementing the <code>SSHClientUser</code>-interface. The * authentication can be done in different ways, all which is handled through an * object implementing the <code>SSHAuthenticator</code>-interface. The * console-output of the <code>SSHClient</code> is (optionally) handled through * an object implementing the <code>SSHConsole</code>-interface. <p> * * A class realizing a full interactive ssh-client is * <code>SSHInteractiveClient</code>. The <code>SSHClient</code>-class * is also used transparently from the <code>SSHSocket</code>- and <code>SSHServerSocket</code>- * classes (through the <code>SSHSocketFactory</code>- and <code>SSHSocketImpl</code>-classes). * * @author Mats Andersson * @version 0.96, 26/11/98 * @see SSHAuthenticator * @see SSHClientUser * @see SSHConsole */public class SSHClient extends SSH { static public class AuthFailException extends IOException { public AuthFailException(String msg) { super(msg); } public AuthFailException() { this("permission denied"); } } static public class ExitMonitor implements Runnable { SSHClient client; long msTimeout; public ExitMonitor(SSHClient client, long msTimeout) { this.msTimeout = msTimeout; this.client = client; } public ExitMonitor(SSHClient client) { this(client, 0); } public void run() { client.waitForExit(msTimeout); // If we have allready exited gracefully don't report... // if(!client.gracefulExit) client.disconnect(false); } } private class KeepAliveThread extends Thread { int interval; public KeepAliveThread(int i) { super("SSH1KeepAlive"); interval = i; } public synchronized void setInterval(int i) { interval = i; } public void run() { int i; SSHPduOutputStream ignmsg; while(true) { try { synchronized(this) { i = interval; } sleep(1000 * i); if(SSHClient.this.controller != null) { ignmsg = new SSHPduOutputStream(MSG_DEBUG, controller.sndCipher, controller.sndComp, rand); ignmsg.writeString("heartbeat"); controller.transmit(ignmsg); } } catch (Exception e) { // !!! } } } } // Local port forwarding // public static class LocalForward { protected String localHost; protected int localPort; protected String remoteHost; protected int remotePort; protected String plugin; public LocalForward(String localHost, int localPort, String remoteHost, int remotePort, String plugin) { this.localHost = localHost; this.localPort = localPort; this.remoteHost = remoteHost; this.remotePort = remotePort; this.plugin = plugin; } } // Remote port forwarding // public static class RemoteForward { protected int remotePort; protected String localHost; protected int localPort; protected String plugin; public RemoteForward(int remotePort, String localHost, int localPort, String plugin) { this.remotePort = remotePort; this.localHost = localHost; this.localPort = localPort; this.plugin = plugin; } } protected Thread myThread; protected KeepAliveThread keepAliveThread; protected SecureRandomAndPad rand; protected InetAddress serverAddr; protected InetAddress serverRealAddr = null; protected InetAddress localAddr; protected String srvVersionStr; protected int srvVersionMajor; protected int srvVersionMinor; protected Vector localForwards; protected Vector remoteForwards; protected String commandLine; protected SSHChannelController controller; protected SSHConsole console; protected SSHAuthenticator authenticator; protected SSHClientUser user; protected SSHInteractor interactor; protected Socket sshSocket; protected BufferedInputStream sshIn; protected BufferedOutputStream sshOut; protected boolean gracefulExit; protected boolean isConnected; protected boolean isOpened; boolean usedOTP; protected int refCount; // !!! KLUDGE protected boolean havePORTFtp = false; protected int firstFTPPort = 0; protected boolean activateTunnels = true; // !!! KLUDGE public SSHClient(SSHAuthenticator authenticator, SSHClientUser user) { this.user = user; this.authenticator = authenticator; this.interactor = user.getInteractor(); this.srvVersionStr = null; this.refCount = 0; this.usedOTP = false; try { this.localAddr = InetAddress.getByName("0.0.0.0"); } catch (UnknownHostException e) { if(interactor != null) interactor.alert("FATAL: Could not create local InetAddress: " + e.getMessage()); } clearAllForwards(); } public void setConsole(SSHConsole console) { this.console = console; if(controller != null) controller.console = console; } public SSHConsole getConsole() { return console; } public InetAddress getServerAddr() { return serverAddr; } public InetAddress getServerRealAddr() { if(serverRealAddr == null) return serverAddr; return serverRealAddr; } public void setServerRealAddr(InetAddress realAddr) { serverRealAddr = realAddr; } public InetAddress getLocalAddr() { return localAddr; } public void setLocalAddr(String addr) throws UnknownHostException { localAddr = InetAddress.getByName(addr); } public String getServerVersion() { return srvVersionStr; } public void addLocalPortForward(int localPort, String remoteHost, int remotePort, String plugin) throws IOException { addLocalPortForward(localAddr.getHostAddress(), localPort, remoteHost, remotePort, plugin); } public void addLocalPortForward(String localHost, int localPort, String remoteHost, int remotePort, String plugin) throws IOException { delLocalPortForward(localHost, localPort); localForwards.addElement(new LocalForward(localHost, localPort, remoteHost, remotePort, plugin)); if(isOpened) { try { requestLocalPortForward(localHost, localPort, remoteHost, remotePort, plugin); } catch(IOException e) { delLocalPortForward(localHost, localPort); throw e; } } } public void delLocalPortForward(String localHost, int port) { if(port == -1) { if(isOpened) controller.killListenChannels(); localForwards = new Vector(); } else { for(int i = 0; i < localForwards.size(); i++) { LocalForward fwd = (LocalForward) localForwards.elementAt(i); if(fwd.localPort == port && fwd.localHost.equals(localHost)) { localForwards.removeElementAt(i); if(isOpened) controller.killListenChannel(fwd.localHost, fwd.localPort); break; } } } } public void addRemotePortForward(int remotePort, String localHost, int localPort, String plugin) { delRemotePortForward(remotePort); remoteForwards.addElement(new RemoteForward(remotePort, localHost, localPort, plugin)); } public void delRemotePortForward(int port) { if(port == -1) { remoteForwards = new Vector(); } else { for(int i = 0; i < remoteForwards.size(); i++) { RemoteForward fwd = (RemoteForward) remoteForwards.elementAt(i); if(fwd.remotePort == port) { remoteForwards.removeElementAt(i); break; } } } } public void delRemotePortForward(String plugin) { for(int i = 0; i < remoteForwards.size(); i++) { RemoteForward fwd = (RemoteForward) remoteForwards.elementAt(i); if(fwd.plugin.equals(plugin)) { remoteForwards.removeElementAt(i); i--; } } } public void clearAllForwards() { this.localForwards = new Vector(); this.remoteForwards = new Vector(); } public void startExitMonitor() { startExitMonitor(0); } public void startExitMonitor(long msTimeout) { Thread t = new Thread(new ExitMonitor(this, msTimeout)); t.setName("ExitMonitor"); t.start(); } public synchronized int addRef() { return ++refCount; } public void forcedDisconnect() { if(controller != null) { controller.sendDisconnect("exit"); controller.killAll(); } else if (interactor != null) { interactor.disconnected(this, false); } } public synchronized int delRef() { if(--refCount <= 0) { forcedDisconnect(); waitForExit(2000); } return refCount; } public void waitForExit(long msTimeout) { try { controller.waitForExit(msTimeout); } catch(InterruptedException e) { if(interactor != null) interactor.alert("Error when shutting down SSHClient: " + e.getMessage()); controller.killAll(); } try { if(sshSocket != null) sshSocket.close(); } catch (IOException e) { // !!! } } public void doSingleCommand(String commandLine, boolean background, long msTimeout) throws IOException { this.commandLine = commandLine; bootSSH(false); if(background) startExitMonitor(msTimeout); else waitForExit(msTimeout); } public void bootSSH(boolean haveCnxWatch) throws IOException { bootSSH(haveCnxWatch, false); } public void bootSSH(boolean haveCnxWatch, boolean releaseConnection) throws IOException { try { myThread = Thread.currentThread(); rand = secureRandom(); // Give the interactor a chance to hold us until the user wants to // "connect" (e.g. with a dialog with server, username, password, // proxy-info) // if(interactor != null) interactor.startNewSession(this); // We first ask for the ssh server address since this might // typically be a prompt in the SSHClientUser // String serverAddrStr = user.getSrvHost(); // When the SSHClientUser has reported which host to connect to we report // this to the interactor as sessionStarted // if(interactor != null) interactor.sessionStarted(this); // It's the responsibility of the SSHClientUser to establish a proxied // connection if that is needed, the SSHClient does not want to know about // proxies. If a proxy is not needed getProxyConnection() just returns // null. // sshSocket = user.getProxyConnection(); if(sshSocket == null) { serverAddr = InetAddress.getByName(serverAddrStr); sshSocket = new Socket(serverAddr, user.getSrvPort()); } else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?