Annotation of src/usr.bin/ssh/canohost.c, Revision 1.14
1.1 deraadt 1: /*
1.7 deraadt 2: * Author: Tatu Ylonen <ylo@cs.hut.fi>
3: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4: * All rights reserved
5: * Functions for returning the canonical host name of the remote site.
1.12 markus 6: *
1.14 ! deraadt 7: * As far as I am concerned, the code I have written for this software
! 8: * can be used freely for any purpose. Any derived versions of this
! 9: * software must be clearly marked as such, and if the derived work is
! 10: * incompatible with the protocol description in the RFC file, it must be
! 11: * called by a name other than "ssh" or "Secure Shell".
! 12: *
! 13: *
! 14: * Copyright (c) 1999,2000 Markus Friedl. All rights reserved.
! 15: *
! 16: * Redistribution and use in source and binary forms, with or without
! 17: * modification, are permitted provided that the following conditions
! 18: * are met:
! 19: * 1. Redistributions of source code must retain the above copyright
! 20: * notice, this list of conditions and the following disclaimer.
! 21: * 2. Redistributions in binary form must reproduce the above copyright
! 22: * notice, this list of conditions and the following disclaimer in the
! 23: * documentation and/or other materials provided with the distribution.
! 24: *
! 25: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 26: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 27: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 28: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 29: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 30: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 31: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 32: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 33: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 34: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.7 deraadt 35: */
1.1 deraadt 36:
37: #include "includes.h"
1.14 ! deraadt 38: RCSID("$OpenBSD: canohost.c,v 1.13 2000/06/20 01:39:39 markus Exp $");
1.1 deraadt 39:
40: #include "packet.h"
41: #include "xmalloc.h"
42: #include "ssh.h"
43:
1.8 markus 44: /*
45: * Return the canonical name of the host at the other end of the socket. The
46: * caller should free the returned string with xfree.
47: */
1.1 deraadt 48:
1.6 markus 49: char *
50: get_remote_hostname(int socket)
1.1 deraadt 51: {
1.10 markus 52: struct sockaddr_storage from;
53: int i;
54: socklen_t fromlen;
55: struct addrinfo hints, *ai, *aitop;
1.6 markus 56: char name[MAXHOSTNAMELEN];
1.10 markus 57: char ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
1.6 markus 58:
59: /* Get IP address of client. */
60: fromlen = sizeof(from);
61: memset(&from, 0, sizeof(from));
62: if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
63: debug("getpeername failed: %.100s", strerror(errno));
64: fatal_cleanup();
65: }
1.10 markus 66: if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
67: NULL, 0, NI_NUMERICHOST) != 0)
68: fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
69:
1.6 markus 70: /* Map the IP address to a host name. */
1.10 markus 71: if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
72: NULL, 0, NI_NAMEREQD) == 0) {
73: /* Got host name. */
74: name[sizeof(name) - 1] = '\0';
1.8 markus 75: /*
76: * Convert it to all lowercase (which is expected by the rest
77: * of this software).
78: */
1.6 markus 79: for (i = 0; name[i]; i++)
80: if (isupper(name[i]))
81: name[i] = tolower(name[i]);
82:
1.8 markus 83: /*
84: * Map it back to an IP address and check that the given
85: * address actually is an address of this host. This is
86: * necessary because anyone with access to a name server can
87: * define arbitrary names for an IP address. Mapping from
88: * name to IP address can be trusted better (but can still be
89: * fooled if the intruder has access to the name server of
90: * the domain).
91: */
1.10 markus 92: memset(&hints, 0, sizeof(hints));
93: hints.ai_family = from.ss_family;
1.11 markus 94: hints.ai_socktype = SOCK_STREAM;
1.10 markus 95: if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
96: log("reverse mapping checking getaddrinfo for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
97: strlcpy(name, ntop, sizeof name);
1.6 markus 98: goto check_ip_options;
99: }
100: /* Look for the address from the list of addresses. */
1.10 markus 101: for (ai = aitop; ai; ai = ai->ai_next) {
102: if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
103: sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
104: (strcmp(ntop, ntop2) == 0))
105: break;
106: }
107: freeaddrinfo(aitop);
108: /* If we reached the end of the list, the address was not there. */
109: if (!ai) {
1.6 markus 110: /* Address not found for the host name. */
111: log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
1.10 markus 112: ntop, name);
113: strlcpy(name, ntop, sizeof name);
1.6 markus 114: goto check_ip_options;
115: }
116: /* Address was found for the host name. We accept the host name. */
117: } else {
118: /* Host name not found. Use ascii representation of the address. */
1.10 markus 119: strlcpy(name, ntop, sizeof name);
1.6 markus 120: log("Could not reverse map address %.100s.", name);
121: }
122:
123: check_ip_options:
124:
1.8 markus 125: /*
126: * If IP options are supported, make sure there are none (log and
127: * disconnect them if any are found). Basically we are worried about
128: * source routing; it can be used to pretend you are somebody
129: * (ip-address) you are not. That itself may be "almost acceptable"
130: * under certain circumstances, but rhosts autentication is useless
131: * if source routing is accepted. Notice also that if we just dropped
132: * source routing here, the other side could use IP spoofing to do
133: * rest of the interaction and could still bypass security. So we
134: * exit here if we detect any IP options.
135: */
1.10 markus 136: /* IP options -- IPv4 only */
137: if (from.ss_family == AF_INET) {
1.6 markus 138: unsigned char options[200], *ucp;
139: char text[1024], *cp;
1.10 markus 140: socklen_t option_size;
141: int ipproto;
1.6 markus 142: struct protoent *ip;
143:
144: if ((ip = getprotobyname("ip")) != NULL)
145: ipproto = ip->p_proto;
146: else
147: ipproto = IPPROTO_IP;
148: option_size = sizeof(options);
149: if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options,
1.10 markus 150: &option_size) >= 0 && option_size != 0) {
1.6 markus 151: cp = text;
152: /* Note: "text" buffer must be at least 3x as big as options. */
153: for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
154: sprintf(cp, " %2.2x", *ucp);
155: log("Connection from %.100s with IP options:%.800s",
1.10 markus 156: ntop, text);
1.6 markus 157: packet_disconnect("Connection from %.100s with IP options:%.800s",
1.10 markus 158: ntop, text);
1.6 markus 159: }
160: }
1.1 deraadt 161:
1.6 markus 162: return xstrdup(name);
1.1 deraadt 163: }
164:
1.8 markus 165: /*
166: * Return the canonical name of the host in the other side of the current
167: * connection. The host name is cached, so it is efficient to call this
168: * several times.
169: */
1.1 deraadt 170:
1.6 markus 171: const char *
172: get_canonical_hostname()
1.1 deraadt 173: {
1.10 markus 174: static char *canonical_host_name = NULL;
175:
1.6 markus 176: /* Check if we have previously retrieved this same name. */
177: if (canonical_host_name != NULL)
178: return canonical_host_name;
179:
180: /* Get the real hostname if socket; otherwise return UNKNOWN. */
1.10 markus 181: if (packet_connection_is_on_socket())
1.6 markus 182: canonical_host_name = get_remote_hostname(packet_get_connection_in());
183: else
184: canonical_host_name = xstrdup("UNKNOWN");
1.1 deraadt 185:
1.6 markus 186: return canonical_host_name;
1.1 deraadt 187: }
188:
1.8 markus 189: /*
190: * Returns the IP-address of the remote host as a string. The returned
1.10 markus 191: * string must not be freed.
1.8 markus 192: */
1.1 deraadt 193:
1.6 markus 194: const char *
195: get_remote_ipaddr()
1.1 deraadt 196: {
1.10 markus 197: static char *canonical_host_ip = NULL;
198: struct sockaddr_storage from;
199: socklen_t fromlen;
200: int socket;
201: char ntop[NI_MAXHOST];
1.1 deraadt 202:
1.8 markus 203: /* Check whether we have chached the name. */
1.6 markus 204: if (canonical_host_ip != NULL)
205: return canonical_host_ip;
206:
207: /* If not a socket, return UNKNOWN. */
1.10 markus 208: if (!packet_connection_is_on_socket()) {
1.6 markus 209: canonical_host_ip = xstrdup("UNKNOWN");
210: return canonical_host_ip;
211: }
212: /* Get client socket. */
213: socket = packet_get_connection_in();
1.1 deraadt 214:
1.6 markus 215: /* Get IP address of client. */
216: fromlen = sizeof(from);
217: memset(&from, 0, sizeof(from));
218: if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
219: debug("getpeername failed: %.100s", strerror(errno));
220: fatal_cleanup();
221: }
222: /* Get the IP address in ascii. */
1.10 markus 223: if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
224: NULL, 0, NI_NUMERICHOST) != 0)
225: fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
226:
227: canonical_host_ip = xstrdup(ntop);
1.1 deraadt 228:
1.6 markus 229: /* Return ip address string. */
230: return canonical_host_ip;
1.1 deraadt 231: }
232:
1.10 markus 233: /* Returns the local/remote port for the socket. */
1.1 deraadt 234:
1.10 markus 235: int
236: get_sock_port(int sock, int local)
1.1 deraadt 237: {
1.10 markus 238: struct sockaddr_storage from;
239: socklen_t fromlen;
240: char strport[NI_MAXSERV];
1.1 deraadt 241:
1.6 markus 242: /* Get IP address of client. */
243: fromlen = sizeof(from);
244: memset(&from, 0, sizeof(from));
1.10 markus 245: if (local) {
246: if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
247: error("getsockname failed: %.100s", strerror(errno));
248: return 0;
249: }
250: } else {
251: if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
252: debug("getpeername failed: %.100s", strerror(errno));
253: fatal_cleanup();
254: }
1.6 markus 255: }
256: /* Return port number. */
1.10 markus 257: if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
258: strport, sizeof(strport), NI_NUMERICSERV) != 0)
259: fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
260: return atoi(strport);
1.1 deraadt 261: }
262:
1.10 markus 263: /* Returns remote/local port number for the current connection. */
1.1 deraadt 264:
1.12 markus 265: int
1.10 markus 266: get_port(int local)
1.1 deraadt 267: {
1.8 markus 268: /*
269: * If the connection is not a socket, return 65535. This is
270: * intentionally chosen to be an unprivileged port number.
271: */
1.10 markus 272: if (!packet_connection_is_on_socket())
1.6 markus 273: return 65535;
1.1 deraadt 274:
1.10 markus 275: /* Get socket and return the port number. */
276: return get_sock_port(packet_get_connection_in(), local);
277: }
278:
1.12 markus 279: int
1.10 markus 280: get_peer_port(int sock)
281: {
282: return get_sock_port(sock, 0);
283: }
284:
1.12 markus 285: int
1.10 markus 286: get_remote_port()
287: {
288: return get_port(0);
289: }
1.1 deraadt 290:
1.10 markus 291: int
292: get_local_port()
293: {
294: return get_port(1);
1.1 deraadt 295: }