1262566Sdes/* $OpenBSD: canohost.c,v 1.70 2014/01/19 04:17:29 dtucker Exp $ */
257429Smarkm/*
357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
557429Smarkm *                    All rights reserved
657429Smarkm * Functions for returning the canonical host name of the remote site.
760573Skris *
865674Skris * As far as I am concerned, the code I have written for this software
965674Skris * can be used freely for any purpose.  Any derived versions of this
1065674Skris * software must be clearly marked as such, and if the derived work is
1165674Skris * incompatible with the protocol description in the RFC file, it must be
1265674Skris * called by a name other than "ssh" or "Secure Shell".
1357429Smarkm */
1457429Smarkm
1557429Smarkm#include "includes.h"
1657429Smarkm
17162856Sdes#include <sys/types.h>
18162856Sdes#include <sys/socket.h>
19162856Sdes
20162856Sdes#include <netinet/in.h>
21162856Sdes#include <arpa/inet.h>
22162856Sdes
23162856Sdes#include <errno.h>
24162856Sdes#include <netdb.h>
25162856Sdes#include <stdio.h>
26162856Sdes#include <stdlib.h>
27162856Sdes#include <string.h>
28162856Sdes#include <stdarg.h>
29204917Sdes#include <unistd.h>
30162856Sdes
31162856Sdes#include "xmalloc.h"
3257429Smarkm#include "packet.h"
3376262Sgreen#include "log.h"
3476262Sgreen#include "canohost.h"
35181111Sdes#include "misc.h"
3657429Smarkm
3792559Sdesstatic void check_ip_options(int, char *);
38197679Sdesstatic char *canonical_host_ip = NULL;
39197679Sdesstatic int cached_port = -1;
4076262Sgreen
4157429Smarkm/*
4257429Smarkm * Return the canonical name of the host at the other end of the socket. The
43255767Sdes * caller should free the returned string.
4457429Smarkm */
4557429Smarkm
4692559Sdesstatic char *
47137019Sdesget_remote_hostname(int sock, int use_dns)
4857429Smarkm{
4957429Smarkm	struct sockaddr_storage from;
5057429Smarkm	socklen_t fromlen;
5157429Smarkm	struct addrinfo hints, *ai, *aitop;
5276262Sgreen	char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
5357429Smarkm
5457429Smarkm	/* Get IP address of client. */
5557429Smarkm	fromlen = sizeof(from);
5657429Smarkm	memset(&from, 0, sizeof(from));
57137019Sdes	if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) {
5857429Smarkm		debug("getpeername failed: %.100s", strerror(errno));
59126277Sdes		cleanup_exit(255);
6057429Smarkm	}
6176262Sgreen
62162856Sdes	if (from.ss_family == AF_INET)
63162856Sdes		check_ip_options(sock, ntop);
64162856Sdes
65126277Sdes	ipv64_normalise_mapped(&from, &fromlen);
6698941Sdes
67113911Sdes	if (from.ss_family == AF_INET6)
68113911Sdes		fromlen = sizeof(struct sockaddr_in6);
6998941Sdes
7057429Smarkm	if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
7192559Sdes	    NULL, 0, NI_NUMERICHOST) != 0)
7257429Smarkm		fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
7357429Smarkm
74124211Sdes	if (!use_dns)
75124211Sdes		return xstrdup(ntop);
76124211Sdes
7776262Sgreen	debug3("Trying to reverse map address %.100s.", ntop);
7857429Smarkm	/* Map the IP address to a host name. */
7957429Smarkm	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
8092559Sdes	    NULL, 0, NI_NAMEREQD) != 0) {
8176262Sgreen		/* Host name not found.  Use ip address. */
8276262Sgreen		return xstrdup(ntop);
8357429Smarkm	}
8457429Smarkm
8576262Sgreen	/*
86124211Sdes	 * if reverse lookup result looks like a numeric hostname,
87124211Sdes	 * someone is trying to trick us by PTR record like following:
88124211Sdes	 *	1.1.1.10.in-addr.arpa.	IN PTR	2.3.4.5
89124211Sdes	 */
90124211Sdes	memset(&hints, 0, sizeof(hints));
91124211Sdes	hints.ai_socktype = SOCK_DGRAM;	/*dummy*/
92124211Sdes	hints.ai_flags = AI_NUMERICHOST;
93181111Sdes	if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
94124211Sdes		logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
95124211Sdes		    name, ntop);
96124211Sdes		freeaddrinfo(ai);
97124211Sdes		return xstrdup(ntop);
98124211Sdes	}
99124211Sdes
100262566Sdes	/* Names are stores in lowercase. */
101262566Sdes	lowercase(name);
102262566Sdes
103124211Sdes	/*
10476262Sgreen	 * Map it back to an IP address and check that the given
10576262Sgreen	 * address actually is an address of this host.  This is
10676262Sgreen	 * necessary because anyone with access to a name server can
10776262Sgreen	 * define arbitrary names for an IP address. Mapping from
10876262Sgreen	 * name to IP address can be trusted better (but can still be
10976262Sgreen	 * fooled if the intruder has access to the name server of
11076262Sgreen	 * the domain).
11157429Smarkm	 */
11276262Sgreen	memset(&hints, 0, sizeof(hints));
11376262Sgreen	hints.ai_family = from.ss_family;
11476262Sgreen	hints.ai_socktype = SOCK_STREAM;
11576262Sgreen	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
116124211Sdes		logit("reverse mapping checking getaddrinfo for %.700s "
117162856Sdes		    "[%s] failed - POSSIBLE BREAK-IN ATTEMPT!", name, ntop);
11876262Sgreen		return xstrdup(ntop);
11957429Smarkm	}
12076262Sgreen	/* Look for the address from the list of addresses. */
12176262Sgreen	for (ai = aitop; ai; ai = ai->ai_next) {
12276262Sgreen		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
12376262Sgreen		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
12476262Sgreen		    (strcmp(ntop, ntop2) == 0))
12576262Sgreen				break;
12676262Sgreen	}
12776262Sgreen	freeaddrinfo(aitop);
12876262Sgreen	/* If we reached the end of the list, the address was not there. */
12976262Sgreen	if (!ai) {
13076262Sgreen		/* Address not found for the host name. */
131124211Sdes		logit("Address %.100s maps to %.600s, but this does not "
132157019Sdes		    "map back to the address - POSSIBLE BREAK-IN ATTEMPT!",
13376262Sgreen		    ntop, name);
13476262Sgreen		return xstrdup(ntop);
13576262Sgreen	}
13657429Smarkm	return xstrdup(name);
13757429Smarkm}
13857429Smarkm
13957429Smarkm/*
14076262Sgreen * If IP options are supported, make sure there are none (log and
14176262Sgreen * disconnect them if any are found).  Basically we are worried about
14276262Sgreen * source routing; it can be used to pretend you are somebody
14376262Sgreen * (ip-address) you are not. That itself may be "almost acceptable"
14476262Sgreen * under certain circumstances, but rhosts autentication is useless
14576262Sgreen * if source routing is accepted. Notice also that if we just dropped
14676262Sgreen * source routing here, the other side could use IP spoofing to do
14776262Sgreen * rest of the interaction and could still bypass security.  So we
14876262Sgreen * exit here if we detect any IP options.
14976262Sgreen */
15076262Sgreen/* IPv4 only */
15192559Sdesstatic void
152137019Sdescheck_ip_options(int sock, char *ipaddr)
15376262Sgreen{
154124211Sdes#ifdef IP_OPTIONS
15576262Sgreen	u_char options[200];
15676262Sgreen	char text[sizeof(options) * 3 + 1];
157262566Sdes	socklen_t option_size, i;
158149753Sdes	int ipproto;
15976262Sgreen	struct protoent *ip;
16076262Sgreen
16176262Sgreen	if ((ip = getprotobyname("ip")) != NULL)
16276262Sgreen		ipproto = ip->p_proto;
16376262Sgreen	else
16476262Sgreen		ipproto = IPPROTO_IP;
16576262Sgreen	option_size = sizeof(options);
166137019Sdes	if (getsockopt(sock, ipproto, IP_OPTIONS, options,
16776262Sgreen	    &option_size) >= 0 && option_size != 0) {
16876262Sgreen		text[0] = '\0';
16976262Sgreen		for (i = 0; i < option_size; i++)
17076262Sgreen			snprintf(text + i*3, sizeof(text) - i*3,
17176262Sgreen			    " %2.2x", options[i]);
172157019Sdes		fatal("Connection from %.100s with IP options:%.800s",
17376262Sgreen		    ipaddr, text);
17476262Sgreen	}
175124211Sdes#endif /* IP_OPTIONS */
17676262Sgreen}
17776262Sgreen
178147005Sdesvoid
179126277Sdesipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len)
180126277Sdes{
181126277Sdes	struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)addr;
182126277Sdes	struct sockaddr_in *a4 = (struct sockaddr_in *)addr;
183126277Sdes	struct in_addr inaddr;
184126277Sdes	u_int16_t port;
185126277Sdes
186149753Sdes	if (addr->ss_family != AF_INET6 ||
187126277Sdes	    !IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr))
188126277Sdes		return;
189126277Sdes
190126277Sdes	debug3("Normalising mapped IPv4 in IPv6 address");
191126277Sdes
192126277Sdes	memcpy(&inaddr, ((char *)&a6->sin6_addr) + 12, sizeof(inaddr));
193126277Sdes	port = a6->sin6_port;
194126277Sdes
195264377Sdes	memset(a4, 0, sizeof(*a4));
196126277Sdes
197126277Sdes	a4->sin_family = AF_INET;
198126277Sdes	*len = sizeof(*a4);
199126277Sdes	memcpy(&a4->sin_addr, &inaddr, sizeof(inaddr));
200126277Sdes	a4->sin_port = port;
201126277Sdes}
202126277Sdes
20376262Sgreen/*
20457429Smarkm * Return the canonical name of the host in the other side of the current
20557429Smarkm * connection.  The host name is cached, so it is efficient to call this
20657429Smarkm * several times.
20757429Smarkm */
20857429Smarkm
20957429Smarkmconst char *
210124211Sdesget_canonical_hostname(int use_dns)
21157429Smarkm{
212157019Sdes	char *host;
21357429Smarkm	static char *canonical_host_name = NULL;
214157019Sdes	static char *remote_ip = NULL;
21557429Smarkm
21676262Sgreen	/* Check if we have previously retrieved name with same option. */
217157019Sdes	if (use_dns && canonical_host_name != NULL)
218157019Sdes		return canonical_host_name;
219157019Sdes	if (!use_dns && remote_ip != NULL)
220157019Sdes		return remote_ip;
22157429Smarkm
22257429Smarkm	/* Get the real hostname if socket; otherwise return UNKNOWN. */
22357429Smarkm	if (packet_connection_is_on_socket())
224157019Sdes		host = get_remote_hostname(packet_get_connection_in(), use_dns);
22557429Smarkm	else
226157019Sdes		host = "UNKNOWN";
22757429Smarkm
228157019Sdes	if (use_dns)
229157019Sdes		canonical_host_name = host;
230157019Sdes	else
231157019Sdes		remote_ip = host;
232157019Sdes	return host;
23357429Smarkm}
23457429Smarkm
23557429Smarkm/*
236113911Sdes * Returns the local/remote IP-address/hostname of socket as a string.
237113911Sdes * The returned string must be freed.
23857429Smarkm */
23992559Sdesstatic char *
240137019Sdesget_socket_address(int sock, int remote, int flags)
24157429Smarkm{
24276262Sgreen	struct sockaddr_storage addr;
24376262Sgreen	socklen_t addrlen;
24457429Smarkm	char ntop[NI_MAXHOST];
245147005Sdes	int r;
24657429Smarkm
24776262Sgreen	/* Get IP address of client. */
24876262Sgreen	addrlen = sizeof(addr);
24976262Sgreen	memset(&addr, 0, sizeof(addr));
25057429Smarkm
25176262Sgreen	if (remote) {
252137019Sdes		if (getpeername(sock, (struct sockaddr *)&addr, &addrlen)
253106130Sdes		    < 0)
25476262Sgreen			return NULL;
25576262Sgreen	} else {
256137019Sdes		if (getsockname(sock, (struct sockaddr *)&addr, &addrlen)
257106130Sdes		    < 0)
25876262Sgreen			return NULL;
25957429Smarkm	}
260113911Sdes
261113911Sdes	/* Work around Linux IPv6 weirdness */
262113911Sdes	if (addr.ss_family == AF_INET6)
263113911Sdes		addrlen = sizeof(struct sockaddr_in6);
264113911Sdes
265147005Sdes	ipv64_normalise_mapped(&addr, &addrlen);
266147005Sdes
26776262Sgreen	/* Get the address in ascii. */
268147005Sdes	if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop,
269147005Sdes	    sizeof(ntop), NULL, 0, flags)) != 0) {
270147005Sdes		error("get_socket_address: getnameinfo %d failed: %s", flags,
271181111Sdes		    ssh_gai_strerror(r));
27276262Sgreen		return NULL;
27357429Smarkm	}
27476262Sgreen	return xstrdup(ntop);
27576262Sgreen}
27657429Smarkm
27776262Sgreenchar *
278137019Sdesget_peer_ipaddr(int sock)
27976262Sgreen{
280106130Sdes	char *p;
281106130Sdes
282137019Sdes	if ((p = get_socket_address(sock, 1, NI_NUMERICHOST)) != NULL)
283106130Sdes		return p;
284106130Sdes	return xstrdup("UNKNOWN");
28576262Sgreen}
28657429Smarkm
28776262Sgreenchar *
288137019Sdesget_local_ipaddr(int sock)
28976262Sgreen{
290106130Sdes	char *p;
291106130Sdes
292137019Sdes	if ((p = get_socket_address(sock, 0, NI_NUMERICHOST)) != NULL)
293106130Sdes		return p;
294106130Sdes	return xstrdup("UNKNOWN");
29557429Smarkm}
29657429Smarkm
29776262Sgreenchar *
298204917Sdesget_local_name(int fd)
29976262Sgreen{
300204917Sdes	char *host, myname[NI_MAXHOST];
301204917Sdes
302204917Sdes	/* Assume we were passed a socket */
303204917Sdes	if ((host = get_socket_address(fd, 0, NI_NAMEREQD)) != NULL)
304204917Sdes		return host;
305204917Sdes
306204917Sdes	/* Handle the case where we were passed a pipe */
307204917Sdes	if (gethostname(myname, sizeof(myname)) == -1) {
308204917Sdes		verbose("get_local_name: gethostname: %s", strerror(errno));
309204917Sdes	} else {
310204917Sdes		host = xstrdup(myname);
311204917Sdes	}
312204917Sdes
313204917Sdes	return host;
31476262Sgreen}
31576262Sgreen
316197679Sdesvoid
317197679Sdesclear_cached_addr(void)
318197679Sdes{
319255767Sdes	free(canonical_host_ip);
320255767Sdes	canonical_host_ip = NULL;
321197679Sdes	cached_port = -1;
322197679Sdes}
323197679Sdes
32462101Sgreen/*
32576262Sgreen * Returns the IP-address of the remote host as a string.  The returned
32676262Sgreen * string must not be freed.
32762101Sgreen */
32862101Sgreen
32962101Sgreenconst char *
33092559Sdesget_remote_ipaddr(void)
33162101Sgreen{
33276262Sgreen	/* Check whether we have cached the ipaddr. */
33376262Sgreen	if (canonical_host_ip == NULL) {
33476262Sgreen		if (packet_connection_is_on_socket()) {
33576262Sgreen			canonical_host_ip =
33676262Sgreen			    get_peer_ipaddr(packet_get_connection_in());
33776262Sgreen			if (canonical_host_ip == NULL)
338126277Sdes				cleanup_exit(255);
33976262Sgreen		} else {
34076262Sgreen			/* If not on socket, return UNKNOWN. */
34176262Sgreen			canonical_host_ip = xstrdup("UNKNOWN");
34276262Sgreen		}
34362101Sgreen	}
34476262Sgreen	return canonical_host_ip;
34576262Sgreen}
34662101Sgreen
34776262Sgreenconst char *
348124211Sdesget_remote_name_or_ip(u_int utmp_len, int use_dns)
34976262Sgreen{
35076262Sgreen	static const char *remote = "";
35176262Sgreen	if (utmp_len > 0)
352124211Sdes		remote = get_canonical_hostname(use_dns);
35376262Sgreen	if (utmp_len == 0 || strlen(remote) > utmp_len)
35476262Sgreen		remote = get_remote_ipaddr();
35576262Sgreen	return remote;
35662101Sgreen}
35762101Sgreen
35857429Smarkm/* Returns the local/remote port for the socket. */
35957429Smarkm
360192595Sdesint
36157429Smarkmget_sock_port(int sock, int local)
36257429Smarkm{
36357429Smarkm	struct sockaddr_storage from;
36457429Smarkm	socklen_t fromlen;
36557429Smarkm	char strport[NI_MAXSERV];
366147005Sdes	int r;
36757429Smarkm
36857429Smarkm	/* Get IP address of client. */
36957429Smarkm	fromlen = sizeof(from);
37057429Smarkm	memset(&from, 0, sizeof(from));
37157429Smarkm	if (local) {
37257429Smarkm		if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
37357429Smarkm			error("getsockname failed: %.100s", strerror(errno));
37457429Smarkm			return 0;
37557429Smarkm		}
37657429Smarkm	} else {
377113911Sdes		if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) {
37857429Smarkm			debug("getpeername failed: %.100s", strerror(errno));
379149753Sdes			return -1;
38057429Smarkm		}
38157429Smarkm	}
382113911Sdes
383113911Sdes	/* Work around Linux IPv6 weirdness */
384113911Sdes	if (from.ss_family == AF_INET6)
385113911Sdes		fromlen = sizeof(struct sockaddr_in6);
386113911Sdes
38757429Smarkm	/* Return port number. */
388147005Sdes	if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
389147005Sdes	    strport, sizeof(strport), NI_NUMERICSERV)) != 0)
390147005Sdes		fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed: %s",
391181111Sdes		    ssh_gai_strerror(r));
39257429Smarkm	return atoi(strport);
39357429Smarkm}
39457429Smarkm
39557429Smarkm/* Returns remote/local port number for the current connection. */
39657429Smarkm
39792559Sdesstatic int
39857429Smarkmget_port(int local)
39957429Smarkm{
40057429Smarkm	/*
40157429Smarkm	 * If the connection is not a socket, return 65535.  This is
40257429Smarkm	 * intentionally chosen to be an unprivileged port number.
40357429Smarkm	 */
40457429Smarkm	if (!packet_connection_is_on_socket())
40557429Smarkm		return 65535;
40657429Smarkm
40757429Smarkm	/* Get socket and return the port number. */
40857429Smarkm	return get_sock_port(packet_get_connection_in(), local);
40957429Smarkm}
41057429Smarkm
41160573Skrisint
41257429Smarkmget_peer_port(int sock)
41357429Smarkm{
41457429Smarkm	return get_sock_port(sock, 0);
41557429Smarkm}
41657429Smarkm
41760573Skrisint
41892559Sdesget_remote_port(void)
41957429Smarkm{
420137019Sdes	/* Cache to avoid getpeername() on a dead connection */
421197679Sdes	if (cached_port == -1)
422197679Sdes		cached_port = get_port(0);
423137019Sdes
424197679Sdes	return cached_port;
42557429Smarkm}
42657429Smarkm
42757429Smarkmint
42892559Sdesget_local_port(void)
42957429Smarkm{
43057429Smarkm	return get_port(1);
43157429Smarkm}
432