Merge pull request #537 from MF1-MS/mf1-ms/use_xmpp_connection_as_local_socks5_address
Use XMPP connection as local socks5 address
This commit is contained in:
commit
19b20fefec
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
||||||
import java.io.PipedReader;
|
import java.io.PipedReader;
|
||||||
import java.io.PipedWriter;
|
import java.io.PipedWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
@ -314,6 +315,11 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetAddress getLocalAddress() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void shutdown() {
|
protected void shutdown() {
|
||||||
instantShutdown();
|
instantShutdown();
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jivesoftware.smack;
|
package org.jivesoftware.smack;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.xml.namespace.QName;
|
import javax.xml.namespace.QName;
|
||||||
|
@ -160,6 +161,14 @@ public interface XMPPConnection {
|
||||||
*/
|
*/
|
||||||
EntityFullJid getUser();
|
EntityFullJid getUser();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the local address currently in use for this connection, or <code>null</code> if
|
||||||
|
* this is invalid for the type of underlying connection.
|
||||||
|
*
|
||||||
|
* @return the local address currently in use for this connection
|
||||||
|
*/
|
||||||
|
InetAddress getLocalAddress();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the stream ID for this connection, which is the value set by the server
|
* Returns the stream ID for this connection, which is the value set by the server
|
||||||
* when opening an XMPP stream. This value will be <code>null</code> if not connected to the server.
|
* when opening an XMPP stream. This value will be <code>null</code> if not connected to the server.
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.jivesoftware.smack.c2s;
|
package org.jivesoftware.smack.c2s;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -1128,6 +1129,11 @@ public final class ModularXmppClientToServerConnection extends AbstractXMPPConne
|
||||||
walkStateGraph(walkStateGraphContext);
|
walkStateGraph(walkStateGraphContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetAddress getLocalAddress() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, Object> getFilterStats() {
|
private Map<String, Object> getFilterStats() {
|
||||||
Collection<XmppInputOutputFilter> filters;
|
Collection<XmppInputOutputFilter> filters;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.jivesoftware.smack;
|
package org.jivesoftware.smack;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
@ -139,6 +140,11 @@ public class DummyConnection extends AbstractXMPPConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InetAddress getLocalAddress() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of packets that's sent through {@link #sendStanza(Stanza)} and
|
* Returns the number of packets that's sent through {@link #sendStanza(Stanza)} and
|
||||||
* that has not been returned by {@link #getSentPacket()}.
|
* that has not been returned by {@link #getSentPacket()}.
|
||||||
|
|
|
@ -656,13 +656,23 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream
|
||||||
*/
|
*/
|
||||||
public List<StreamHost> getLocalStreamHost() {
|
public List<StreamHost> getLocalStreamHost() {
|
||||||
// Ensure that the local SOCKS5 proxy is running (if enabled).
|
// Ensure that the local SOCKS5 proxy is running (if enabled).
|
||||||
Socks5Proxy.getSocks5Proxy();
|
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
|
||||||
|
|
||||||
List<StreamHost> streamHosts = new ArrayList<>();
|
List<StreamHost> streamHosts = new ArrayList<>();
|
||||||
|
|
||||||
XMPPConnection connection = connection();
|
XMPPConnection connection = connection();
|
||||||
EntityFullJid myJid = connection.getUser();
|
EntityFullJid myJid = connection.getUser();
|
||||||
|
|
||||||
|
// The default local address is often just 'the first address found in the
|
||||||
|
// list of addresses read from the OS' and this might mean an internal
|
||||||
|
// IP address that cannot reach external servers. So wherever possible
|
||||||
|
// use the same IP address being used to connect to the XMPP server
|
||||||
|
// because this local address has a better chance of being suitable.
|
||||||
|
InetAddress xmppLocalAddress = connection.getLocalAddress();
|
||||||
|
if (xmppLocalAddress != null) {
|
||||||
|
socks5Proxy.replaceLocalAddresses(Collections.singletonList(xmppLocalAddress));
|
||||||
|
}
|
||||||
|
|
||||||
for (Socks5Proxy socks5Server : Socks5Proxy.getRunningProxies()) {
|
for (Socks5Proxy socks5Server : Socks5Proxy.getRunningProxies()) {
|
||||||
List<InetAddress> addresses = socks5Server.getLocalAddresses();
|
List<InetAddress> addresses = socks5Server.getLocalAddresses();
|
||||||
if (addresses.isEmpty()) {
|
if (addresses.isEmpty()) {
|
||||||
|
|
|
@ -24,12 +24,16 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.net.Inet4Address;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
@ -1002,6 +1006,72 @@ public class Socks5ByteStreamManagerTest {
|
||||||
protocol.verifyAll();
|
protocol.verifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoking {@link Socks5BytestreamManager#getLocalStreamHost()} should return only a local address
|
||||||
|
* from XMPP connection when it is connected and has a socket with a bound non-localhost IP address.
|
||||||
|
*
|
||||||
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
|
* @throws SmackException if Smack detected an exceptional situation.
|
||||||
|
* @throws XMPPErrorException if an XMPP protocol error was received.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldUseXMPPConnectionLocalAddressWhenConnected() throws InterruptedException, XMPPErrorException, SmackException {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
|
||||||
|
// prepare XMPP local address
|
||||||
|
Inet4Address xmppLocalAddress = mock(Inet4Address.class);
|
||||||
|
when(xmppLocalAddress.getHostAddress()).thenReturn("81.72.63.54");
|
||||||
|
when(connection.getLocalAddress()).thenReturn(xmppLocalAddress);
|
||||||
|
|
||||||
|
// get Socks5ByteStreamManager for connection
|
||||||
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
|
||||||
|
List<StreamHost> localStreamHost = byteStreamManager.getLocalStreamHost();
|
||||||
|
|
||||||
|
// must be only 1 stream host with XMPP local address IP
|
||||||
|
assertEquals(1, localStreamHost.size());
|
||||||
|
assertEquals("81.72.63.54", localStreamHost.get(0).getAddress().toString());
|
||||||
|
assertEquals(initiatorJID, localStreamHost.get(0).getJID());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoking {@link Socks5BytestreamManager#getLocalStreamHost()} should return all non-localhost
|
||||||
|
* local addresses when its XMPP connection's socket is null.
|
||||||
|
*
|
||||||
|
* @throws InterruptedException if the calling thread was interrupted.
|
||||||
|
* @throws SmackException if Smack detected an exceptional situation.
|
||||||
|
* @throws XMPPErrorException if an XMPP protocol error was received.
|
||||||
|
* @throws UnknownHostException if address cannot be resolved.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void shouldUseSocks5LocalAddressesWhenNotConnected() throws InterruptedException, XMPPErrorException, SmackException, UnknownHostException {
|
||||||
|
final Protocol protocol = new Protocol();
|
||||||
|
final XMPPConnection connection = ConnectionUtils.createMockedConnection(protocol, initiatorJID);
|
||||||
|
|
||||||
|
// No XMPP local address
|
||||||
|
when(connection.getLocalAddress()).thenReturn(null);
|
||||||
|
|
||||||
|
// get Socks5ByteStreamManager for connection
|
||||||
|
Socks5BytestreamManager byteStreamManager = Socks5BytestreamManager.getBytestreamManager(connection);
|
||||||
|
|
||||||
|
List<InetAddress> localAddresses = new ArrayList<>();
|
||||||
|
for (InetAddress inetAddress : Socks5Proxy.getSocks5Proxy().getLocalAddresses()) {
|
||||||
|
if (!inetAddress.isLoopbackAddress()) {
|
||||||
|
localAddresses.add(inetAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<StreamHost> localStreamHost = byteStreamManager.getLocalStreamHost();
|
||||||
|
|
||||||
|
// Must be the same addresses as in SOCKS5 proxy local address list (excluding loopback)
|
||||||
|
assertEquals(localAddresses.size(), localStreamHost.size());
|
||||||
|
for (StreamHost streamHost : localStreamHost) {
|
||||||
|
assertTrue(localAddresses.contains(streamHost.getAddress().asInetAddress()));
|
||||||
|
assertEquals(initiatorJID, streamHost.getJID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void createResponses(Protocol protocol, String sessionID,
|
private static void createResponses(Protocol protocol, String sessionID,
|
||||||
Verification<Bytestream, Bytestream> streamHostUsedVerification, Socks5TestProxy socks5TestProxy)
|
Verification<Bytestream, Bytestream> streamHostUsedVerification, Socks5TestProxy socks5TestProxy)
|
||||||
throws XmppStringprepException {
|
throws XmppStringprepException {
|
||||||
|
|
|
@ -1938,4 +1938,20 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
||||||
this.bundleAndDeferCallback = bundleAndDeferCallback;
|
this.bundleAndDeferCallback = bundleAndDeferCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the local address currently in use for this connection.
|
||||||
|
*
|
||||||
|
* @return the local address
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public InetAddress getLocalAddress() {
|
||||||
|
final Socket socket = this.socket;
|
||||||
|
if (socket == null) return null;
|
||||||
|
|
||||||
|
InetAddress localAddress = socket.getLocalAddress();
|
||||||
|
if (localAddress.isAnyLocalAddress()) return null;
|
||||||
|
|
||||||
|
return localAddress;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue