LCOV - code coverage report
Current view: top level - openssh-6.6p1 - canohost.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 88 141 62.4 %
Date: 2014-08-01 Functions: 13 16 81.2 %
Branches: 53 98 54.1 %

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

Generated by: LCOV version 1.9