From cea841d71c025f9c998b7d5fc9f2a2839df62921 Mon Sep 17 00:00:00 2001
From: Norbert Pocs <norbertpocs0@gmail.com>
Date: Tue, 28 Nov 2023 15:26:45 +0100
Subject: [PATCH] CVE-2023-6004 misc: Add ipv6 link-local check for an ip
 address

Signed-off-by: Norbert Pocs <norbertpocs0@gmail.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>

CVE: CVE-2023-6004
Upstream-Status: Backport [https://gitlab.com/libssh/libssh-mirror/-/commit/cea841d71c025f9c998b7d5fc9f2a2839df62921]
Signed-off-by: nikhil r <nikhil.r@kpit.com>
Comment: Refreshed hunk 1 from CMakeLists.txt, hunk 1 from connect.c and
hunks 2,3,4 from misc.c
---
 src/CMakeLists.txt |  1 +
 src/connect.c      |  2 +-
 src/misc.c         | 44 ++++++++++++++++++++++++++++++++++++++------
 3 files changed, 40 insertions(+), 7 deletions(-)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d6245c0db..807313b59 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -14,6 +14,7 @@ set(LIBSSH_LINK_LIBRARIES
 if (WIN32)
   set(LIBSSH_LINK_LIBRARIES
     ${LIBSSH_LINK_LIBRARIES}
+    iphlpapi
     ws2_32
   )
 endif (WIN32)
diff --git a/src/connect.c b/src/connect.c
index 57e37e634..15cae6444 100644
--- a/src/connect.c
+++ b/src/connect.c
@@ -130,7 +130,7 @@ static int getai(const char *host, int port, struct addrinfo **ai) {
 #endif
   }
 
-  if (ssh_is_ipaddr(host)) {
+  if (ssh_is_ipaddr(host) == 1) {
     /* this is an IP address */
     SSH_LOG(SSH_LOG_PACKET,"host %s matches an IP address",host);
     hints.ai_flags |= AI_NUMERICHOST;
diff --git a/src/misc.c b/src/misc.c
index be6ee836e..7081f12ae 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -32,6 +32,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <net/if.h>
 
 #endif /* _WIN32 */
 
@@ -59,6 +60,7 @@
 #include <ws2tcpip.h>
 #include <shlobj.h>
 #include <direct.h>
+#include <netioapi.h>
 
 #ifdef HAVE_IO_H
 #include <io.h>
@@ -191,22 +191,37 @@ int ssh_is_ipaddr_v4(const char *str) {
 
 int ssh_is_ipaddr(const char *str) {
     int rc = SOCKET_ERROR;
+    char *s = strdup(str);
 
-    if (strchr(str, ':')) {
+    if (s == NULL) {
+        return -1;
+    }
+    if (strchr(s, ':')) {
         struct sockaddr_storage ss;
         int sslen = sizeof(ss);
+        char *network_interface = strchr(s, '%');
 
-        /* TODO link-local (IP:v6:addr%ifname). */
-        rc = WSAStringToAddressA((LPSTR) str,
+        /* link-local (IP:v6:addr%ifname). */
+        if (network_interface != NULL) {
+            rc = if_nametoindex(network_interface + 1);
+            if (rc == 0) {
+                free(s);
+                return 0;
+            }
+            *network_interface = '\0';
+        }
+        rc = WSAStringToAddressA((LPSTR) s,
                                  AF_INET6,
                                  NULL,
                                  (struct sockaddr*)&ss,
                                  &sslen);
         if (rc == 0) {
+            free(s);
             return 1;
         }
     }
 
+    free(s);
     return ssh_is_ipaddr_v4(str);
 }
 #else /* _WIN32 */
@@ -285,17 +300,32 @@ int ssh_is_ipaddr_v4(const char *str) {
 
 int ssh_is_ipaddr(const char *str) {
     int rc = -1;
+    char *s = strdup(str);
 
-    if (strchr(str, ':')) {
+    if (s == NULL) {
+        return -1;
+    }
+    if (strchr(s, ':')) {
         struct in6_addr dest6;
+        char *network_interface = strchr(s, '%');
 
-        /* TODO link-local (IP:v6:addr%ifname). */
-        rc = inet_pton(AF_INET6, str, &dest6);
+        /* link-local (IP:v6:addr%ifname). */
+        if (network_interface != NULL) {
+            rc = if_nametoindex(network_interface + 1);
+            if (rc == 0) {
+                free(s);
+                return 0;
+            }
+            *network_interface = '\0';
+        }
+        rc = inet_pton(AF_INET6, s, &dest6);
         if (rc > 0) {
+	    free(s);
             return 1;
         }
     }
 
+    free(s);
     return ssh_is_ipaddr_v4(str);
 }
