1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2025-09-09 00:59:39 +02: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:
Florian Schmaus 2023-04-26 11:35:04 +00:00 committed by GitHub
commit 19b20fefec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 124 additions and 1 deletions

View file

@ -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()) {

View file

@ -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 {