]> andersk Git - openssh.git/blob - canohost.c
Avoid breakage on systems lacking IPv6 headers
[openssh.git] / canohost.c
1 /*
2  * 
3  * canohost.c
4  * 
5  * Author: Tatu Ylonen <ylo@cs.hut.fi>
6  * 
7  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8  *                    All rights reserved
9  * 
10  * Created: Sun Jul  2 17:52:22 1995 ylo
11  * 
12  * Functions for returning the canonical host name of the remote site.
13  * 
14  */
15
16 #include "includes.h"
17 RCSID("$Id$");
18
19 #include "packet.h"
20 #include "xmalloc.h"
21 #include "ssh.h"
22
23 /*
24  * Return the canonical name of the host at the other end of the socket. The
25  * caller should free the returned string with xfree.
26  */
27
28 char *
29 get_remote_hostname(int socket)
30 {
31         struct sockaddr_in from;
32         int fromlen, i;
33         struct hostent *hp;
34         char name[MAXHOSTNAMELEN];
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         /* Map the IP address to a host name. */
44         hp = gethostbyaddr((char *) &from.sin_addr, sizeof(struct in_addr),
45                            from.sin_family);
46         if (hp) {
47                 /* Got host name, find canonic host name. */
48                 if (strchr(hp->h_name, '.') != 0)
49                         strlcpy(name, hp->h_name, sizeof(name));
50                 else if (hp->h_aliases != 0
51                          && hp->h_aliases[0] != 0
52                          && strchr(hp->h_aliases[0], '.') != 0)
53                         strlcpy(name, hp->h_aliases[0], sizeof(name));
54                 else
55                         strlcpy(name, hp->h_name, sizeof(name));
56
57                 /*
58                  * Convert it to all lowercase (which is expected by the rest
59                  * of this software).
60                  */
61                 for (i = 0; name[i]; i++)
62                         if (isupper(name[i]))
63                                 name[i] = tolower(name[i]);
64
65                 /*
66                  * Map it back to an IP address and check that the given
67                  * address actually is an address of this host.  This is
68                  * necessary because anyone with access to a name server can
69                  * define arbitrary names for an IP address. Mapping from
70                  * name to IP address can be trusted better (but can still be
71                  * fooled if the intruder has access to the name server of
72                  * the domain).
73                  */
74                 hp = gethostbyname(name);
75                 if (!hp) {
76                         log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
77                         strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
78                         goto check_ip_options;
79                 }
80                 /* Look for the address from the list of addresses. */
81                 for (i = 0; hp->h_addr_list[i]; i++)
82                         if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr))
83                             == 0)
84                                 break;
85                 /*
86                  * If we reached the end of the list, the address was not
87                  * there.
88                  */
89                 if (!hp->h_addr_list[i]) {
90                         /* Address not found for the host name. */
91                         log("Address %.100s maps to %.600s, but this does not map back to the address - POSSIBLE BREAKIN ATTEMPT!",
92                             inet_ntoa(from.sin_addr), name);
93                         strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
94                         goto check_ip_options;
95                 }
96                 /* Address was found for the host name.  We accept the host name. */
97         } else {
98                 /* Host name not found.  Use ascii representation of the address. */
99                 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name);
100                 log("Could not reverse map address %.100s.", name);
101         }
102
103 check_ip_options:
104
105         /*
106          * If IP options are supported, make sure there are none (log and
107          * disconnect them if any are found).  Basically we are worried about
108          * source routing; it can be used to pretend you are somebody
109          * (ip-address) you are not. That itself may be "almost acceptable"
110          * under certain circumstances, but rhosts autentication is useless
111          * if source routing is accepted. Notice also that if we just dropped
112          * source routing here, the other side could use IP spoofing to do
113          * rest of the interaction and could still bypass security.  So we
114          * exit here if we detect any IP options.
115          */
116         {
117                 unsigned char options[200], *ucp;
118                 char text[1024], *cp;
119                 int option_size, ipproto;
120                 struct protoent *ip;
121
122                 if ((ip = getprotobyname("ip")) != NULL)
123                         ipproto = ip->p_proto;
124                 else
125                         ipproto = IPPROTO_IP;
126                 option_size = sizeof(options);
127                 if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options,
128                                &option_size) >= 0 && option_size != 0) {
129                         cp = text;
130                         /* Note: "text" buffer must be at least 3x as big as options. */
131                         for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
132                                 sprintf(cp, " %2.2x", *ucp);
133                         log("Connection from %.100s with IP options:%.800s",
134                             inet_ntoa(from.sin_addr), text);
135                         packet_disconnect("Connection from %.100s with IP options:%.800s",
136                                           inet_ntoa(from.sin_addr), text);
137                 }
138         }
139
140         return xstrdup(name);
141 }
142
143 static char *canonical_host_name = NULL;
144 static char *canonical_host_ip = NULL;
145
146 /* Returns 1 if remote host is connected via socket, 0 if not. */
147
148 int
149 peer_connection_is_on_socket()
150 {
151         struct sockaddr_in from;
152         int fromlen;
153         int in = packet_get_connection_in();
154         int out = packet_get_connection_out();
155
156         /* filedescriptors in and out are the same, so it's a socket */
157         if (in == out)
158                 return 1;
159         fromlen = sizeof(from);
160         memset(&from, 0, sizeof(from));
161         if (getpeername(in, (struct sockaddr *) & from, &fromlen) < 0)
162                 return 0;
163         if (from.sin_family != AF_INET)
164                 return 0;
165
166         return 1;
167 }
168
169 /*
170  * Return the canonical name of the host in the other side of the current
171  * connection.  The host name is cached, so it is efficient to call this
172  * several times.
173  */
174
175 const char *
176 get_canonical_hostname()
177 {
178         /* Check if we have previously retrieved this same name. */
179         if (canonical_host_name != NULL)
180                 return canonical_host_name;
181
182         /* Get the real hostname if socket; otherwise return UNKNOWN. */
183         if (peer_connection_is_on_socket())
184                 canonical_host_name = get_remote_hostname(packet_get_connection_in());
185         else
186                 canonical_host_name = xstrdup("UNKNOWN");
187
188         return canonical_host_name;
189 }
190
191 /*
192  * Returns the IP-address of the remote host as a string.  The returned
193  * string need not be freed.
194  */
195
196 const char *
197 get_remote_ipaddr()
198 {
199         struct sockaddr_in from;
200         int fromlen, socket;
201
202         /* Check whether we have chached the name. */
203         if (canonical_host_ip != NULL)
204                 return canonical_host_ip;
205
206         /* If not a socket, return UNKNOWN. */
207         if (!peer_connection_is_on_socket()) {
208                 canonical_host_ip = xstrdup("UNKNOWN");
209                 return canonical_host_ip;
210         }
211         /* Get client socket. */
212         socket = packet_get_connection_in();
213
214         /* Get IP address of client. */
215         fromlen = sizeof(from);
216         memset(&from, 0, sizeof(from));
217         if (getpeername(socket, (struct sockaddr *) & from, &fromlen) < 0) {
218                 debug("getpeername failed: %.100s", strerror(errno));
219                 fatal_cleanup();
220         }
221         /* Get the IP address in ascii. */
222         canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr));
223
224         /* Return ip address string. */
225         return canonical_host_ip;
226 }
227
228 /* Returns the port of the peer of the socket. */
229
230 int 
231 get_peer_port(int sock)
232 {
233         struct sockaddr_in from;
234         int fromlen;
235
236         /* Get IP address of client. */
237         fromlen = sizeof(from);
238         memset(&from, 0, sizeof(from));
239         if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
240                 debug("getpeername failed: %.100s", strerror(errno));
241                 fatal_cleanup();
242         }
243         /* Return port number. */
244         return ntohs(from.sin_port);
245 }
246
247 /* Returns the port number of the remote host.  */
248
249 int 
250 get_remote_port()
251 {
252         int socket;
253
254         /*
255          * If the connection is not a socket, return 65535.  This is
256          * intentionally chosen to be an unprivileged port number.
257          */
258         if (!peer_connection_is_on_socket())
259                 return 65535;
260
261         /* Get client socket. */
262         socket = packet_get_connection_in();
263
264         /* Get and return the peer port number. */
265         return get_peer_port(socket);
266 }
This page took 0.061229 seconds and 5 git commands to generate.