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