148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/* 248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Copyright (c) 2006-2011 Christian Plattner. All rights reserved. 348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Please refer to the LICENSE.txt for licensing details. 448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodpackage ch.ethz.ssh2.transport; 748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.IOException; 948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.InputStream; 1048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.OutputStream; 1148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.net.InetAddress; 1248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.net.InetSocketAddress; 1348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.net.Socket; 1448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.net.SocketTimeoutException; 1548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.net.UnknownHostException; 1648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.security.SecureRandom; 1748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.util.List; 1848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.util.Vector; 1948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 2048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.ConnectionInfo; 2148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.ConnectionMonitor; 2248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.DHGexParameters; 2348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.HTTPProxyData; 2448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.HTTPProxyException; 2548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.ProxyData; 2648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.ServerHostKeyVerifier; 2748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.crypto.Base64; 2848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.crypto.CryptoWishList; 2948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.crypto.cipher.BlockCipher; 3048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.crypto.digest.MAC; 3148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.log.Logger; 3248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.packets.PacketDisconnect; 3348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.packets.Packets; 3448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.packets.TypesReader; 3548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.util.StringEncoder; 3648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.util.Tokenizer; 3748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 3848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/* 3948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Yes, the "standard" is a big mess. On one side, the say that arbitary channel 4048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * packets are allowed during kex exchange, on the other side we need to blindly 4148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * ignore the next _packet_ if the KEX guess was wrong. Where do we know from that 4248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * the next packet is not a channel data packet? Yes, we could check if it is in 4348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * the KEX range. But the standard says nothing about this. The OpenSSH guys 4448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * block local "normal" traffic during KEX. That's fine - however, they assume 4548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * that the other side is doing the same. During re-key, if they receive traffic 4648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * other than KEX, they become horribly irritated and kill the connection. Since 4748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * we are very likely going to communicate with OpenSSH servers, we have to play 4848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * the same game - even though we could do better. 4948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * 5048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * btw: having stdout and stderr on the same channel, with a shared window, is 5148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * also a VERY good idea... =( 5248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 5348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 5448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/** 5548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * TransportManager. 5648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * 5748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @author Christian Plattner 5848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @version $Id: TransportManager.java 41 2011-06-02 10:36:41Z dkocher@sudo.ch $ 5948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 6048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodpublic class TransportManager 6148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood{ 6248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private static final Logger log = Logger.getLogger(TransportManager.class); 6348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 6448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private static class HandlerEntry 6548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 6648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood MessageHandler mh; 6748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int low; 6848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int high; 6948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 7048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 7148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private final List<byte[]> asynchronousQueue = new Vector<byte[]>(); 7248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private Thread asynchronousThread = null; 7348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 7448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood class AsynchronousWorker extends Thread 7548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 7648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood @Override 7748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void run() 7848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 7948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood while (true) 8048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 8148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood byte[] msg = null; 8248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 8348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (asynchronousQueue) 8448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 8548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (asynchronousQueue.size() == 0) 8648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 8748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* After the queue is empty for about 2 seconds, stop this thread */ 8848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 8948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 9048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 9148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood asynchronousQueue.wait(2000); 9248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 9348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (InterruptedException ignore) 9448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 9548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 9648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 9748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (asynchronousQueue.size() == 0) 9848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 9948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood asynchronousThread = null; 10048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return; 10148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 10248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 10348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 10448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood msg = asynchronousQueue.remove(0); 10548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 10648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 10748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* The following invocation may throw an IOException. 10848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * There is no point in handling it - it simply means 10948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * that the connection has a problem and we should stop 11048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * sending asynchronously messages. We do not need to signal that 11148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * we have exited (asynchronousThread = null): further 11248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * messages in the queue cannot be sent by this or any 11348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * other thread. 11448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Other threads will sooner or later (when receiving or 11548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * sending the next message) get the same IOException and 11648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * get to the same conclusion. 11748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 11848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 11948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 12048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 12148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sendMessage(msg); 12248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 12348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (IOException e) 12448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 12548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return; 12648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 12748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 12848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 12948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 13048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 13148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private String hostname; 13248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private int port; 13348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private final Socket sock = new Socket(); 13448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 13548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private final Object connectionSemaphore = new Object(); 13648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 13748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private boolean flagKexOngoing = false; 13848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private boolean connectionClosed = false; 13948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 14048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private Throwable reasonClosedCause = null; 14148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 14248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private TransportConnection tc; 14348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private KexManager km; 14448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 14548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private final List<HandlerEntry> messageHandlers = new Vector<HandlerEntry>(); 14648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 14748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private Thread receiveThread; 14848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 14948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private List<ConnectionMonitor> connectionMonitors = new Vector<ConnectionMonitor>(); 15048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private boolean monitorsWereInformed = false; 15148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 15248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /** 15348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * There were reports that there are JDKs which use 15448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * the resolver even though one supplies a dotted IP 15548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * address in the Socket constructor. That is why we 15648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * try to generate the InetAdress "by hand". 15748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * 15848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @param host 15948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @return the InetAddress 16048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @throws UnknownHostException 16148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 16248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private InetAddress createInetAddress(String host) throws UnknownHostException 16348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 16448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* Check if it is a dotted IP4 address */ 16548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 16648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood InetAddress addr = parseIPv4Address(host); 16748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 16848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (addr != null) 16948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 17048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return addr; 17148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 17248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 17348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return InetAddress.getByName(host); 17448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 17548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 17648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private InetAddress parseIPv4Address(String host) throws UnknownHostException 17748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 17848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (host == null) 17948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 18048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return null; 18148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 18248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 18348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood String[] quad = Tokenizer.parseTokens(host, '.'); 18448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 18548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((quad == null) || (quad.length != 4)) 18648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 18748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return null; 18848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 18948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 19048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood byte[] addr = new byte[4]; 19148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 19248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood for (int i = 0; i < 4; i++) 19348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 19448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int part = 0; 19548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 19648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((quad[i].length() == 0) || (quad[i].length() > 3)) 19748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 19848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return null; 19948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 20048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 20148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood for (int k = 0; k < quad[i].length(); k++) 20248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 20348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood char c = quad[i].charAt(k); 20448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 20548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* No, Character.isDigit is not the same */ 20648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((c < '0') || (c > '9')) 20748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 20848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return null; 20948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 21048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 21148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood part = part * 10 + (c - '0'); 21248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 21348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 21448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (part > 255) /* 300.1.2.3 is invalid =) */ 21548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 21648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return null; 21748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 21848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 21948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood addr[i] = (byte) part; 22048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 22148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 22248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return InetAddress.getByAddress(host, addr); 22348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 22448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 22548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public TransportManager(String host, int port) throws IOException 22648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 22748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood this.hostname = host; 22848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood this.port = port; 22948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 23048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 23148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public int getPacketOverheadEstimate() 23248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 23348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return tc.getPacketOverheadEstimate(); 23448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 23548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 23648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void setTcpNoDelay(boolean state) throws IOException 23748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 23848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sock.setTcpNoDelay(state); 23948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 24048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 24148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void setSoTimeout(int timeout) throws IOException 24248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 24348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sock.setSoTimeout(timeout); 24448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 24548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 24648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public ConnectionInfo getConnectionInfo(int kexNumber) throws IOException 24748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 24848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return km.getOrWaitForConnectionInfo(kexNumber); 24948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 25048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 25148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public Throwable getReasonClosedCause() 25248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 25348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (connectionSemaphore) 25448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 25548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return reasonClosedCause; 25648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 25748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 25848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 25948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public byte[] getSessionIdentifier() 26048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 26148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return km.sessionId; 26248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 26348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 26448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void close(Throwable cause, boolean useDisconnectPacket) 26548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 26648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (useDisconnectPacket == false) 26748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 26848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* OK, hard shutdown - do not aquire the semaphore, 26948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * perhaps somebody is inside (and waits until the remote 27048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * side is ready to accept new data). */ 27148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 27248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 27348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 27448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sock.close(); 27548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 27648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (IOException ignore) 27748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 27848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 27948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 28048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* OK, whoever tried to send data, should now agree that 28148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * there is no point in further waiting =) 28248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * It is safe now to aquire the semaphore. 28348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 28448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 28548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 28648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (connectionSemaphore) 28748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 28848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (connectionClosed == false) 28948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 29048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (useDisconnectPacket == true) 29148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 29248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 29348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 29448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood byte[] msg = new PacketDisconnect(Packets.SSH_DISCONNECT_BY_APPLICATION, cause.getMessage(), "") 29548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood .getPayload(); 29648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (tc != null) 29748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 29848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood tc.sendMessage(msg); 29948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 30048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 30148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (IOException ignore) 30248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 30348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 30448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 30548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 30648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 30748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sock.close(); 30848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 30948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (IOException ignore) 31048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 31148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 31248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 31348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 31448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood connectionClosed = true; 31548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood reasonClosedCause = cause; /* may be null */ 31648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 31748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood connectionSemaphore.notifyAll(); 31848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 31948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 32048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* No check if we need to inform the monitors */ 32148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 32248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood List<ConnectionMonitor> monitors = new Vector<ConnectionMonitor>(); 32348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 32448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (this) 32548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 32648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* Short term lock to protect "connectionMonitors" 32748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * and "monitorsWereInformed" 32848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * (they may be modified concurrently) 32948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 33048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 33148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (monitorsWereInformed == false) 33248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 33348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood monitorsWereInformed = true; 33448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood monitors.addAll(connectionMonitors); 33548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 33648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 33748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 33848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood for (ConnectionMonitor cmon : monitors) 33948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 34048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 34148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 34248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood cmon.connectionLost(reasonClosedCause); 34348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 34448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (Exception ignore) 34548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 34648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 34748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 34848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 34948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 35048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private void establishConnection(ProxyData proxyData, int connectTimeout) throws IOException 35148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 35248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* See the comment for createInetAddress() */ 35348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 35448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (proxyData == null) 35548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 35648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood InetAddress addr = createInetAddress(hostname); 35748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sock.connect(new InetSocketAddress(addr, port), connectTimeout); 35848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return; 35948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 36048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 36148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (proxyData instanceof HTTPProxyData) 36248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 36348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood HTTPProxyData pd = (HTTPProxyData) proxyData; 36448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 36548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* At the moment, we only support HTTP proxies */ 36648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 36748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood InetAddress addr = createInetAddress(pd.proxyHost); 36848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sock.connect(new InetSocketAddress(addr, pd.proxyPort), connectTimeout); 36948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 37048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* OK, now tell the proxy where we actually want to connect to */ 37148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 37248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood StringBuilder sb = new StringBuilder(); 37348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 37448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append("CONNECT "); 37548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append(hostname); 37648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append(':'); 37748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append(port); 37848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append(" HTTP/1.0\r\n"); 37948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 38048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((pd.proxyUser != null) && (pd.proxyPass != null)) 38148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 38248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood String credentials = pd.proxyUser + ":" + pd.proxyPass; 38348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood char[] encoded = Base64.encode(StringEncoder.GetBytes(credentials)); 38448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append("Proxy-Authorization: Basic "); 38548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append(encoded); 38648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append("\r\n"); 38748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 38848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 38948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (pd.requestHeaderLines != null) 39048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 39148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood for (int i = 0; i < pd.requestHeaderLines.length; i++) 39248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 39348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (pd.requestHeaderLines[i] != null) 39448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 39548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append(pd.requestHeaderLines[i]); 39648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append("\r\n"); 39748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 39848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 39948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 40048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 40148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood sb.append("\r\n"); 40248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 40348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood OutputStream out = sock.getOutputStream(); 40448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 40548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood out.write(StringEncoder.GetBytes(sb.toString())); 40648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood out.flush(); 40748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 40848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* Now parse the HTTP response */ 40948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 41048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood byte[] buffer = new byte[1024]; 41148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood InputStream in = sock.getInputStream(); 41248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 41348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int len = ClientServerHello.readLineRN(in, buffer); 41448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 41548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood String httpReponse = StringEncoder.GetString(buffer, 0, len); 41648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 41748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (httpReponse.startsWith("HTTP/") == false) 41848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 41948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("The proxy did not send back a valid HTTP response."); 42048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 42148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 42248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* "HTTP/1.X XYZ X" => 14 characters minimum */ 42348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 42448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((httpReponse.length() < 14) || (httpReponse.charAt(8) != ' ') || (httpReponse.charAt(12) != ' ')) 42548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 42648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("The proxy did not send back a valid HTTP response."); 42748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 42848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 42948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int errorCode = 0; 43048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 43148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 43248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 43348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood errorCode = Integer.parseInt(httpReponse.substring(9, 12)); 43448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 43548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (NumberFormatException ignore) 43648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 43748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("The proxy did not send back a valid HTTP response."); 43848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 43948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 44048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((errorCode < 0) || (errorCode > 999)) 44148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 44248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("The proxy did not send back a valid HTTP response."); 44348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 44448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 44548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (errorCode != 200) 44648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 44748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new HTTPProxyException(httpReponse.substring(13), errorCode); 44848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 44948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 45048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* OK, read until empty line */ 45148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 45248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood while (true) 45348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 45448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood len = ClientServerHello.readLineRN(in, buffer); 45548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (len == 0) 45648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 45748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood break; 45848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 45948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 46048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood return; 46148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 46248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 46348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("Unsupported ProxyData"); 46448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 46548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 46648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void initialize(String identification, CryptoWishList cwl, ServerHostKeyVerifier verifier, 46748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood DHGexParameters dhgex, int connectTimeout, SecureRandom rnd, ProxyData proxyData) 46848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throws IOException 46948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 47048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* First, establish the TCP connection to the SSH-2 server */ 47148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 47248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood establishConnection(proxyData, connectTimeout); 47348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 47448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* Parse the server line and say hello - important: this information is later needed for the 47548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * key exchange (to stop man-in-the-middle attacks) - that is why we wrap it into an object 47648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * for later use. 47748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 47848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 47948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood ClientServerHello csh = new ClientServerHello(identification, sock.getInputStream(), sock.getOutputStream()); 48048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 48148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood tc = new TransportConnection(sock.getInputStream(), sock.getOutputStream(), rnd); 48248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 48348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood km = new KexManager(this, csh, cwl, hostname, port, verifier, rnd); 48448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood km.initiateKEX(cwl, dhgex); 48548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 48648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood receiveThread = new Thread(new Runnable() 48748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 48848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void run() 48948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 49048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 49148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 49248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood receiveLoop(); 49348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 49448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (IOException e) 49548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 49648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood close(e, false); 49748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 49848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood log.warning("Receive thread: error in receiveLoop: " + e.getMessage()); 49948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 50048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 50148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (log.isDebugEnabled()) 50248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 50348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood log.debug("Receive thread: back from receiveLoop"); 50448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 50548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 50648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* Tell all handlers that it is time to say goodbye */ 50748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 50848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (km != null) 50948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 51048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 51148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 51248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood km.handleMessage(null, 0); 51348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 51448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (IOException ignored) 51548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 51648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 51748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 51848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 51948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood for (HandlerEntry he : messageHandlers) 52048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 52148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 52248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 52348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood he.mh.handleMessage(null, 0); 52448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 52548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (Exception ignore) 52648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 52748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 52848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 52948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 53048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood }); 53148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 53248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood receiveThread.setDaemon(true); 53348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood receiveThread.start(); 53448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 53548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 53648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void registerMessageHandler(MessageHandler mh, int low, int high) 53748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 53848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood HandlerEntry he = new HandlerEntry(); 53948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood he.mh = mh; 54048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood he.low = low; 54148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood he.high = high; 54248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 54348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (messageHandlers) 54448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 54548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood messageHandlers.add(he); 54648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 54748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 54848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 54948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void removeMessageHandler(MessageHandler mh, int low, int high) 55048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 55148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (messageHandlers) 55248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 55348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood for (int i = 0; i < messageHandlers.size(); i++) 55448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 55548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood HandlerEntry he = messageHandlers.get(i); 55648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((he.mh == mh) && (he.low == low) && (he.high == high)) 55748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 55848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood messageHandlers.remove(i); 55948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood break; 56048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 56148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 56248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 56348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 56448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 56548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void sendKexMessage(byte[] msg) throws IOException 56648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 56748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (connectionSemaphore) 56848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 56948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (connectionClosed) 57048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 57148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw (IOException) new IOException("Sorry, this connection is closed.").initCause(reasonClosedCause); 57248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 57348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 57448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood flagKexOngoing = true; 57548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 57648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 57748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 57848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood tc.sendMessage(msg); 57948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 58048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (IOException e) 58148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 58248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood close(e, false); 58348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw e; 58448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 58548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 58648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 58748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 58848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void kexFinished() throws IOException 58948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 59048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (connectionSemaphore) 59148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 59248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood flagKexOngoing = false; 59348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood connectionSemaphore.notifyAll(); 59448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 59548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 59648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 59748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void forceKeyExchange(CryptoWishList cwl, DHGexParameters dhgex) throws IOException 59848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 59948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood km.initiateKEX(cwl, dhgex); 60048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 60148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 60248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void changeRecvCipher(BlockCipher bc, MAC mac) 60348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 60448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood tc.changeRecvCipher(bc, mac); 60548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 60648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 60748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void changeSendCipher(BlockCipher bc, MAC mac) 60848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 60948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood tc.changeSendCipher(bc, mac); 61048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 61148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 61248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void sendAsynchronousMessage(byte[] msg) throws IOException 61348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 61448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (asynchronousQueue) 61548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 61648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood asynchronousQueue.add(msg); 61748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 61848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* This limit should be flexible enough. We need this, otherwise the peer 61948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * can flood us with global requests (and other stuff where we have to reply 62048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * with an asynchronous message) and (if the server just sends data and does not 62148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * read what we send) this will probably put us in a low memory situation 62248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * (our send queue would grow and grow and...) */ 62348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 62448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (asynchronousQueue.size() > 100) 62548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 62648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("Error: the peer is not consuming our asynchronous replies."); 62748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 62848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 62948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* Check if we have an asynchronous sending thread */ 63048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 63148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (asynchronousThread == null) 63248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 63348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood asynchronousThread = new AsynchronousWorker(); 63448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood asynchronousThread.setDaemon(true); 63548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood asynchronousThread.start(); 63648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 63748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* The thread will stop after 2 seconds of inactivity (i.e., empty queue) */ 63848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 63948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 64048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 64148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 64248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void setConnectionMonitors(List<ConnectionMonitor> monitors) 64348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 64448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (this) 64548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 64648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood connectionMonitors = new Vector<ConnectionMonitor>(); 64748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood connectionMonitors.addAll(monitors); 64848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 64948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 65048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 65148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /** 65248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * True if no response message expected. 65348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 65448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood private boolean idle; 65548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 65648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void sendMessage(byte[] msg) throws IOException 65748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 65848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (Thread.currentThread() == receiveThread) 65948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 66048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("Assertion error: sendMessage may never be invoked by the receiver thread!"); 66148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 66248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 66348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood boolean wasInterrupted = false; 66448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 66548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 66648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 66748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood synchronized (connectionSemaphore) 66848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 66948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood while (true) 67048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 67148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (connectionClosed) 67248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 67348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw (IOException) new IOException("Sorry, this connection is closed.") 67448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood .initCause(reasonClosedCause); 67548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 67648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 67748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (flagKexOngoing == false) 67848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 67948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood break; 68048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 68148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 68248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 68348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 68448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood connectionSemaphore.wait(); 68548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 68648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (InterruptedException e) 68748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 68848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood wasInterrupted = true; 68948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 69048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 69148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 69248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 69348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 69448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood tc.sendMessage(msg); 69548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood idle = false; 69648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 69748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (IOException e) 69848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 69948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood close(e, false); 70048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw e; 70148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 70248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 70348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 70448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood finally 70548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 70648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (wasInterrupted) 70748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood Thread.currentThread().interrupt(); 70848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 70948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 71048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 71148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood public void receiveLoop() throws IOException 71248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 71348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood byte[] msg = new byte[35000]; 71448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 71548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood while (true) 71648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 71748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int msglen; 71848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood try 71948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 72048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood msglen = tc.receiveMessage(msg, 0, msg.length); 72148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 72248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood catch (SocketTimeoutException e) 72348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 72448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood // Timeout in read 72548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (idle) 72648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 72748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood log.debug("Ignoring socket timeout"); 72848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood continue; 72948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 73048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw e; 73148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 73248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood idle = true; 73348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 73448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int type = msg[0] & 0xff; 73548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 73648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (type == Packets.SSH_MSG_IGNORE) 73748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 73848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood continue; 73948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 74048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 74148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (type == Packets.SSH_MSG_DEBUG) 74248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 74348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (log.isDebugEnabled()) 74448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 74548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood TypesReader tr = new TypesReader(msg, 0, msglen); 74648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood tr.readByte(); 74748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood tr.readBoolean(); 74848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood StringBuilder debugMessageBuffer = new StringBuilder(); 74948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood debugMessageBuffer.append(tr.readString("UTF-8")); 75048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 75148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood for (int i = 0; i < debugMessageBuffer.length(); i++) 75248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 75348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood char c = debugMessageBuffer.charAt(i); 75448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 75548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((c >= 32) && (c <= 126)) 75648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 75748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood continue; 75848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 75948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood debugMessageBuffer.setCharAt(i, '\uFFFD'); 76048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 76148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 76248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood log.debug("DEBUG Message from remote: '" + debugMessageBuffer.toString() + "'"); 76348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 76448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood continue; 76548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 76648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 76748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (type == Packets.SSH_MSG_UNIMPLEMENTED) 76848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 76948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("Peer sent UNIMPLEMENTED message, that should not happen."); 77048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 77148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 77248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (type == Packets.SSH_MSG_DISCONNECT) 77348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 77448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood TypesReader tr = new TypesReader(msg, 0, msglen); 77548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood tr.readByte(); 77648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood int reason_code = tr.readUINT32(); 77748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood StringBuilder reasonBuffer = new StringBuilder(); 77848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood reasonBuffer.append(tr.readString("UTF-8")); 77948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 78048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* 78148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Do not get fooled by servers that send abnormal long error 78248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * messages 78348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 78448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 78548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (reasonBuffer.length() > 255) 78648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 78748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood reasonBuffer.setLength(255); 78848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood reasonBuffer.setCharAt(254, '.'); 78948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood reasonBuffer.setCharAt(253, '.'); 79048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood reasonBuffer.setCharAt(252, '.'); 79148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 79248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 79348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* 79448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Also, check that the server did not send characters that may 79548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * screw up the receiver -> restrict to reasonable US-ASCII 79648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * subset -> "printable characters" (ASCII 32 - 126). Replace 79748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * all others with 0xFFFD (UNICODE replacement character). 79848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 79948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 80048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood for (int i = 0; i < reasonBuffer.length(); i++) 80148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 80248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood char c = reasonBuffer.charAt(i); 80348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 80448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((c >= 32) && (c <= 126)) 80548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 80648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood continue; 80748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 80848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood reasonBuffer.setCharAt(i, '\uFFFD'); 80948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 81048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 81148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("Peer sent DISCONNECT message (reason code " + reason_code + "): " 81248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood + reasonBuffer.toString()); 81348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 81448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 81548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood /* 81648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Is it a KEX Packet? 81748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */ 81848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 81948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((type == Packets.SSH_MSG_KEXINIT) || (type == Packets.SSH_MSG_NEWKEYS) 82048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood || ((type >= 30) && (type <= 49))) 82148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 82248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood km.handleMessage(msg, msglen); 82348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood continue; 82448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 82548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 82648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood MessageHandler mh = null; 82748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 82848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood for (int i = 0; i < messageHandlers.size(); i++) 82948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 83048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood HandlerEntry he = messageHandlers.get(i); 83148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if ((he.low <= type) && (type <= he.high)) 83248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 83348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood mh = he.mh; 83448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood break; 83548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 83648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 83748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 83848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood if (mh == null) 83948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood { 84048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood throw new IOException("Unexpected SSH message (type " + type + ")"); 84148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 84248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood 84348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood mh.handleMessage(msg, msglen); 84448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 84548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood } 84648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood} 847