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