• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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