fix(ssh): linear host-pattern matching, per-hop forwarding gates, loopback remote forwards
- known_hosts: the @cert-authority pattern matcher was recursive and backtracking; a pattern of a few hundred thousand stars overflowed the connect thread's stack on every handshake and '*a*a*a…b' went exponential. It is now the iterative two-pointer match, and patterns over 1 KiB are refused on import and in Trust a CA. - Agent-forward and remote-forward channels are only honoured on the final hop: a jump host could previously open auth-agent channels and reach remote-forward destinations on the client machine. - Remote forwards with no bind address listen on the server's loopback (as ssh -R does) instead of every interface. - Keyboard-interactive gives up after 10 rounds; dials through jump hosts and run_command have timeouts; the handshake timeout leaves room for the host-key prompt so a slow reader isn't timed out mid-decision. - Known hosts are looked up per key type, so an imported known_hosts with ed25519 and RSA rows no longer produces a false 'key changed' warning. - SFTP download suggests a sanitised base name in the save dialog.
This commit is contained in:
@@ -108,7 +108,7 @@ impl Manager {
|
||||
pub fn host_key_check(self: &Arc<Self>, session: &str, policy: HostKeyPolicy) -> HostKeyCheck {
|
||||
let (me, sid) = (self.clone(), session.to_string());
|
||||
Arc::new(move |k: &HostKeyInfo| {
|
||||
let stored = me.store.get_known_host(&k.host, k.port as i64).map_err(|e| format!("failed to query known hosts: {e}"))?;
|
||||
let stored = me.store.get_known_host(&k.host, k.port as i64, &k.key_type).map_err(|e| format!("failed to query known hosts: {e}"))?;
|
||||
let save = || {
|
||||
let n = now();
|
||||
me.store
|
||||
|
||||
@@ -873,7 +873,7 @@ mod tests {
|
||||
}
|
||||
}));
|
||||
let info = |fp: &str| HostKeyInfo { host: "h".into(), port: 22, key_type: "ssh-ed25519".into(), fingerprint: fp.into(), public_key_b64: "AAAA".into() };
|
||||
let stored = |m: &Manager| m.store.get_known_host("h", 22).unwrap().map(|k| k.fingerprint);
|
||||
let stored = |m: &Manager| m.store.get_known_host("h", 22, "ssh-ed25519").unwrap().map(|k| k.fingerprint);
|
||||
// Unknown key: accept once records nothing; accept & save records it.
|
||||
let check = m.host_key_check("s", HostKeyPolicy::Ask);
|
||||
answers.lock().push(HostKeyDecision::AcceptOnce);
|
||||
|
||||
Reference in New Issue
Block a user