*/
#include "includes.h"
-RCSID("$OpenBSD: canohost.c,v 1.37 2003/06/02 09:17:34 markus Exp $");
+RCSID("$OpenBSD: canohost.c,v 1.42 2005/02/18 03:05:53 djm Exp $");
#include "packet.h"
#include "xmalloc.h"
*/
static char *
-get_remote_hostname(int socket, int use_dns)
+get_remote_hostname(int sock, int use_dns)
{
struct sockaddr_storage from;
int i;
/* Get IP address of client. */
fromlen = sizeof(from);
memset(&from, 0, sizeof(from));
- if (getpeername(socket, (struct sockaddr *)&from, &fromlen) < 0) {
+ if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) {
debug("getpeername failed: %.100s", strerror(errno));
- fatal_cleanup();
+ cleanup_exit(255);
}
-#ifdef IPV4_IN_IPV6
- if (from.ss_family == AF_INET6) {
- struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from;
-
- /* Detect IPv4 in IPv6 mapped address and convert it to */
- /* plain (AF_INET) IPv4 address */
- if (IN6_IS_ADDR_V4MAPPED(&from6->sin6_addr)) {
- struct sockaddr_in *from4 = (struct sockaddr_in *)&from;
- struct in_addr addr;
- u_int16_t port;
-
- memcpy(&addr, ((char *)&from6->sin6_addr) + 12, sizeof(addr));
- port = from6->sin6_port;
-
- memset(&from, 0, sizeof(from));
-
- from4->sin_family = AF_INET;
- fromlen = sizeof(*from4);
- memcpy(&from4->sin_addr, &addr, sizeof(addr));
- from4->sin_port = port;
- }
- }
-#endif
+
+ if (from.ss_family == AF_INET)
+ check_ip_options(sock, ntop);
+
+ ipv64_normalise_mapped(&from, &fromlen);
+
if (from.ss_family == AF_INET6)
fromlen = sizeof(struct sockaddr_in6);
if (!use_dns)
return xstrdup(ntop);
- if (from.ss_family == AF_INET)
- check_ip_options(socket, ntop);
-
debug3("Trying to reverse map address %.100s.", ntop);
/* Map the IP address to a host name. */
if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
*/
/* IPv4 only */
static void
-check_ip_options(int socket, char *ipaddr)
+check_ip_options(int sock, char *ipaddr)
{
#ifdef IP_OPTIONS
u_char options[200];
else
ipproto = IPPROTO_IP;
option_size = sizeof(options);
- if (getsockopt(socket, ipproto, IP_OPTIONS, options,
+ if (getsockopt(sock, ipproto, IP_OPTIONS, options,
&option_size) >= 0 && option_size != 0) {
text[0] = '\0';
for (i = 0; i < option_size; i++)
#endif /* IP_OPTIONS */
}
+void
+ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len)
+{
+ struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)addr;
+ struct sockaddr_in *a4 = (struct sockaddr_in *)addr;
+ struct in_addr inaddr;
+ u_int16_t port;
+
+ if (addr->ss_family != AF_INET6 ||
+ !IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr))
+ return;
+
+ debug3("Normalising mapped IPv4 in IPv6 address");
+
+ memcpy(&inaddr, ((char *)&a6->sin6_addr) + 12, sizeof(inaddr));
+ port = a6->sin6_port;
+
+ memset(addr, 0, sizeof(*a4));
+
+ a4->sin_family = AF_INET;
+ *len = sizeof(*a4);
+ memcpy(&a4->sin_addr, &inaddr, sizeof(inaddr));
+ a4->sin_port = port;
+}
+
/*
* Return the canonical name of the host in the other side of the current
* connection. The host name is cached, so it is efficient to call this
* The returned string must be freed.
*/
static char *
-get_socket_address(int socket, int remote, int flags)
+get_socket_address(int sock, int remote, int flags)
{
struct sockaddr_storage addr;
socklen_t addrlen;
char ntop[NI_MAXHOST];
+ int r;
/* Get IP address of client. */
addrlen = sizeof(addr);
memset(&addr, 0, sizeof(addr));
if (remote) {
- if (getpeername(socket, (struct sockaddr *)&addr, &addrlen)
+ if (getpeername(sock, (struct sockaddr *)&addr, &addrlen)
< 0)
return NULL;
} else {
- if (getsockname(socket, (struct sockaddr *)&addr, &addrlen)
+ if (getsockname(sock, (struct sockaddr *)&addr, &addrlen)
< 0)
return NULL;
}
if (addr.ss_family == AF_INET6)
addrlen = sizeof(struct sockaddr_in6);
+ ipv64_normalise_mapped(&addr, &addrlen);
+
/* Get the address in ascii. */
- if (getnameinfo((struct sockaddr *)&addr, addrlen, ntop, sizeof(ntop),
- NULL, 0, flags) != 0) {
- error("get_socket_address: getnameinfo %d failed", flags);
+ if ((r = getnameinfo((struct sockaddr *)&addr, addrlen, ntop,
+ sizeof(ntop), NULL, 0, flags)) != 0) {
+ error("get_socket_address: getnameinfo %d failed: %s", flags,
+ r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r));
return NULL;
}
return xstrdup(ntop);
}
char *
-get_peer_ipaddr(int socket)
+get_peer_ipaddr(int sock)
{
char *p;
- if ((p = get_socket_address(socket, 1, NI_NUMERICHOST)) != NULL)
+ if ((p = get_socket_address(sock, 1, NI_NUMERICHOST)) != NULL)
return p;
return xstrdup("UNKNOWN");
}
char *
-get_local_ipaddr(int socket)
+get_local_ipaddr(int sock)
{
char *p;
- if ((p = get_socket_address(socket, 0, NI_NUMERICHOST)) != NULL)
+ if ((p = get_socket_address(sock, 0, NI_NUMERICHOST)) != NULL)
return p;
return xstrdup("UNKNOWN");
}
char *
-get_local_name(int socket)
+get_local_name(int sock)
{
- return get_socket_address(socket, 0, NI_NAMEREQD);
+ return get_socket_address(sock, 0, NI_NAMEREQD);
}
/*
canonical_host_ip =
get_peer_ipaddr(packet_get_connection_in());
if (canonical_host_ip == NULL)
- fatal_cleanup();
+ cleanup_exit(255);
} else {
/* If not on socket, return UNKNOWN. */
canonical_host_ip = xstrdup("UNKNOWN");
struct sockaddr_storage from;
socklen_t fromlen;
char strport[NI_MAXSERV];
+ int r;
/* Get IP address of client. */
fromlen = sizeof(from);
} else {
if (getpeername(sock, (struct sockaddr *)&from, &fromlen) < 0) {
debug("getpeername failed: %.100s", strerror(errno));
- fatal_cleanup();
+ cleanup_exit(255);
}
}
fromlen = sizeof(struct sockaddr_in6);
/* Return port number. */
- if (getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
- strport, sizeof(strport), NI_NUMERICSERV) != 0)
- fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed");
+ if ((r = getnameinfo((struct sockaddr *)&from, fromlen, NULL, 0,
+ strport, sizeof(strport), NI_NUMERICSERV)) != 0)
+ fatal("get_sock_port: getnameinfo NI_NUMERICSERV failed: %s",
+ r == EAI_SYSTEM ? strerror(errno) : gai_strerror(r));
return atoi(strport);
}
int
get_remote_port(void)
{
- return get_port(0);
+ static int port = -1;
+
+ /* Cache to avoid getpeername() on a dead connection */
+ if (port == -1)
+ port = get_port(0);
+
+ return port;
}
int