1511b41d2SMark Murray /* 2511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi> 3511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4511b41d2SMark Murray * All rights reserved 5511b41d2SMark Murray * Functions for returning the canonical host name of the remote site. 6511b41d2SMark Murray * 7c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software 8c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this 9c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is 10c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 11c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 12511b41d2SMark Murray */ 13511b41d2SMark Murray 14511b41d2SMark Murray #include "includes.h" 15d4ecd108SDag-Erling Smørgrav RCSID("$OpenBSD: canohost.c,v 1.44 2005/06/17 02:44:32 djm Exp $"); 16511b41d2SMark Murray 17511b41d2SMark Murray #include "packet.h" 18511b41d2SMark Murray #include "xmalloc.h" 19ca3176e7SBrian Feldman #include "log.h" 20ca3176e7SBrian Feldman #include "canohost.h" 21ca3176e7SBrian Feldman 22af12a3e7SDag-Erling Smørgrav static void check_ip_options(int, char *); 23511b41d2SMark Murray 24511b41d2SMark Murray /* 25511b41d2SMark Murray * Return the canonical name of the host at the other end of the socket. The 26511b41d2SMark Murray * caller should free the returned string with xfree. 27511b41d2SMark Murray */ 28511b41d2SMark Murray 29af12a3e7SDag-Erling Smørgrav static char * 3021e764dfSDag-Erling Smørgrav get_remote_hostname(int sock, int use_dns) 31511b41d2SMark Murray { 32511b41d2SMark Murray struct sockaddr_storage from; 33511b41d2SMark Murray int i; 34511b41d2SMark Murray socklen_t fromlen; 35511b41d2SMark Murray struct addrinfo hints, *ai, *aitop; 36ca3176e7SBrian Feldman char name[NI_MAXHOST], ntop[NI_MAXHOST], ntop2[NI_MAXHOST]; 37511b41d2SMark Murray 38511b41d2SMark Murray /* Get IP address of client. */ 39511b41d2SMark Murray fromlen = sizeof(from); 40511b41d2SMark Murray memset(&from, 0, sizeof(from)); 4121e764dfSDag-Erling Smørgrav if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) { 42511b41d2SMark Murray debug("getpeername failed: %.100s", strerror(errno)); 431ec0d754SDag-Erling Smørgrav cleanup_exit(255); 44511b41d2SMark Murray } 45989dd127SDag-Erling Smørgrav 465962c0e9SDag-Erling Smørgrav if (from.ss_family == AF_INET) 4721e764dfSDag-Erling Smørgrav check_ip_options(sock, ntop); 485962c0e9SDag-Erling Smørgrav 491ec0d754SDag-Erling Smørgrav ipv64_normalise_mapped(&from, &fromlen); 50989dd127SDag-Erling Smørgrav 51e73e9afaSDag-Erling Smørgrav if (from.ss_family == AF_INET6) 52e73e9afaSDag-Erling Smørgrav fromlen = sizeof(struct sockaddr_in6); 53ca3176e7SBrian Feldman 54511b41d2SMark Murray if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop), 55511b41d2SMark Murray NULL, 0, NI_NUMERICHOST) != 0) 56511b41d2SMark Murray fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed"); 57511b41d2SMark Murray 58cf2b5f3bSDag-Erling Smørgrav if (!use_dns) 59cf2b5f3bSDag-Erling Smørgrav return xstrdup(ntop); 60cf2b5f3bSDag-Erling Smørgrav 61ca3176e7SBrian Feldman debug3("Trying to reverse map address %.100s.", ntop); 62511b41d2SMark Murray /* Map the IP address to a host name. */ 63511b41d2SMark Murray if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), 64ca3176e7SBrian Feldman NULL, 0, NI_NAMEREQD) != 0) { 65ca3176e7SBrian Feldman /* Host name not found. Use ip address. */ 66ca3176e7SBrian Feldman return xstrdup(ntop); 67ca3176e7SBrian Feldman } 68ca3176e7SBrian Feldman 69cf2b5f3bSDag-Erling Smørgrav /* 70cf2b5f3bSDag-Erling Smørgrav * if reverse lookup result looks like a numeric hostname, 71cf2b5f3bSDag-Erling Smørgrav * someone is trying to trick us by PTR record like following: 72cf2b5f3bSDag-Erling Smørgrav * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 73cf2b5f3bSDag-Erling Smørgrav */ 74cf2b5f3bSDag-Erling Smørgrav memset(&hints, 0, sizeof(hints)); 75cf2b5f3bSDag-Erling Smørgrav hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 76cf2b5f3bSDag-Erling Smørgrav hints.ai_flags = AI_NUMERICHOST; 77cf2b5f3bSDag-Erling Smørgrav if (getaddrinfo(name, "0", &hints, &ai) == 0) { 78cf2b5f3bSDag-Erling Smørgrav logit("Nasty PTR record \"%s\" is set up for %s, ignoring", 79cf2b5f3bSDag-Erling Smørgrav name, ntop); 80cf2b5f3bSDag-Erling Smørgrav freeaddrinfo(ai); 81cf2b5f3bSDag-Erling Smørgrav return xstrdup(ntop); 82cf2b5f3bSDag-Erling Smørgrav } 83cf2b5f3bSDag-Erling Smørgrav 84511b41d2SMark Murray /* 85511b41d2SMark Murray * Convert it to all lowercase (which is expected by the rest 86511b41d2SMark Murray * of this software). 87511b41d2SMark Murray */ 88511b41d2SMark Murray for (i = 0; name[i]; i++) 89511b41d2SMark Murray if (isupper(name[i])) 90511b41d2SMark Murray name[i] = tolower(name[i]); 91511b41d2SMark Murray /* 92511b41d2SMark Murray * Map it back to an IP address and check that the given 93511b41d2SMark Murray * address actually is an address of this host. This is 94511b41d2SMark Murray * necessary because anyone with access to a name server can 95511b41d2SMark Murray * define arbitrary names for an IP address. Mapping from 96511b41d2SMark Murray * name to IP address can be trusted better (but can still be 97511b41d2SMark Murray * fooled if the intruder has access to the name server of 98511b41d2SMark Murray * the domain). 99511b41d2SMark Murray */ 100511b41d2SMark Murray memset(&hints, 0, sizeof(hints)); 101511b41d2SMark Murray hints.ai_family = from.ss_family; 102511b41d2SMark Murray hints.ai_socktype = SOCK_STREAM; 103511b41d2SMark Murray if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { 104cf2b5f3bSDag-Erling Smørgrav logit("reverse mapping checking getaddrinfo for %.700s " 105ca3176e7SBrian Feldman "failed - POSSIBLE BREAKIN ATTEMPT!", name); 106ca3176e7SBrian Feldman return xstrdup(ntop); 107511b41d2SMark Murray } 108511b41d2SMark Murray /* Look for the address from the list of addresses. */ 109511b41d2SMark Murray for (ai = aitop; ai; ai = ai->ai_next) { 110511b41d2SMark Murray if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, 111511b41d2SMark Murray sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && 112511b41d2SMark Murray (strcmp(ntop, ntop2) == 0)) 113511b41d2SMark Murray break; 114511b41d2SMark Murray } 115511b41d2SMark Murray freeaddrinfo(aitop); 116511b41d2SMark Murray /* If we reached the end of the list, the address was not there. */ 117511b41d2SMark Murray if (!ai) { 118511b41d2SMark Murray /* Address not found for the host name. */ 119cf2b5f3bSDag-Erling Smørgrav logit("Address %.100s maps to %.600s, but this does not " 120ca3176e7SBrian Feldman "map back to the address - POSSIBLE BREAKIN ATTEMPT!", 121511b41d2SMark Murray ntop, name); 122ca3176e7SBrian Feldman return xstrdup(ntop); 123511b41d2SMark Murray } 124ca3176e7SBrian Feldman return xstrdup(name); 125511b41d2SMark Murray } 126511b41d2SMark Murray 127511b41d2SMark Murray /* 128511b41d2SMark Murray * If IP options are supported, make sure there are none (log and 129511b41d2SMark Murray * disconnect them if any are found). Basically we are worried about 130511b41d2SMark Murray * source routing; it can be used to pretend you are somebody 131511b41d2SMark Murray * (ip-address) you are not. That itself may be "almost acceptable" 132511b41d2SMark Murray * under certain circumstances, but rhosts autentication is useless 133511b41d2SMark Murray * if source routing is accepted. Notice also that if we just dropped 134511b41d2SMark Murray * source routing here, the other side could use IP spoofing to do 135511b41d2SMark Murray * rest of the interaction and could still bypass security. So we 136511b41d2SMark Murray * exit here if we detect any IP options. 137511b41d2SMark Murray */ 138ca3176e7SBrian Feldman /* IPv4 only */ 139af12a3e7SDag-Erling Smørgrav static void 14021e764dfSDag-Erling Smørgrav check_ip_options(int sock, char *ipaddr) 141ca3176e7SBrian Feldman { 142cf2b5f3bSDag-Erling Smørgrav #ifdef IP_OPTIONS 143ca3176e7SBrian Feldman u_char options[200]; 144ca3176e7SBrian Feldman char text[sizeof(options) * 3 + 1]; 145511b41d2SMark Murray socklen_t option_size; 146d4ecd108SDag-Erling Smørgrav u_int i; 147d4ecd108SDag-Erling Smørgrav int ipproto; 148511b41d2SMark Murray struct protoent *ip; 149511b41d2SMark Murray 150511b41d2SMark Murray if ((ip = getprotobyname("ip")) != NULL) 151511b41d2SMark Murray ipproto = ip->p_proto; 152511b41d2SMark Murray else 153511b41d2SMark Murray ipproto = IPPROTO_IP; 154511b41d2SMark Murray option_size = sizeof(options); 15521e764dfSDag-Erling Smørgrav if (getsockopt(sock, ipproto, IP_OPTIONS, options, 156511b41d2SMark Murray &option_size) >= 0 && option_size != 0) { 157ca3176e7SBrian Feldman text[0] = '\0'; 158ca3176e7SBrian Feldman for (i = 0; i < option_size; i++) 159ca3176e7SBrian Feldman snprintf(text + i*3, sizeof(text) - i*3, 160ca3176e7SBrian Feldman " %2.2x", options[i]); 161cf2b5f3bSDag-Erling Smørgrav logit("Connection from %.100s with IP options:%.800s", 162ca3176e7SBrian Feldman ipaddr, text); 163511b41d2SMark Murray packet_disconnect("Connection from %.100s with IP options:%.800s", 164ca3176e7SBrian Feldman ipaddr, text); 165511b41d2SMark Murray } 166cf2b5f3bSDag-Erling Smørgrav #endif /* IP_OPTIONS */ 167511b41d2SMark Murray } 168511b41d2SMark Murray 169aa49c926SDag-Erling Smørgrav void 1701ec0d754SDag-Erling Smørgrav ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) 1711ec0d754SDag-Erling Smørgrav { 1721ec0d754SDag-Erling Smørgrav struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)addr; 1731ec0d754SDag-Erling Smørgrav struct sockaddr_in *a4 = (struct sockaddr_in *)addr; 1741ec0d754SDag-Erling Smørgrav struct in_addr inaddr; 1751ec0d754SDag-Erling Smørgrav u_int16_t port; 1761ec0d754SDag-Erling Smørgrav 1771ec0d754SDag-Erling Smørgrav if (addr->ss_family != AF_INET6 || 1781ec0d754SDag-Erling Smørgrav !IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr)) 1791ec0d754SDag-Erling Smørgrav return; 1801ec0d754SDag-Erling Smørgrav 1811ec0d754SDag-Erling Smørgrav debug3("Normalising mapped IPv4 in IPv6 address"); 1821ec0d754SDag-Erling Smørgrav 1831ec0d754SDag-Erling Smørgrav memcpy(&inaddr, ((char *)&a6->sin6_addr) + 12, sizeof(inaddr)); 1841ec0d754SDag-Erling Smørgrav port = a6->sin6_port; 1851ec0d754SDag-Erling Smørgrav 1861ec0d754SDag-Erling Smørgrav memset(addr, 0, sizeof(*a4)); 1871ec0d754SDag-Erling Smørgrav 1881ec0d754SDag-Erling Smørgrav a4->sin_family = AF_INET; 1891ec0d754SDag-Erling Smørgrav *len = sizeof(*a4); 1901ec0d754SDag-Erling Smørgrav memcpy(&a4->sin_addr, &inaddr, sizeof(inaddr)); 1911ec0d754SDag-Erling Smørgrav a4->sin_port = port; 1921ec0d754SDag-Erling Smørgrav } 1931ec0d754SDag-Erling Smørgrav 194511b41d2SMark Murray /* 195511b41d2SMark Murray * Return the canonical name of the host in the other side of the current 196511b41d2SMark Murray * connection. The host name is cached, so it is efficient to call this 197511b41d2SMark Murray * several times. 198511b41d2SMark Murray */ 199511b41d2SMark Murray 200511b41d2SMark Murray const char * 201cf2b5f3bSDag-Erling Smørgrav get_canonical_hostname(int use_dns) 202511b41d2SMark Murray { 203511b41d2SMark Murray static char *canonical_host_name = NULL; 204cf2b5f3bSDag-Erling Smørgrav static int use_dns_done = 0; 205511b41d2SMark Murray 206ca3176e7SBrian Feldman /* Check if we have previously retrieved name with same option. */ 207ca3176e7SBrian Feldman if (canonical_host_name != NULL) { 208cf2b5f3bSDag-Erling Smørgrav if (use_dns_done != use_dns) 209ca3176e7SBrian Feldman xfree(canonical_host_name); 210ca3176e7SBrian Feldman else 211511b41d2SMark Murray return canonical_host_name; 212ca3176e7SBrian Feldman } 213511b41d2SMark Murray 214511b41d2SMark Murray /* Get the real hostname if socket; otherwise return UNKNOWN. */ 215511b41d2SMark Murray if (packet_connection_is_on_socket()) 216ca3176e7SBrian Feldman canonical_host_name = get_remote_hostname( 217cf2b5f3bSDag-Erling Smørgrav packet_get_connection_in(), use_dns); 218511b41d2SMark Murray else 219511b41d2SMark Murray canonical_host_name = xstrdup("UNKNOWN"); 220511b41d2SMark Murray 221cf2b5f3bSDag-Erling Smørgrav use_dns_done = use_dns; 222511b41d2SMark Murray return canonical_host_name; 223511b41d2SMark Murray } 224511b41d2SMark Murray 225511b41d2SMark Murray /* 226e73e9afaSDag-Erling Smørgrav * Returns the local/remote IP-address/hostname of socket as a string. 227e73e9afaSDag-Erling Smørgrav * The returned string must be freed. 228ca3176e7SBrian Feldman */ 229af12a3e7SDag-Erling Smørgrav static char * 23021e764dfSDag-Erling Smørgrav get_socket_address(int sock, int remote, int flags) 231ca3176e7SBrian Feldman { 232ca3176e7SBrian Feldman struct sockaddr_storage addr; 233ca3176e7SBrian Feldman socklen_t addrlen; 234ca3176e7SBrian Feldman char ntop[NI_MAXHOST]; 235aa49c926SDag-Erling Smørgrav int r; 236ca3176e7SBrian Feldman 237ca3176e7SBrian Feldman /* Get IP address of client. */ 238ca3176e7SBrian Feldman addrlen = sizeof(addr); 239ca3176e7SBrian Feldman memset(&addr, 0, sizeof(addr)); 240ca3176e7SBrian Feldman 241ca3176e7SBrian Feldman if (remote) { 24221e764dfSDag-Erling Smørgrav if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) 243f388f5efSDag-Erling Smørgrav < 0) 244ca3176e7SBrian Feldman return NULL; 245ca3176e7SBrian Feldman } else { 24621e764dfSDag-Erling Smørgrav if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) 247f388f5efSDag-Erling Smørgrav < 0) 248ca3176e7SBrian Feldman return NULL; 249ca3176e7SBrian Feldman } 250e73e9afaSDag-Erling Smørgrav 251e73e9afaSDag-Erling Smørgrav /* Work around Linux IPv6 weirdness */ 252e73e9afaSDag-Erling Smørgrav if (addr.ss_family == AF_INET6) 253e73e9afaSDag-Erling Smørgrav addrlen = sizeof(struct sockaddr_in6); 254e73e9afaSDag-Erling Smørgrav 255aa49c926SDag-Erling Smørgrav ipv64_normalise_mapped(&addr, &addrlen); 256aa49c926SDag-Erling Smørgrav 257ca3176e7SBrian Feldman /* Get the address in ascii. */ 258aa49c926SDag-Erling Smørgrav if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop, 259aa49c926SDag-Erling Smørgrav sizeof(ntop), NULL, 0, flags)) != 0) { 260aa49c926SDag-Erling Smørgrav error("get_socket_address: getnameinfo %d failed: %s", flags, 261aa49c926SDag-Erling Smørgrav r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r)); 262ca3176e7SBrian Feldman return NULL; 263ca3176e7SBrian Feldman } 264ca3176e7SBrian Feldman return xstrdup(ntop); 265ca3176e7SBrian Feldman } 266ca3176e7SBrian Feldman 267ca3176e7SBrian Feldman char * 26821e764dfSDag-Erling Smørgrav get_peer_ipaddr(int sock) 269ca3176e7SBrian Feldman { 270f388f5efSDag-Erling Smørgrav char *p; 271f388f5efSDag-Erling Smørgrav 27221e764dfSDag-Erling Smørgrav if ((p = get_socket_address(sock, 1, NI_NUMERICHOST)) != NULL) 273f388f5efSDag-Erling Smørgrav return p; 274f388f5efSDag-Erling Smørgrav return xstrdup("UNKNOWN"); 275ca3176e7SBrian Feldman } 276ca3176e7SBrian Feldman 277ca3176e7SBrian Feldman char * 27821e764dfSDag-Erling Smørgrav get_local_ipaddr(int sock) 279ca3176e7SBrian Feldman { 280f388f5efSDag-Erling Smørgrav char *p; 281f388f5efSDag-Erling Smørgrav 28221e764dfSDag-Erling Smørgrav if ((p = get_socket_address(sock, 0, NI_NUMERICHOST)) != NULL) 283f388f5efSDag-Erling Smørgrav return p; 284f388f5efSDag-Erling Smørgrav return xstrdup("UNKNOWN"); 285ca3176e7SBrian Feldman } 286ca3176e7SBrian Feldman 287ca3176e7SBrian Feldman char * 28821e764dfSDag-Erling Smørgrav get_local_name(int sock) 289ca3176e7SBrian Feldman { 29021e764dfSDag-Erling Smørgrav return get_socket_address(sock, 0, NI_NAMEREQD); 291ca3176e7SBrian Feldman } 292ca3176e7SBrian Feldman 293ca3176e7SBrian Feldman /* 294511b41d2SMark Murray * Returns the IP-address of the remote host as a string. The returned 295511b41d2SMark Murray * string must not be freed. 296511b41d2SMark Murray */ 297511b41d2SMark Murray 298511b41d2SMark Murray const char * 299af12a3e7SDag-Erling Smørgrav get_remote_ipaddr(void) 300511b41d2SMark Murray { 301511b41d2SMark Murray static char *canonical_host_ip = NULL; 302511b41d2SMark Murray 303ca3176e7SBrian Feldman /* Check whether we have cached the ipaddr. */ 304ca3176e7SBrian Feldman if (canonical_host_ip == NULL) { 305ca3176e7SBrian Feldman if (packet_connection_is_on_socket()) { 306ca3176e7SBrian Feldman canonical_host_ip = 307ca3176e7SBrian Feldman get_peer_ipaddr(packet_get_connection_in()); 308ca3176e7SBrian Feldman if (canonical_host_ip == NULL) 3091ec0d754SDag-Erling Smørgrav cleanup_exit(255); 310ca3176e7SBrian Feldman } else { 311ca3176e7SBrian Feldman /* If not on socket, return UNKNOWN. */ 312ca3176e7SBrian Feldman canonical_host_ip = xstrdup("UNKNOWN"); 313511b41d2SMark Murray } 314ca3176e7SBrian Feldman } 315511b41d2SMark Murray return canonical_host_ip; 316511b41d2SMark Murray } 317511b41d2SMark Murray 3187e03cf33SBrian Feldman const char * 319cf2b5f3bSDag-Erling Smørgrav get_remote_name_or_ip(u_int utmp_len, int use_dns) 3207e03cf33SBrian Feldman { 321ca3176e7SBrian Feldman static const char *remote = ""; 322ca3176e7SBrian Feldman if (utmp_len > 0) 323cf2b5f3bSDag-Erling Smørgrav remote = get_canonical_hostname(use_dns); 324ca3176e7SBrian Feldman if (utmp_len == 0 || strlen(remote) > utmp_len) 325ca3176e7SBrian Feldman remote = get_remote_ipaddr(); 326ca3176e7SBrian Feldman return remote; 3277e03cf33SBrian Feldman } 3287e03cf33SBrian Feldman 329511b41d2SMark Murray /* Returns the local/remote port for the socket. */ 330511b41d2SMark Murray 331af12a3e7SDag-Erling Smørgrav static int 332511b41d2SMark Murray get_sock_port(int sock, int local) 333511b41d2SMark Murray { 334511b41d2SMark Murray struct sockaddr_storage from; 335511b41d2SMark Murray socklen_t fromlen; 336511b41d2SMark Murray char strport[NI_MAXSERV]; 337aa49c926SDag-Erling Smørgrav int r; 338511b41d2SMark Murray 339511b41d2SMark Murray /* Get IP address of client. */ 340511b41d2SMark Murray fromlen = sizeof(from); 341511b41d2SMark Murray memset(&from, 0, sizeof(from)); 342511b41d2SMark Murray if (local) { 343511b41d2SMark Murray if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) { 344511b41d2SMark Murray error("getsockname failed: %.100s", strerror(errno)); 345511b41d2SMark Murray return 0; 346511b41d2SMark Murray } 347511b41d2SMark Murray } else { 348511b41d2SMark Murray if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) { 349511b41d2SMark Murray debug("getpeername failed: %.100s", strerror(errno)); 350d4ecd108SDag-Erling Smørgrav return -1; 351511b41d2SMark Murray } 352511b41d2SMark Murray } 353e73e9afaSDag-Erling Smørgrav 354e73e9afaSDag-Erling Smørgrav /* Work around Linux IPv6 weirdness */ 355e73e9afaSDag-Erling Smørgrav if (from.ss_family == AF_INET6) 356e73e9afaSDag-Erling Smørgrav fromlen = sizeof(struct sockaddr_in6); 357e73e9afaSDag-Erling Smørgrav 358511b41d2SMark Murray /* Return port number. */ 359aa49c926SDag-Erling Smørgrav if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, 360aa49c926SDag-Erling Smørgrav strport, sizeof(strport), NI_NUMERICSERV)) != 0) 361aa49c926SDag-Erling Smørgrav fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed: %s", 362aa49c926SDag-Erling Smørgrav r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r)); 363511b41d2SMark Murray return atoi(strport); 364511b41d2SMark Murray } 365511b41d2SMark Murray 366511b41d2SMark Murray /* Returns remote/local port number for the current connection. */ 367511b41d2SMark Murray 368af12a3e7SDag-Erling Smørgrav static int 369511b41d2SMark Murray get_port(int local) 370511b41d2SMark Murray { 371511b41d2SMark Murray /* 372511b41d2SMark Murray * If the connection is not a socket, return 65535. This is 373511b41d2SMark Murray * intentionally chosen to be an unprivileged port number. 374511b41d2SMark Murray */ 375511b41d2SMark Murray if (!packet_connection_is_on_socket()) 376511b41d2SMark Murray return 65535; 377511b41d2SMark Murray 378511b41d2SMark Murray /* Get socket and return the port number. */ 379511b41d2SMark Murray return get_sock_port(packet_get_connection_in(), local); 380511b41d2SMark Murray } 381511b41d2SMark Murray 382511b41d2SMark Murray int 383511b41d2SMark Murray get_peer_port(int sock) 384511b41d2SMark Murray { 385511b41d2SMark Murray return get_sock_port(sock, 0); 386511b41d2SMark Murray } 387511b41d2SMark Murray 388511b41d2SMark Murray int 389af12a3e7SDag-Erling Smørgrav get_remote_port(void) 390511b41d2SMark Murray { 39121e764dfSDag-Erling Smørgrav static int port = -1; 39221e764dfSDag-Erling Smørgrav 39321e764dfSDag-Erling Smørgrav /* Cache to avoid getpeername() on a dead connection */ 39421e764dfSDag-Erling Smørgrav if (port == -1) 39521e764dfSDag-Erling Smørgrav port = get_port(0); 39621e764dfSDag-Erling Smørgrav 39721e764dfSDag-Erling Smørgrav return port; 398511b41d2SMark Murray } 399511b41d2SMark Murray 400511b41d2SMark Murray int 401af12a3e7SDag-Erling Smørgrav get_local_port(void) 402511b41d2SMark Murray { 403511b41d2SMark Murray return get_port(1); 404511b41d2SMark Murray } 405