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