apache / mina-sshd

Apache MINA sshd is a comprehensive Java library for client- and server-side SSH.
https://mina.apache.org/sshd-project/
Apache License 2.0
881 stars 358 forks source link

proxy jump failure in mina sshd 2.13.2 #609

Open lawmin2021 opened 5 hours ago

lawmin2021 commented 5 hours ago

Version

2.13.2

Bug description

the mina sshd 2.13.2 has problem to parse follow code:

private ClientSession getSessionUsingJumpHost( SshClient sshClient, CommandObject commandObject) throws OcmdException, IOException { String hostName = commandObject.getNode(); String user = commandObject.getUser(); int port = Constants.getSSHPort();

// configure the bastion entry
HostConfigEntry bastion = new HostConfigEntry();
bastion.setHost(Constants.getTunnelHost());
bastion.setHostName(Constants.getTunnelHost());
bastion.setUsername(Constants.getTunnelHostUser());
bastion.setPort(port);
bastion.setIdentities(
  Collections.singleton(Constants.getTunnelHostUserKey()));

// configure the generate target entry
HostConfigEntry targetHost = new HostConfigEntry();
targetHost.setHost("*"); // for all include hostname/ip
targetHost.setProxyJump(Constants.getTunnelHost());

HostConfigEntryResolver resolver =
  HostConfigEntry.toHostConfigEntryResolver(
    GenericUtils.asList(bastion, targetHost));

sshClient.setHostConfigEntryResolver(resolver);

// enable the public auth
sshClient.setUserAuthFactories( Collections.unmodifiableList(
  Arrays.asList(
    UserAuthPublicKeyFactory.INSTANCE,
    UserAuthPasswordFactory.INSTANCE,
    UserAuthKeyboardInteractiveFactory.INSTANCE
  )));

// now try to connect using proxy
try
{
  ClientSession session = sshClient.connect(user, hostName, port)
    .verify(sessionConnectTimeout)
    .getSession();
  return session;
}
catch (Exception ex)
{
  throw  ex;
}

}

above code work in mina sshd 2.12.1.

Actual behavior

The Mina SSHD code in SshClient.parseProxyJumps(HostConfigEntry entry, AttributeRepository context) method has an issue with identifying the variable "additionalHops" , and it causes the list object "hops" continuously grow to the maximum limit of 10, and then throw the IlllegalArgumentException. issue1 issue2

please check the attached debug images

Expected behavior

I think in SshClient.parseProxyJumps() need to check if the return values of "additionalHops" is already in the "hops", it need to stop and return without throw exception

Relevant log output

No response

Other information

No response

lawmin2021 commented 2 hours ago

I made the following change to pass my case, hope it work for GH-318 Handle cascaded proxy jumps

protected List parseProxyJumps(HostConfigEntry entry, AttributeRepository context) throws IOException { List hops; try { hops = parseProxyJumps(entry.getProxyJump(), context); if (GenericUtils.isEmpty(hops)) { return hops; } // If the last entry itself has proxy jumps, we need to append them. Guard against possible proxy jump // loops by imposing an upper limit on the total number of jumps. for (;;) { HostConfigEntry last = hops.get(hops.size() - 1); try { List additionalHops = parseProxyJumps(last.getProxyJump(), context); if (additionalHops.isEmpty()) { break; } else { boolean isFound = false; for (HostConfigEntry checkAddHop : additionalHops) { for (HostConfigEntry checkHop : hops) { String fullHopStr = checkHop.toString(); String fullAddHopStr = checkAddHop.toString(); if (fullHopStr.equals(fullAddHopStr)) { isFound = true; break; } } if (!isFound) { hops.add(checkAddHop); }

                    }

                    if (isFound) {
                        return hops;
                    }

                    if (hops.size() > CoreModuleProperties.MAX_PROXY_JUMPS.getRequired(this)) {
                        throw new IllegalArgumentException("Too many proxy jumps for host " + entry.getHost());
                    }
                }
            } catch (IOException | RuntimeException e) {
                throw new IllegalArgumentException("Problem parsing proxyJump from host config " + last.getHost(), e);
            }
        }
    } catch (IOException | RuntimeException e) {
        throw new IllegalArgumentException("Problem parsing proxyJump from host config " + entry.getHost(), e);
    }
    return hops;
}