ronf / asyncssh

AsyncSSH is a Python package which provides an asynchronous client and server implementation of the SSHv2 protocol on top of the Python asyncio framework.
Eclipse Public License 2.0
1.51k stars 146 forks source link

TypeError: getnameinfo() argument 1 must be a tuple #563

Closed yuqingm7 closed 1 year ago

yuqingm7 commented 1 year ago

Hi experts!

I'm using asyncssh to connect to remote hosts via proxy, which gives me the Connection failure: getnameinfo() argument 1 must be a tuple.

Dug a little, the failure comes from host_based_auth piece. The stacktrace is

2023-04-24 15:44:47,422:INFO:asyncssh: [conn=0] Connected to SSH server at <IP>, port 22
2023-04-24 15:44:47,423:INFO:asyncssh: [conn=0]   Proxy command: <SOME_PROXY_COMMAND>
2023-04-24 15:44:47,423:DEBUG:asyncssh: [conn=0] Sending version SSH-2.0-AsyncSSH_2.12.0
2023-04-24 15:44:48,355:DEBUG:asyncssh: [conn=0] Received version SSH-2.0-OpenSSH_7.4
2023-04-24 15:44:48,356:DEBUG:asyncssh: [conn=0] Requesting key exchange
2023-04-24 15:44:48,381:DEBUG:asyncssh: [conn=0] Received key exchange request
2023-04-24 15:44:48,383:DEBUG:asyncssh: [conn=0] Beginning key exchange
2023-04-24 15:44:48,407:DEBUG:asyncssh: [conn=0] Completed key exchange
2023-04-24 15:44:48,423:INFO:asyncssh: [conn=0] Beginning auth for user
2023-04-24 15:44:48,440:DEBUG:asyncssh: [conn=0] Uncaught exception
Traceback (most recent call last):
  File "/mnt/xarfuse/uid-179052/958becd3-seed-nspid4026531836_cgpid68747028-ns-4026531840/asyncssh/connection.py", line 1046, in _reap_task
    task.result()
  File "/mnt/xarfuse/uid-179052/958becd3-seed-nspid4026531836_cgpid68747028-ns-4026531840/asyncssh/auth.py", line 294, in _start
    await self._conn.host_based_auth_requested()
  File "/mnt/xarfuse/uid-179052/958becd3-seed-nspid4026531836_cgpid68747028-ns-4026531840/asyncssh/connection.py", line 3333, in host_based_auth_requested
    client_host, _ = await self._loop.getnameinfo(
  File "uvloop/loop.pyx", line 1525, in getnameinfo
TypeError: getnameinfo() argument 1 must be a tuple
2023-04-24 15:44:48,445:INFO:asyncssh: [conn=0] Connection failure: getnameinfo() argument 1 must be a tuple
2023-04-24 15:44:48,445:INFO:asyncssh: [conn=0] Aborting connection 

Dug a bit deeper, this is caused by the fact that self.get_extra_info('sockname') returns None.

Wondering if anyone could help me debug this issue. Thanks a lot!

ronf commented 1 year ago

First, just to confirm, did you want to be using host-based auth here? That's a relatively rarely used feature compared to username/password or public key based auth.

The problem seems to occur when it is trying to determine a client hostname to use. I'm not sure why the sockaddr wouldn't have been set by the time auth begins. That should be set by the asyncio code when the connection is made. Is there anything unusual about how you are opening the TCP connection? Are you letting asyncssh.connect() do this, or are you trying to do something with a jump host or proxy command?

If needed, you can specify the client host explicitly using the client_host argument when you connect. You'll need this to be set to something that the remote system would recognize and trust. If you do that, it shouldn't need to get the client_host from the sockname. You just need to make sure the client host is something the remote system recognizes and trusts.

ronf commented 1 year ago

I just noticed you said "via proxy" above. Could you say a bit more about what kind of proxy you are using? I suspect that's the problem -- if the sockname information isn't being filled in, you'd see the problem you reported here.

yuqingm7 commented 1 year ago

Hi @ronf!

Thank you for your quick response!

did you want to be using host-based auth here? That's a relatively rarely used feature compared to username/password or public key based auth.

This is a good question! Yeah, publickey based and pwd based auth are heavily used. HostbasedAuthentication is configured on server side in sshd_config. We could probably enforce password based authentication in the future for this machine, but still I'd love to understand why this error happens.

Could you say a bit more about what kind of proxy you are using?

The proxy itself is an internal tool provided by other folks. I don't really have a deep understanding other than it supports HTTP/HTTPs/SOCKS proxy. The code snippet is

options = asyncssh.SSHClientConnectionOptions(
      client_factory=lambda: _SSHClient(self),
      username=username,
      password=self.pw if self.pw else None,
      client_keys=[(privkey, cert)] if not self.pw else None,
      known_hosts=None,
      x509_trusted_certs=None,
      proxy_command=proxy_command,
 )
self.conn = await asyncio.wait_for(
     asyncssh.connect(
             host=self.hostip if self.hostip else self.host,
             port=self.port,
             options=options,
     ),
            timeout=conn_timeout,
 )

If I use ssh -o "ProxyCommand=<proxy_cmd>" hostname, it prompts for password. I can log into the machine with the password. So I'm a bit curious if it makes sense in asyncssh to at least catch the exceptions raised in host-based authN part and try other preferred authN methods. Thanks a lot!

ronf commented 1 year ago

Yeah - I should probably automatically disable host-based auth when the connection doesn't have 'sockname' available, such as in the case where proxy_command is used and AsyncSSH can only see a pipe to the proxy process rather than a TCP socket it can query the address of, unless client_host is set manually by the caller. I'll look into this.

As a workaround for now, you should be able to explicitly set host_based_auth=False in your asyncssh.connect() call or when creating theSSHClientConnectionOptions. You should only need this if you were on a system where client host keys were available.

Thanks for the report!

ronf commented 1 year ago

I have a potential fix for this in commit 1469ac9 in the "develop" branch, if you'd like to give it a try.

yuqingm7 commented 1 year ago

Hi @ronf, thank you so much for your quick fix. Yeah, we're planning to go with host_based_auth=False or preferred_auth="keyboard-interactive" for now. Thanks!

ronf commented 1 year ago

Happy to help!

ronf commented 1 year ago

The fix mentioned here is now available in AsyncSSH 2.13.2.