1diff --git a/include/curl/curl.h b/include/curl/curl.h 2index a7bfef09e..090a0acfe 100644 3--- a/include/curl/curl.h 4+++ b/include/curl/curl.h 5@@ -393,6 +393,8 @@ typedef int (*curl_seek_callback)(void *instream, 6 #define CURL_MAX_CIPHER_NUM 512 7 #define CURL_MAX_ISSUER_NAME 256 8 #define CURL_MAX_CERT_NUM 4 9+#define CURL_MAX_IP_LENGTH INET6_ADDRSTRLEN 10+#define CURL_MAX_CONNECTED_IP_NUM 8 11 #endif 12 /* This is a return code for the read callback that, when returned, will 13 signal libcurl to pause sending data on the current transfer. */ 14@@ -2889,6 +2891,7 @@ struct curl_tlssessioninfo { 15 #define CURLINFO_OFF_T 0x600000 16 #ifdef USE_ARES 17 #define CURLINFO_P_STRING 0xe00000 18+#define CURLINFO_P_UINT16 0xd00000 19 #endif 20 #define CURLINFO_MASK 0x0fffff 21 #define CURLINFO_TYPEMASK 0xf00000 22@@ -3008,6 +3011,9 @@ typedef enum { 23 CURLINFO_CERT_NUM = CURLINFO_LONG + 1019, 24 CURLINFO_TRY_CONN_IPV4 = CURLINFO_LONG + 1020, 25 CURLINFO_TRY_CONN_IPV6 = CURLINFO_LONG + 1021, 26+ CURLINFO_CONNECTED_IP = CURLINFO_STRING + 1022, 27+ CURLINFO_CONNECTED_PORT = CURLINFO_P_UINT16 + 1023, 28+ CURLINFO_CONNECTED_IP_NUM = CURLINFO_LONG + 1024, 29 #endif 30 CURLINFO_LASTONE = 66 31 } CURLINFO; 32diff --git a/lib/cf-socket.c b/lib/cf-socket.c 33index f0b3bc034..d8f49c7b1 100644 34--- a/lib/cf-socket.c 35+++ b/lib/cf-socket.c 36@@ -1065,6 +1065,31 @@ out: 37 return result; 38 } 39 40+#ifdef USE_ARES 41+static void record_connected_ip_and_port(struct cf_socket_ctx *ctx, struct Curl_easy *data) 42+{ 43+ if (0 <= data->connected_ip_num && data->connected_ip_num < CURL_MAX_CONNECTED_IP_NUM) { 44+ void *address = NULL; 45+ uint16_t port = 0; 46+ if (ctx->addr.sa_addr.sa_family == AF_INET) { 47+ struct sockaddr_in *addr4 = (struct sockaddr_in *) (void *) (&ctx->addr.sa_addr); 48+ address = &addr4->sin_addr; 49+ port = addr4->sin_port; 50+ } else if (ctx->addr.sa_addr.sa_family == AF_INET6) { 51+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) (void *) (&ctx->addr.sa_addr); 52+ address = &addr6->sin6_addr; 53+ port = addr6->sin6_port; 54+ } 55+ if (address) { 56+ inet_ntop(ctx->addr.sa_addr.sa_family, address, data->connected_ip[data->connected_ip_num], 57+ sizeof(data->connected_ip[data->connected_ip_num])); 58+ data->connected_port[data->connected_ip_num] = ntohs(port); 59+ ++data->connected_ip_num; 60+ } 61+ } 62+} 63+#endif 64+ 65 static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data, 66 bool is_tcp_fastopen) 67 { 68@@ -1111,6 +1136,7 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data, 69 } else if (ctx->addr.sa_addr.sa_family == AF_INET6) { 70 data->try_connect_ipv6 = 1; 71 } 72+ record_connected_ip_and_port(ctx, data); 73 #endif 74 rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen); 75 #elif defined(MSG_FASTOPEN) /* old Linux */ 76@@ -1127,6 +1153,7 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data, 77 } else if (ctx->addr.sa_addr.sa_family == AF_INET6) { 78 data->try_connect_ipv6 = 1; 79 } 80+ record_connected_ip_and_port(ctx, data); 81 #endif 82 rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen); 83 } 84@@ -1644,6 +1671,7 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf, 85 } else if (ctx->addr.sa_addr.sa_family == AF_INET6) { 86 data->try_connect_ipv6 = 1; 87 } 88+ record_connected_ip_and_port(ctx, data); 89 #endif 90 rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen); 91 if(-1 == rc) { 92diff --git a/lib/easy.c b/lib/easy.c 93index 8ce849f77..78a8af099 100644 94--- a/lib/easy.c 95+++ b/lib/easy.c 96@@ -940,6 +940,10 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) 97 98 outcurl->try_connect_ipv4 = 0; 99 outcurl->try_connect_ipv6 = 0; 100+ 101+ memset(outcurl->connected_ip, 0, sizeof(outcurl->connected_ip)); 102+ memset(outcurl->connected_port, 0, sizeof(outcurl->connected_port)); 103+ outcurl->connected_ip_num = 0; 104 #endif 105 106 /* copy all userdefined values */ 107diff --git a/lib/getinfo.c b/lib/getinfo.c 108index 420b76fcf..3e82cdaf0 100644 109--- a/lib/getinfo.c 110+++ b/lib/getinfo.c 111@@ -103,6 +103,18 @@ static CURLcode getinfo_pchar(struct Curl_easy *data, CURLINFO info, 112 } 113 return CURLE_OK; 114 } 115+ 116+static CURLcode getinfo_puint16(struct Curl_easy *data, CURLINFO info, 117+ uint16_t **param_puint16) { 118+ switch (info) { 119+ case CURLINFO_CONNECTED_PORT: 120+ *param_puint16 = data->connected_port; 121+ break; 122+ default: 123+ break; 124+ } 125+ return CURLE_OK; 126+} 127 #endif 128 129 static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, 130@@ -110,6 +122,9 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, 131 { 132 switch(info) { 133 #ifdef USE_ARES 134+ case CURLINFO_CONNECTED_IP: 135+ memcpy(param_charp, data->connected_ip, sizeof(data->connected_ip)); 136+ break; 137 case CURLINFO_ISSUER_NAMES: 138 memcpy(param_charp, data->cert_issuer_names, sizeof(data->cert_issuer_names)); 139 break; 140@@ -266,6 +281,9 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, 141 142 switch(info) { 143 #ifdef USE_ARES 144+ case CURLINFO_CONNECTED_IP_NUM: 145+ *param_longp = data->connected_ip_num; 146+ break; 147 case CURLINFO_TRY_CONN_IPV4: 148 *param_longp = data->try_connect_ipv4; 149 break; 150@@ -686,6 +704,7 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...) 151 const char **param_charp = NULL; 152 #ifdef USE_ARES 153 const char ***param_pcharp = NULL; 154+ uint16_t **param_puint16 = NULL; 155 #endif 156 struct curl_slist **param_slistp = NULL; 157 curl_socket_t *param_socketp = NULL; 158@@ -705,6 +724,11 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...) 159 if(param_pcharp) 160 result = getinfo_pchar(data, info, param_pcharp); 161 break; 162+ case CURLINFO_P_UINT16: 163+ param_puint16 = va_arg(arg, uint16_t **); 164+ if(param_puint16) 165+ result = getinfo_puint16(data, info, param_puint16); 166+ break; 167 #endif 168 case CURLINFO_STRING: 169 param_charp = va_arg(arg, const char **); 170diff --git a/lib/url.c b/lib/url.c 171index a54e2af01..c749a1885 100644 172--- a/lib/url.c 173+++ b/lib/url.c 174@@ -550,6 +550,10 @@ CURLcode Curl_open(struct Curl_easy **curl) 175 176 data->try_connect_ipv4 = 0; 177 data->try_connect_ipv6 = 0; 178+ 179+ memset(data->connected_ip, 0, sizeof(data->connected_ip)); 180+ memset(data->connected_port, 0, sizeof(data->connected_port)); 181+ data->connected_ip_num = 0; 182 #endif 183 184 Curl_req_init(&data->req); 185diff --git a/lib/urldata.h b/lib/urldata.h 186index c11655c27..afc79e864 100644 187--- a/lib/urldata.h 188+++ b/lib/urldata.h 189@@ -1998,6 +1998,9 @@ struct Curl_easy { 190 long cert_num; 191 long try_connect_ipv4; 192 long try_connect_ipv6; 193+ char connected_ip[CURL_MAX_CONNECTED_IP_NUM][CURL_MAX_IP_LENGTH]; 194+ uint16_t connected_port[CURL_MAX_CONNECTED_IP_NUM]; 195+ long connected_ip_num; 196 #endif 197 }; 198 199