diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index 49494dda86..7470f1d3d0 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt @@ -1672,6 +1672,24 @@ of them. + By default, *:29418. +[[sshd.advertisedAddress]]sshd.advertisedAddress:: ++ +Specifies the addresses clients should be told to connect to. +This may differ from sshd.listenAddress if a firewall based port +redirector is being used, making Gerrit appear to answer on port +22. The following forms may be used to specify an address. In any +form, `:'port'` may be omitted to use the default SSH port of 22. ++ +* 'hostname':'port' (for example `review.example.com:22`) +* 'IPv4':'port' (for example `10.0.0.1:29418`) +* ['IPv6']:'port' (for example `[ff02::1]:29418`) + ++ +If multiple values are supplied, the daemon will advertise all +of them. ++ +By default, sshd.listenAddress. + [[sshd.reuseAddress]]sshd.reuseAddress:: + If true, permits the daemon to bind to the port even if the port diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java index 2052343b29..fe9d9eb153 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshDaemon.java @@ -120,6 +120,7 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener { private static final Logger log = LoggerFactory.getLogger(SshDaemon.class); private final List listen; + private final List advertisedAddress; private final boolean keepAlive; private final List hostKeys; private volatile IoAcceptor acceptor; @@ -132,6 +133,7 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener { setPort(IANA_SSH_PORT /* never used */); listen = parseListen(cfg); + advertisedAddress = parseAdvertisedAddress(cfg); reuseAddress = cfg.getBoolean("sshd", "reuseaddress", true); keepAlive = cfg.getBoolean("sshd", "tcpkeepalive", true); @@ -262,9 +264,9 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener { buf.putRawPublicKey(pub); final byte[] keyBin = buf.getCompactData(); - for (final InetSocketAddress addr : myAddresses()) { + for (final String addr : myAdvertisedAddresses()) { try { - r.add(new HostKey(SocketUtil.format(addr, IANA_SSH_PORT), keyBin)); + r.add(new HostKey(addr, keyBin)); } catch (JSchException e) { log.warn("Cannot format SSHD host key", e); } @@ -273,6 +275,19 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener { return Collections.unmodifiableList(r); } + private List myAdvertisedAddresses() { + if (advertisedAddress != null) { + return advertisedAddress; + } else { + List addrs = myAddresses(); + List strAddrs = new ArrayList(addrs.size()); + for (final InetSocketAddress addr : addrs) { + strAddrs.add(SocketUtil.format(addr, IANA_SSH_PORT)); + } + return strAddrs; + } + } + private List myAddresses() { ArrayList pub = new ArrayList(); ArrayList local = new ArrayList(); @@ -317,6 +332,14 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener { return r.toString(); } + private List parseAdvertisedAddress(final Config cfg) { + final String[] want = cfg.getStringList("sshd", null, "advertisedaddress"); + if (want.length == 0) { + return null; + } + return Arrays.asList(want); + } + private List parseListen(final Config cfg) { final ArrayList bind = new ArrayList(2); final String[] want = cfg.getStringList("sshd", null, "listenaddress");