diff --git a/src/org/torproject/jtor/connections/ConnectionCache.java b/src/org/torproject/jtor/connections/ConnectionCache.java index 844deb0f..02d411d4 100644 --- a/src/org/torproject/jtor/connections/ConnectionCache.java +++ b/src/org/torproject/jtor/connections/ConnectionCache.java @@ -16,8 +16,6 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Logger; -import javax.net.ssl.SSLSocket; - import org.torproject.jtor.circuits.Connection; import org.torproject.jtor.circuits.ConnectionFailedException; import org.torproject.jtor.circuits.ConnectionHandshakeException; @@ -40,8 +38,7 @@ private class ConnectionTask implements Callable { } public ConnectionImpl call() throws Exception { - SSLSocket socket = factory.createSocket(); - ConnectionImpl conn = new ConnectionImpl(socket, router, initializationTracker, isDirectoryConnection); + ConnectionImpl conn = new ConnectionImpl(router, initializationTracker, isDirectoryConnection); conn.connect(); return conn; } @@ -61,7 +58,6 @@ public void run() { } private final ConcurrentMap> activeConnections = new ConcurrentHashMap>(); - private final ConnectionSocketFactory factory = new ConnectionSocketFactory(); private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); private TorInitializationTracker initializationTracker; diff --git a/src/org/torproject/jtor/connections/ConnectionImpl.java b/src/org/torproject/jtor/connections/ConnectionImpl.java index aca90afe..e3dddec5 100644 --- a/src/org/torproject/jtor/connections/ConnectionImpl.java +++ b/src/org/torproject/jtor/connections/ConnectionImpl.java @@ -45,7 +45,8 @@ public class ConnectionImpl implements Connection, DashboardRenderable { private final static int DEFAULT_CONNECT_TIMEOUT = 5000; private final static Cell connectionClosedSentinel = CellImpl.createCell(0, 0); - private final SSLSocket socket; + private final ConnectionSocketFactory factory = new ConnectionSocketFactory(); + private SSLSocket socket; private InputStream input; private OutputStream output; private final Router router; @@ -55,14 +56,11 @@ public class ConnectionImpl implements Connection, DashboardRenderable { private final boolean isDirectoryConnection; private int currentId = 1; - private boolean isConnected; - private volatile boolean isClosed; private final Thread readCellsThread; private final Object connectLock = new Object(); private Date lastActivity; - public ConnectionImpl(SSLSocket socket, Router router, TorInitializationTracker tracker, boolean isDirectoryConnection) { - this.socket = socket; + public ConnectionImpl(Router router, TorInitializationTracker tracker, boolean isDirectoryConnection) { this.router = router; this.circuitMap = new HashMap(); this.readCellsThread = new Thread(createReadCellsRunnable()); @@ -83,7 +81,7 @@ public Router getRouter() { } public boolean isClosed() { - return isClosed; + return (socket != null && socket.isClosed()); } public int allocateCircuitId(Circuit circuit) { @@ -102,12 +100,12 @@ private void incrementNextId() { } public boolean isConnected() { - return isConnected; + return (socket != null && socket.isConnected()); } public void connect() throws ConnectionFailedException, ConnectionTimeoutException, ConnectionHandshakeException { synchronized (connectLock) { - if(isConnected) { + if(isConnected()) { return; } try { @@ -124,7 +122,6 @@ public void connect() throws ConnectionFailedException, ConnectionTimeoutExcepti } catch (ConnectionIOException e) { throw new ConnectionFailedException(e.getMessage()); } - isConnected = true; } } @@ -147,8 +144,8 @@ private void connectSocket() throws IOException { } } - socket.connect(routerToSocketAddress(router), DEFAULT_CONNECT_TIMEOUT); - + socket = factory.createSocket(routerToSocketAddress(router), DEFAULT_CONNECT_TIMEOUT); + if(initializationTracker != null) { if(isDirectoryConnection) { initializationTracker.notifyEvent(Tor.BOOTSTRAP_STATUS_HANDSHAKE_DIR); @@ -186,7 +183,7 @@ private Cell recvCell() throws ConnectionIOException { closeSocket(); throw new ConnectionIOException(); } catch (IOException e) { - if(!isClosed) { + if(!isClosed()) { logger.fine("IOException reading cell from connection "+ this + " : "+ e.getMessage()); closeSocket(); } @@ -197,9 +194,7 @@ private Cell recvCell() throws ConnectionIOException { private void closeSocket() { try { logger.fine("Closing connection to "+ this); - isClosed = true; socket.close(); - isConnected = false; } catch (IOException e) { logger.warning("Error closing socket: "+ e.getMessage()); } @@ -291,7 +286,7 @@ private void processControlCell(Cell cell) { void idleCloseCheck() { synchronized (circuitMap) { - final boolean needClose = (!isClosed && circuitMap.isEmpty() && getIdleMilliseconds() > CONNECTION_IDLE_TIMEOUT); + final boolean needClose = (!isClosed() && circuitMap.isEmpty() && getIdleMilliseconds() > CONNECTION_IDLE_TIMEOUT); if(needClose) { logger.fine("Closing connection to "+ this +" on idle timeout"); closeSocket(); diff --git a/src/org/torproject/jtor/connections/ConnectionSocketFactory.java b/src/org/torproject/jtor/connections/ConnectionSocketFactory.java index 0347dcc1..f8f406a9 100644 --- a/src/org/torproject/jtor/connections/ConnectionSocketFactory.java +++ b/src/org/torproject/jtor/connections/ConnectionSocketFactory.java @@ -1,6 +1,13 @@ package org.torproject.jtor.connections; import java.io.IOException; + +import java.lang.reflect.Constructor; + +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketImpl; + import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; @@ -63,9 +70,11 @@ private static SSLContext createSSLContext() { socketFactory = createSSLContext().getSocketFactory(); } - SSLSocket createSocket() { + SSLSocket createSocket(SocketAddress address, int timeout) { try { - final SSLSocket socket = (SSLSocket) socketFactory.createSocket(); + Socket s = createOriginalSocket(); + s.connect(address, timeout); + final SSLSocket socket = (SSLSocket) socketFactory.createSocket(s, null, -1, true); socket.setEnabledCipherSuites(MANDATORY_CIPHERS); socket.setUseClientMode(true); return socket; @@ -73,4 +82,17 @@ SSLSocket createSocket() { throw new TorException(e); } } + + Socket createOriginalSocket() throws IOException { + try { + Class clazz = Class.forName("java.net.SocksSocketImpl"); + Constructor constructor = clazz.getDeclaredConstructor(); + // this maybe does not work because of security restrictions: + constructor.setAccessible(true); + SocketImpl impl = (SocketImpl)constructor.newInstance(); + return new Socket(impl) {}; + } catch (Throwable t) { + throw new IOException("Cannot create original socket", t); + } + } } diff --git a/src/org/torproject/jtor/sockets/JTorSocketImpl.java b/src/org/torproject/jtor/sockets/JTorSocketImpl.java index 9c93b55d..0909a9bc 100644 --- a/src/org/torproject/jtor/sockets/JTorSocketImpl.java +++ b/src/org/torproject/jtor/sockets/JTorSocketImpl.java @@ -28,7 +28,7 @@ public class JTorSocketImpl extends SocketImpl { } public void setOption(int optID, Object value) throws SocketException { - throw new UnsupportedOperationException(); + // don't throw exception here, this is required for original socket } public Object getOption(int optID) throws SocketException {