From 7e37d10e47289a6f42785119e74f6961b4ac933f Mon Sep 17 00:00:00 2001
From: Andy Green <andy.green@linaro.org>
Date: Wed, 28 Jan 2015 21:03:49 +0800
Subject: [PATCH] gethostbyname removal from lws get peer addresses

This replaces gethostbyname in libwebsockets_get_peer_addresses and
in the client handshake path.

There's one left in lws-plat-win but that can be done another time.

Let's see how much damage that did to the cross-platform and option
builds...

Signed-off-by: Andy Green <andy.green@linaro.org>
---
 lib/client-handshake.c      |  28 +++++--
 lib/libwebsockets.c         | 147 ++++++++++++++++++------------------
 lib/libwebsockets.h         |   3 +-
 lib/private-libwebsockets.h |   4 +
 4 files changed, 102 insertions(+), 80 deletions(-)

diff --git a/lib/client-handshake.c b/lib/client-handshake.c
index ca550bfc..40916d6b 100644
--- a/lib/client-handshake.c
+++ b/lib/client-handshake.c
@@ -12,7 +12,6 @@ struct libwebsocket *libwebsocket_client_connect_2(
 #endif
 	struct sockaddr_in server_addr4;
 	struct sockaddr_in client_addr4;
-	struct hostent *server_hostent;
 
 	struct sockaddr *v;
 	int n;
@@ -97,15 +96,32 @@ struct libwebsocket *libwebsocket_client_connect_2(
 	} else
 #endif
 	{
-		server_hostent = gethostbyname(ads);
-		if (!server_hostent) {
-			lwsl_err("Unable to get host name from %s\n", ads);
+		struct addrinfo ai, *res;
+		void *p = NULL;
+
+		memset (&ai, 0, sizeof ai);
+		ai.ai_family = PF_UNSPEC;
+		ai.ai_socktype = SOCK_STREAM;
+		ai.ai_flags = AI_CANONNAME;
+
+		if (getaddrinfo(ads, NULL, &ai, &res))
 			goto oom4;
+
+		while (!p && res) {
+			switch (res->ai_family) {
+			case AF_INET:
+				p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
+				break;
+			}
+
+			res = res->ai_next;
 		}
+		
+		if (!p)
+			goto oom4;
 
 		server_addr4.sin_family = AF_INET;
-		server_addr4.sin_addr =
-				*((struct in_addr *)server_hostent->h_addr);
+		server_addr4.sin_addr = *((struct in_addr *)p);
 		bzero(&server_addr4.sin_zero, 8);
 	}
 
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 5a950ca1..2295cc06 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -295,6 +295,71 @@ just_kill_connection:
 	lws_free(wsi);
 }
 
+LWS_VISIBLE int
+libwebsockets_get_addresses(struct libwebsocket_context *context,
+			    void *ads, char *name, int name_len,
+			    char *rip, int rip_len)
+{
+	struct addrinfo ai, *res;
+	void *p = NULL;
+
+	rip[0] = '\0';
+	name[0] = '\0';
+
+#ifdef LWS_USE_IPV6
+	if (LWS_IPV6_ENABLED(context)) {
+		if (!lws_plat_inet_ntop(AF_INET6, &((struct sockaddr_in6 *)ads)->sin6_addr, rip, rip_len)) {
+			lwsl_err("inet_ntop", strerror(LWS_ERRNO));
+			return -1;
+		}
+
+		// Strip off the IPv4 to IPv6 header if one exists
+		if (strncmp(rip, "::ffff:", 7) == 0)
+			memmove(rip, rip + 7, strlen(rip) - 6);
+
+		getnameinfo((struct sockaddr *)ads,
+				sizeof(struct sockaddr_in6), name,
+							name_len, NULL, 0, 0);
+		
+		return 0;
+	} else
+#endif
+	{
+		memset(&ai, 0, sizeof ai);
+		ai.ai_family = PF_UNSPEC;
+		ai.ai_socktype = SOCK_STREAM;
+		ai.ai_flags = AI_CANONNAME;
+
+		if (getnameinfo((struct sockaddr *)ads,
+				sizeof(struct sockaddr_in),
+				name, name_len, NULL, 0, 0))
+			return -1;
+
+		if (!rip)
+			return 0;
+
+		if (getaddrinfo(name, NULL, &ai, &res))
+			return -1;
+
+		while (!p && res) {
+			switch (res->ai_family) {
+			case AF_INET:
+				p = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
+				break;
+			}
+
+			res = res->ai_next;
+		}
+	}
+
+	if (!p)
+		return -1;
+
+	inet_ntop(AF_INET, p, rip, rip_len);
+
+	return 0;
+}
+
 /**
  * libwebsockets_get_peer_addresses() - Get client address information
  * @context:	Libwebsockets context
@@ -321,15 +386,8 @@ libwebsockets_get_peer_addresses(struct libwebsocket_context *context,
 	struct sockaddr_in6 sin6;
 #endif
 	struct sockaddr_in sin4;
-	struct hostent *host;
-	struct hostent *host1;
-	char ip[128];
-	unsigned char *p;
-	int n;
-#ifdef AF_LOCAL
-	struct sockaddr_un *un;
-#endif
 	int ret = -1;
+	void *p;
 
 	rip[0] = '\0';
 	name[0] = '\0';
@@ -338,83 +396,26 @@ libwebsockets_get_peer_addresses(struct libwebsocket_context *context,
 
 #ifdef LWS_USE_IPV6
 	if (LWS_IPV6_ENABLED(context)) {
-
 		len = sizeof(sin6);
-		if (getpeername(fd, (struct sockaddr *) &sin6, &len) < 0) {
-			lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
-			goto bail;
-		}
-
-		if (!lws_plat_inet_ntop(AF_INET6, &sin6.sin6_addr, rip, rip_len)) {
-			lwsl_err("inet_ntop", strerror(LWS_ERRNO));
-			goto bail;
-		}
-
-		// Strip off the IPv4 to IPv6 header if one exists
-		if (strncmp(rip, "::ffff:", 7) == 0)
-			memmove(rip, rip + 7, strlen(rip) - 6);
-
-		getnameinfo((struct sockaddr *)&sin6,
-				sizeof(struct sockaddr_in6), name,
-							name_len, NULL, 0, 0);
-
+		p = &sin6;
 	} else
 #endif
 	{
 		len = sizeof(sin4);
-		if (getpeername(fd, (struct sockaddr *) &sin4, &len) < 0) {
-			lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
-			goto bail;
-		}
-		host = gethostbyaddr((char *) &sin4.sin_addr,
-						sizeof(sin4.sin_addr), AF_INET);
-		if (host == NULL) {
-			lwsl_warn("gethostbyaddr: %s\n", strerror(LWS_ERRNO));
-			goto bail;
-		}
+		p = &sin4;
+	}
 
-		strncpy(name, host->h_name, name_len);
-		name[name_len - 1] = '\0';
-
-		host1 = gethostbyname(host->h_name);
-		if (host1 == NULL)
-			goto bail;
-		p = (unsigned char *)host1;
-		n = 0;
-		while (p != NULL) {
-			p = (unsigned char *)host1->h_addr_list[n++];
-			if (p == NULL)
-				continue;
-			if ((host1->h_addrtype != AF_INET)
-#ifdef AF_LOCAL
-				&& (host1->h_addrtype != AF_LOCAL)
-#endif
-				)
-				continue;
-
-			if (host1->h_addrtype == AF_INET)
-				sprintf(ip, "%u.%u.%u.%u",
-						p[0], p[1], p[2], p[3]);
-#ifdef AF_LOCAL
-			else {
-				un = (struct sockaddr_un *)p;
-				strncpy(ip, un->sun_path, sizeof(ip) - 1);
-				ip[sizeof(ip) - 1] = '\0';
-			}
-#endif
-			p = NULL;
-			strncpy(rip, ip, rip_len);
-			rip[rip_len - 1] = '\0';
-		}
+	if (getpeername(fd, p, &len) < 0) {
+		lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
+		goto bail;
 	}
+	
+	ret = libwebsockets_get_addresses(context, p, name, name_len, rip, rip_len);
 
-	ret = 0;
 bail:
 	lws_latency(context, wsi, "libwebsockets_get_peer_addresses", ret, 1);
 }
 
-
-
 /**
  * libwebsocket_context_user() - get the user data associated with the context
  * @context: Websocket context
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 9aa07cb7..969de6e3 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -1,7 +1,7 @@
 /*
  * libwebsockets - small server side websockets and web server implementation
  *
- * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
+ * Copyright (C) 2010-2015 Andy Green <andy@warmcat.com>
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -62,6 +62,7 @@ extern "C" {
 
 #include <poll.h>
 #include <unistd.h>
+#include <netdb.h>
 
 #if defined(__GNUC__)
 #define LWS_VISIBLE __attribute__((visibility("default")))
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index de43ec42..9c760705 100755
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -1162,6 +1162,10 @@ lws_ssl_capable_write_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int l
 #define _libwebsocket_rx_flow_control(_a) (0)
 #define lws_handshake_server(_a, _b, _c, _d) (0)
 #endif
+	
+LWS_EXTERN int libwebsockets_get_addresses(struct libwebsocket_context *context,
+			    void *ads, char *name, int name_len,
+			    char *rip, int rip_len);
 
 /*
  * custom allocator
-- 
GitLab