canohost.c revision 1.15
1/*	$NetBSD: canohost.c,v 1.15 2023/07/26 17:58:15 christos Exp $	*/
2/* $OpenBSD: canohost.c,v 1.76 2023/03/03 05:00:34 djm Exp $ */
3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
5 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 *                    All rights reserved
7 * Functions for returning the canonical host name of the remote site.
8 *
9 * As far as I am concerned, the code I have written for this software
10 * can be used freely for any purpose.  Any derived versions of this
11 * software must be clearly marked as such, and if the derived work is
12 * incompatible with the protocol description in the RFC file, it must be
13 * called by a name other than "ssh" or "Secure Shell".
14 */
15
16#include "includes.h"
17__RCSID("$NetBSD: canohost.c,v 1.15 2023/07/26 17:58:15 christos Exp $");
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <sys/un.h>
21
22#include <netinet/in.h>
23
24#include <errno.h>
25#include <netdb.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <stdarg.h>
30#include <time.h>
31#include <unistd.h>
32
33#include "xmalloc.h"
34#include "packet.h"
35#include "log.h"
36#include "canohost.h"
37#include "misc.h"
38
39/*
40 * Returns the local/remote IP-address/hostname of socket as a string.
41 * The returned string must be freed.
42 */
43static char *
44get_socket_address(int sock, int remote, int flags)
45{
46	struct sockaddr_storage addr;
47	socklen_t addrlen;
48	char ntop[NI_MAXHOST];
49	int r;
50
51	if (sock < 0)
52		return NULL;
53
54	/* Get IP address of client. */
55	addrlen = sizeof(addr);
56	memset(&addr, 0, sizeof(addr));
57
58	if (remote) {
59		if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) != 0)
60			return NULL;
61	} else {
62		if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) != 0)
63			return NULL;
64	}
65
66	switch (addr.ss_family) {
67	case AF_INET:
68	case AF_INET6:
69		/* Get the address in ascii. */
70		if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop,
71		    sizeof(ntop), NULL, 0, flags)) != 0) {
72			error_f("getnameinfo %d failed: %s",
73			    flags, ssh_gai_strerror(r));
74			return NULL;
75		}
76		return xstrdup(ntop);
77	case AF_UNIX:
78		/* Get the Unix domain socket path. */
79		return xstrdup(((struct sockaddr_un *)&addr)->sun_path);
80	default:
81		/* We can't look up remote Unix domain sockets. */
82		return NULL;
83	}
84}
85
86char *
87get_peer_ipaddr(int sock)
88{
89	char *p;
90
91	if ((p = get_socket_address(sock, 1, NI_NUMERICHOST)) != NULL)
92		return p;
93	return xstrdup("UNKNOWN");
94}
95
96char *
97get_local_ipaddr(int sock)
98{
99	char *p;
100
101	if ((p = get_socket_address(sock, 0, NI_NUMERICHOST)) != NULL)
102		return p;
103	return xstrdup("UNKNOWN");
104}
105
106char *
107get_local_name(int fd)
108{
109	char *host, myname[NI_MAXHOST];
110
111	/* Assume we were passed a socket */
112	if ((host = get_socket_address(fd, 0, NI_NAMEREQD)) != NULL)
113		return host;
114
115	/* Handle the case where we were passed a pipe */
116	if (gethostname(myname, sizeof(myname)) == -1) {
117		verbose_f("gethostname: %s", strerror(errno));
118		host = xstrdup("UNKNOWN");
119	} else {
120		host = xstrdup(myname);
121	}
122
123	return host;
124}
125
126/* Returns the local/remote port for the socket. */
127
128static int
129get_sock_port(int sock, int local)
130{
131	struct sockaddr_storage from;
132	socklen_t fromlen;
133	char strport[NI_MAXSERV];
134	int r;
135
136	/* Get IP address of client. */
137	fromlen = sizeof(from);
138	memset(&from, 0, sizeof(from));
139	if (local) {
140		if (getsockname(sock, (struct sockaddr *)&from, &fromlen) == -1) {
141			error("getsockname failed: %.100s", strerror(errno));
142			return 0;
143		}
144	} else {
145		if (getpeername(sock, (struct sockaddr *)&from, &fromlen) == -1) {
146			debug("getpeername failed: %.100s", strerror(errno));
147			return -1;
148		}
149	}
150
151	/* Non-inet sockets don't have a port number. */
152	if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
153		return 0;
154
155	/* Return port number. */
156	if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
157	    strport, sizeof(strport), NI_NUMERICSERV)) != 0)
158		fatal_f("getnameinfo NI_NUMERICSERV failed: %s",
159		    ssh_gai_strerror(r));
160	return atoi(strport);
161}
162
163int
164get_peer_port(int sock)
165{
166	return get_sock_port(sock, 0);
167}
168
169int
170get_local_port(int sock)
171{
172	return get_sock_port(sock, 1);
173}
174