]> andersk Git - openssh.git/blob - canohost.c
One way to massive patch. <sigh> It compiles and works under Linux..
[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.17 2000/12/19 23:17:55 markus Exp $");
16
17 #include "packet.h"
18 #include "xmalloc.h"
19 #include "ssh.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 IP-address of the remote host as a string.  The returned
192  * string must not be freed.
193  */
194
195 const char *
196 get_remote_ipaddr()
197 {
198         static char *canonical_host_ip = NULL;
199         struct sockaddr_storage from;
200         socklen_t fromlen;
201         int socket;
202         char ntop[NI_MAXHOST];
203
204         /* Check whether we have chached the name. */
205         if (canonical_host_ip != NULL)
206                 return canonical_host_ip;
207
208         /* If not a socket, return UNKNOWN. */
209         if (!packet_connection_is_on_socket()) {
210                 canonical_host_ip = xstrdup("UNKNOWN");
211                 return canonical_host_ip;
212         }
213         /* Get client socket. */
214         socket = packet_get_connection_in();
215
216         /* Get IP address of client. */
217         fromlen = sizeof(from);
218         memset(&from, 0, sizeof(from));
219         if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
220                 debug("getpeername failed: %.100s", strerror(errno));
221                 fatal_cleanup();
222         }
223         /* Get the IP address in ascii. */
224         if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
225              NULL, 0, NI_NUMERICHOST) != 0)
226                 fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
227
228         canonical_host_ip = xstrdup(ntop);
229
230         /* Return ip address string. */
231         return canonical_host_ip;
232 }
233
234 /* Returns the local/remote port for the socket. */
235
236 int
237 get_sock_port(int sock, int local)
238 {
239         struct sockaddr_storage from;
240         socklen_t fromlen;
241         char strport[NI_MAXSERV];
242
243         /* Get IP address of client. */
244         fromlen = sizeof(from);
245         memset(&from, 0, sizeof(from));
246         if (local) {
247                 if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
248                         error("getsockname failed: %.100s", strerror(errno));
249                         return 0;
250                 }
251         } else {
252                 if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
253                         debug("getpeername failed: %.100s", strerror(errno));
254                         fatal_cleanup();
255                 }
256         }
257         /* Return port number. */
258         if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
259              strport, sizeof(strport), NI_NUMERICSERV) != 0)
260                 fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
261         return atoi(strport);
262 }
263
264 /* Returns remote/local port number for the current connection. */
265
266 int
267 get_port(int local)
268 {
269         /*
270          * If the connection is not a socket, return 65535.  This is
271          * intentionally chosen to be an unprivileged port number.
272          */
273         if (!packet_connection_is_on_socket())
274                 return 65535;
275
276         /* Get socket and return the port number. */
277         return get_sock_port(packet_get_connection_in(), local);
278 }
279
280 int
281 get_peer_port(int sock)
282 {
283         return get_sock_port(sock, 0);
284 }
285
286 int
287 get_remote_port()
288 {
289         return get_port(0);
290 }
291
292 int
293 get_local_port()
294 {
295         return get_port(1);
296 }
This page took 0.065404 seconds and 5 git commands to generate.