source: trunk/third/openssh/canohost.c @ 18759

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