@@ -393,6 +393,8 @@ typedef int (*curl_seek_callback)(void *instream,
#define CURL_MAX_CIPHER_NUM 512
#define CURL_MAX_ISSUER_NAME 256
#define CURL_MAX_CERT_NUM 4
+#define CURL_MAX_IP_LENGTH INET6_ADDRSTRLEN
+#define CURL_MAX_CONNECTED_IP_NUM 8
#endif
/* This is a return code for the read callback that, when returned, will
signal libcurl to pause sending data on the current transfer. */
@@ -2889,6 +2891,7 @@ struct curl_tlssessioninfo {
#define CURLINFO_OFF_T 0x600000
#ifdef USE_ARES
#define CURLINFO_P_STRING 0xe00000
+#define CURLINFO_P_UINT16 0xd00000
#endif
#define CURLINFO_MASK 0x0fffff
#define CURLINFO_TYPEMASK 0xf00000
@@ -3008,6 +3011,9 @@ typedef enum {
CURLINFO_CERT_NUM = CURLINFO_LONG + 1019,
CURLINFO_TRY_CONN_IPV4 = CURLINFO_LONG + 1020,
CURLINFO_TRY_CONN_IPV6 = CURLINFO_LONG + 1021,
+ CURLINFO_CONNECTED_IP = CURLINFO_STRING + 1022,
+ CURLINFO_CONNECTED_PORT = CURLINFO_P_UINT16 + 1023,
+ CURLINFO_CONNECTED_IP_NUM = CURLINFO_LONG + 1024,
#endif
CURLINFO_LASTONE = 66
} CURLINFO;
@@ -1065,6 +1065,31 @@ out:
return result;
}
+#ifdef USE_ARES
+static void record_connected_ip_and_port(struct cf_socket_ctx *ctx, struct Curl_easy *data)
+{
+ if (0 <= data->connected_ip_num && data->connected_ip_num < CURL_MAX_CONNECTED_IP_NUM) {
+ void *address = NULL;
+ uint16_t port = 0;
+ if (ctx->addr.sa_addr.sa_family == AF_INET) {
+ struct sockaddr_in *addr4 = (struct sockaddr_in *) (void *) (&ctx->addr.sa_addr);
+ address = &addr4->sin_addr;
+ port = addr4->sin_port;
+ } else if (ctx->addr.sa_addr.sa_family == AF_INET6) {
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) (void *) (&ctx->addr.sa_addr);
+ address = &addr6->sin6_addr;
+ port = addr6->sin6_port;
+ }
+ if (address) {
+ inet_ntop(ctx->addr.sa_addr.sa_family, address, data->connected_ip[data->connected_ip_num],
+ sizeof(data->connected_ip[data->connected_ip_num]));
+ data->connected_port[data->connected_ip_num] = ntohs(port);
+ ++data->connected_ip_num;
+ }
+ }
+}
+#endif
+
static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
bool is_tcp_fastopen)
{
@@ -1111,6 +1136,7 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
} else if (ctx->addr.sa_addr.sa_family == AF_INET6) {
data->try_connect_ipv6 = 1;
}
+ record_connected_ip_and_port(ctx, data);
#endif
rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
#elif defined(MSG_FASTOPEN) /* old Linux */
@@ -1127,6 +1153,7 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
} else if (ctx->addr.sa_addr.sa_family == AF_INET6) {
data->try_connect_ipv6 = 1;
}
+ record_connected_ip_and_port(ctx, data);
#endif
rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
}
@@ -1644,6 +1671,7 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
} else if (ctx->addr.sa_addr.sa_family == AF_INET6) {
data->try_connect_ipv6 = 1;
}
+ record_connected_ip_and_port(ctx, data);
#endif
rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
if(-1 == rc) {
@@ -940,6 +940,10 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
outcurl->try_connect_ipv4 = 0;
outcurl->try_connect_ipv6 = 0;
+
+ memset(outcurl->connected_ip, 0, sizeof(outcurl->connected_ip));
+ memset(outcurl->connected_port, 0, sizeof(outcurl->connected_port));
+ outcurl->connected_ip_num = 0;
#endif
/* copy all userdefined values */
@@ -103,6 +103,18 @@ static CURLcode getinfo_pchar(struct Curl_easy *data, CURLINFO info,
}
return CURLE_OK;
}
+
+static CURLcode getinfo_puint16(struct Curl_easy *data, CURLINFO info,
+ uint16_t **param_puint16) {
+ switch (info) {
+ case CURLINFO_CONNECTED_PORT:
+ *param_puint16 = data->connected_port;
+ break;
+ default:
+ break;
+ }
+ return CURLE_OK;
+}
#endif
static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
@@ -110,6 +122,9 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
{
switch(info) {
#ifdef USE_ARES
+ case CURLINFO_CONNECTED_IP:
+ memcpy(param_charp, data->connected_ip, sizeof(data->connected_ip));
+ break;
case CURLINFO_ISSUER_NAMES:
memcpy(param_charp, data->cert_issuer_names, sizeof(data->cert_issuer_names));
break;
@@ -266,6 +281,9 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
switch(info) {
#ifdef USE_ARES
+ case CURLINFO_CONNECTED_IP_NUM:
+ *param_longp = data->connected_ip_num;
+ break;
case CURLINFO_TRY_CONN_IPV4:
*param_longp = data->try_connect_ipv4;
break;
@@ -686,6 +704,7 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
const char **param_charp = NULL;
#ifdef USE_ARES
const char ***param_pcharp = NULL;
+ uint16_t **param_puint16 = NULL;
#endif
struct curl_slist **param_slistp = NULL;
curl_socket_t *param_socketp = NULL;
@@ -705,6 +724,11 @@ CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
if(param_pcharp)
result = getinfo_pchar(data, info, param_pcharp);
break;
+ case CURLINFO_P_UINT16:
+ param_puint16 = va_arg(arg, uint16_t **);
+ if(param_puint16)
+ result = getinfo_puint16(data, info, param_puint16);
+ break;
#endif
case CURLINFO_STRING:
param_charp = va_arg(arg, const char **);
@@ -550,6 +550,10 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->try_connect_ipv4 = 0;
data->try_connect_ipv6 = 0;
+
+ memset(data->connected_ip, 0, sizeof(data->connected_ip));
+ memset(data->connected_port, 0, sizeof(data->connected_port));
+ data->connected_ip_num = 0;
#endif
Curl_req_init(&data->req);
@@ -1998,6 +1998,9 @@ struct Curl_easy {
long cert_num;
long try_connect_ipv4;
long try_connect_ipv6;
+ char connected_ip[CURL_MAX_CONNECTED_IP_NUM][CURL_MAX_IP_LENGTH];
+ uint16_t connected_port[CURL_MAX_CONNECTED_IP_NUM];
+ long connected_ip_num;
#endif
};