]> andersk Git - openssh.git/blob - canohost.c
- (djm) OpenBSD CVS Sync:
[openssh.git] / canohost.c
1 /*
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.
6  *
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 #include "includes.h"
15 RCSID("$OpenBSD: canohost.c,v 1.19 2001/01/29 19:42:33 markus Exp $");
16
17 #include "packet.h"
18 #include "xmalloc.h"
19 #include "log.h"
20
21 /*
22  * Return the canonical name of the host at the other end of the socket. The
23  * caller should free the returned string with xfree.
24  */
25
26 char *
27 get_remote_hostname(int socket)
28 {
29         struct sockaddr_storage from;
30         int i;
31         socklen_t fromlen;
32         struct addrinfo hints, *ai, *aitop;
33         char name[MAXHOSTNAMELEN];
34         char ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
35
36         /* Get IP address of client. */
37         fromlen = sizeof(from);
38         memset(&from, 0, sizeof(from));
39         if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
40                 debug("getpeername failed: %.100s", strerror(errno));
41                 fatal_cleanup();
42         }
43
44 #ifdef IPV4_IN_IPV6
45         if (from.ss_family == AF_INET6) {
46                 struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from;
47
48                 /* Detect IPv4 in IPv6 mapped address and convert it to */
49                 /* plain (AF_INET) IPv4 address */
50                 if (IN6_IS_ADDR_V4MAPPED(&from6->sin6_addr)) {
51                         struct sockaddr_in *from4 = (struct sockaddr_in *)&from;
52                         struct in_addr addr;
53                         u_int16_t port;
54
55                         memcpy(&addr, ((char *)&from6->sin6_addr) + 12, sizeof(addr));
56                         port = from6->sin6_port;
57
58                         memset(&from, 0, sizeof(from));
59                         
60                         from4->sin_family = AF_INET;
61                         memcpy(&from4->sin_addr, &addr, sizeof(addr));
62                         from4->sin_port = port;
63                 }
64         }
65 #endif
66
67         if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
68              NULL, 0, NI_NUMERICHOST) != 0)
69                 fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
70
71         /* Map the IP address to a host name. */
72         if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
73              NULL, 0, NI_NAMEREQD) == 0) {
74                 /* Got host name. */
75                 name[sizeof(name) - 1] = '\0';
76                 /*
77                  * Convert it to all lowercase (which is expected by the rest
78                  * of this software).
79                  */
80                 for (i = 0; name[i]; i++)
81                         if (isupper(name[i]))
82                                 name[i] = tolower(name[i]);
83
84                 /*
85                  * Map it back to an IP address and check that the given
86                  * address actually is an address of this host.  This is
87                  * necessary because anyone with access to a name server can
88                  * define arbitrary names for an IP address. Mapping from
89                  * name to IP address can be trusted better (but can still be
90                  * fooled if the intruder has access to the name server of
91                  * the domain).
92                  */
93                 memset(&hints, 0, sizeof(hints));
94                 hints.ai_family = from.ss_family;
95                 hints.ai_socktype = SOCK_STREAM;
96                 if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
97                         log("reverse mapping checking getaddrinfo for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
98                         strlcpy(name, ntop, sizeof name);
99                         goto check_ip_options;
100                 }
101                 /* Look for the address from the list of addresses. */
102                 for (ai = aitop; ai; ai = ai->ai_next) {
103                         if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
104                             sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
105                             (strcmp(ntop, ntop2) == 0))
106                                         break;
107                 }
108                 freeaddrinfo(aitop);
109                 /* If we reached the end of the list, the address was not there. */
110                 if (!ai) {
111                         /* Address not found for the host name. */
112                         log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
113                             ntop, name);
114                         strlcpy(name, ntop, sizeof name);
115                         goto check_ip_options;
116                 }
117                 /* Address was found for the host name.  We accept the host name. */
118         } else {
119                 /* Host name not found.  Use ascii representation of the address. */
120                 strlcpy(name, ntop, sizeof name);
121                 log("Could not reverse map address %.100s.", name);
122         }
123
124 check_ip_options:
125
126         /*
127          * If IP options are supported, make sure there are none (log and
128          * disconnect them if any are found).  Basically we are worried about
129          * source routing; it can be used to pretend you are somebody
130          * (ip-address) you are not. That itself may be "almost acceptable"
131          * under certain circumstances, but rhosts autentication is useless
132          * if source routing is accepted. Notice also that if we just dropped
133          * source routing here, the other side could use IP spoofing to do
134          * rest of the interaction and could still bypass security.  So we
135          * exit here if we detect any IP options.
136          */
137         /* IP options -- IPv4 only */
138         if (from.ss_family == AF_INET) {
139                 u_char options[200], *ucp;
140                 char text[1024], *cp;
141                 socklen_t option_size;
142                 int ipproto;
143                 struct protoent *ip;
144
145                 if ((ip = getprotobyname("ip")) != NULL)
146                         ipproto = ip->p_proto;
147                 else
148                         ipproto = IPPROTO_IP;
149                 option_size = sizeof(options);
150                 if (getsockopt(socket, ipproto, IP_OPTIONS, (char *) options,
151                     &option_size) >= 0 && option_size != 0) {
152                         cp = text;
153                         /* Note: "text" buffer must be at least 3x as big as options. */
154                         for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
155                                 sprintf(cp, " %2.2x", *ucp);
156                         log("Connection from %.100s with IP options:%.800s",
157                             ntop, text);
158                         packet_disconnect("Connection from %.100s with IP options:%.800s",
159                                           ntop, text);
160                 }
161         }
162
163         return xstrdup(name);
164 }
165
166 /*
167  * Return the canonical name of the host in the other side of the current
168  * connection.  The host name is cached, so it is efficient to call this
169  * several times.
170  */
171
172 const char *
173 get_canonical_hostname()
174 {
175         static char *canonical_host_name = NULL;
176
177         /* Check if we have previously retrieved this same name. */
178         if (canonical_host_name != NULL)
179                 return canonical_host_name;
180
181         /* Get the real hostname if socket; otherwise return UNKNOWN. */
182         if (packet_connection_is_on_socket())
183                 canonical_host_name = get_remote_hostname(packet_get_connection_in());
184         else
185                 canonical_host_name = xstrdup("UNKNOWN");
186
187         return canonical_host_name;
188 }
189
190 /*
191  * Returns the remote IP-address of socket as a string.  The returned
192  * string must be freed.
193  */
194
195 char *
196 get_peer_ipaddr(int socket)
197 {
198         struct sockaddr_storage from;
199         socklen_t fromlen;
200         char ntop[NI_MAXHOST];
201
202         /* Get IP address of client. */
203         fromlen = sizeof(from);
204         memset(&from, 0, sizeof(from));
205         if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
206                 debug("get_peer_ipaddr: getpeername failed: %.100s", strerror(errno));
207                 return NULL;
208         }
209         /* Get the IP address in ascii. */
210         if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
211              NULL, 0, NI_NUMERICHOST) != 0) {
212                 error("get_peer_ipaddr: getnameinfo NI_NUMERICHOST failed");
213                 return NULL;
214         }
215         return xstrdup(ntop);
216 }
217
218 /*
219  * Returns the IP-address of the remote host as a string.  The returned
220  * string must not be freed.
221  */
222
223 const char *
224 get_remote_ipaddr()
225 {
226         static char *canonical_host_ip = NULL;
227
228         /* Check whether we have cached the ipaddr. */
229         if (canonical_host_ip == NULL) {
230                 if (packet_connection_is_on_socket()) {
231                         canonical_host_ip =
232                             get_peer_ipaddr(packet_get_connection_in());
233                         if (canonical_host_ip == NULL)
234                                 fatal_cleanup();
235                 } else {
236                         /* If not on socket, return UNKNOWN. */
237                         canonical_host_ip = xstrdup("UNKNOWN");
238                 }
239         }
240         return canonical_host_ip;
241 }
242
243 /* Returns the local/remote port for the socket. */
244
245 int
246 get_sock_port(int sock, int local)
247 {
248         struct sockaddr_storage from;
249         socklen_t fromlen;
250         char strport[NI_MAXSERV];
251
252         /* Get IP address of client. */
253         fromlen = sizeof(from);
254         memset(&from, 0, sizeof(from));
255         if (local) {
256                 if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
257                         error("getsockname failed: %.100s", strerror(errno));
258                         return 0;
259                 }
260         } else {
261                 if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
262                         debug("getpeername failed: %.100s", strerror(errno));
263                         fatal_cleanup();
264                 }
265         }
266         /* Return port number. */
267         if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
268              strport, sizeof(strport), NI_NUMERICSERV) != 0)
269                 fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
270         return atoi(strport);
271 }
272
273 /* Returns remote/local port number for the current connection. */
274
275 int
276 get_port(int local)
277 {
278         /*
279          * If the connection is not a socket, return 65535.  This is
280          * intentionally chosen to be an unprivileged port number.
281          */
282         if (!packet_connection_is_on_socket())
283                 return 65535;
284
285         /* Get socket and return the port number. */
286         return get_sock_port(packet_get_connection_in(), local);
287 }
288
289 int
290 get_peer_port(int sock)
291 {
292         return get_sock_port(sock, 0);
293 }
294
295 int
296 get_remote_port()
297 {
298         return get_port(0);
299 }
300
301 int
302 get_local_port()
303 {
304         return get_port(1);
305 }
This page took 1.174039 seconds and 5 git commands to generate.