diff options
Diffstat (limited to 'paramiko/config.py')
-rw-r--r-- | paramiko/config.py | 145 |
1 files changed, 70 insertions, 75 deletions
diff --git a/paramiko/config.py b/paramiko/config.py index 1705de7..77fa13d 100644 --- a/paramiko/config.py +++ b/paramiko/config.py @@ -18,7 +18,7 @@ # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. """ -L{SSHConfig}. +Configuration file (aka ``ssh_config``) support. """ import fnmatch @@ -30,69 +30,15 @@ SSH_PORT = 22 proxy_re = re.compile(r"^(proxycommand)\s*=*\s*(.*)", re.I) -class LazyFqdn(object): - """ - Returns the host's fqdn on request as string. - """ - - def __init__(self, config, host=None): - self.fqdn = None - self.config = config - self.host = host - - def __str__(self): - if self.fqdn is None: - # - # If the SSH config contains AddressFamily, use that when - # determining the local host's FQDN. Using socket.getfqdn() from - # the standard library is the most general solution, but can - # result in noticeable delays on some platforms when IPv6 is - # misconfigured or not available, as it calls getaddrinfo with no - # address family specified, so both IPv4 and IPv6 are checked. - # - - # Handle specific option - fqdn = None - address_family = self.config.get('addressfamily', 'any').lower() - if address_family != 'any': - try: - family = socket.AF_INET if address_family == 'inet' \ - else socket.AF_INET6 - results = socket.getaddrinfo( - self.host, - None, - family, - socket.SOCK_DGRAM, - socket.IPPROTO_IP, - socket.AI_CANONNAME - ) - for res in results: - af, socktype, proto, canonname, sa = res - if canonname and '.' in canonname: - fqdn = canonname - break - # giaerror -> socket.getaddrinfo() can't resolve self.host - # (which is from socket.gethostname()). Fall back to the - # getfqdn() call below. - except socket.gaierror: - pass - # Handle 'any' / unspecified - if fqdn is None: - fqdn = socket.getfqdn() - # Cache - self.fqdn = fqdn - return self.fqdn - - class SSHConfig (object): """ Representation of config information as stored in the format used by - OpenSSH. Queries can be made via L{lookup}. The format is described in - OpenSSH's C{ssh_config} man page. This class is provided primarily as a + OpenSSH. Queries can be made via `lookup`. The format is described in + OpenSSH's ``ssh_config`` man page. This class is provided primarily as a convenience to posix users (since the OpenSSH format is a de-facto standard on posix) but should work fine on Windows too. - @since: 1.6 + .. versionadded:: 1.6 """ def __init__(self): @@ -105,8 +51,7 @@ class SSHConfig (object): """ Read an OpenSSH config from the given file object. - @param file_obj: a file-like object to read the config file from - @type file_obj: file + :param file file_obj: a file-like object to read the config file from """ host = {"host": ['*'], "config": {}} for line in file_obj: @@ -152,28 +97,26 @@ class SSHConfig (object): """ Return a dict of config options for a given hostname. - The host-matching rules of OpenSSH's C{ssh_config} man page are used, + The host-matching rules of OpenSSH's ``ssh_config`` man page are used, which means that all configuration options from matching host specifications are merged, with more specific hostmasks taking - precedence. In other words, if C{"Port"} is set under C{"Host *"} - and also C{"Host *.example.com"}, and the lookup is for - C{"ssh.example.com"}, then the port entry for C{"Host *.example.com"} + precedence. In other words, if ``"Port"`` is set under ``"Host *"`` + and also ``"Host *.example.com"``, and the lookup is for + ``"ssh.example.com"``, then the port entry for ``"Host *.example.com"`` will win out. The keys in the returned dict are all normalized to lowercase (look for - C{"port"}, not C{"Port"}. The values are processed according to the - rules for substitution variable expansion in C{ssh_config}. + ``"port"``, not ``"Port"``. The values are processed according to the + rules for substitution variable expansion in ``ssh_config``. - @param hostname: the hostname to lookup - @type hostname: str + :param str hostname: the hostname to lookup """ - matches = [config for config in self._config if self._allowed(hostname, config['host'])] ret = {} for match in matches: - for key, value in match['config'].iteritems(): + for key, value in match['config'].items(): if key not in ret: # Create a copy of the original value, # else it will reference the original list @@ -199,13 +142,11 @@ class SSHConfig (object): Return a dict of config options with expanded substitutions for a given hostname. - Please refer to man C{ssh_config} for the parameters that + Please refer to man ``ssh_config`` for the parameters that are replaced. - @param config: the config for the hostname - @type hostname: dict - @param hostname: the hostname that the config belongs to - @type hostname: str + :param dict config: the config for the hostname + :param str hostname: the hostname that the config belongs to """ if 'hostname' in config: @@ -264,3 +205,57 @@ class SSHConfig (object): else: config[k] = config[k].replace(find, str(replace)) return config + + +class LazyFqdn(object): + """ + Returns the host's fqdn on request as string. + """ + + def __init__(self, config, host=None): + self.fqdn = None + self.config = config + self.host = host + + def __str__(self): + if self.fqdn is None: + # + # If the SSH config contains AddressFamily, use that when + # determining the local host's FQDN. Using socket.getfqdn() from + # the standard library is the most general solution, but can + # result in noticeable delays on some platforms when IPv6 is + # misconfigured or not available, as it calls getaddrinfo with no + # address family specified, so both IPv4 and IPv6 are checked. + # + + # Handle specific option + fqdn = None + address_family = self.config.get('addressfamily', 'any').lower() + if address_family != 'any': + try: + family = socket.AF_INET if address_family == 'inet' \ + else socket.AF_INET6 + results = socket.getaddrinfo( + self.host, + None, + family, + socket.SOCK_DGRAM, + socket.IPPROTO_IP, + socket.AI_CANONNAME + ) + for res in results: + af, socktype, proto, canonname, sa = res + if canonname and '.' in canonname: + fqdn = canonname + break + # giaerror -> socket.getaddrinfo() can't resolve self.host + # (which is from socket.gethostname()). Fall back to the + # getfqdn() call below. + except socket.gaierror: + pass + # Handle 'any' / unspecified + if fqdn is None: + fqdn = socket.getfqdn() + # Cache + self.fqdn = fqdn + return self.fqdn |