diff options
author | Damien Miller <djm@mindrot.org> | 2000-01-14 15:45:46 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2000-01-14 15:45:46 +1100 |
commit | 34132e54cbd221d17d373fc54f4e3f7b85727f7f (patch) | |
tree | 7c73917b1082ff91786f9e02d25b853bedd1d472 /canohost.c | |
parent | 25e4256ad4f453d8a7c1866243ec1984f859b1de (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.c | 184 |
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" |
17 | RCSID("$Id: canohost.c,v 1.6 1999/12/18 09:57:40 damien Exp $"); | 17 | RCSID("$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 $"); | |||
28 | char * | 28 | char * |
29 | get_remote_hostname(int socket) | 29 | get_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 | ||
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 | /* | 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() | |||
175 | const char * | 150 | const char * |
176 | get_canonical_hostname() | 151 | get_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 | ||
196 | const char * | 173 | const char * |
197 | get_remote_ipaddr() | 174 | get_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 | ||
230 | int | 214 | int |
231 | get_peer_port(int sock) | 215 | get_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 | ||
249 | int | 244 | int |
250 | get_remote_port() | 245 | get_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 | |||
258 | int | ||
259 | get_peer_port(int sock) | ||
260 | { | ||
261 | return get_sock_port(sock, 0); | ||
262 | } | ||
263 | 263 | ||
264 | /* Get and return the peer port number. */ | 264 | int |
265 | return get_peer_port(socket); | 265 | get_remote_port() |
266 | { | ||
267 | return get_port(0); | ||
268 | } | ||
269 | |||
270 | int | ||
271 | get_local_port() | ||
272 | { | ||
273 | return get_port(1); | ||
266 | } | 274 | } |