Skip to content

Commit 4a8dc75

Browse files
committed
Add a way to get the connection addresses
The local and remote socket address is used for tracking connectivity in ConnectBot.
1 parent 8240abf commit 4a8dc75

6 files changed

Lines changed: 123 additions & 5 deletions

File tree

src/main/java/com/trilead/ssh2/Connection.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,34 @@ public synchronized ConnectionInfo getConnectionInfo() throws IOException
10751075
return tm.getConnectionInfo(1);
10761076
}
10771077

1078+
/**
1079+
* Returns the local address to which the socket is bound.
1080+
*
1081+
* @return the local address to which the socket is bound.
1082+
* @throws IOException
1083+
* in case of any problem.
1084+
*/
1085+
public synchronized InetSocketAddress getLocalSocketAddress() throws IOException
1086+
{
1087+
if (tm == null)
1088+
throw new IllegalStateException("You need to establish a connection first.");
1089+
return tm.getLocalSocketAddress();
1090+
}
1091+
1092+
/**
1093+
* Returns the address of the endpoint this socket is connected to.
1094+
*
1095+
* @return the address of the endpoint this socket is connected to.
1096+
* @throws IOException
1097+
* in case of any problem.
1098+
*/
1099+
public synchronized InetSocketAddress getRemoteSocketAddress() throws IOException
1100+
{
1101+
if (tm == null)
1102+
throw new IllegalStateException("You need to establish a connection first.");
1103+
return tm.getRemoteSocketAddress();
1104+
}
1105+
10781106
/**
10791107
* After a successful connect, one has to authenticate oneself. This method
10801108
* can be used to tell which authentication methods are supported by the

src/main/java/com/trilead/ssh2/ConnectionInfo.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
package com.trilead.ssh2;
33

4+
import java.net.InetSocketAddress;
5+
46
/**
57
* In most cases you probably do not need the information contained in here.
68
*
@@ -9,6 +11,16 @@
911
*/
1012
public class ConnectionInfo
1113
{
14+
/**
15+
* The address of the local socket.
16+
*/
17+
public InetSocketAddress localSocketAddress;
18+
19+
/**
20+
* The address of the remote socket.
21+
*/
22+
public InetSocketAddress remoteSocketAddress;
23+
1224
/**
1325
* The used key exchange (KEX) algorithm in the latest key exchange.
1426
*/

src/main/java/com/trilead/ssh2/transport/KexManager.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,16 @@ public synchronized void handleMessage(byte[] msg, int msglen) throws IOExceptio
729729

730730
ConnectionInfo sci = new ConnectionInfo();
731731

732+
try
733+
{
734+
sci.localSocketAddress = tm.getLocalSocketAddress();
735+
sci.remoteSocketAddress = tm.getRemoteSocketAddress();
736+
}
737+
catch (IOException e)
738+
{
739+
/* Ignore, if the connection is closed then it doesn't matter much anyway */
740+
}
741+
732742
kexCount++;
733743

734744
sci.keyExchangeAlgorithm = kxs.np.kex_algo;

src/main/java/com/trilead/ssh2/transport/TransportManager.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.trilead.ssh2.ExtensionInfo;
55
import com.trilead.ssh2.packets.PacketExtInfo;
66
import java.io.IOException;
7+
import java.net.InetSocketAddress;
78
import java.net.Socket;
89
import java.security.SecureRandom;
910
import java.util.Vector;
@@ -184,6 +185,26 @@ public int getPort()
184185
return port;
185186
}
186187

188+
public InetSocketAddress getLocalSocketAddress() throws IOException
189+
{
190+
synchronized (connectionSemaphore)
191+
{
192+
if (sock == null)
193+
throw new IOException("The connection is closed.");
194+
return (InetSocketAddress) sock.getLocalSocketAddress();
195+
}
196+
}
197+
198+
public InetSocketAddress getRemoteSocketAddress() throws IOException
199+
{
200+
synchronized (connectionSemaphore)
201+
{
202+
if (sock == null)
203+
throw new IOException("The connection is closed.");
204+
return (InetSocketAddress) sock.getRemoteSocketAddress();
205+
}
206+
}
207+
187208
public ServerHostKeyVerifier getServerHostKeyVerifier()
188209
{
189210
return km != null ? km.getServerHostKeyVerifier() : null;

src/test/java/com/trilead/ssh2/ConnectionTest.java

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,36 @@ public void testSetSecureRandomWithNull() {
149149
@Test
150150
public void testGetConnectionInfoThrowsWhenNotConnected() {
151151
try {
152-
connection.getConnectionInfo();
153-
fail("Should throw IllegalStateException when not connected");
152+
connection.getConnectionInfo();
153+
fail("Should throw IllegalStateException when not connected");
154154
} catch (IllegalStateException e) {
155-
assertTrue(e.getMessage().contains("establish a connection first"), "Exception message should indicate connection required");
155+
assertTrue(e.getMessage().contains("establish a connection first"), "Exception message should indicate connection required");
156156
} catch (Exception e) {
157-
fail("Should throw IllegalStateException, got: " +
158-
e.getClass().getSimpleName());
157+
fail("Should throw IllegalStateException, got: " + e.getClass().getSimpleName());
158+
}
159+
}
160+
161+
@Test
162+
public void testGetLocalSocketAddressThrowsWhenNotConnected() {
163+
try {
164+
connection.getLocalSocketAddress();
165+
fail("Should throw IllegalStateException when not connected");
166+
} catch (IllegalStateException e) {
167+
assertTrue(e.getMessage().contains("establish a connection first"), "Exception message should indicate connection required");
168+
} catch (Exception e) {
169+
fail("Should throw IllegalStateException, got: " + e.getClass().getSimpleName());
170+
}
171+
}
172+
173+
@Test
174+
public void testGetRemoteSocketAddressThrowsWhenNotConnected() {
175+
try {
176+
connection.getRemoteSocketAddress();
177+
fail("Should throw IllegalStateException when not connected");
178+
} catch (IllegalStateException e) {
179+
assertTrue(e.getMessage().contains("establish a connection first"), "Exception message should indicate connection required");
180+
} catch (Exception e) {
181+
fail("Should throw IllegalStateException, got: " + e.getClass().getSimpleName());
159182
}
160183
}
161184

src/test/java/com/trilead/ssh2/OpenSSHCompatibilityTest.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
import org.testcontainers.images.builder.ImageFromDockerfile;
1616

1717
import java.io.IOException;
18+
import java.net.InetSocketAddress;
1819

1920
import com.trilead.ssh2.crypto.Base64;
2021

2122
import static org.hamcrest.CoreMatchers.is;
23+
import static org.hamcrest.CoreMatchers.notNullValue;
2224
import static org.hamcrest.MatcherAssert.assertThat;
2325

2426
/**
@@ -101,6 +103,28 @@ private void canConnectWithPubkey(String keyFilename) throws Exception {
101103
}
102104
}
103105

106+
@Test
107+
public void testSocketAddress() throws IOException {
108+
try (GenericContainer<?> server = getBaseContainer()) {
109+
server.start();
110+
try (Connection c = withServer(server)) {
111+
c.connect(verifier);
112+
113+
InetSocketAddress local = c.getLocalSocketAddress();
114+
InetSocketAddress remote = c.getRemoteSocketAddress();
115+
116+
assertThat(local, notNullValue());
117+
assertThat(remote, notNullValue());
118+
assertThat(remote.getHostString(), is(server.getHost()));
119+
assertThat(remote.getPort(), is(server.getMappedPort(22)));
120+
121+
ConnectionInfo info = c.getConnectionInfo();
122+
assertThat(info.localSocketAddress.toString(), is(local.toString()));
123+
assertThat(info.remoteSocketAddress.toString(), is(remote.toString()));
124+
}
125+
}
126+
}
127+
104128
@Test
105129
public void canConnectWithEd25519() throws Exception {
106130
canConnectWithPubkey("ed25519-openssh2-private-key.txt");

0 commit comments

Comments
 (0)