canohost.c revision 98684
1/*
2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 *                    All rights reserved
5 * Functions for returning the canonical host name of the remote site.
6 *
7 * As far as I am concerned, the code I have written for this software
8 * can be used freely for any purpose.  Any derived versions of this
9 * software must be clearly marked as such, and if the derived work is
10 * incompatible with the protocol description in the RFC file, it must be
11 * called by a name other than "ssh" or "Secure Shell".
12 */
13
14#include "includes.h"
15RCSID("$OpenBSD: canohost.c,v 1.32 2002/06/11 08:11:45 itojun Exp $");
16RCSID("$FreeBSD: head/crypto/openssh/canohost.c 98684 2002-06-23 16:09:08Z des $");
17
18#include "packet.h"
19#include "xmalloc.h"
20#include "log.h"
21#include "canohost.h"
22
23static void check_ip_options(int, char *);
24
25/*
26 * Return the canonical name of the host at the other end of the socket. The
27 * caller should free the returned string with xfree.
28 */
29
30static char *
31get_remote_hostname(int socket, int verify_reverse_mapping)
32{
33	struct sockaddr_storage from;
34	int i;
35	socklen_t fromlen;
36	struct addrinfo hints, *ai, *aitop;
37	char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
38
39	/* Get IP address of client. */
40	fromlen = sizeof(from);
41	memset(&from, 0, sizeof(from));
42	if (getpeername(socket, (struct sockaddr *) &from, &fromlen) < 0) {
43		debug("getpeername failed: %.100s", strerror(errno));
44		fatal_cleanup();
45	}
46
47	if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
48	    NULL, 0, NI_NUMERICHOST) != 0)
49		fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
50
51	if (from.ss_family == AF_INET)
52		check_ip_options(socket, ntop);
53
54	debug3("Trying to reverse map address %.100s.", ntop);
55	/* Map the IP address to a host name. */
56	if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
57	    NULL, 0, NI_NAMEREQD) != 0) {
58		/* Host name not found.  Use ip address. */
59		log("Could not reverse map address %.100s.", ntop);
60		return xstrdup(ntop);
61	}
62
63	/* Got host name. */
64	name[sizeof(name) - 1] = '\0';
65	/*
66	 * Convert it to all lowercase (which is expected by the rest
67	 * of this software).
68	 */
69	for (i = 0; name[i]; i++)
70		if (isupper(name[i]))
71			name[i] = tolower(name[i]);
72
73	if (!verify_reverse_mapping)
74		return xstrdup(name);
75	/*
76	 * Map it back to an IP address and check that the given
77	 * address actually is an address of this host.  This is
78	 * necessary because anyone with access to a name server can
79	 * define arbitrary names for an IP address. Mapping from
80	 * name to IP address can be trusted better (but can still be
81	 * fooled if the intruder has access to the name server of
82	 * the domain).
83	 */
84	memset(&hints, 0, sizeof(hints));
85	hints.ai_family = from.ss_family;
86	hints.ai_socktype = SOCK_STREAM;
87	if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
88		log("reverse mapping checking getaddrinfo for %.700s "
89		    "failed - POSSIBLE BREAKIN ATTEMPT!", name);
90		return xstrdup(ntop);
91	}
92	/* Look for the address from the list of addresses. */
93	for (ai = aitop; ai; ai = ai->ai_next) {
94		if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
95		    sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
96		    (strcmp(ntop, ntop2) == 0))
97				break;
98	}
99	freeaddrinfo(aitop);
100	/* If we reached the end of the list, the address was not there. */
101	if (!ai) {
102		/* Address not found for the host name. */
103		log("Address %.100s maps to %.600s, but this does not "
104		    "map back to the address - POSSIBLE BREAKIN ATTEMPT!",
105		    ntop, name);
106		return xstrdup(ntop);
107	}
108	return xstrdup(name);
109}
110
111/*
112 * If IP options are supported, make sure there are none (log and
113 * disconnect them if any are found).  Basically we are worried about
114 * source routing; it can be used to pretend you are somebody
115 * (ip-address) you are not. That itself may be "almost acceptable"
116 * under certain circumstances, but rhosts autentication is useless
117 * if source routing is accepted. Notice also that if we just dropped
118 * source routing here, the other side could use IP spoofing to do
119 * rest of the interaction and could still bypass security.  So we
120 * exit here if we detect any IP options.
121 */
122/* IPv4 only */
123static void
124check_ip_options(int socket, char *ipaddr)
125{
126	u_char options[200];
127	char text[sizeof(options) * 3 + 1];
128	socklen_t option_size;
129	int i, ipproto;
130	struct protoent *ip;
131
132	if ((ip = getprotobyname("ip")) != NULL)
133		ipproto = ip->p_proto;
134	else
135		ipproto = IPPROTO_IP;
136	option_size = sizeof(options);
137	if (getsockopt(socket, ipproto, IP_OPTIONS, options,
138	    &option_size) >= 0 && option_size != 0) {
139		text[0] = '\0';
140		for (i = 0; i < option_size; i++)
141			snprintf(text + i*3, sizeof(text) - i*3,
142			    " %2.2x", options[i]);
143		log("Connection from %.100s with IP options:%.800s",
144		    ipaddr, text);
145		packet_disconnect("Connection from %.100s with IP options:%.800s",
146		    ipaddr, text);
147	}
148}
149
150/*
151 * Return the canonical name of the host in the other side of the current
152 * connection.  The host name is cached, so it is efficient to call this
153 * several times.
154 */
155
156const char *
157get_canonical_hostname(int verify_reverse_mapping)
158{
159	static char *canonical_host_name = NULL;
160	static int verify_reverse_mapping_done = 0;
161
162	/* Check if we have previously retrieved name with same option. */
163	if (canonical_host_name != NULL) {
164		if (verify_reverse_mapping_done != verify_reverse_mapping)
165			xfree(canonical_host_name);
166		else
167			return canonical_host_name;
168	}
169
170	/* Get the real hostname if socket; otherwise return UNKNOWN. */
171	if (packet_connection_is_on_socket())
172		canonical_host_name = get_remote_hostname(
173		    packet_get_connection_in(), verify_reverse_mapping);
174	else
175		canonical_host_name = xstrdup("UNKNOWN");
176
177	verify_reverse_mapping_done = verify_reverse_mapping;
178	return canonical_host_name;
179}
180
181/*
182 * Returns the remote IP-address of socket as a string.  The returned
183 * string must be freed.
184 */
185static char *
186get_socket_address(int socket, int remote, int flags)
187{
188	struct sockaddr_storage addr;
189	socklen_t addrlen;
190	char ntop[NI_MAXHOST];
191
192	/* Get IP address of client. */
193	addrlen = sizeof(addr);
194	memset(&addr, 0, sizeof(addr));
195
196	if (remote) {
197		if (getpeername(socket, (struct sockaddr *)&addr, &addrlen)
198		    < 0) {
199			debug("get_socket_ipaddr: getpeername failed: %.100s",
200			    strerror(errno));
201			return NULL;
202		}
203	} else {
204		if (getsockname(socket, (struct sockaddr *)&addr, &addrlen)
205		    < 0) {
206			debug("get_socket_ipaddr: getsockname failed: %.100s",
207			    strerror(errno));
208			return NULL;
209		}
210	}
211	/* Get the address in ascii. */
212	if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop),
213	    NULL, 0, flags) != 0) {
214		error("get_socket_ipaddr: getnameinfo %d failed", flags);
215		return NULL;
216	}
217	return xstrdup(ntop);
218}
219
220char *
221get_peer_ipaddr(int socket)
222{
223	return get_socket_address(socket, 1, NI_NUMERICHOST);
224}
225
226char *
227get_local_ipaddr(int socket)
228{
229	return get_socket_address(socket, 0, NI_NUMERICHOST);
230}
231
232char *
233get_local_name(int socket)
234{
235	return get_socket_address(socket, 0, NI_NAMEREQD);
236}
237
238/*
239 * Returns the IP-address of the remote host as a string.  The returned
240 * string must not be freed.
241 */
242
243const char *
244get_remote_ipaddr(void)
245{
246	static char *canonical_host_ip = NULL;
247
248	/* Check whether we have cached the ipaddr. */
249	if (canonical_host_ip == NULL) {
250		if (packet_connection_is_on_socket()) {
251			canonical_host_ip =
252			    get_peer_ipaddr(packet_get_connection_in());
253			if (canonical_host_ip == NULL)
254				fatal_cleanup();
255		} else {
256			/* If not on socket, return UNKNOWN. */
257			canonical_host_ip = xstrdup("UNKNOWN");
258		}
259	}
260	return canonical_host_ip;
261}
262
263const char *
264get_remote_name_or_ip(u_int utmp_len, int verify_reverse_mapping)
265{
266	static const char *remote = "";
267	if (utmp_len > 0)
268		remote = get_canonical_hostname(verify_reverse_mapping);
269	if (utmp_len == 0 || strlen(remote) > utmp_len)
270		remote = get_remote_ipaddr();
271	return remote;
272}
273
274/* Returns the local/remote port for the socket. */
275
276static int
277get_sock_port(int sock, int local)
278{
279	struct sockaddr_storage from;
280	socklen_t fromlen;
281	char strport[NI_MAXSERV];
282
283	/* Get IP address of client. */
284	fromlen = sizeof(from);
285	memset(&from, 0, sizeof(from));
286	if (local) {
287		if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
288			error("getsockname failed: %.100s", strerror(errno));
289			return 0;
290		}
291	} else {
292		if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
293			debug("getpeername failed: %.100s", strerror(errno));
294			fatal_cleanup();
295		}
296	}
297	/* Return port number. */
298	if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
299	    strport, sizeof(strport), NI_NUMERICSERV) != 0)
300		fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
301	return atoi(strport);
302}
303
304/* Returns remote/local port number for the current connection. */
305
306static int
307get_port(int local)
308{
309	/*
310	 * If the connection is not a socket, return 65535.  This is
311	 * intentionally chosen to be an unprivileged port number.
312	 */
313	if (!packet_connection_is_on_socket())
314		return 65535;
315
316	/* Get socket and return the port number. */
317	return get_sock_port(packet_get_connection_in(), local);
318}
319
320int
321get_peer_port(int sock)
322{
323	return get_sock_port(sock, 0);
324}
325
326int
327get_remote_port(void)
328{
329	return get_port(0);
330}
331
332int
333get_local_port(void)
334{
335	return get_port(1);
336}
337