mirror of
https://github.com/vanitasvitae/Smack.git
synced 2024-11-19 02:22:05 +01:00
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
7 changed files with 124 additions and 1 deletions
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
|||
import java.io.PipedReader;
|
||||
import java.io.PipedWriter;
|
||||
import java.io.Writer;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
@ -314,6 +315,11 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getLocalAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shutdown() {
|
||||
instantShutdown();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
package org.jivesoftware.smack;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
|
@ -160,6 +161,14 @@ public interface XMPPConnection {
|
|||
*/
|
||||
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
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -1128,6 +1129,11 @@ public final class ModularXmppClientToServerConnection extends AbstractXMPPConne
|
|||
walkStateGraph(walkStateGraphContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getLocalAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Map<String, Object> getFilterStats() {
|
||||
Collection<XmppInputOutputFilter> filters;
|
||||
synchronized (this) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.jivesoftware.smack;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Date;
|
||||
import java.util.Random;
|
||||
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
|
||||
* that has not been returned by {@link #getSentPacket()}.
|
||||
|
|
|
@ -656,13 +656,23 @@ public final class Socks5BytestreamManager extends Manager implements Bytestream
|
|||
*/
|
||||
public List<StreamHost> getLocalStreamHost() {
|
||||
// Ensure that the local SOCKS5 proxy is running (if enabled).
|
||||
Socks5Proxy.getSocks5Proxy();
|
||||
Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
|
||||
|
||||
List<StreamHost> streamHosts = new ArrayList<>();
|
||||
|
||||
XMPPConnection connection = connection();
|
||||
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()) {
|
||||
List<InetAddress> addresses = socks5Server.getLocalAddresses();
|
||||
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.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
|
@ -1002,6 +1006,72 @@ public class Socks5ByteStreamManagerTest {
|
|||
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,
|
||||
Verification<Bytestream, Bytestream> streamHostUsedVerification, Socks5TestProxy socks5TestProxy)
|
||||
throws XmppStringprepException {
|
||||
|
|
|
@ -1938,4 +1938,20 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
|
|||
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 a new issue