Browse Source

lib: keep conn IP information together

new struct ip_quadruple for holding local/remote addr+port

- used in data->info and conn and cf-socket.c
- copy back and forth complete struct
- add 'secondary' to conn
- use secondary in reporting success for ftp 2nd connection

Reported-by: DasKutti on github
Fixes #13084
Closes #13090
Stefan Eissing 1 month ago
parent
commit
fcef00db1a
20 changed files with 148 additions and 200 deletions
  1. 4 4
      lib/cf-haproxy.c
  2. 33 49
      lib/cf-socket.c
  3. 3 6
      lib/cf-socket.h
  4. 1 1
      lib/cfilters.c
  5. 1 1
      lib/conncache.c
  6. 10 10
      lib/connect.c
  7. 2 1
      lib/connect.h
  8. 4 4
      lib/ftp.c
  9. 8 8
      lib/getinfo.c
  10. 7 7
      lib/ldap.c
  11. 5 5
      lib/multi.c
  12. 2 2
      lib/socks.c
  13. 22 17
      lib/url.c
  14. 3 2
      lib/url.h
  15. 19 20
      lib/urldata.h
  16. 0 21
      lib/vquic/curl_msh3.c
  17. 4 7
      lib/vquic/curl_ngtcp2.c
  18. 7 13
      lib/vquic/curl_osslq.c
  19. 4 7
      lib/vquic/curl_quiche.c
  20. 9 15
      lib/vquic/vquic.c

+ 4 - 4
lib/cf-haproxy.c

@@ -86,14 +86,14 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
   if(data->set.str[STRING_HAPROXY_CLIENT_IP])
     client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
   else
-    client_ip = data->info.conn_local_ip;
+    client_ip = data->info.primary.local_ip;
 
   result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
                          tcp_version,
                          client_ip,
-                         data->info.conn_primary_ip,
-                         data->info.conn_local_port,
-                         data->info.conn_primary_port);
+                         data->info.primary.remote_ip,
+                         data->info.primary.local_port,
+                         data->info.primary.remote_port);
 
 #ifdef USE_UNIX_SOCKETS
   }

+ 33 - 49
lib/cf-socket.c

@@ -776,10 +776,7 @@ struct cf_socket_ctx {
   struct Curl_sockaddr_ex addr;      /* address to connect to */
   curl_socket_t sock;                /* current attempt socket */
   struct bufq recvbuf;               /* used when `buffer_recv` is set */
-  char r_ip[MAX_IPADR_LEN];          /* remote IP as string */
-  int r_port;                        /* remote port number */
-  char l_ip[MAX_IPADR_LEN];          /* local IP as string */
-  int l_port;                        /* local port number */
+  struct ip_quadruple ip;            /* The IP quadruple 2x(addr+port) */
   struct curltime started_at;        /* when socket was created */
   struct curltime connected_at;      /* when socket connected/got first byte */
   struct curltime first_byte_at;     /* when first byte was recvd */
@@ -941,7 +938,7 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf,
       return CURLE_FAILED_INIT;
     }
     if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
-                         ctx->l_ip, &ctx->l_port)) {
+                         ctx->ip.local_ip, &ctx->ip.local_port)) {
       failf(data, "ssloc inet_ntop() failed with errno %d: %s",
             errno, Curl_strerror(errno, buffer, sizeof(buffer)));
       return CURLE_FAILED_INIT;
@@ -962,7 +959,7 @@ static CURLcode set_remote_ip(struct Curl_cfilter *cf,
 
   /* store remote address and port used in this connection attempt */
   if(!Curl_addr2string(&ctx->addr.sa_addr, ctx->addr.addrlen,
-                       ctx->r_ip, &ctx->r_port)) {
+                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
     char buffer[STRERROR_LEN];
 
     ctx->error = errno;
@@ -997,11 +994,11 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
 #ifdef ENABLE_IPV6
   if(ctx->addr.family == AF_INET6) {
     set_ipv6_v6only(ctx->sock, 0);
-    infof(data, "  Trying [%s]:%d...", ctx->r_ip, ctx->r_port);
+    infof(data, "  Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
   }
   else
 #endif
-    infof(data, "  Trying %s:%d...", ctx->r_ip, ctx->r_port);
+    infof(data, "  Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
 
 #ifdef ENABLE_IPV6
   is_tcp = (ctx->addr.family == AF_INET
@@ -1167,9 +1164,9 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
     error = SOCKERRNO;
     set_local_ip(cf, data);
     CURL_TRC_CF(data, cf, "local address %s port %d...",
-                ctx->l_ip, ctx->l_port);
+                ctx->ip.local_ip, ctx->ip.local_port);
     if(-1 == rc) {
-      result = socket_connect_result(data, ctx->r_ip, error);
+      result = socket_connect_result(data, ctx->ip.remote_ip, error);
       goto out;
     }
   }
@@ -1214,7 +1211,8 @@ out:
       {
         char buffer[STRERROR_LEN];
         infof(data, "connect to %s port %u from %s port %d failed: %s",
-              ctx->r_ip, ctx->r_port, ctx->l_ip, ctx->l_port,
+              ctx->ip.remote_ip, ctx->ip.remote_port,
+              ctx->ip.local_ip, ctx->ip.local_port,
               Curl_strerror(ctx->error, buffer, sizeof(buffer)));
       }
 #endif
@@ -1234,10 +1232,11 @@ static void cf_socket_get_host(struct Curl_cfilter *cf,
                                const char **pdisplay_host,
                                int *pport)
 {
+  struct cf_socket_ctx *ctx = cf->ctx;
   (void)data;
   *phost = cf->conn->host.name;
   *pdisplay_host = cf->conn->host.dispname;
-  *pport = cf->conn->port;
+  *pport = ctx->ip.remote_port;
 }
 
 static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
@@ -1436,31 +1435,24 @@ out:
   return nread;
 }
 
-static void conn_set_primary_ip(struct Curl_cfilter *cf,
-                                struct Curl_easy *data)
-{
-  struct cf_socket_ctx *ctx = cf->ctx;
-
-  (void)data;
-  DEBUGASSERT(sizeof(ctx->r_ip) == sizeof(cf->conn->primary_ip));
-  memcpy(cf->conn->primary_ip, ctx->r_ip, sizeof(cf->conn->primary_ip));
-}
-
 static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
 
   /* use this socket from now on */
   cf->conn->sock[cf->sockindex] = ctx->sock;
-  /* the first socket info gets set at conn and data */
+  set_local_ip(cf, data);
+  if(cf->sockindex == SECONDARYSOCKET)
+    cf->conn->secondary = ctx->ip;
+  else
+    cf->conn->primary = ctx->ip;
+  /* the first socket info gets some specials */
   if(cf->sockindex == FIRSTSOCKET) {
     cf->conn->remote_addr = &ctx->addr;
   #ifdef ENABLE_IPV6
     cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
   #endif
-    conn_set_primary_ip(cf, data);
-    set_local_ip(cf, data);
-    Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
+    Curl_persistconninfo(data, cf->conn, &ctx->ip);
     /* buffering is currently disabled by default because we have stalls
      * in parallel transfers where not all buffered data is consumed and no
      * socket events happen.
@@ -1483,7 +1475,7 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
     cf_socket_active(cf, data);
     break;
   case CF_CTRL_DATA_SETUP:
-    Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
+    Curl_persistconninfo(data, cf->conn, &ctx->ip);
     break;
   case CF_CTRL_FORGET_SOCKET:
     ctx->sock = CURL_SOCKET_BAD;
@@ -1640,7 +1632,7 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
 #else
   rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
   if(-1 == rc) {
-    return socket_connect_result(data, ctx->r_ip, SOCKERRNO);
+    return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
   }
   ctx->sock_connected = TRUE;
 #endif
@@ -1648,7 +1640,8 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
   CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
               " connected: [%s:%d] -> [%s:%d]",
               (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
-              ctx->sock, ctx->l_ip, ctx->l_port, ctx->r_ip, ctx->r_port);
+              ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
+              ctx->ip.remote_ip, ctx->ip.remote_port);
 
   (void)curlx_nonblock(ctx->sock, TRUE);
   switch(ctx->addr.family) {
@@ -1698,7 +1691,7 @@ static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
         goto out;
       CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
                   CURL_FORMAT_SOCKET_T " (%s:%d)",
-                  ctx->sock, ctx->l_ip, ctx->l_port);
+                  ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
     }
     else {
       CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
@@ -1894,8 +1887,8 @@ static void set_accepted_remote_ip(struct Curl_cfilter *cf,
   struct Curl_sockaddr_storage ssrem;
   curl_socklen_t plen;
 
-  ctx->r_ip[0] = 0;
-  ctx->r_port = 0;
+  ctx->ip.remote_ip[0] = 0;
+  ctx->ip.remote_port = 0;
   plen = sizeof(ssrem);
   memset(&ssrem, 0, plen);
   if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
@@ -1905,14 +1898,14 @@ static void set_accepted_remote_ip(struct Curl_cfilter *cf,
     return;
   }
   if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
-                       ctx->r_ip, &ctx->r_port)) {
+                       ctx->ip.remote_ip, &ctx->ip.remote_port)) {
     failf(data, "ssrem inet_ntop() failed with errno %d: %s",
           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
     return;
   }
 #else
-  ctx->r_ip[0] = 0;
-  ctx->r_port = 0;
+  ctx->ip.remote_ip[0] = 0;
+  ctx->ip.remote_port = 0;
   (void)data;
 #endif
 }
@@ -1941,7 +1934,7 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
   cf->connected = TRUE;
   CURL_TRC_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T
               ", remote=%s port=%d)",
-              ctx->sock, ctx->r_ip, ctx->r_port);
+              ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
 
   return CURLE_OK;
 }
@@ -1961,9 +1954,9 @@ CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              curl_socket_t *psock,
                              const struct Curl_sockaddr_ex **paddr,
-                             const char **pr_ip_str, int *pr_port,
-                             const char **pl_ip_str, int *pl_port)
+                             struct ip_quadruple *pip)
 {
+  (void)data;
   if(cf_is_socket(cf) && cf->ctx) {
     struct cf_socket_ctx *ctx = cf->ctx;
 
@@ -1971,17 +1964,8 @@ CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
       *psock = ctx->sock;
     if(paddr)
       *paddr = &ctx->addr;
-    if(pr_ip_str)
-      *pr_ip_str = ctx->r_ip;
-    if(pr_port)
-      *pr_port = ctx->r_port;
-    if(pl_port ||pl_ip_str) {
-      set_local_ip(cf, data);
-      if(pl_ip_str)
-        *pl_ip_str = ctx->l_ip;
-      if(pl_port)
-        *pl_port = ctx->l_port;
-    }
+    if(pip)
+      *pip = ctx->ip;
     return CURLE_OK;
   }
   return CURLE_FAILED_INIT;

+ 3 - 6
lib/cf-socket.h

@@ -33,6 +33,7 @@ struct Curl_cfilter;
 struct Curl_easy;
 struct connectdata;
 struct Curl_sockaddr_ex;
+struct ip_quadruple;
 
 /*
  * The Curl_sockaddr_ex structure is basically libcurl's external API
@@ -153,18 +154,14 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
  * The filter owns all returned values.
  * @param psock             pointer to hold socket descriptor or NULL
  * @param paddr             pointer to hold addr reference or NULL
- * @param pr_ip_str         pointer to hold remote addr as string or NULL
- * @param pr_port           pointer to hold remote port number or NULL
- * @param pl_ip_str         pointer to hold local addr as string or NULL
- * @param pl_port           pointer to hold local port number or NULL
+ * @param pip               pointer to get IP quadruple or NULL
  * Returns error if the filter is of invalid type.
  */
 CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              curl_socket_t *psock,
                              const struct Curl_sockaddr_ex **paddr,
-                             const char **pr_ip_str, int *pr_port,
-                             const char **pl_ip_str, int *pl_port);
+                             struct ip_quadruple *pip);
 
 extern struct Curl_cftype Curl_cft_tcp;
 extern struct Curl_cftype Curl_cft_udp;

+ 1 - 1
lib/cfilters.c

@@ -67,7 +67,7 @@ void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
   else {
     *phost = cf->conn->host.name;
     *pdisplay_host = cf->conn->host.dispname;
-    *pport = cf->conn->port;
+    *pport = cf->conn->primary.remote_port;
   }
 }
 

+ 1 - 1
lib/conncache.c

@@ -131,7 +131,7 @@ static void hashkey(struct connectdata *conn, char *buf, size_t len)
 #ifndef CURL_DISABLE_PROXY
   if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
     hostname = conn->http_proxy.host.name;
-    port = conn->port;
+    port = conn->primary.remote_port;
   }
   else
 #endif

+ 10 - 10
lib/connect.c

@@ -145,19 +145,19 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
 /* Copies connection info into the transfer handle to make it available when
    the transfer handle is no longer associated with the connection. */
 void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
-                          char *local_ip, int local_port)
+                          struct ip_quadruple *ip)
 {
-  memcpy(data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
-  if(local_ip && local_ip[0])
-    memcpy(data->info.conn_local_ip, local_ip, MAX_IPADR_LEN);
-  else
-    data->info.conn_local_ip[0] = 0;
+  if(ip)
+    data->info.primary = *ip;
+  else {
+    memset(&data->info.primary, 0, sizeof(data->info.primary));
+    data->info.primary.remote_port = -1;
+    data->info.primary.local_port = -1;
+  }
   data->info.conn_scheme = conn->handler->scheme;
   /* conn_protocol can only provide "old" protocols */
   data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
-  data->info.conn_primary_port = conn->port;
   data->info.conn_remote_port = conn->remote_port;
-  data->info.conn_local_port = local_port;
   data->info.used_proxy =
 #ifdef CURL_DISABLE_PROXY
     0
@@ -728,7 +728,7 @@ evaluate:
 
   failf(data, "Failed to connect to %s port %u after "
         "%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
-        hostname, conn->port,
+        hostname, conn->primary.remote_port,
         Curl_timediff(now, data->progress.t_startsingle),
         curl_easy_strerror(result));
 
@@ -918,7 +918,7 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
 
         if(cf->conn->handler->protocol & PROTO_FAMILY_SSH)
           Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
-        Curl_verboseconnect(data, cf->conn);
+        Curl_verboseconnect(data, cf->conn, cf->sockindex);
         data->info.numconnects++; /* to track the # of connections made */
       }
       break;

+ 2 - 1
lib/connect.h

@@ -30,6 +30,7 @@
 #include "timeval.h"
 
 struct Curl_dns_entry;
+struct ip_quadruple;
 
 /* generic function that returns how much time there's left to run, according
    to the timeouts set */
@@ -52,7 +53,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
                       char *addr, int *port);
 
 void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
-                          char *local_ip, int local_port);
+                          struct ip_quadruple *ip);
 
 /*
  * Curl_conncontrol() marks the end of a connection/stream. The 'closeit'

+ 4 - 4
lib/ftp.c

@@ -1903,7 +1903,7 @@ static char *control_address(struct connectdata *conn)
   if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
     return conn->host.name;
 #endif
-  return conn->primary_ip;
+  return conn->primary.remote_ip;
 }
 
 static bool match_pasv_6nums(const char *p,
@@ -2040,14 +2040,14 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
      */
     const char * const host_name = conn->bits.socksproxy ?
       conn->socks_proxy.host.name : conn->http_proxy.host.name;
-    rc = Curl_resolv(data, host_name, conn->port, FALSE, &addr);
+    rc = Curl_resolv(data, host_name, conn->primary.remote_port, FALSE, &addr);
     if(rc == CURLRESOLV_PENDING)
       /* BLOCKING, ignores the return code but 'addr' will be NULL in
          case of failure */
       (void)Curl_resolver_wait_resolv(data, &addr);
 
-    connectport =
-      (unsigned short)conn->port; /* we connect to the proxy's port */
+    /* we connect to the proxy's port */
+    connectport = (unsigned short)conn->primary.remote_port;
 
     if(!addr) {
       failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);

+ 8 - 8
lib/getinfo.c

@@ -76,10 +76,10 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
   free(info->wouldredirect);
   info->wouldredirect = NULL;
 
-  info->conn_primary_ip[0] = '\0';
-  info->conn_local_ip[0] = '\0';
-  info->conn_primary_port = 0;
-  info->conn_local_port = 0;
+  info->primary.remote_ip[0] = '\0';
+  info->primary.local_ip[0] = '\0';
+  info->primary.remote_port = 0;
+  info->primary.local_port = 0;
   info->retry_after = 0;
 
   info->conn_scheme = 0;
@@ -153,12 +153,12 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
     break;
   case CURLINFO_PRIMARY_IP:
     /* Return the ip address of the most recent (primary) connection */
-    *param_charp = data->info.conn_primary_ip;
+    *param_charp = data->info.primary.remote_ip;
     break;
   case CURLINFO_LOCAL_IP:
     /* Return the source/local ip address of the most recent (primary)
        connection */
-    *param_charp = data->info.conn_local_ip;
+    *param_charp = data->info.primary.local_ip;
     break;
   case CURLINFO_RTSP_SESSION_ID:
     *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
@@ -284,11 +284,11 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
     break;
   case CURLINFO_PRIMARY_PORT:
     /* Return the (remote) port of the most recent (primary) connection */
-    *param_longp = data->info.conn_primary_port;
+    *param_longp = data->info.primary.remote_port;
     break;
   case CURLINFO_LOCAL_PORT:
     /* Return the local port of the most recent (primary) connection */
-    *param_longp = data->info.conn_local_port;
+    *param_longp = data->info.primary.local_port;
     break;
   case CURLINFO_PROXY_ERROR:
     *param_longp = (long)data->info.pxcode;

+ 7 - 7
lib/ldap.c

@@ -371,7 +371,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
 #ifdef HAVE_LDAP_SSL
 #ifdef USE_WIN32_LDAP
     /* Win32 LDAP SDK doesn't support insecure mode without CA! */
-    server = ldap_sslinit(host, conn->port, 1);
+    server = ldap_sslinit(host, conn->primary.remote_port, 1);
     ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
 #else
     int ldap_option;
@@ -417,10 +417,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
       result = CURLE_SSL_CERTPROBLEM;
       goto quit;
     }
-    server = ldapssl_init(host, conn->port, 1);
+    server = ldapssl_init(host, conn->primary.remote_port, 1);
     if(!server) {
       failf(data, "LDAP local: Cannot connect to %s:%u",
-            conn->host.dispname, conn->port);
+            conn->host.dispname, conn->primary.remote_port);
       result = CURLE_COULDNT_CONNECT;
       goto quit;
     }
@@ -458,10 +458,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
       result = CURLE_SSL_CERTPROBLEM;
       goto quit;
     }
-    server = ldap_init(host, conn->port);
+    server = ldap_init(host, conn->primary.remote_port);
     if(!server) {
       failf(data, "LDAP local: Cannot connect to %s:%u",
-            conn->host.dispname, conn->port);
+            conn->host.dispname, conn->primary.remote_port);
       result = CURLE_COULDNT_CONNECT;
       goto quit;
     }
@@ -499,10 +499,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
     goto quit;
   }
   else {
-    server = ldap_init(host, conn->port);
+    server = ldap_init(host, conn->primary.remote_port);
     if(!server) {
       failf(data, "LDAP local: Cannot connect to %s:%u",
-            conn->host.dispname, conn->port);
+            conn->host.dispname, conn->primary.remote_port);
       result = CURLE_COULDNT_CONNECT;
       goto quit;
     }

+ 5 - 5
lib/multi.c

@@ -1987,7 +1987,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         hostname = conn->host.name;
 
       /* check if we have the name resolved by now */
-      dns = Curl_fetch_addr(data, hostname, (int)conn->port);
+      dns = Curl_fetch_addr(data, hostname, conn->primary.remote_port);
 
       if(dns) {
 #ifdef CURLRES_ASYNCH
@@ -2133,10 +2133,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         /* call the prerequest callback function */
         Curl_set_in_callback(data, true);
         prereq_rc = data->set.fprereq(data->set.prereq_userp,
-                                      data->info.conn_primary_ip,
-                                      data->info.conn_local_ip,
-                                      data->info.conn_primary_port,
-                                      data->info.conn_local_port);
+                                      data->info.primary.remote_ip,
+                                      data->info.primary.local_ip,
+                                      data->info.primary.remote_port,
+                                      data->info.primary.local_port);
         Curl_set_in_callback(data, false);
         if(prereq_rc != CURL_PREREQFUNC_OK) {
           failf(data, "operation aborted by pre-request callback");

+ 2 - 2
lib/socks.c

@@ -341,7 +341,7 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
 
   case CONNECT_RESOLVING:
     /* check if we have the name resolved by now */
-    dns = Curl_fetch_addr(data, sx->hostname, (int)conn->port);
+    dns = Curl_fetch_addr(data, sx->hostname, conn->primary.remote_port);
 
     if(dns) {
 #ifdef CURLRES_ASYNCH
@@ -1175,7 +1175,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
   result = connect_SOCKS(cf, sx, data);
   if(!result && sx->state == CONNECT_DONE) {
     cf->connected = TRUE;
-    Curl_verboseconnect(data, conn);
+    Curl_verboseconnect(data, conn, cf->sockindex);
     socks_proxy_cf_free(cf);
   }
 

+ 22 - 17
lib/url.c

@@ -1002,9 +1002,9 @@ ConnectionExists(struct Curl_easy *data,
 
     if(!canmultiplex) {
       if(Curl_resolver_asynch() &&
-         /* primary_ip[0] is NUL only if the resolving of the name hasn't
+         /* remote_ip[0] is NUL only if the resolving of the name hasn't
             completed yet and until then we don't reuse this connection */
-         !check->primary_ip[0])
+         !check->primary.remote_ip[0])
         continue;
     }
 
@@ -1327,11 +1327,15 @@ ConnectionExists(struct Curl_easy *data,
  */
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
 void Curl_verboseconnect(struct Curl_easy *data,
-                         struct connectdata *conn)
+                         struct connectdata *conn, int sockindex)
 {
-  if(data->set.verbose)
+  if(data->set.verbose && sockindex == SECONDARYSOCKET)
+    infof(data, "Connected 2nd connection to %s port %u",
+          conn->secondary.remote_ip, conn->secondary.remote_port);
+  else
     infof(data, "Connected to %s (%s) port %u",
-          CURL_CONN_HOST_DISPNAME(conn), conn->primary_ip, conn->port);
+          CURL_CONN_HOST_DISPNAME(conn), conn->primary.remote_ip,
+          conn->primary.remote_port);
 }
 #endif
 
@@ -1351,7 +1355,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
   conn->sockfd = CURL_SOCKET_BAD;
   conn->writesockfd = CURL_SOCKET_BAD;
   conn->connection_id = -1;    /* no ID */
-  conn->port = -1; /* unknown at this point */
+  conn->primary.remote_port = -1; /* unknown at this point */
   conn->remote_port = -1; /* unknown at this point */
 
   /* Default protocol-independent behavior doesn't support persistent
@@ -1964,7 +1968,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
   }
   else {
     unsigned long port = strtoul(data->state.up.port, NULL, 10);
-    conn->port = conn->remote_port =
+    conn->primary.remote_port = conn->remote_port =
       (data->set.use_port && data->state.allow_port) ?
       data->set.use_port : curlx_ultous(port);
   }
@@ -2040,10 +2044,10 @@ static CURLcode setup_connection_internals(struct Curl_easy *data,
     p = conn->handler;              /* May have changed. */
   }
 
-  if(conn->port < 0)
+  if(conn->primary.remote_port < 0)
     /* we check for -1 here since if proxy was detected already, this
        was very likely already set to the proxy port */
-    conn->port = p->defport;
+    conn->primary.remote_port = p->defport;
 
   return CURLE_OK;
 }
@@ -2289,8 +2293,9 @@ static CURLcode parse_proxy(struct Curl_easy *data,
   }
   if(port >= 0) {
     proxyinfo->port = port;
-    if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc)
-      conn->port = port;
+    if(conn->primary.remote_port < 0 || sockstype ||
+       !conn->socks_proxy.host.rawalloc)
+      conn->primary.remote_port = port;
   }
 
   /* now, clone the proxy host name */
@@ -3188,8 +3193,8 @@ static CURLcode resolve_proxy(struct Curl_easy *data,
   if(!conn->hostname_resolve)
     return CURLE_OUT_OF_MEMORY;
 
-  rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
-                           &hostaddr, timeout_ms);
+  rc = Curl_resolv_timeout(data, conn->hostname_resolve,
+                           conn->primary.remote_port, &hostaddr, timeout_ms);
   conn->dns_entry = hostaddr;
   if(rc == CURLRESOLV_PENDING)
     *async = TRUE;
@@ -3219,7 +3224,7 @@ static CURLcode resolve_host(struct Curl_easy *data,
 
   /* If not connecting via a proxy, extract the port from the URL, if it is
    * there, thus overriding any defaults that might have been set above. */
-  conn->port = conn->bits.conn_to_port ? conn->conn_to_port :
+  conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port :
     conn->remote_port;
 
   /* Resolve target host right on */
@@ -3227,8 +3232,8 @@ static CURLcode resolve_host(struct Curl_easy *data,
   if(!conn->hostname_resolve)
     return CURLE_OUT_OF_MEMORY;
 
-  rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
-                           &hostaddr, timeout_ms);
+  rc = Curl_resolv_timeout(data, conn->hostname_resolve,
+                           conn->primary.remote_port, &hostaddr, timeout_ms);
   conn->dns_entry = hostaddr;
   if(rc == CURLRESOLV_PENDING)
     *async = TRUE;
@@ -3565,7 +3570,7 @@ static CURLcode create_conn(struct Curl_easy *data,
     /* this is supposed to be the connect function so we better at least check
        that the file is present here! */
     DEBUGASSERT(conn->handler->connect_it);
-    Curl_persistconninfo(data, conn, NULL, -1);
+    Curl_persistconninfo(data, conn, NULL);
     result = conn->handler->connect_it(data, &done);
 
     /* Setup a "faked" transfer that'll do nothing */

+ 3 - 2
lib/url.h

@@ -58,9 +58,10 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
                                              specified */
 
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
-#define Curl_verboseconnect(x,y)  Curl_nop_stmt
+#define Curl_verboseconnect(x,y,z)  Curl_nop_stmt
 #else
-void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn);
+void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn,
+                         int sockindex);
 #endif
 
 #if defined(USE_HTTP2) || defined(USE_HTTP3)

+ 19 - 20
lib/urldata.h

@@ -759,6 +759,13 @@ struct Curl_handler {
 #define CONNRESULT_NONE 0                /* No extra information. */
 #define CONNRESULT_DEAD (1<<0)           /* The connection is dead. */
 
+struct ip_quadruple {
+  char remote_ip[MAX_IPADR_LEN];
+  char local_ip[MAX_IPADR_LEN];
+  int remote_port;
+  int local_port;
+};
+
 struct proxy_info {
   struct hostname host;
   int port;
@@ -814,14 +821,13 @@ struct connectdata {
   struct proxy_info socks_proxy;
   struct proxy_info http_proxy;
 #endif
-  /* 'primary_ip' and 'primary_port' get filled with peer's numerical
-     ip address and port number whenever an outgoing connection is
-     *attempted* from the primary socket to a remote address. When more
-     than one address is tried for a connection these will hold data
+  /* 'primary' and 'secondary' get filled with IP quadruple
+     (local/remote numerical ip address and port) whenever a is *attempted*.
+     When more than one address is tried for a connection these will hold data
      for the last attempt. When the connection is actually established
      these are updated with data which comes directly from the socket. */
-
-  char primary_ip[MAX_IPADR_LEN];
+  struct ip_quadruple primary;
+  struct ip_quadruple secondary;
   char *user;    /* user name string, allocated */
   char *passwd;  /* password string, allocated */
   char *options; /* options string, allocated */
@@ -967,7 +973,6 @@ struct connectdata {
   int socks5_gssapi_enctype;
 #endif
   /* The field below gets set in connect.c:connecthost() */
-  int port;        /* which port to use locally - to connect to */
   int remote_port; /* the remote port, not the proxy port! */
   int conn_to_port; /* the remote port to connect to. valid only if
                        bits.conn_to_port is set */
@@ -1022,22 +1027,16 @@ struct PureInfo {
   curl_off_t retry_after; /* info from Retry-After: header */
   unsigned int header_size;  /* size of read header(s) in bytes */
 
-  /* PureInfo members 'conn_primary_ip', 'conn_primary_port', 'conn_local_ip'
-     and, 'conn_local_port' are copied over from the connectdata struct in
-     order to allow curl_easy_getinfo() to return this information even when
-     the session handle is no longer associated with a connection, and also
-     allow curl_easy_reset() to clear this information from the session handle
-     without disturbing information which is still alive, and that might be
-     reused, in the connection cache. */
-
-  char conn_primary_ip[MAX_IPADR_LEN];
-  int conn_primary_port; /* this is the destination port to the connection,
-                            which might have been a proxy */
+  /* PureInfo primary ip_quadruple is copied over from the connectdata
+     struct in order to allow curl_easy_getinfo() to return this information
+     even when the session handle is no longer associated with a connection,
+     and also allow curl_easy_reset() to clear this information from the
+     session handle without disturbing information which is still alive, and
+     that might be reused, in the connection cache. */
+  struct ip_quadruple primary;
   int conn_remote_port;  /* this is the "remote port", which is the port
                             number of the used URL, independent of proxy or
                             not */
-  char conn_local_ip[MAX_IPADR_LEN];
-  int conn_local_port;
   const char *conn_scheme;
   unsigned int conn_protocol;
   struct curl_certinfo certs; /* info about the certs. Asked for with

+ 0 - 21
lib/vquic/curl_msh3.c

@@ -722,23 +722,6 @@ static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
   return pending;
 }
 
-static void cf_msh3_active(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
-  struct cf_msh3_ctx *ctx = cf->ctx;
-
-  /* use this socket from now on */
-  cf->conn->sock[cf->sockindex] = ctx->sock[SP_LOCAL];
-  /* the first socket info gets set at conn and data */
-  if(cf->sockindex == FIRSTSOCKET) {
-    cf->conn->remote_addr = &ctx->addr;
-  #ifdef ENABLE_IPV6
-    cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
-  #endif
-    Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
-  }
-  ctx->active = TRUE;
-}
-
 static CURLcode h3_data_pause(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               bool pause)
@@ -785,10 +768,6 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
       }
     }
     break;
-  case CF_CTRL_CONN_INFO_UPDATE:
-    CURL_TRC_CF(data, cf, "req: update info");
-    cf_msh3_active(cf, data);
-    break;
   default:
     break;
   }

+ 4 - 7
lib/vquic/curl_ngtcp2.c

@@ -1980,8 +1980,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
   if(result)
     return result;
 
-  Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd,
-                      &sockaddr, NULL, NULL, NULL, NULL);
+  Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
   if(!sockaddr)
     return CURLE_QUIC_CONNECT_ERROR;
   ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
@@ -2096,13 +2095,11 @@ out:
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   if(result) {
-    const char *r_ip = NULL;
-    int r_port = 0;
+    struct ip_quadruple ip;
 
-    Curl_cf_socket_peek(cf->next, data, NULL, NULL,
-                        &r_ip, &r_port, NULL, NULL);
+    Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
     infof(data, "QUIC connect to %s port %u failed: %s",
-          r_ip, r_port, curl_easy_strerror(result));
+          ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
   }
 #endif
   if(!result && ctx->qconn) {

+ 7 - 13
lib/vquic/curl_osslq.c

@@ -443,16 +443,14 @@ static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf,
   if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
     char extramsg[80]="";
     int sockerr = SOCKERRNO;
-    const char *r_ip = NULL;
-    int r_port = 0;
+    struct ip_quadruple ip;
 
-    Curl_cf_socket_peek(cf->next, data, NULL, NULL,
-                        &r_ip, &r_port, NULL, NULL);
+    Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
     if(sockerr && detail == SSL_ERROR_SYSCALL)
       Curl_strerror(sockerr, extramsg, sizeof(extramsg));
     failf(data, "QUIC connect: %s in connection to %s:%d (%s)",
           extramsg[0] ? extramsg : osslq_SSL_ERROR_to_str(detail),
-          ctx->peer.dispname, r_port, r_ip);
+          ctx->peer.dispname, ip.remote_port, ip.remote_ip);
   }
   else {
     /* Could be a CERT problem */
@@ -1039,7 +1037,6 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
   CURLcode result;
   int rv;
   const struct Curl_sockaddr_ex *peer_addr = NULL;
-  int peer_port;
   BIO *bio = NULL;
   BIO_ADDR *baddr = NULL;
 
@@ -1061,8 +1058,7 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
     goto out;
 
   result = CURLE_QUIC_CONNECT_ERROR;
-  Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd,
-                      &peer_addr, NULL, &peer_port, NULL, NULL);
+  Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &peer_addr, NULL);
   if(!peer_addr)
     goto out;
 
@@ -1657,13 +1653,11 @@ out:
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   if(result) {
-    const char *r_ip = NULL;
-    int r_port = 0;
+    struct ip_quadruple ip;
 
-    Curl_cf_socket_peek(cf->next, data, NULL, NULL,
-                        &r_ip, &r_port, NULL, NULL);
+    Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
     infof(data, "QUIC connect to %s port %u failed: %s",
-          r_ip, r_port, curl_easy_strerror(result));
+          ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
   }
 #endif
   if(!result)

+ 4 - 7
lib/vquic/curl_quiche.c

@@ -1243,8 +1243,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
   if(result)
     return result;
 
-  Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd,
-                      &sockaddr, NULL, NULL, NULL, NULL);
+  Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
   ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
   rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
                    &ctx->q.local_addrlen);
@@ -1390,13 +1389,11 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
 out:
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   if(result && result != CURLE_AGAIN) {
-    const char *r_ip;
-    int r_port;
+    struct ip_quadruple ip;
 
-    Curl_cf_socket_peek(cf->next, data, NULL, NULL,
-                        &r_ip, &r_port, NULL, NULL);
+    Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
     infof(data, "connect to %s port %u failed: %s",
-          r_ip, r_port, curl_easy_strerror(result));
+          ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
   }
 #endif
   return result;

+ 9 - 15
lib/vquic/vquic.c

@@ -370,12 +370,10 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
         goto out;
       }
       if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
-        const char *r_ip = NULL;
-        int r_port = 0;
-        Curl_cf_socket_peek(cf->next, data, NULL, NULL,
-                            &r_ip, &r_port, NULL, NULL);
+        struct ip_quadruple ip;
+        Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
         failf(data, "QUIC: connection to %s port %u refused",
-              r_ip, r_port);
+              ip.remote_ip, ip.remote_port);
         result = CURLE_COULDNT_CONNECT;
         goto out;
       }
@@ -440,12 +438,10 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
         goto out;
       }
       if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
-        const char *r_ip = NULL;
-        int r_port = 0;
-        Curl_cf_socket_peek(cf->next, data, NULL, NULL,
-                            &r_ip, &r_port, NULL, NULL);
+        struct ip_quadruple ip;
+        Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
         failf(data, "QUIC: connection to %s port %u refused",
-              r_ip, r_port);
+              ip.remote_ip, ip.remote_port);
         result = CURLE_COULDNT_CONNECT;
         goto out;
       }
@@ -500,12 +496,10 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf,
         goto out;
       }
       if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
-        const char *r_ip = NULL;
-        int r_port = 0;
-        Curl_cf_socket_peek(cf->next, data, NULL, NULL,
-                            &r_ip, &r_port, NULL, NULL);
+        struct ip_quadruple ip;
+        Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
         failf(data, "QUIC: connection to %s port %u refused",
-              r_ip, r_port);
+              ip.remote_ip, ip.remote_port);
         result = CURLE_COULDNT_CONNECT;
         goto out;
       }