[rtmpdump] [PATCH] librtmp: support resolving hostnames to IPv6

Adam Gausmann adam at gaussian.dev
Fri Jun 16 02:24:45 EEST 2023


Updated to use the generic sockaddr and sockaddr_storage types
where possible, and using getaddrinfo instead of gethostbyname.

This only fixes domain name resolution; it is still not possible to
pass IPv6 addresses directly in the URL, because the parser assumes
that the host/address field does not contain colon characters.

Signed-off-by: Adam Gausmann <adam at gaussian.dev>
---
 librtmp/rtmp.c | 76 +++++++++++++++++++++++++++++++++++---------------
 1 file changed, 53 insertions(+), 23 deletions(-)

diff --git a/librtmp/rtmp.c b/librtmp/rtmp.c
index 0865689..f333c32 100644
--- a/librtmp/rtmp.c
+++ b/librtmp/rtmp.c
@@ -867,9 +867,11 @@ int RTMP_SetupURL(RTMP *r, char *url)
 }
 
 static int
-add_addr_info(struct sockaddr_in *service, AVal *host, int port)
+add_addr_info(struct sockaddr_storage *service, AVal *host, int port, const struct addrinfo *hints)
 {
   char *hostname;
+  struct addrinfo *addr_info = NULL;
+  int gai_result;
   int ret = TRUE;
   if (host->av_val[host->av_len])
     {
@@ -882,21 +884,32 @@ add_addr_info(struct sockaddr_in *service, AVal *host, int port)
       hostname = host->av_val;
     }
 
-  service->sin_addr.s_addr = inet_addr(hostname);
-  if (service->sin_addr.s_addr == INADDR_NONE)
+  gai_result = getaddrinfo(hostname, NULL, hints, &addr_info);
+  if (gai_result)
     {
-      struct hostent *host = gethostbyname(hostname);
-      if (host == NULL || host->h_addr == NULL)
-	{
-	  RTMP_Log(RTMP_LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname);
-	  ret = FALSE;
-	  goto finish;
-	}
-      service->sin_addr = *(struct in_addr *)host->h_addr;
+      RTMP_Log(RTMP_LOGERROR, "Address lookup failed. (addr: %s) %d (%s)",
+        hostname, gai_result, gai_strerror(gai_result));
+      ret = FALSE;
+      goto finish;
     }
+  memcpy(service, addr_info->ai_addr, addr_info->ai_addrlen);
 
-  service->sin_port = htons(port);
+  switch (service->ss_family)
+    {
+    case AF_INET:
+      ((struct sockaddr_in *)service)->sin_port = htons(port);
+      break;
+    case AF_INET6:
+      ((struct sockaddr_in6 *)service)->sin6_port = htons(port);
+      break;
+    default:
+      RTMP_Log(RTMP_LOGERROR, "Unsupported address family.");
+      ret = FALSE;
+      goto finish;
+    }
 finish:
+  if (addr_info)
+    freeaddrinfo(addr_info);
   if (hostname != host->av_val)
     free(hostname);
   return ret;
@@ -905,15 +918,26 @@ finish:
 int
 RTMP_Connect0(RTMP *r, struct sockaddr * service)
 {
+  socklen_t addrlen = sizeof(struct sockaddr);
+  switch (service->sa_family)
+    {
+    case AF_INET:
+      addrlen = sizeof(struct sockaddr_in);
+      break;
+    case AF_INET6:
+      addrlen = sizeof(struct sockaddr_in6);
+      break;
+    }
+
   int on = 1;
   r->m_sb.sb_timedout = FALSE;
   r->m_pausing = 0;
   r->m_fDuration = 0.0;
 
-  r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  r->m_sb.sb_socket = socket(service->sa_family, SOCK_STREAM, IPPROTO_TCP);
   if (r->m_sb.sb_socket != -1)
     {
-      if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr)) < 0)
+      if (connect(r->m_sb.sb_socket, service, addrlen) < 0)
 	{
 	  int err = GetSockError();
 	  RTMP_Log(RTMP_LOGERROR, "%s, failed to connect socket. %d (%s)",
@@ -1030,23 +1054,22 @@ RTMP_Connect1(RTMP *r, RTMPPacket *cp)
 int
 RTMP_Connect(RTMP *r, RTMPPacket *cp)
 {
-  struct sockaddr_in service;
+  struct sockaddr_storage service;
   if (!r->Link.hostname.av_len)
     return FALSE;
 
-  memset(&service, 0, sizeof(struct sockaddr_in));
-  service.sin_family = AF_INET;
+  memset(&service, 0, sizeof(struct sockaddr_storage));
 
   if (r->Link.socksport)
     {
       /* Connect via SOCKS */
-      if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport))
+      if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport, NULL))
 	return FALSE;
     }
   else
     {
       /* Connect directly */
-      if (!add_addr_info(&service, &r->Link.hostname, r->Link.port))
+      if (!add_addr_info(&service, &r->Link.hostname, r->Link.port, NULL))
 	return FALSE;
     }
 
@@ -1062,11 +1085,18 @@ static int
 SocksNegotiate(RTMP *r)
 {
   unsigned long addr;
-  struct sockaddr_in service;
-  memset(&service, 0, sizeof(struct sockaddr_in));
+  struct sockaddr_storage service;
+  memset(&service, 0, sizeof(struct sockaddr_storage));
+
+  struct addrinfo hints;
+  memset(&hints, 0, sizeof(struct addrinfo));
+  // Only IPv4 is supported by SOCKS4.
+  hints.ai_family = AF_INET;
+
+  if (!add_addr_info(&service, &r->Link.hostname, r->Link.port, &hints))
+    return FALSE;
 
-  add_addr_info(&service, &r->Link.hostname, r->Link.port);
-  addr = htonl(service.sin_addr.s_addr);
+  addr = htonl(((struct sockaddr_in *)&service)->sin_addr.s_addr);
 
   {
     char packet[] = {
-- 
2.40.1



More information about the rtmpdump mailing list