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