Main Page | Namespace List | Class List | Directories | File List | Class Members | File Members

canohost.c

Go to the documentation of this file.
00001 /*
00002  * Author: Tatu Ylonen <ylo@cs.hut.fi>
00003  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
00004  *                    All rights reserved
00005  * Functions for returning the canonical host name of the remote site.
00006  *
00007  * As far as I am concerned, the code I have written for this software
00008  * can be used freely for any purpose.  Any derived versions of this
00009  * software must be clearly marked as such, and if the derived work is
00010  * incompatible with the protocol description in the RFC file, it must be
00011  * called by a name other than "ssh" or "Secure Shell".
00012  */
00013 
00014 #include "includes.h"
00015 RCSID("$OpenBSD: canohost.c,v 1.48 2005/12/28 22:46:06 stevesk Exp $");
00016 
00017 #include "packet.h"
00018 #include "xmalloc.h"
00019 #include "log.h"
00020 #include "canohost.h"
00021 
00022 static void check_ip_options(int, char *);
00023 
00024 /*
00025  * Return the canonical name of the host at the other end of the socket. The
00026  * caller should free the returned string with xfree.
00027  */
00028 
00029 static char *
00030 get_remote_hostname(int sock, int use_dns)
00031 {
00032         struct sockaddr_storage from;
00033         int i;
00034         socklen_t fromlen;
00035         struct addrinfo hints, *ai, *aitop;
00036         char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
00037 
00038         /* Get IP address of client. */
00039         fromlen = sizeof(from);
00040         memset(&from, 0, sizeof(from));
00041         if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) {
00042                 debug("getpeername failed: %.100s", strerror(errno));
00043                 cleanup_exit(255);
00044         }
00045 
00046         ipv64_normalise_mapped(&from, &fromlen);
00047 
00048         if (from.ss_family == AF_INET6)
00049                 fromlen = sizeof(struct sockaddr_in6);
00050 
00051         if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
00052             NULL, 0, NI_NUMERICHOST) != 0)
00053                 fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
00054 
00055         if (from.ss_family == AF_INET)
00056                 check_ip_options(sock, ntop);
00057 
00058         if (!use_dns)
00059                 return xstrdup(ntop);
00060 
00061         debug3("Trying to reverse map address %.100s.", ntop);
00062         /* Map the IP address to a host name. */
00063         if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
00064             NULL, 0, NI_NAMEREQD) != 0) {
00065                 /* Host name not found.  Use ip address. */
00066                 return xstrdup(ntop);
00067         }
00068 
00069         /*
00070          * if reverse lookup result looks like a numeric hostname,
00071          * someone is trying to trick us by PTR record like following:
00072          *      1.1.1.10.in-addr.arpa.  IN PTR  2.3.4.5
00073          */
00074         memset(&hints, 0, sizeof(hints));
00075         hints.ai_socktype = SOCK_DGRAM; /*dummy*/
00076         hints.ai_flags = AI_NUMERICHOST;
00077         if (getaddrinfo(name, "0", &hints, &ai) == 0) {
00078                 logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
00079                     name, ntop);
00080                 freeaddrinfo(ai);
00081                 return xstrdup(ntop);
00082         }
00083 
00084         /*
00085          * Convert it to all lowercase (which is expected by the rest
00086          * of this software).
00087          */
00088         for (i = 0; name[i]; i++)
00089                 if (isupper(name[i]))
00090                         name[i] = tolower(name[i]);
00091         /*
00092          * Map it back to an IP address and check that the given
00093          * address actually is an address of this host.  This is
00094          * necessary because anyone with access to a name server can
00095          * define arbitrary names for an IP address. Mapping from
00096          * name to IP address can be trusted better (but can still be
00097          * fooled if the intruder has access to the name server of
00098          * the domain).
00099          */
00100         memset(&hints, 0, sizeof(hints));
00101         hints.ai_family = from.ss_family;
00102         hints.ai_socktype = SOCK_STREAM;
00103         if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
00104                 logit("reverse mapping checking getaddrinfo for %.700s "
00105                     "failed - POSSIBLE BREAK-IN ATTEMPT!", name);
00106                 return xstrdup(ntop);
00107         }
00108         /* Look for the address from the list of addresses. */
00109         for (ai = aitop; ai; ai = ai->ai_next) {
00110                 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
00111                     sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
00112                     (strcmp(ntop, ntop2) == 0))
00113                                 break;
00114         }
00115         freeaddrinfo(aitop);
00116         /* If we reached the end of the list, the address was not there. */
00117         if (!ai) {
00118                 /* Address not found for the host name. */
00119                 logit("Address %.100s maps to %.600s, but this does not "
00120                     "map back to the address - POSSIBLE BREAK-IN ATTEMPT!",
00121                     ntop, name);
00122                 return xstrdup(ntop);
00123         }
00124         return xstrdup(name);
00125 }
00126 
00127 /*
00128  * If IP options are supported, make sure there are none (log and
00129  * disconnect them if any are found).  Basically we are worried about
00130  * source routing; it can be used to pretend you are somebody
00131  * (ip-address) you are not. That itself may be "almost acceptable"
00132  * under certain circumstances, but rhosts autentication is useless
00133  * if source routing is accepted. Notice also that if we just dropped
00134  * source routing here, the other side could use IP spoofing to do
00135  * rest of the interaction and could still bypass security.  So we
00136  * exit here if we detect any IP options.
00137  */
00138 /* IPv4 only */
00139 static void
00140 check_ip_options(int sock, char *ipaddr)
00141 {
00142 #ifdef IP_OPTIONS
00143         u_char options[200];
00144         char text[sizeof(options) * 3 + 1];
00145         socklen_t option_size;
00146         u_int i;
00147         int ipproto;
00148         struct protoent *ip;
00149 
00150         if ((ip = getprotobyname("ip")) != NULL)
00151                 ipproto = ip->p_proto;
00152         else
00153                 ipproto = IPPROTO_IP;
00154         option_size = sizeof(options);
00155         if (getsockopt(sock, ipproto, IP_OPTIONS, options,
00156             &option_size) >= 0 && option_size != 0) {
00157                 text[0] = '\0';
00158                 for (i = 0; i < option_size; i++)
00159                         snprintf(text + i*3, sizeof(text) - i*3,
00160                             " %2.2x", options[i]);
00161                 fatal("Connection from %.100s with IP options:%.800s",
00162                     ipaddr, text);
00163         }
00164 #endif /* IP_OPTIONS */
00165 }
00166 
00167 void
00168 ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len)
00169 {
00170         struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)addr;
00171         struct sockaddr_in *a4 = (struct sockaddr_in *)addr;
00172         struct in_addr inaddr;
00173         u_int16_t port;
00174 
00175         if (addr->ss_family != AF_INET6 ||
00176             !IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr))
00177                 return;
00178 
00179         debug3("Normalising mapped IPv4 in IPv6 address");
00180 
00181         memcpy(&inaddr, ((char *)&a6->sin6_addr) + 12, sizeof(inaddr));
00182         port = a6->sin6_port;
00183 
00184         memset(addr, 0, sizeof(*a4));
00185 
00186         a4->sin_family = AF_INET;
00187         *len = sizeof(*a4);
00188         memcpy(&a4->sin_addr, &inaddr, sizeof(inaddr));
00189         a4->sin_port = port;
00190 }
00191 
00192 /*
00193  * Return the canonical name of the host in the other side of the current
00194  * connection.  The host name is cached, so it is efficient to call this
00195  * several times.
00196  */
00197 
00198 const char *
00199 get_canonical_hostname(int use_dns)
00200 {
00201         char *host;
00202         static char *canonical_host_name = NULL;
00203         static char *remote_ip = NULL;
00204 
00205         /* Check if we have previously retrieved name with same option. */
00206         if (use_dns && canonical_host_name != NULL)
00207                 return canonical_host_name;
00208         if (!use_dns && remote_ip != NULL)
00209                 return remote_ip;
00210 
00211         /* Get the real hostname if socket; otherwise return UNKNOWN. */
00212         if (packet_connection_is_on_socket())
00213                 host = get_remote_hostname(packet_get_connection_in(), use_dns);
00214         else
00215                 host = "UNKNOWN";
00216 
00217         if (use_dns)
00218                 canonical_host_name = host;
00219         else
00220                 remote_ip = host;
00221         return host;
00222 }
00223 
00224 /*
00225  * Returns the local/remote IP-address/hostname of socket as a string.
00226  * The returned string must be freed.
00227  */
00228 static char *
00229 get_socket_address(int sock, int remote, int flags)
00230 {
00231         struct sockaddr_storage addr;
00232         socklen_t addrlen;
00233         char ntop[NI_MAXHOST];
00234         int r;
00235 
00236         /* Get IP address of client. */
00237         addrlen = sizeof(addr);
00238         memset(&addr, 0, sizeof(addr));
00239 
00240         if (remote) {
00241                 if (getpeername(sock, (struct sockaddr *)&addr, &addrlen)
00242                     < 0)
00243                         return NULL;
00244         } else {
00245                 if (getsockname(sock, (struct sockaddr *)&addr, &addrlen)
00246                     < 0)
00247                         return NULL;
00248         }
00249 
00250         /* Work around Linux IPv6 weirdness */
00251         if (addr.ss_family == AF_INET6)
00252                 addrlen = sizeof(struct sockaddr_in6);
00253 
00254         ipv64_normalise_mapped(&addr, &addrlen);
00255 
00256         /* Get the address in ascii. */
00257         if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop,
00258             sizeof(ntop), NULL, 0, flags)) != 0) {
00259                 error("get_socket_address: getnameinfo %d failed: %s", flags,
00260                     r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r));
00261                 return NULL;
00262         }
00263         return xstrdup(ntop);
00264 }
00265 
00266 char *
00267 get_peer_ipaddr(int sock)
00268 {
00269         char *p;
00270 
00271         if ((p = get_socket_address(sock, 1, NI_NUMERICHOST)) != NULL)
00272                 return p;
00273         return xstrdup("UNKNOWN");
00274 }
00275 
00276 char *
00277 get_local_ipaddr(int sock)
00278 {
00279         char *p;
00280 
00281         if ((p = get_socket_address(sock, 0, NI_NUMERICHOST)) != NULL)
00282                 return p;
00283         return xstrdup("UNKNOWN");
00284 }
00285 
00286 char *
00287 get_local_name(int sock)
00288 {
00289         return get_socket_address(sock, 0, NI_NAMEREQD);
00290 }
00291 
00292 /*
00293  * Returns the IP-address of the remote host as a string.  The returned
00294  * string must not be freed.
00295  */
00296 
00297 const char *
00298 get_remote_ipaddr(void)
00299 {
00300         static char *canonical_host_ip = NULL;
00301 
00302         /* Check whether we have cached the ipaddr. */
00303         if (canonical_host_ip == NULL) {
00304                 if (packet_connection_is_on_socket()) {
00305                         canonical_host_ip =
00306                             get_peer_ipaddr(packet_get_connection_in());
00307                         if (canonical_host_ip == NULL)
00308                                 cleanup_exit(255);
00309                 } else {
00310                         /* If not on socket, return UNKNOWN. */
00311                         canonical_host_ip = xstrdup("UNKNOWN");
00312                 }
00313         }
00314         return canonical_host_ip;
00315 }
00316 
00317 const char *
00318 get_remote_name_or_ip(u_int utmp_len, int use_dns)
00319 {
00320         static const char *remote = "";
00321         if (utmp_len > 0)
00322                 remote = get_canonical_hostname(use_dns);
00323         if (utmp_len == 0 || strlen(remote) > utmp_len)
00324                 remote = get_remote_ipaddr();
00325         return remote;
00326 }
00327 
00328 /* Returns the local/remote port for the socket. */
00329 
00330 static int
00331 get_sock_port(int sock, int local)
00332 {
00333         struct sockaddr_storage from;
00334         socklen_t fromlen;
00335         char strport[NI_MAXSERV];
00336         int r;
00337 
00338         /* Get IP address of client. */
00339         fromlen = sizeof(from);
00340         memset(&from, 0, sizeof(from));
00341         if (local) {
00342                 if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
00343                         error("getsockname failed: %.100s", strerror(errno));
00344                         return 0;
00345                 }
00346         } else {
00347                 if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) {
00348                         debug("getpeername failed: %.100s", strerror(errno));
00349                         return -1;
00350                 }
00351         }
00352 
00353         /* Work around Linux IPv6 weirdness */
00354         if (from.ss_family == AF_INET6)
00355                 fromlen = sizeof(struct sockaddr_in6);
00356 
00357         /* Return port number. */
00358         if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
00359             strport, sizeof(strport), NI_NUMERICSERV)) != 0)
00360                 fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed: %s",
00361                     r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r));
00362         return atoi(strport);
00363 }
00364 
00365 /* Returns remote/local port number for the current connection. */
00366 
00367 static int
00368 get_port(int local)
00369 {
00370         /*
00371          * If the connection is not a socket, return 65535.  This is
00372          * intentionally chosen to be an unprivileged port number.
00373          */
00374         if (!packet_connection_is_on_socket())
00375                 return 65535;
00376 
00377         /* Get socket and return the port number. */
00378         return get_sock_port(packet_get_connection_in(), local);
00379 }
00380 
00381 int
00382 get_peer_port(int sock)
00383 {
00384         return get_sock_port(sock, 0);
00385 }
00386 
00387 int
00388 get_remote_port(void)
00389 {
00390         static int port = -1;
00391 
00392         /* Cache to avoid getpeername() on a dead connection */
00393         if (port == -1)
00394                 port = get_port(0);
00395 
00396         return port;
00397 }
00398 
00399 int
00400 get_local_port(void)
00401 {
00402         return get_port(1);
00403 }

© sourcejam.com 2005-2008