canohost.c revision 60573
157429Smarkm/*
260573Skris *
357429Smarkm * canohost.c
460573Skris *
557429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi>
660573Skris *
757429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
857429Smarkm *                    All rights reserved
960573Skris *
1057429Smarkm * Created: Sun Jul  2 17:52:22 1995 ylo
1160573Skris *
1257429Smarkm * Functions for returning the canonical host name of the remote site.
1360573Skris *
1457429Smarkm */
1557429Smarkm
1657429Smarkm#include "includes.h"
1760573SkrisRCSID("$Id: canohost.c,v 1.12 2000/04/14 10:30:30 markus Exp $");
1857429Smarkm
1957429Smarkm#include "packet.h"
2057429Smarkm#include "xmalloc.h"
2157429Smarkm#include "ssh.h"
2257429Smarkm
2357429Smarkm/*
2457429Smarkm * Return the canonical name of the host at the other end of the socket. The
2557429Smarkm * caller should free the returned string with xfree.
2657429Smarkm */
2757429Smarkm
2857429Smarkmchar *
2957429Smarkmget_remote_hostname(int socket)
3057429Smarkm{
3157429Smarkm	struct sockaddr_storage from;
3257429Smarkm	int i;
3357429Smarkm	socklen_t fromlen;
3457429Smarkm	struct addrinfo hints, *ai, *aitop;
3557429Smarkm	char name[MAXHOSTNAMELEN];
3657429Smarkm	char ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
3757429Smarkm
3857429Smarkm	/* Get IP address of client. */
3957429Smarkm	fromlen = sizeof(from);
4057429Smarkm	memset(&from, 0, sizeof(from));
4157429Smarkm	if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
4257429Smarkm		debug("getpeername failed: %.100s", strerror(errno));
4357429Smarkm		fatal_cleanup();
4457429Smarkm	}
4557429Smarkm	if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
4657429Smarkm	     NULL, 0, NI_NUMERICHOST) != 0)
4757429Smarkm		fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
4857429Smarkm
4957429Smarkm	/* Map the IP address to a host name. */
5057429Smarkm	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
5157429Smarkm	     NULL, 0, NI_NAMEREQD) == 0) {
5257429Smarkm		/* Got host name. */
5357429Smarkm		name[sizeof(name) - 1] = '\0';
5457429Smarkm		/*
5557429Smarkm		 * Convert it to all lowercase (which is expected by the rest
5657429Smarkm		 * of this software).
5757429Smarkm		 */
5857429Smarkm		for (i = 0; name[i]; i++)
5957429Smarkm			if (isupper(name[i]))
6057429Smarkm				name[i] = tolower(name[i]);
6157429Smarkm
6257429Smarkm		/*
6357429Smarkm		 * Map it back to an IP address and check that the given
6457429Smarkm		 * address actually is an address of this host.  This is
6557429Smarkm		 * necessary because anyone with access to a name server can
6657429Smarkm		 * define arbitrary names for an IP address. Mapping from
6757429Smarkm		 * name to IP address can be trusted better (but can still be
6857429Smarkm		 * fooled if the intruder has access to the name server of
6957429Smarkm		 * the domain).
7057429Smarkm		 */
7157429Smarkm		memset(&hints, 0, sizeof(hints));
7257429Smarkm		hints.ai_family = from.ss_family;
7357429Smarkm		hints.ai_socktype = SOCK_STREAM;
7457429Smarkm		if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
7557429Smarkm			log("reverse mapping checking getaddrinfo for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
7657429Smarkm			strlcpy(name, ntop, sizeof name);
7757429Smarkm			goto check_ip_options;
7857429Smarkm		}
7957429Smarkm		/* Look for the address from the list of addresses. */
8057429Smarkm		for (ai = aitop; ai; ai = ai->ai_next) {
8157429Smarkm			if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
8257429Smarkm			    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
8357429Smarkm			    (strcmp(ntop, ntop2) == 0))
8457429Smarkm					break;
8557429Smarkm		}
8657429Smarkm		freeaddrinfo(aitop);
8757429Smarkm		/* If we reached the end of the list, the address was not there. */
8857429Smarkm		if (!ai) {
8957429Smarkm			/* Address not found for the host name. */
9057429Smarkm			log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
9157429Smarkm			    ntop, name);
9257429Smarkm			strlcpy(name, ntop, sizeof name);
9357429Smarkm			goto check_ip_options;
9457429Smarkm		}
9557429Smarkm		/* Address was found for the host name.  We accept the host name. */
9657429Smarkm	} else {
9757429Smarkm		/* Host name not found.  Use ascii representation of the address. */
9857429Smarkm		strlcpy(name, ntop, sizeof name);
9957429Smarkm		log("Could not reverse map address %.100s.", name);
10057429Smarkm	}
10157429Smarkm
10257429Smarkmcheck_ip_options:
10357429Smarkm
10457429Smarkm	/*
10557429Smarkm	 * If IP options are supported, make sure there are none (log and
10657429Smarkm	 * disconnect them if any are found).  Basically we are worried about
10757429Smarkm	 * source routing; it can be used to pretend you are somebody
10857429Smarkm	 * (ip-address) you are not. That itself may be "almost acceptable"
10957429Smarkm	 * under certain circumstances, but rhosts autentication is useless
11057429Smarkm	 * if source routing is accepted. Notice also that if we just dropped
11157429Smarkm	 * source routing here, the other side could use IP spoofing to do
11257429Smarkm	 * rest of the interaction and could still bypass security.  So we
11357429Smarkm	 * exit here if we detect any IP options.
11457429Smarkm	 */
11557429Smarkm	/* IP options -- IPv4 only */
11657429Smarkm	if (from.ss_family == AF_INET) {
11757429Smarkm		unsigned char options[200], *ucp;
11857429Smarkm		char text[1024], *cp;
11957429Smarkm		socklen_t option_size;
12057429Smarkm		int ipproto;
12157429Smarkm		struct protoent *ip;
12257429Smarkm
12357429Smarkm		if ((ip = getprotobyname("ip")) != NULL)
12457429Smarkm			ipproto = ip->p_proto;
12557429Smarkm		else
12657429Smarkm			ipproto = IPPROTO_IP;
12757429Smarkm		option_size = sizeof(options);
12857429Smarkm		if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options,
12957429Smarkm		    &option_size) >= 0 && option_size != 0) {
13057429Smarkm			cp = text;
13157429Smarkm			/* Note: "text" buffer must be at least 3x as big as options. */
13257429Smarkm			for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
13357429Smarkm				sprintf(cp, " %2.2x", *ucp);
13457429Smarkm			log("Connection from %.100s with IP options:%.800s",
13557429Smarkm			    ntop, text);
13657429Smarkm			packet_disconnect("Connection from %.100s with IP options:%.800s",
13757429Smarkm					  ntop, text);
13857429Smarkm		}
13957429Smarkm	}
14057429Smarkm
14157429Smarkm	return xstrdup(name);
14257429Smarkm}
14357429Smarkm
14457429Smarkm/*
14557429Smarkm * Return the canonical name of the host in the other side of the current
14657429Smarkm * connection.  The host name is cached, so it is efficient to call this
14757429Smarkm * several times.
14857429Smarkm */
14957429Smarkm
15057429Smarkmconst char *
15157429Smarkmget_canonical_hostname()
15257429Smarkm{
15357429Smarkm	static char *canonical_host_name = NULL;
15457429Smarkm
15557429Smarkm	/* Check if we have previously retrieved this same name. */
15657429Smarkm	if (canonical_host_name != NULL)
15757429Smarkm		return canonical_host_name;
15857429Smarkm
15957429Smarkm	/* Get the real hostname if socket; otherwise return UNKNOWN. */
16057429Smarkm	if (packet_connection_is_on_socket())
16157429Smarkm		canonical_host_name = get_remote_hostname(packet_get_connection_in());
16257429Smarkm	else
16357429Smarkm		canonical_host_name = xstrdup("UNKNOWN");
16457429Smarkm
16557429Smarkm	return canonical_host_name;
16657429Smarkm}
16757429Smarkm
16857429Smarkm/*
16957429Smarkm * Returns the IP-address of the remote host as a string.  The returned
17057429Smarkm * string must not be freed.
17157429Smarkm */
17257429Smarkm
17357429Smarkmconst char *
17457429Smarkmget_remote_ipaddr()
17557429Smarkm{
17657429Smarkm	static char *canonical_host_ip = NULL;
17757429Smarkm	struct sockaddr_storage from;
17857429Smarkm	socklen_t fromlen;
17957429Smarkm	int socket;
18057429Smarkm	char ntop[NI_MAXHOST];
18157429Smarkm
18257429Smarkm	/* Check whether we have chached the name. */
18357429Smarkm	if (canonical_host_ip != NULL)
18457429Smarkm		return canonical_host_ip;
18557429Smarkm
18657429Smarkm	/* If not a socket, return UNKNOWN. */
18757429Smarkm	if (!packet_connection_is_on_socket()) {
18857429Smarkm		canonical_host_ip = xstrdup("UNKNOWN");
18957429Smarkm		return canonical_host_ip;
19057429Smarkm	}
19157429Smarkm	/* Get client socket. */
19257429Smarkm	socket = packet_get_connection_in();
19357429Smarkm
19457429Smarkm	/* Get IP address of client. */
19557429Smarkm	fromlen = sizeof(from);
19657429Smarkm	memset(&from, 0, sizeof(from));
19757429Smarkm	if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
19857429Smarkm		debug("getpeername failed: %.100s", strerror(errno));
19957429Smarkm		fatal_cleanup();
20057429Smarkm	}
20157429Smarkm	/* Get the IP address in ascii. */
20257429Smarkm	if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
20357429Smarkm	     NULL, 0, NI_NUMERICHOST) != 0)
20457429Smarkm		fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
20557429Smarkm
20657429Smarkm	canonical_host_ip = xstrdup(ntop);
20757429Smarkm
20857429Smarkm	/* Return ip address string. */
20957429Smarkm	return canonical_host_ip;
21057429Smarkm}
21157429Smarkm
21257429Smarkm/* Returns the local/remote port for the socket. */
21357429Smarkm
21457429Smarkmint
21557429Smarkmget_sock_port(int sock, int local)
21657429Smarkm{
21757429Smarkm	struct sockaddr_storage from;
21857429Smarkm	socklen_t fromlen;
21957429Smarkm	char strport[NI_MAXSERV];
22057429Smarkm
22157429Smarkm	/* Get IP address of client. */
22257429Smarkm	fromlen = sizeof(from);
22357429Smarkm	memset(&from, 0, sizeof(from));
22457429Smarkm	if (local) {
22557429Smarkm		if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
22657429Smarkm			error("getsockname failed: %.100s", strerror(errno));
22757429Smarkm			return 0;
22857429Smarkm		}
22957429Smarkm	} else {
23057429Smarkm		if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
23157429Smarkm			debug("getpeername failed: %.100s", strerror(errno));
23257429Smarkm			fatal_cleanup();
23357429Smarkm		}
23457429Smarkm	}
23557429Smarkm	/* Return port number. */
23657429Smarkm	if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
23757429Smarkm	     strport, sizeof(strport), NI_NUMERICSERV) != 0)
23857429Smarkm		fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
23957429Smarkm	return atoi(strport);
24057429Smarkm}
24157429Smarkm
24257429Smarkm/* Returns remote/local port number for the current connection. */
24357429Smarkm
24460573Skrisint
24557429Smarkmget_port(int local)
24657429Smarkm{
24757429Smarkm	/*
24857429Smarkm	 * If the connection is not a socket, return 65535.  This is
24957429Smarkm	 * intentionally chosen to be an unprivileged port number.
25057429Smarkm	 */
25157429Smarkm	if (!packet_connection_is_on_socket())
25257429Smarkm		return 65535;
25357429Smarkm
25457429Smarkm	/* Get socket and return the port number. */
25557429Smarkm	return get_sock_port(packet_get_connection_in(), local);
25657429Smarkm}
25757429Smarkm
25860573Skrisint
25957429Smarkmget_peer_port(int sock)
26057429Smarkm{
26157429Smarkm	return get_sock_port(sock, 0);
26257429Smarkm}
26357429Smarkm
26460573Skrisint
26557429Smarkmget_remote_port()
26657429Smarkm{
26757429Smarkm	return get_port(0);
26857429Smarkm}
26957429Smarkm
27057429Smarkmint
27157429Smarkmget_local_port()
27257429Smarkm{
27357429Smarkm	return get_port(1);
27457429Smarkm}
275