summaryrefslogtreecommitdiff
path: root/canohost.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2000-01-14 15:45:46 +1100
committerDamien Miller <djm@mindrot.org>2000-01-14 15:45:46 +1100
commit34132e54cbd221d17d373fc54f4e3f7b85727f7f (patch)
tree7c73917b1082ff91786f9e02d25b853bedd1d472 /canohost.c
parent25e4256ad4f453d8a7c1866243ec1984f859b1de (diff)
- Merged OpenBSD IPv6 patch:
- [sshd.c sshd.8 sshconnect.c ssh.h ssh.c servconf.h servconf.c scp.1] [scp.c packet.h packet.c login.c log.c canohost.c channels.c] [hostfile.c sshd_config] ipv6 support: mostly gethostbyname->getaddrinfo/getnameinfo, new features: sshd allows multiple ListenAddress and Port options. note that libwrap is not IPv6-ready. (based on patches from fujiwara@rcac.tdi.co.jp) - [ssh.c canohost.c] more hints (hints.ai_socktype=SOCK_STREAM) for getaddrinfo, from itojun@ - [channels.c] listen on _all_ interfaces for X11-Fwd (hints.ai_flags = AI_PASSIVE) - [packet.h] allow auth-kerberos for IPv4 only - [scp.1 sshd.8 servconf.h scp.c] document -4, -6, and 'ssh -L 2022/::1/22' - [ssh.c] 'ssh @host' is illegal (null user name), from karsten@gedankenpolizei.de - [sshconnect.c] better error message - [sshd.c] allow auth-kerberos for IPv4 only - Big IPv6 merge: - Cleanup overrun in sockaddr copying on RHL 6.1 - Replacements for getaddrinfo, getnameinfo, etc based on versions from patch from KIKUCHI Takahiro <kick@kyoto.wide.ad.jp> - Replacement for missing structures on systems that lack IPv6 - record_login needed to know about AF_INET6 addresses - Borrowed more code from OpenBSD: rresvport_af and requisites
Diffstat (limited to 'canohost.c')
-rw-r--r--canohost.c184
1 files changed, 96 insertions, 88 deletions
diff --git a/canohost.c b/canohost.c
index edfaa94e1..9a6d8b732 100644
--- a/canohost.c
+++ b/canohost.c
@@ -14,7 +14,7 @@
14 */ 14 */
15 15
16#include "includes.h" 16#include "includes.h"
17RCSID("$Id: canohost.c,v 1.6 1999/12/18 09:57:40 damien Exp $"); 17RCSID("$Id: canohost.c,v 1.7 2000/01/14 04:45:48 damien Exp $");
18 18
19#include "packet.h" 19#include "packet.h"
20#include "xmalloc.h" 20#include "xmalloc.h"
@@ -28,10 +28,12 @@ RCSID("$Id: canohost.c,v 1.6 1999/12/18 09:57:40 damien Exp $");
28char * 28char *
29get_remote_hostname(int socket) 29get_remote_hostname(int socket)
30{ 30{
31 struct sockaddr_in from; 31 struct sockaddr_storage from;
32 int fromlen, i; 32 int i;
33 struct hostent *hp; 33 socklen_t fromlen;
34 struct addrinfo hints, *ai, *aitop;
34 char name[MAXHOSTNAMELEN]; 35 char name[MAXHOSTNAMELEN];
36 char ntop[NI_MAXHOST], ntop2[NI_MAXHOST];
35 37
36 /* Get IP address of client. */ 38 /* Get IP address of client. */
37 fromlen = sizeof(from); 39 fromlen = sizeof(from);
@@ -40,20 +42,15 @@ get_remote_hostname(int socket)
40 debug("getpeername failed: %.100s", strerror(errno)); 42 debug("getpeername failed: %.100s", strerror(errno));
41 fatal_cleanup(); 43 fatal_cleanup();
42 } 44 }
43 /* Map the IP address to a host name. */ 45 if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
44 hp = gethostbyaddr((char *) &from.sin_addr, sizeof(struct in_addr), 46 NULL, 0, NI_NUMERICHOST) != 0)
45 from.sin_family); 47 fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
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 48
49 /* Map the IP address to a host name. */
50 if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
51 NULL, 0, NI_NAMEREQD) == 0) {
52 /* Got host name. */
53 name[sizeof(name) - 1] = '\0';
57 /* 54 /*
58 * Convert it to all lowercase (which is expected by the rest 55 * Convert it to all lowercase (which is expected by the rest
59 * of this software). 56 * of this software).
@@ -71,32 +68,34 @@ get_remote_hostname(int socket)
71 * fooled if the intruder has access to the name server of 68 * fooled if the intruder has access to the name server of
72 * the domain). 69 * the domain).
73 */ 70 */
74 hp = gethostbyname(name); 71 memset(&hints, 0, sizeof(hints));
75 if (!hp) { 72 hints.ai_family = from.ss_family;
76 log("reverse mapping checking gethostbyname for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name); 73 hints.ai_socktype = SOCK_STREAM;
77 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); 74 if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
75 log("reverse mapping checking getaddrinfo for %.700s failed - POSSIBLE BREAKIN ATTEMPT!", name);
76 strlcpy(name, ntop, sizeof name);
78 goto check_ip_options; 77 goto check_ip_options;
79 } 78 }
80 /* Look for the address from the list of addresses. */ 79 /* Look for the address from the list of addresses. */
81 for (i = 0; hp->h_addr_list[i]; i++) 80 for (ai = aitop; ai; ai = ai->ai_next) {
82 if (memcmp(hp->h_addr_list[i], &from.sin_addr, sizeof(from.sin_addr)) 81 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
83 == 0) 82 sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
84 break; 83 (strcmp(ntop, ntop2) == 0))
85 /* 84 break;
86 * If we reached the end of the list, the address was not 85 }
87 * there. 86 freeaddrinfo(aitop);
88 */ 87 /* If we reached the end of the list, the address was not there. */
89 if (!hp->h_addr_list[i]) { 88 if (!ai) {
90 /* Address not found for the host name. */ 89 /* 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!", 90 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); 91 ntop, name);
93 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); 92 strlcpy(name, ntop, sizeof name);
94 goto check_ip_options; 93 goto check_ip_options;
95 } 94 }
96 /* Address was found for the host name. We accept the host name. */ 95 /* Address was found for the host name. We accept the host name. */
97 } else { 96 } else {
98 /* Host name not found. Use ascii representation of the address. */ 97 /* Host name not found. Use ascii representation of the address. */
99 strlcpy(name, inet_ntoa(from.sin_addr), sizeof name); 98 strlcpy(name, ntop, sizeof name);
100 log("Could not reverse map address %.100s.", name); 99 log("Could not reverse map address %.100s.", name);
101 } 100 }
102 101
@@ -113,10 +112,12 @@ check_ip_options:
113 * rest of the interaction and could still bypass security. So we 112 * rest of the interaction and could still bypass security. So we
114 * exit here if we detect any IP options. 113 * exit here if we detect any IP options.
115 */ 114 */
116 { 115 /* IP options -- IPv4 only */
116 if (from.ss_family == AF_INET) {
117 unsigned char options[200], *ucp; 117 unsigned char options[200], *ucp;
118 char text[1024], *cp; 118 char text[1024], *cp;
119 int option_size, ipproto; 119 socklen_t option_size;
120 int ipproto;
120 struct protoent *ip; 121 struct protoent *ip;
121 122
122 if ((ip = getprotobyname("ip")) != NULL) 123 if ((ip = getprotobyname("ip")) != NULL)
@@ -125,47 +126,21 @@ check_ip_options:
125 ipproto = IPPROTO_IP; 126 ipproto = IPPROTO_IP;
126 option_size = sizeof(options); 127 option_size = sizeof(options);
127 if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options, 128 if (getsockopt(0, ipproto, IP_OPTIONS, (char *) options,
128 &option_size) >= 0 && option_size != 0) { 129 &option_size) >= 0 && option_size != 0) {
129 cp = text; 130 cp = text;
130 /* Note: "text" buffer must be at least 3x as big as options. */ 131 /* 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 for (ucp = options; option_size > 0; ucp++, option_size--, cp += 3)
132 sprintf(cp, " %2.2x", *ucp); 133 sprintf(cp, " %2.2x", *ucp);
133 log("Connection from %.100s with IP options:%.800s", 134 log("Connection from %.100s with IP options:%.800s",
134 inet_ntoa(from.sin_addr), text); 135 ntop, text);
135 packet_disconnect("Connection from %.100s with IP options:%.800s", 136 packet_disconnect("Connection from %.100s with IP options:%.800s",
136 inet_ntoa(from.sin_addr), text); 137 ntop, text);
137 } 138 }
138 } 139 }
139 140
140 return xstrdup(name); 141 return xstrdup(name);
141} 142}
142 143
143static char *canonical_host_name = NULL;
144static char *canonical_host_ip = NULL;
145
146/* Returns 1 if remote host is connected via socket, 0 if not. */
147
148int
149peer_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/* 144/*
170 * Return the canonical name of the host in the other side of the current 145 * 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 146 * connection. The host name is cached, so it is efficient to call this
@@ -175,12 +150,14 @@ peer_connection_is_on_socket()
175const char * 150const char *
176get_canonical_hostname() 151get_canonical_hostname()
177{ 152{
153 static char *canonical_host_name = NULL;
154
178 /* Check if we have previously retrieved this same name. */ 155 /* Check if we have previously retrieved this same name. */
179 if (canonical_host_name != NULL) 156 if (canonical_host_name != NULL)
180 return canonical_host_name; 157 return canonical_host_name;
181 158
182 /* Get the real hostname if socket; otherwise return UNKNOWN. */ 159 /* Get the real hostname if socket; otherwise return UNKNOWN. */
183 if (peer_connection_is_on_socket()) 160 if (packet_connection_is_on_socket())
184 canonical_host_name = get_remote_hostname(packet_get_connection_in()); 161 canonical_host_name = get_remote_hostname(packet_get_connection_in());
185 else 162 else
186 canonical_host_name = xstrdup("UNKNOWN"); 163 canonical_host_name = xstrdup("UNKNOWN");
@@ -190,21 +167,24 @@ get_canonical_hostname()
190 167
191/* 168/*
192 * Returns the IP-address of the remote host as a string. The returned 169 * Returns the IP-address of the remote host as a string. The returned
193 * string need not be freed. 170 * string must not be freed.
194 */ 171 */
195 172
196const char * 173const char *
197get_remote_ipaddr() 174get_remote_ipaddr()
198{ 175{
199 struct sockaddr_in from; 176 static char *canonical_host_ip = NULL;
200 int fromlen, socket; 177 struct sockaddr_storage from;
178 socklen_t fromlen;
179 int socket;
180 char ntop[NI_MAXHOST];
201 181
202 /* Check whether we have chached the name. */ 182 /* Check whether we have chached the name. */
203 if (canonical_host_ip != NULL) 183 if (canonical_host_ip != NULL)
204 return canonical_host_ip; 184 return canonical_host_ip;
205 185
206 /* If not a socket, return UNKNOWN. */ 186 /* If not a socket, return UNKNOWN. */
207 if (!peer_connection_is_on_socket()) { 187 if (!packet_connection_is_on_socket()) {
208 canonical_host_ip = xstrdup("UNKNOWN"); 188 canonical_host_ip = xstrdup("UNKNOWN");
209 return canonical_host_ip; 189 return canonical_host_ip;
210 } 190 }
@@ -219,48 +199,76 @@ get_remote_ipaddr()
219 fatal_cleanup(); 199 fatal_cleanup();
220 } 200 }
221 /* Get the IP address in ascii. */ 201 /* Get the IP address in ascii. */
222 canonical_host_ip = xstrdup(inet_ntoa(from.sin_addr)); 202 if (getnameinfo((struct sockaddr *)&from, fromlen, ntop, sizeof(ntop),
203 NULL, 0, NI_NUMERICHOST) != 0)
204 fatal("get_remote_hostname: getnameinfo NI_NUMERICHOST failed");
205
206 canonical_host_ip = xstrdup(ntop);
223 207
224 /* Return ip address string. */ 208 /* Return ip address string. */
225 return canonical_host_ip; 209 return canonical_host_ip;
226} 210}
227 211
228/* Returns the port of the peer of the socket. */ 212/* Returns the local/remote port for the socket. */
229 213
230int 214int
231get_peer_port(int sock) 215get_sock_port(int sock, int local)
232{ 216{
233 struct sockaddr_in from; 217 struct sockaddr_storage from;
234 int fromlen; 218 socklen_t fromlen;
219 char strport[NI_MAXSERV];
235 220
236 /* Get IP address of client. */ 221 /* Get IP address of client. */
237 fromlen = sizeof(from); 222 fromlen = sizeof(from);
238 memset(&from, 0, sizeof(from)); 223 memset(&from, 0, sizeof(from));
239 if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) { 224 if (local) {
240 debug("getpeername failed: %.100s", strerror(errno)); 225 if (getsockname(sock, (struct sockaddr *)&from, &fromlen) < 0) {
241 fatal_cleanup(); 226 error("getsockname failed: %.100s", strerror(errno));
227 return 0;
228 }
229 } else {
230 if (getpeername(sock, (struct sockaddr *) & from, &fromlen) < 0) {
231 debug("getpeername failed: %.100s", strerror(errno));
232 fatal_cleanup();
233 }
242 } 234 }
243 /* Return port number. */ 235 /* Return port number. */
244 return ntohs(from.sin_port); 236 if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
237 strport, sizeof(strport), NI_NUMERICSERV) != 0)
238 fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
239 return atoi(strport);
245} 240}
246 241
247/* Returns the port number of the remote host. */ 242/* Returns remote/local port number for the current connection. */
248 243
249int 244int
250get_remote_port() 245get_port(int local)
251{ 246{
252 int socket;
253
254 /* 247 /*
255 * If the connection is not a socket, return 65535. This is 248 * If the connection is not a socket, return 65535. This is
256 * intentionally chosen to be an unprivileged port number. 249 * intentionally chosen to be an unprivileged port number.
257 */ 250 */
258 if (!peer_connection_is_on_socket()) 251 if (!packet_connection_is_on_socket())
259 return 65535; 252 return 65535;
260 253
261 /* Get client socket. */ 254 /* Get socket and return the port number. */
262 socket = packet_get_connection_in(); 255 return get_sock_port(packet_get_connection_in(), local);
256}
257
258int
259get_peer_port(int sock)
260{
261 return get_sock_port(sock, 0);
262}
263 263
264 /* Get and return the peer port number. */ 264int
265 return get_peer_port(socket); 265get_remote_port()
266{
267 return get_port(0);
268}
269
270int
271get_local_port()
272{
273 return get_port(1);
266} 274}