canohost.c revision 60573
157429Smarkm/* 260573Skris * 357429Smarkm * canohost.c 460573Skris * 557429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 660573Skris * 757429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 857429Smarkm * All rights reserved 960573Skris * 1057429Smarkm * Created: Sun Jul 2 17:52:22 1995 ylo 1160573Skris * 1257429Smarkm * Functions for returning the canonical host name of the remote site. 1360573Skris * 1457429Smarkm */ 1557429Smarkm 1657429Smarkm#include "includes.h" 1760573SkrisRCSID("$Id: canohost.c,v 1.12 2000/04/14 10:30:30 markus Exp $"); 1857429Smarkm 1957429Smarkm#include "packet.h" 2057429Smarkm#include "xmalloc.h" 2157429Smarkm#include "ssh.h" 2257429Smarkm 2357429Smarkm/* 2457429Smarkm * Return the canonical name of the host at the other end of the socket. The 2557429Smarkm * caller should free the returned string with xfree. 2657429Smarkm */ 2757429Smarkm 2857429Smarkmchar * 2957429Smarkmget_remote_hostname(int socket) 3057429Smarkm{ 3157429Smarkm struct sockaddr_storage from; 3257429Smarkm int i; 3357429Smarkm socklen_t fromlen; 3457429Smarkm struct addrinfo hints, *ai, *aitop; 3557429Smarkm char name[MAXHOSTNAMELEN]; 3657429Smarkm char ntop[NI_MAXHOST], ntop2[NI_MAXHOST]; 3757429Smarkm 3857429Smarkm /* Get IP address of client. */ 3957429Smarkm fromlen = sizeof(from); 4057429Smarkm memset(&from, 0, sizeof(from)); 4157429Smarkm if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) { 4257429Smarkm debug("getpeername failed: %.100s", strerror(errno)); 4357429Smarkm fatal_cleanup(); 4457429Smarkm } 4557429Smarkm if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), 4657429Smarkm NULL, 0, NI_NUMERICHOST) != 0) 4757429Smarkm fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed"); 4857429Smarkm 4957429Smarkm /* Map the IP address to a host name. */ 5057429Smarkm if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), 5157429Smarkm NULL, 0, NI_NAMEREQD) == 0) { 5257429Smarkm /* Got host name. */ 5357429Smarkm name[sizeof(name) - 1] = '\0'; 5457429Smarkm /* 5557429Smarkm * Convert it to all lowercase (which is expected by the rest 5657429Smarkm * of this software). 5757429Smarkm */ 5857429Smarkm for (i = 0; name[i]; i++) 5957429Smarkm if (isupper(name[i])) 6057429Smarkm name[i] = tolower(name[i]); 6157429Smarkm 6257429Smarkm /* 6357429Smarkm * Map it back to an IP address and check that the given 6457429Smarkm * address actually is an address of this host. This is 6557429Smarkm * necessary because anyone with access to a name server can 6657429Smarkm * define arbitrary names for an IP address. Mapping from 6757429Smarkm * name to IP address can be trusted better (but can still be 6857429Smarkm * fooled if the intruder has access to the name server of 6957429Smarkm * the domain). 7057429Smarkm */ 7157429Smarkm memset(&hints, 0, sizeof(hints)); 7257429Smarkm hints.ai_family = from.ss_family; 7357429Smarkm hints.ai_socktype = SOCK_STREAM; 7457429Smarkm if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { 7557429Smarkm log("reverse mapping checking getaddrinfo for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name); 7657429Smarkm strlcpy(name, ntop, sizeof name); 7757429Smarkm goto check_ip_options; 7857429Smarkm } 7957429Smarkm /* Look for the address from the list of addresses. */ 8057429Smarkm for (ai = aitop; ai; ai = ai->ai_next) { 8157429Smarkm if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, 8257429Smarkm sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && 8357429Smarkm (strcmp(ntop, ntop2) == 0)) 8457429Smarkm break; 8557429Smarkm } 8657429Smarkm freeaddrinfo(aitop); 8757429Smarkm /* If we reached the end of the list, the address was not there. */ 8857429Smarkm if (!ai) { 8957429Smarkm /* Address not found for the host name. */ 9057429Smarkm log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!", 9157429Smarkm ntop, name); 9257429Smarkm strlcpy(name, ntop, sizeof name); 9357429Smarkm goto check_ip_options; 9457429Smarkm } 9557429Smarkm /* Address was found for the host name. We accept the host name. */ 9657429Smarkm } else { 9757429Smarkm /* Host name not found. Use ascii representation of the address. */ 9857429Smarkm strlcpy(name, ntop, sizeof name); 9957429Smarkm log("Could not reverse map address %.100s.", name); 10057429Smarkm } 10157429Smarkm 10257429Smarkmcheck_ip_options: 10357429Smarkm 10457429Smarkm /* 10557429Smarkm * If IP options are supported, make sure there are none (log and 10657429Smarkm * disconnect them if any are found). Basically we are worried about 10757429Smarkm * source routing; it can be used to pretend you are somebody 10857429Smarkm * (ip-address) you are not. That itself may be "almost acceptable" 10957429Smarkm * under certain circumstances, but rhosts autentication is useless 11057429Smarkm * if source routing is accepted. Notice also that if we just dropped 11157429Smarkm * source routing here, the other side could use IP spoofing to do 11257429Smarkm * rest of the interaction and could still bypass security. So we 11357429Smarkm * exit here if we detect any IP options. 11457429Smarkm */ 11557429Smarkm /* IP options -- IPv4 only */ 11657429Smarkm if (from.ss_family == AF_INET) { 11757429Smarkm unsigned char options[200], *ucp; 11857429Smarkm char text[1024], *cp; 11957429Smarkm socklen_t option_size; 12057429Smarkm int ipproto; 12157429Smarkm struct protoent *ip; 12257429Smarkm 12357429Smarkm if ((ip = getprotobyname("ip")) != NULL) 12457429Smarkm ipproto = ip->p_proto; 12557429Smarkm else 12657429Smarkm ipproto = IPPROTO_IP; 12757429Smarkm option_size = sizeof(options); 12857429Smarkm if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options, 12957429Smarkm &option_size) >= 0 && option_size != 0) { 13057429Smarkm cp = text; 13157429Smarkm /* Note: "text" buffer must be at least 3x as big as options. */ 13257429Smarkm for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3) 13357429Smarkm sprintf(cp, " %2.2x", *ucp); 13457429Smarkm log("Connection from %.100s with IP options:%.800s", 13557429Smarkm ntop, text); 13657429Smarkm packet_disconnect("Connection from %.100s with IP options:%.800s", 13757429Smarkm ntop, text); 13857429Smarkm } 13957429Smarkm } 14057429Smarkm 14157429Smarkm return xstrdup(name); 14257429Smarkm} 14357429Smarkm 14457429Smarkm/* 14557429Smarkm * Return the canonical name of the host in the other side of the current 14657429Smarkm * connection. The host name is cached, so it is efficient to call this 14757429Smarkm * several times. 14857429Smarkm */ 14957429Smarkm 15057429Smarkmconst char * 15157429Smarkmget_canonical_hostname() 15257429Smarkm{ 15357429Smarkm static char *canonical_host_name = NULL; 15457429Smarkm 15557429Smarkm /* Check if we have previously retrieved this same name. */ 15657429Smarkm if (canonical_host_name != NULL) 15757429Smarkm return canonical_host_name; 15857429Smarkm 15957429Smarkm /* Get the real hostname if socket; otherwise return UNKNOWN. */ 16057429Smarkm if (packet_connection_is_on_socket()) 16157429Smarkm canonical_host_name = get_remote_hostname(packet_get_connection_in()); 16257429Smarkm else 16357429Smarkm canonical_host_name = xstrdup("UNKNOWN"); 16457429Smarkm 16557429Smarkm return canonical_host_name; 16657429Smarkm} 16757429Smarkm 16857429Smarkm/* 16957429Smarkm * Returns the IP-address of the remote host as a string. The returned 17057429Smarkm * string must not be freed. 17157429Smarkm */ 17257429Smarkm 17357429Smarkmconst char * 17457429Smarkmget_remote_ipaddr() 17557429Smarkm{ 17657429Smarkm static char *canonical_host_ip = NULL; 17757429Smarkm struct sockaddr_storage from; 17857429Smarkm socklen_t fromlen; 17957429Smarkm int socket; 18057429Smarkm char ntop[NI_MAXHOST]; 18157429Smarkm 18257429Smarkm /* Check whether we have chached the name. */ 18357429Smarkm if (canonical_host_ip != NULL) 18457429Smarkm return canonical_host_ip; 18557429Smarkm 18657429Smarkm /* If not a socket, return UNKNOWN. */ 18757429Smarkm if (!packet_connection_is_on_socket()) { 18857429Smarkm canonical_host_ip = xstrdup("UNKNOWN"); 18957429Smarkm return canonical_host_ip; 19057429Smarkm } 19157429Smarkm /* Get client socket. */ 19257429Smarkm socket = packet_get_connection_in(); 19357429Smarkm 19457429Smarkm /* Get IP address of client. */ 19557429Smarkm fromlen = sizeof(from); 19657429Smarkm memset(&from, 0, sizeof(from)); 19757429Smarkm if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) { 19857429Smarkm debug("getpeername failed: %.100s", strerror(errno)); 19957429Smarkm fatal_cleanup(); 20057429Smarkm } 20157429Smarkm /* Get the IP address in ascii. */ 20257429Smarkm if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), 20357429Smarkm NULL, 0, NI_NUMERICHOST) != 0) 20457429Smarkm fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed"); 20557429Smarkm 20657429Smarkm canonical_host_ip = xstrdup(ntop); 20757429Smarkm 20857429Smarkm /* Return ip address string. */ 20957429Smarkm return canonical_host_ip; 21057429Smarkm} 21157429Smarkm 21257429Smarkm/* Returns the local/remote port for the socket. */ 21357429Smarkm 21457429Smarkmint 21557429Smarkmget_sock_port(int sock, int local) 21657429Smarkm{ 21757429Smarkm struct sockaddr_storage from; 21857429Smarkm socklen_t fromlen; 21957429Smarkm char strport[NI_MAXSERV]; 22057429Smarkm 22157429Smarkm /* Get IP address of client. */ 22257429Smarkm fromlen = sizeof(from); 22357429Smarkm memset(&from, 0, sizeof(from)); 22457429Smarkm if (local) { 22557429Smarkm if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) { 22657429Smarkm error("getsockname failed: %.100s", strerror(errno)); 22757429Smarkm return 0; 22857429Smarkm } 22957429Smarkm } else { 23057429Smarkm if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) { 23157429Smarkm debug("getpeername failed: %.100s", strerror(errno)); 23257429Smarkm fatal_cleanup(); 23357429Smarkm } 23457429Smarkm } 23557429Smarkm /* Return port number. */ 23657429Smarkm if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, 23757429Smarkm strport, sizeof(strport), NI_NUMERICSERV) != 0) 23857429Smarkm fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed"); 23957429Smarkm return atoi(strport); 24057429Smarkm} 24157429Smarkm 24257429Smarkm/* Returns remote/local port number for the current connection. */ 24357429Smarkm 24460573Skrisint 24557429Smarkmget_port(int local) 24657429Smarkm{ 24757429Smarkm /* 24857429Smarkm * If the connection is not a socket, return 65535. This is 24957429Smarkm * intentionally chosen to be an unprivileged port number. 25057429Smarkm */ 25157429Smarkm if (!packet_connection_is_on_socket()) 25257429Smarkm return 65535; 25357429Smarkm 25457429Smarkm /* Get socket and return the port number. */ 25557429Smarkm return get_sock_port(packet_get_connection_in(), local); 25657429Smarkm} 25757429Smarkm 25860573Skrisint 25957429Smarkmget_peer_port(int sock) 26057429Smarkm{ 26157429Smarkm return get_sock_port(sock, 0); 26257429Smarkm} 26357429Smarkm 26460573Skrisint 26557429Smarkmget_remote_port() 26657429Smarkm{ 26757429Smarkm return get_port(0); 26857429Smarkm} 26957429Smarkm 27057429Smarkmint 27157429Smarkmget_local_port() 27257429Smarkm{ 27357429Smarkm return get_port(1); 27457429Smarkm} 275