blob: f71a08568ed9fa0883a96126e08c1cbc11029bc3 [file] [log] [blame]
djm@openbsd.org95767262016-03-07 19:02:43 +00001/* $OpenBSD: canohost.c,v 1.73 2016/03/07 19:02:43 djm Exp $ */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002/*
Damien Miller95def091999-11-25 00:26:21 +11003 * Author: Tatu Ylonen <ylo@cs.hut.fi>
Damien Miller95def091999-11-25 00:26:21 +11004 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
Damien Miller95def091999-11-25 00:26:21 +11006 * Functions for returning the canonical host name of the remote site.
Damien Miller4af51302000-04-16 11:18:38 +10007 *
Damien Millere4340be2000-09-16 13:29:08 +11008 * As far as I am concerned, the code I have written for this software
9 * can be used freely for any purpose. Any derived versions of this
10 * software must be clearly marked as such, and if the derived work is
11 * incompatible with the protocol description in the RFC file, it must be
12 * called by a name other than "ssh" or "Secure Shell".
Damien Miller95def091999-11-25 00:26:21 +110013 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100014
15#include "includes.h"
Damien Millerc7b06362006-03-15 11:53:45 +110016
Damien Millere3b60b52006-07-10 21:08:03 +100017#include <sys/types.h>
Damien Miller8ec8c3e2006-07-10 20:35:38 +100018#include <sys/socket.h>
Damien Miller7acefbb2014-07-18 14:11:24 +100019#include <sys/un.h>
Damien Miller8ec8c3e2006-07-10 20:35:38 +100020
21#include <netinet/in.h>
Darren Tuckerdace2332006-09-22 19:22:17 +100022#include <arpa/inet.h>
Damien Miller8ec8c3e2006-07-10 20:35:38 +100023
Darren Tucker39972492006-07-12 22:22:46 +100024#include <errno.h>
Damien Millerb8fe89c2006-07-24 14:51:00 +100025#include <netdb.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100026#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100027#include <stdlib.h>
Damien Millere3476ed2006-07-24 14:13:33 +100028#include <string.h>
Damien Millerd7834352006-08-05 12:39:39 +100029#include <stdarg.h>
Darren Tuckerdaaa4502010-01-13 22:43:33 +110030#include <unistd.h>
Damien Millerd4a8b7e1999-10-27 13:42:43 +100031
Damien Millerd4a8b7e1999-10-27 13:42:43 +100032#include "xmalloc.h"
Damien Millerd7834352006-08-05 12:39:39 +100033#include "packet.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000034#include "log.h"
Ben Lindstrom31ca54a2001-02-09 02:11:24 +000035#include "canohost.h"
Darren Tucker4abde772007-12-29 02:43:51 +110036#include "misc.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100037
Darren Tucker2fba9932005-02-02 23:30:24 +110038void
Damien Miller927f5272003-11-24 12:57:25 +110039ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len)
40{
41 struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)addr;
42 struct sockaddr_in *a4 = (struct sockaddr_in *)addr;
43 struct in_addr inaddr;
44 u_int16_t port;
45
Damien Miller94cf4c82005-07-17 17:04:47 +100046 if (addr->ss_family != AF_INET6 ||
Damien Miller927f5272003-11-24 12:57:25 +110047 !IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr))
48 return;
49
50 debug3("Normalising mapped IPv4 in IPv6 address");
51
52 memcpy(&inaddr, ((char *)&a6->sin6_addr) + 12, sizeof(inaddr));
53 port = a6->sin6_port;
54
Damien Miller1d2c4562014-02-04 11:18:20 +110055 memset(a4, 0, sizeof(*a4));
Damien Miller927f5272003-11-24 12:57:25 +110056
57 a4->sin_family = AF_INET;
58 *len = sizeof(*a4);
59 memcpy(&a4->sin_addr, &inaddr, sizeof(inaddr));
60 a4->sin_port = port;
61}
62
Damien Miller33804262001-02-04 23:20:18 +110063/*
Ben Lindstromacaac972002-12-23 02:13:37 +000064 * Returns the local/remote IP-address/hostname of socket as a string.
65 * The returned string must be freed.
Damien Millerd83ff352001-01-30 09:19:34 +110066 */
Ben Lindstrombba81212001-06-25 05:01:22 +000067static char *
Darren Tucker3f9fdc72004-06-22 12:56:01 +100068get_socket_address(int sock, int remote, int flags)
Ben Lindstrom5eabda32001-04-12 23:34:34 +000069{
70 struct sockaddr_storage addr;
71 socklen_t addrlen;
72 char ntop[NI_MAXHOST];
Damien Miller9b8073e2005-03-01 21:16:18 +110073 int r;
Ben Lindstrom5eabda32001-04-12 23:34:34 +000074
75 /* Get IP address of client. */
76 addrlen = sizeof(addr);
77 memset(&addr, 0, sizeof(addr));
78
79 if (remote) {
djm@openbsd.org95767262016-03-07 19:02:43 +000080 if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) != 0)
Ben Lindstrom5eabda32001-04-12 23:34:34 +000081 return NULL;
Ben Lindstrom5eabda32001-04-12 23:34:34 +000082 } else {
djm@openbsd.org95767262016-03-07 19:02:43 +000083 if (getsockname(sock, (struct sockaddr *)&addr, &addrlen) != 0)
Ben Lindstrom5eabda32001-04-12 23:34:34 +000084 return NULL;
Ben Lindstrom5eabda32001-04-12 23:34:34 +000085 }
Damien Miller5e4471e2003-01-07 10:51:23 +110086
87 /* Work around Linux IPv6 weirdness */
millert@openbsd.org39e2f122015-03-01 15:44:40 +000088 if (addr.ss_family == AF_INET6) {
Damien Miller5e4471e2003-01-07 10:51:23 +110089 addrlen = sizeof(struct sockaddr_in6);
millert@openbsd.org39e2f122015-03-01 15:44:40 +000090 ipv64_normalise_mapped(&addr, &addrlen);
91 }
Damien Miller5e4471e2003-01-07 10:51:23 +110092
millert@openbsd.org39e2f122015-03-01 15:44:40 +000093 switch (addr.ss_family) {
94 case AF_INET:
95 case AF_INET6:
96 /* Get the address in ascii. */
97 if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop,
98 sizeof(ntop), NULL, 0, flags)) != 0) {
djm@openbsd.org95767262016-03-07 19:02:43 +000099 error("%s: getnameinfo %d failed: %s", __func__,
millert@openbsd.org39e2f122015-03-01 15:44:40 +0000100 flags, ssh_gai_strerror(r));
101 return NULL;
102 }
103 return xstrdup(ntop);
104 case AF_UNIX:
Damien Miller7acefbb2014-07-18 14:11:24 +1000105 /* Get the Unix domain socket path. */
106 return xstrdup(((struct sockaddr_un *)&addr)->sun_path);
millert@openbsd.org39e2f122015-03-01 15:44:40 +0000107 default:
108 /* We can't look up remote Unix domain sockets. */
Ben Lindstrom5eabda32001-04-12 23:34:34 +0000109 return NULL;
110 }
Ben Lindstrom5eabda32001-04-12 23:34:34 +0000111}
Damien Millerd83ff352001-01-30 09:19:34 +1100112
113char *
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000114get_peer_ipaddr(int sock)
Damien Millerd83ff352001-01-30 09:19:34 +1100115{
Damien Millerb2f844d2002-09-25 12:19:08 +1000116 char *p;
117
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000118 if ((p = get_socket_address(sock, 1, NI_NUMERICHOST)) != NULL)
Damien Millerb2f844d2002-09-25 12:19:08 +1000119 return p;
120 return xstrdup("UNKNOWN");
Ben Lindstrom5eabda32001-04-12 23:34:34 +0000121}
Damien Millerd83ff352001-01-30 09:19:34 +1100122
Ben Lindstrom5eabda32001-04-12 23:34:34 +0000123char *
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000124get_local_ipaddr(int sock)
Ben Lindstrom5eabda32001-04-12 23:34:34 +0000125{
Damien Millerb2f844d2002-09-25 12:19:08 +1000126 char *p;
127
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000128 if ((p = get_socket_address(sock, 0, NI_NUMERICHOST)) != NULL)
Damien Millerb2f844d2002-09-25 12:19:08 +1000129 return p;
130 return xstrdup("UNKNOWN");
Ben Lindstrom5eabda32001-04-12 23:34:34 +0000131}
132
133char *
Darren Tuckerdaaa4502010-01-13 22:43:33 +1100134get_local_name(int fd)
Ben Lindstrom5eabda32001-04-12 23:34:34 +0000135{
Darren Tuckerdaaa4502010-01-13 22:43:33 +1100136 char *host, myname[NI_MAXHOST];
137
138 /* Assume we were passed a socket */
139 if ((host = get_socket_address(fd, 0, NI_NAMEREQD)) != NULL)
140 return host;
141
142 /* Handle the case where we were passed a pipe */
143 if (gethostname(myname, sizeof(myname)) == -1) {
djm@openbsd.org95767262016-03-07 19:02:43 +0000144 verbose("%s: gethostname: %s", __func__, strerror(errno));
145 host = xstrdup("UNKNOWN");
Darren Tuckerdaaa4502010-01-13 22:43:33 +1100146 } else {
147 host = xstrdup(myname);
148 }
149
150 return host;
Damien Millerd83ff352001-01-30 09:19:34 +1100151}
152
Damien Miller34132e52000-01-14 15:45:46 +1100153/* Returns the local/remote port for the socket. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000154
djm@openbsd.org95767262016-03-07 19:02:43 +0000155static int
Damien Miller34132e52000-01-14 15:45:46 +1100156get_sock_port(int sock, int local)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000157{
Damien Miller34132e52000-01-14 15:45:46 +1100158 struct sockaddr_storage from;
159 socklen_t fromlen;
160 char strport[NI_MAXSERV];
Damien Miller9b8073e2005-03-01 21:16:18 +1100161 int r;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000162
Damien Miller95def091999-11-25 00:26:21 +1100163 /* Get IP address of client. */
164 fromlen = sizeof(from);
165 memset(&from, 0, sizeof(from));
Damien Miller34132e52000-01-14 15:45:46 +1100166 if (local) {
167 if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
168 error("getsockname failed: %.100s", strerror(errno));
169 return 0;
170 }
171 } else {
Ben Lindstromacaac972002-12-23 02:13:37 +0000172 if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) {
Damien Miller34132e52000-01-14 15:45:46 +1100173 debug("getpeername failed: %.100s", strerror(errno));
Damien Miller677257f2005-06-17 12:55:03 +1000174 return -1;
Damien Miller34132e52000-01-14 15:45:46 +1100175 }
Damien Miller95def091999-11-25 00:26:21 +1100176 }
Damien Miller5e4471e2003-01-07 10:51:23 +1100177
178 /* Work around Linux IPv6 weirdness */
179 if (from.ss_family == AF_INET6)
180 fromlen = sizeof(struct sockaddr_in6);
181
millert@openbsd.org39e2f122015-03-01 15:44:40 +0000182 /* Non-inet sockets don't have a port number. */
183 if (from.ss_family != AF_INET && from.ss_family != AF_INET6)
Damien Miller7acefbb2014-07-18 14:11:24 +1000184 return 0;
185
Damien Miller95def091999-11-25 00:26:21 +1100186 /* Return port number. */
Damien Miller9b8073e2005-03-01 21:16:18 +1100187 if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
188 strport, sizeof(strport), NI_NUMERICSERV)) != 0)
djm@openbsd.org95767262016-03-07 19:02:43 +0000189 fatal("%s: getnameinfo NI_NUMERICSERV failed: %s", __func__,
Darren Tucker4abde772007-12-29 02:43:51 +1100190 ssh_gai_strerror(r));
Damien Miller34132e52000-01-14 15:45:46 +1100191 return atoi(strport);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000192}
193
Damien Miller4af51302000-04-16 11:18:38 +1000194int
Damien Miller34132e52000-01-14 15:45:46 +1100195get_peer_port(int sock)
196{
197 return get_sock_port(sock, 0);
198}
199
Damien Miller4af51302000-04-16 11:18:38 +1000200int
djm@openbsd.org95767262016-03-07 19:02:43 +0000201get_local_port(int sock)
Damien Miller34132e52000-01-14 15:45:46 +1100202{
djm@openbsd.org95767262016-03-07 19:02:43 +0000203 return get_sock_port(sock, 1);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000204}