mirror of git://anongit.mindrot.org/openssh.git
upstream commit
when hostname canonicalisation is enabled, try to parse hostnames as addresses before looking them up for canonicalisation. fixes bz#2074 and avoids needless DNS lookups in some cases; ok markus
This commit is contained in:
parent
2ae4f337b2
commit
9010902954
77
ssh.c
77
ssh.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh.c,v 1.412 2015/01/14 20:05:27 djm Exp $ */
|
||||
/* $OpenBSD: ssh.c,v 1.413 2015/01/16 07:19:48 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -276,6 +276,60 @@ resolve_host(const char *name, int port, int logerr, char *cname, size_t clen)
|
|||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to resolve a numeric host address / port to a single address.
|
||||
* Returns a canonical address string.
|
||||
* Returns NULL on failure.
|
||||
* NB. this function must operate with a options having undefined members.
|
||||
*/
|
||||
static struct addrinfo *
|
||||
resolve_addr(const char *name, int port, char *caddr, size_t clen)
|
||||
{
|
||||
char addr[NI_MAXHOST], strport[NI_MAXSERV];
|
||||
struct addrinfo hints, *res;
|
||||
int gaierr;
|
||||
|
||||
if (port <= 0)
|
||||
port = default_ssh_port();
|
||||
snprintf(strport, sizeof strport, "%u", port);
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = options.address_family == -1 ?
|
||||
AF_UNSPEC : options.address_family;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV;
|
||||
if ((gaierr = getaddrinfo(name, strport, &hints, &res)) != 0) {
|
||||
debug2("%s: could not resolve name %.100s as address: %s",
|
||||
__func__, name, ssh_gai_strerror(gaierr));
|
||||
return NULL;
|
||||
}
|
||||
if (res == NULL) {
|
||||
debug("%s: getaddrinfo %.100s returned no addresses",
|
||||
__func__, name);
|
||||
return NULL;
|
||||
}
|
||||
if (res->ai_next != NULL) {
|
||||
debug("%s: getaddrinfo %.100s returned multiple addresses",
|
||||
__func__, name);
|
||||
goto fail;
|
||||
}
|
||||
if ((gaierr = getnameinfo(res->ai_addr, res->ai_addrlen,
|
||||
addr, sizeof(addr), NULL, 0, NI_NUMERICHOST)) != 0) {
|
||||
debug("%s: Could not format address for name %.100s: %s",
|
||||
__func__, name, ssh_gai_strerror(gaierr));
|
||||
goto fail;
|
||||
}
|
||||
if (strlcpy(caddr, addr, clen) >= clen) {
|
||||
error("%s: host \"%s\" addr \"%s\" too long (max %lu)",
|
||||
__func__, name, addr, (u_long)clen);
|
||||
if (clen > 0)
|
||||
*caddr = '\0';
|
||||
fail:
|
||||
freeaddrinfo(res);
|
||||
return NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the cname is a permitted replacement for the hostname
|
||||
* and perform the replacement if it is.
|
||||
|
@ -326,7 +380,7 @@ static struct addrinfo *
|
|||
resolve_canonicalize(char **hostp, int port)
|
||||
{
|
||||
int i, ndots;
|
||||
char *cp, *fullhost, cname_target[NI_MAXHOST];
|
||||
char *cp, *fullhost, newname[NI_MAXHOST];
|
||||
struct addrinfo *addrs;
|
||||
|
||||
if (options.canonicalize_hostname == SSH_CANONICALISE_NO)
|
||||
|
@ -340,6 +394,19 @@ resolve_canonicalize(char **hostp, int port)
|
|||
options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
|
||||
return NULL;
|
||||
|
||||
/* Try numeric hostnames first */
|
||||
if ((addrs = resolve_addr(*hostp, port,
|
||||
newname, sizeof(newname))) != NULL) {
|
||||
debug2("%s: hostname %.100s is address", __func__, *hostp);
|
||||
if (strcasecmp(*hostp, newname) != 0) {
|
||||
debug2("%s: canonicalised address \"%s\" => \"%s\"",
|
||||
__func__, *hostp, newname);
|
||||
free(*hostp);
|
||||
*hostp = xstrdup(newname);
|
||||
}
|
||||
return addrs;
|
||||
}
|
||||
|
||||
/* Don't apply canonicalization to sufficiently-qualified hostnames */
|
||||
ndots = 0;
|
||||
for (cp = *hostp; *cp != '\0'; cp++) {
|
||||
|
@ -353,20 +420,20 @@ resolve_canonicalize(char **hostp, int port)
|
|||
}
|
||||
/* Attempt each supplied suffix */
|
||||
for (i = 0; i < options.num_canonical_domains; i++) {
|
||||
*cname_target = '\0';
|
||||
*newname = '\0';
|
||||
xasprintf(&fullhost, "%s.%s.", *hostp,
|
||||
options.canonical_domains[i]);
|
||||
debug3("%s: attempting \"%s\" => \"%s\"", __func__,
|
||||
*hostp, fullhost);
|
||||
if ((addrs = resolve_host(fullhost, port, 0,
|
||||
cname_target, sizeof(cname_target))) == NULL) {
|
||||
newname, sizeof(newname))) == NULL) {
|
||||
free(fullhost);
|
||||
continue;
|
||||
}
|
||||
/* Remove trailing '.' */
|
||||
fullhost[strlen(fullhost) - 1] = '\0';
|
||||
/* Follow CNAME if requested */
|
||||
if (!check_follow_cname(&fullhost, cname_target)) {
|
||||
if (!check_follow_cname(&fullhost, newname)) {
|
||||
debug("Canonicalized hostname \"%s\" => \"%s\"",
|
||||
*hostp, fullhost);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue