1323124Sdes/* $OpenBSD: canohost.c,v 1.73 2016/03/07 19:02:43 djm Exp $ */ 257429Smarkm/* 357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 557429Smarkm * All rights reserved 657429Smarkm * Functions for returning the canonical host name of the remote site. 760573Skris * 865674Skris * As far as I am concerned, the code I have written for this software 965674Skris * can be used freely for any purpose. Any derived versions of this 1065674Skris * software must be clearly marked as such, and if the derived work is 1165674Skris * incompatible with the protocol description in the RFC file, it must be 1265674Skris * called by a name other than "ssh" or "Secure Shell". 1357429Smarkm */ 1457429Smarkm 1557429Smarkm#include "includes.h" 1657429Smarkm 17162856Sdes#include <sys/types.h> 18162856Sdes#include <sys/socket.h> 19295367Sdes#include <sys/un.h> 20162856Sdes 21162856Sdes#include <netinet/in.h> 22162856Sdes#include <arpa/inet.h> 23162856Sdes 24162856Sdes#include <errno.h> 25162856Sdes#include <netdb.h> 26162856Sdes#include <stdio.h> 27162856Sdes#include <stdlib.h> 28162856Sdes#include <string.h> 29162856Sdes#include <stdarg.h> 30204917Sdes#include <unistd.h> 31162856Sdes 32162856Sdes#include "xmalloc.h" 3357429Smarkm#include "packet.h" 3476262Sgreen#include "log.h" 3576262Sgreen#include "canohost.h" 36181111Sdes#include "misc.h" 3757429Smarkm 38147005Sdesvoid 39126277Sdesipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) 40126277Sdes{ 41126277Sdes struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)addr; 42126277Sdes struct sockaddr_in *a4 = (struct sockaddr_in *)addr; 43126277Sdes struct in_addr inaddr; 44126277Sdes u_int16_t port; 45126277Sdes 46149753Sdes if (addr->ss_family != AF_INET6 || 47126277Sdes !IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr)) 48126277Sdes return; 49126277Sdes 50126277Sdes debug3("Normalising mapped IPv4 in IPv6 address"); 51126277Sdes 52126277Sdes memcpy(&inaddr, ((char *)&a6->sin6_addr) + 12, sizeof(inaddr)); 53126277Sdes port = a6->sin6_port; 54126277Sdes 55264377Sdes memset(a4, 0, sizeof(*a4)); 56126277Sdes 57126277Sdes a4->sin_family = AF_INET; 58126277Sdes *len = sizeof(*a4); 59126277Sdes memcpy(&a4->sin_addr, &inaddr, sizeof(inaddr)); 60126277Sdes a4->sin_port = port; 61126277Sdes} 62126277Sdes 6376262Sgreen/* 64113911Sdes * Returns the local/remote IP-address/hostname of socket as a string. 65113911Sdes * The returned string must be freed. 6657429Smarkm */ 6792559Sdesstatic char * 68137019Sdesget_socket_address(int sock, int remote, int flags) 6957429Smarkm{ 7076262Sgreen struct sockaddr_storage addr; 7176262Sgreen socklen_t addrlen; 7257429Smarkm char ntop[NI_MAXHOST]; 73147005Sdes int r; 7457429Smarkm 7576262Sgreen /* Get IP address of client. */ 7676262Sgreen addrlen = sizeof(addr); 7776262Sgreen memset(&addr, 0, sizeof(addr)); 7857429Smarkm 7976262Sgreen if (remote) { 80323124Sdes if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) != 0) 8176262Sgreen return NULL; 8276262Sgreen } else { 83323124Sdes if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) != 0) 8476262Sgreen return NULL; 8557429Smarkm } 86113911Sdes 87113911Sdes /* Work around Linux IPv6 weirdness */ 88295367Sdes if (addr.ss_family == AF_INET6) { 89113911Sdes addrlen = sizeof(struct sockaddr_in6); 90295367Sdes ipv64_normalise_mapped(&addr, &addrlen); 91295367Sdes } 92113911Sdes 93295367Sdes switch (addr.ss_family) { 94295367Sdes case AF_INET: 95295367Sdes case AF_INET6: 96295367Sdes /* Get the address in ascii. */ 97295367Sdes if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop, 98295367Sdes sizeof(ntop), NULL, 0, flags)) != 0) { 99323124Sdes error("%s: getnameinfo %d failed: %s", __func__, 100295367Sdes flags, ssh_gai_strerror(r)); 101295367Sdes return NULL; 102295367Sdes } 103295367Sdes return xstrdup(ntop); 104295367Sdes case AF_UNIX: 105295367Sdes /* Get the Unix domain socket path. */ 106295367Sdes return xstrdup(((struct sockaddr_un *)&addr)->sun_path); 107295367Sdes default: 108295367Sdes /* We can't look up remote Unix domain sockets. */ 10976262Sgreen return NULL; 11057429Smarkm } 11176262Sgreen} 11257429Smarkm 11376262Sgreenchar * 114137019Sdesget_peer_ipaddr(int sock) 11576262Sgreen{ 116106130Sdes char *p; 117106130Sdes 118137019Sdes if ((p = get_socket_address(sock, 1, NI_NUMERICHOST)) != NULL) 119106130Sdes return p; 120106130Sdes return xstrdup("UNKNOWN"); 12176262Sgreen} 12257429Smarkm 12376262Sgreenchar * 124137019Sdesget_local_ipaddr(int sock) 12576262Sgreen{ 126106130Sdes char *p; 127106130Sdes 128137019Sdes if ((p = get_socket_address(sock, 0, NI_NUMERICHOST)) != NULL) 129106130Sdes return p; 130106130Sdes return xstrdup("UNKNOWN"); 13157429Smarkm} 13257429Smarkm 13376262Sgreenchar * 134204917Sdesget_local_name(int fd) 13576262Sgreen{ 136204917Sdes char *host, myname[NI_MAXHOST]; 137204917Sdes 138204917Sdes /* Assume we were passed a socket */ 139204917Sdes if ((host = get_socket_address(fd, 0, NI_NAMEREQD)) != NULL) 140204917Sdes return host; 141204917Sdes 142204917Sdes /* Handle the case where we were passed a pipe */ 143204917Sdes if (gethostname(myname, sizeof(myname)) == -1) { 144323124Sdes verbose("%s: gethostname: %s", __func__, strerror(errno)); 145323124Sdes host = xstrdup("UNKNOWN"); 146204917Sdes } else { 147204917Sdes host = xstrdup(myname); 148204917Sdes } 149204917Sdes 150204917Sdes return host; 15176262Sgreen} 15276262Sgreen 15357429Smarkm/* Returns the local/remote port for the socket. */ 15457429Smarkm 155323124Sdesstatic int 15657429Smarkmget_sock_port(int sock, int local) 15757429Smarkm{ 15857429Smarkm struct sockaddr_storage from; 15957429Smarkm socklen_t fromlen; 16057429Smarkm char strport[NI_MAXSERV]; 161147005Sdes int r; 16257429Smarkm 16357429Smarkm /* Get IP address of client. */ 16457429Smarkm fromlen = sizeof(from); 16557429Smarkm memset(&from, 0, sizeof(from)); 16657429Smarkm if (local) { 16757429Smarkm if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) { 16857429Smarkm error("getsockname failed: %.100s", strerror(errno)); 16957429Smarkm return 0; 17057429Smarkm } 17157429Smarkm } else { 172113911Sdes if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) { 17357429Smarkm debug("getpeername failed: %.100s", strerror(errno)); 174149753Sdes return -1; 17557429Smarkm } 17657429Smarkm } 177113911Sdes 178113911Sdes /* Work around Linux IPv6 weirdness */ 179113911Sdes if (from.ss_family == AF_INET6) 180113911Sdes fromlen = sizeof(struct sockaddr_in6); 181113911Sdes 182295367Sdes /* Non-inet sockets don't have a port number. */ 183295367Sdes if (from.ss_family != AF_INET && from.ss_family != AF_INET6) 184295367Sdes return 0; 185295367Sdes 18657429Smarkm /* Return port number. */ 187147005Sdes if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0, 188147005Sdes strport, sizeof(strport), NI_NUMERICSERV)) != 0) 189323124Sdes fatal("%s: getnameinfo NI_NUMERICSERV failed: %s", __func__, 190181111Sdes ssh_gai_strerror(r)); 19157429Smarkm return atoi(strport); 19257429Smarkm} 19357429Smarkm 19460573Skrisint 19557429Smarkmget_peer_port(int sock) 19657429Smarkm{ 19757429Smarkm return get_sock_port(sock, 0); 19857429Smarkm} 19957429Smarkm 20060573Skrisint 201323124Sdesget_local_port(int sock) 20257429Smarkm{ 203323124Sdes return get_sock_port(sock, 1); 20457429Smarkm} 205