-
Notifications
You must be signed in to change notification settings - Fork 51
Add support for specifying IP version #332
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -46,6 +46,16 @@ | |||||||||||||
|
|
||||||||||||||
| public class Connection implements AutoCloseable | ||||||||||||||
| { | ||||||||||||||
| /** | ||||||||||||||
| * Allow the caller to restrict the IP version of the connection to | ||||||||||||||
| * be established. | ||||||||||||||
| */ | ||||||||||||||
| public enum IpVersion { | ||||||||||||||
| IPV4_AND_IPV6, ///< Allow both IPV4 and IPv6, the default. | ||||||||||||||
| IPV4_ONLY, ///< Require that the connection be over IPv4 only. | ||||||||||||||
| IPV6_ONLY ///< Require that the connection be over IPv6 only. | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * The identifier presented to the SSH-2 server. | ||||||||||||||
| */ | ||||||||||||||
|
|
@@ -564,30 +574,74 @@ private void close(Throwable t, boolean hard) | |||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Same as | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int) connect(null, 0, 0)}. | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int, IpVersion) connect(null, 0, 0, IpVersion.IPV4_AND_IPV6)}. | ||||||||||||||
| * | ||||||||||||||
| * @return see comments for the | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int, IpVersion) connect(ServerHostKeyVerifier, int, int, IpVersion)} | ||||||||||||||
| * method. | ||||||||||||||
| * @throws IOException | ||||||||||||||
| */ | ||||||||||||||
| public synchronized ConnectionInfo connect() throws IOException | ||||||||||||||
| { | ||||||||||||||
| return connect(null, 0, 0); | ||||||||||||||
| return connect(null, 0, 0, IpVersion.IPV4_AND_IPV6); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Same as | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int, IpVersion) connect(null, 0, 0, ipVersion)}. | ||||||||||||||
| * | ||||||||||||||
| * @return see comments for the | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int, IpVersion) connect(ServerHostKeyVerifier, int, int, IpVersion)} | ||||||||||||||
| * method. | ||||||||||||||
| * @throws IOException | ||||||||||||||
| */ | ||||||||||||||
| public synchronized ConnectionInfo connect(IpVersion ipVersion) throws IOException | ||||||||||||||
| { | ||||||||||||||
| return connect(null, 0, 0, ipVersion); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Same as | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int) connect(verifier, 0, 0)}. | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int, IpVersion) connect(verifier, 0, 0, IpVersion.IPV4_AND_IPV6)}. | ||||||||||||||
| * | ||||||||||||||
| * @return see comments for the | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int, IpVersion) connect(ServerHostKeyVerifier, int, int, IpVersion)} | ||||||||||||||
| * method. | ||||||||||||||
| * @throws IOException | ||||||||||||||
| */ | ||||||||||||||
| public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier) throws IOException | ||||||||||||||
| { | ||||||||||||||
| return connect(verifier, 0, 0); | ||||||||||||||
| return connect(verifier, 0, 0, IpVersion.IPV4_AND_IPV6); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Same as | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int, IpVersion) connect(verifier, 0, 0, ipVersion)}. | ||||||||||||||
| * | ||||||||||||||
| * @return see comments for the | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int, IpVersion) connect(ServerHostKeyVerifier, int, int, IpVersion)} | ||||||||||||||
| * method. | ||||||||||||||
| * @throws IOException | ||||||||||||||
| */ | ||||||||||||||
| public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier, IpVersion ipVersion) throws IOException | ||||||||||||||
| { | ||||||||||||||
| return connect(verifier, 0, 0, ipVersion); | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Same as | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int, IpVersion) connect(verifier, connectTimeout, kexTimeout, IpVersion.IPV4_AND_IPV6)}. | ||||||||||||||
| * | ||||||||||||||
| * @return see comments for the | ||||||||||||||
| * {@link #connect(ServerHostKeyVerifier, int, int, IpVersion) connect(ServerHostKeyVerifier, int, int, IpVersion)} | ||||||||||||||
| * method. | ||||||||||||||
| * @throws IOException | ||||||||||||||
| */ | ||||||||||||||
| public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier, int connectTimeout, int kexTimeout) | ||||||||||||||
| throws IOException | ||||||||||||||
| { | ||||||||||||||
| return connect(verifier, connectTimeout, kexTimeout, IpVersion.IPV4_AND_IPV6); | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+598
to
645
|
||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
|
|
@@ -649,6 +703,11 @@ public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier) throw | |||||||||||||
| * but it will only have an effect after the | ||||||||||||||
| * <code>verifier</code> returns. | ||||||||||||||
| * | ||||||||||||||
| * @param ipVersion | ||||||||||||||
| * Specify whether the connection should be restricted to one of | ||||||||||||||
| * IPv4 or IPv6, with a default of allowing both. See | ||||||||||||||
| * {@link IpVersion}. | ||||||||||||||
|
||||||||||||||
| * {@link IpVersion}. | |
| * {@link IpVersion}. <b>Note:</b> This parameter is ignored if a proxy connection is used | |
| * (i.e., if {@link #setProxyData(ProxyData)} has been called); in that case, the proxy | |
| * determines the IP version used for the connection. |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing input validation: The ipVersion parameter is not validated for null. If a caller passes null for ipVersion, the code will fail with a NullPointerException at line 808. Consider adding a null check and either throwing an IllegalArgumentException with a clear message or defaulting to IPV4_AND_IPV6.
| TransportManager.IpVersion tmIpVersion; | |
| TransportManager.IpVersion tmIpVersion; | |
| // Default to IPV4_AND_IPV6 if ipVersion is null | |
| if (ipVersion == null) { | |
| ipVersion = IpVersion.IPV4_AND_IPV6; | |
| } |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate enum definition: The IpVersion enum is defined identically in both Connection and TransportManager classes. This violates the DRY principle and creates a maintenance burden. Consider defining the enum once in a shared location (e.g., in Connection as the public API) and having TransportManager reference it directly, or create a shared constants class. The current approach requires maintaining two identical enums and manual conversion code (lines 807-818).
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |||||||||||||||||||||||||||||||
| import com.trilead.ssh2.ExtensionInfo; | ||||||||||||||||||||||||||||||||
| import com.trilead.ssh2.packets.PacketExtInfo; | ||||||||||||||||||||||||||||||||
| import java.io.IOException; | ||||||||||||||||||||||||||||||||
| import java.net.Inet6Address; | ||||||||||||||||||||||||||||||||
| import java.net.InetAddress; | ||||||||||||||||||||||||||||||||
| import java.net.InetSocketAddress; | ||||||||||||||||||||||||||||||||
| import java.net.Socket; | ||||||||||||||||||||||||||||||||
|
|
@@ -49,6 +50,16 @@ | |||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||
| public class TransportManager | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||
| * Allow the caller to restrict the IP version of the connection to | ||||||||||||||||||||||||||||||||
| * be established. | ||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||
| public enum IpVersion { | ||||||||||||||||||||||||||||||||
| IPV4_AND_IPV6, ///< Allow both IPV4 and IPv6, the default. | ||||||||||||||||||||||||||||||||
| IPV4_ONLY, ///< Require that the connection be over IPv4 only. | ||||||||||||||||||||||||||||||||
| IPV6_ONLY ///< Require that the connection be over IPv6 only. | ||||||||||||||||||||||||||||||||
|
Comment on lines
+58
to
+60
|
||||||||||||||||||||||||||||||||
| IPV4_AND_IPV6, ///< Allow both IPV4 and IPv6, the default. | |
| IPV4_ONLY, ///< Require that the connection be over IPv4 only. | |
| IPV6_ONLY ///< Require that the connection be over IPv6 only. | |
| /** | |
| * Allow both IPV4 and IPv6, the default. | |
| */ | |
| IPV4_AND_IPV6, | |
| /** | |
| * Require that the connection be over IPv4 only. | |
| */ | |
| IPV4_ONLY, | |
| /** | |
| * Require that the connection be over IPv6 only. | |
| */ | |
| IPV6_ONLY |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing input validation: The ipVersion parameter is not validated for null. If a caller passes null for ipVersion, the code will fail with a NullPointerException at line 309. Consider adding a null check and either throwing an IllegalArgumentException with a clear message or defaulting to IPV4_AND_IPV6.
| { | |
| { | |
| if (ipVersion == null) { | |
| ipVersion = IpVersion.IPV4_AND_IPV6; | |
| } |
Copilot
AI
Dec 16, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Null pointer exception risk: When ipVersion is IPV4_ONLY or IPV6_ONLY, getIPv4Address or getIPv6Address may return null if the hostname doesn't resolve to that IP version. The null address will cause a NullPointerException when passed to InetSocketAddress constructor. Add null check and throw an IOException with a clear error message explaining that the hostname doesn't resolve to the requested IP version.
| } | |
| } | |
| if (addr == null) { | |
| throw new IOException("The hostname '" + hostname + "' does not resolve to the requested IP version: " + ipVersion); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C-style comments are not idiomatic in Java. The codebase uses Javadoc-style comments (/** ... */) for documentation. These inline comments after enum values should either be removed or converted to proper Javadoc comments above each enum value, following the pattern used elsewhere in the codebase for documenting class members.