summaryrefslogtreecommitdiff
path: root/ssh.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2018-01-23 05:06:25 +0000
committerDamien Miller <djm@mindrot.org>2018-01-23 16:40:28 +1100
commitfc21ea97968264ad9bb86b13fedaaec8fd3bf97d (patch)
tree96711e8ad330c961deb6f5ea52b98eb8ea099f9c /ssh.c
parentd6364f6fb1a3d753d7ca9bf15b2adce961324513 (diff)
upstream commit
don't attempt to force hostnames that are addresses to lowercase, but instead canonicalise them through getnameinfo/getaddrinfo to remove ambiguities (e.g. ::0001 => ::1) before they are matched against known_hosts; bz#2763, ok dtucker@ OpenBSD-Commit-ID: ba0863ff087e61e5c65efdbe53be3cb92c9aefa0
Diffstat (limited to 'ssh.c')
-rw-r--r--ssh.c88
1 files changed, 71 insertions, 17 deletions
diff --git a/ssh.c b/ssh.c
index 862625432..ac85b2bb5 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.469 2017/11/01 00:04:15 djm Exp $ */ 1/* $OpenBSD: ssh.c,v 1.470 2018/01/23 05:06:25 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -271,6 +271,40 @@ resolve_host(const char *name, int port, int logerr, char *cname, size_t clen)
271 return res; 271 return res;
272} 272}
273 273
274/* Returns non-zero if name can only be an address and not a hostname */
275static int
276is_addr_fast(const char *name)
277{
278 return (strchr(name, '%') != NULL || strchr(name, ':') != NULL ||
279 strspn(name, "0123456789.") == strlen(name));
280}
281
282/* Returns non-zero if name represents a valid, single address */
283static int
284is_addr(const char *name)
285{
286 char strport[NI_MAXSERV];
287 struct addrinfo hints, *res;
288
289 if (is_addr_fast(name))
290 return 1;
291
292 snprintf(strport, sizeof strport, "%u", default_ssh_port());
293 memset(&hints, 0, sizeof(hints));
294 hints.ai_family = options.address_family == -1 ?
295 AF_UNSPEC : options.address_family;
296 hints.ai_socktype = SOCK_STREAM;
297 hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV;
298 if (getaddrinfo(name, strport, &hints, &res) != 0)
299 return 0;
300 if (res == NULL || res->ai_next != NULL) {
301 freeaddrinfo(res);
302 return 0;
303 }
304 freeaddrinfo(res);
305 return 1;
306}
307
274/* 308/*
275 * Attempt to resolve a numeric host address / port to a single address. 309 * Attempt to resolve a numeric host address / port to a single address.
276 * Returns a canonical address string. 310 * Returns a canonical address string.
@@ -376,20 +410,10 @@ resolve_canonicalize(char **hostp, int port)
376 char *cp, *fullhost, newname[NI_MAXHOST]; 410 char *cp, *fullhost, newname[NI_MAXHOST];
377 struct addrinfo *addrs; 411 struct addrinfo *addrs;
378 412
379 if (options.canonicalize_hostname == SSH_CANONICALISE_NO)
380 return NULL;
381
382 /* 413 /*
383 * Don't attempt to canonicalize names that will be interpreted by 414 * Attempt to canonicalise addresses, regardless of
384 * a proxy unless the user specifically requests so. 415 * whether hostname canonicalisation was requested
385 */ 416 */
386 direct = option_clear_or_none(options.proxy_command) &&
387 options.jump_host == NULL;
388 if (!direct &&
389 options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
390 return NULL;
391
392 /* Try numeric hostnames first */
393 if ((addrs = resolve_addr(*hostp, port, 417 if ((addrs = resolve_addr(*hostp, port,
394 newname, sizeof(newname))) != NULL) { 418 newname, sizeof(newname))) != NULL) {
395 debug2("%s: hostname %.100s is address", __func__, *hostp); 419 debug2("%s: hostname %.100s is address", __func__, *hostp);
@@ -402,6 +426,30 @@ resolve_canonicalize(char **hostp, int port)
402 return addrs; 426 return addrs;
403 } 427 }
404 428
429 /*
430 * If this looks like an address but didn't parse as one, it might
431 * be an address with an invalid interface scope. Skip further
432 * attempts at canonicalisation.
433 */
434 if (is_addr_fast(*hostp)) {
435 debug("%s: hostname %.100s is an unrecognised address",
436 __func__, *hostp);
437 return NULL;
438 }
439
440 if (options.canonicalize_hostname == SSH_CANONICALISE_NO)
441 return NULL;
442
443 /*
444 * Don't attempt to canonicalize names that will be interpreted by
445 * a proxy unless the user specifically requests so.
446 */
447 direct = option_clear_or_none(options.proxy_command) &&
448 options.jump_host == NULL;
449 if (!direct &&
450 options.canonicalize_hostname != SSH_CANONICALISE_ALWAYS)
451 return NULL;
452
405 /* If domain name is anchored, then resolve it now */ 453 /* If domain name is anchored, then resolve it now */
406 if ((*hostp)[strlen(*hostp) - 1] == '.') { 454 if ((*hostp)[strlen(*hostp) - 1] == '.') {
407 debug3("%s: name is fully qualified", __func__); 455 debug3("%s: name is fully qualified", __func__);
@@ -514,7 +562,7 @@ main(int ac, char **av)
514{ 562{
515 struct ssh *ssh = NULL; 563 struct ssh *ssh = NULL;
516 int i, r, opt, exit_status, use_syslog, direct, timeout_ms; 564 int i, r, opt, exit_status, use_syslog, direct, timeout_ms;
517 int config_test = 0, opt_terminated = 0; 565 int was_addr, config_test = 0, opt_terminated = 0;
518 char *p, *cp, *line, *argv0, buf[PATH_MAX], *logfile; 566 char *p, *cp, *line, *argv0, buf[PATH_MAX], *logfile;
519 char cname[NI_MAXHOST]; 567 char cname[NI_MAXHOST];
520 struct stat st; 568 struct stat st;
@@ -1055,9 +1103,15 @@ main(int ac, char **av)
1055 options.hostname = xstrdup(host); 1103 options.hostname = xstrdup(host);
1056 } 1104 }
1057 1105
1058 /* If canonicalization requested then try to apply it */ 1106 /* Don't lowercase addresses, they will be explicitly canonicalised */
1059 lowercase(host); 1107 if ((was_addr = is_addr(host)) == 0)
1060 if (options.canonicalize_hostname != SSH_CANONICALISE_NO) 1108 lowercase(host);
1109
1110 /*
1111 * Try to canonicalize if requested by configuration or the
1112 * hostname is an address.
1113 */
1114 if (options.canonicalize_hostname != SSH_CANONICALISE_NO || was_addr)
1061 addrs = resolve_canonicalize(&host, options.port); 1115 addrs = resolve_canonicalize(&host, options.port);
1062 1116
1063 /* 1117 /*