diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3 index 32f0ae9..f8c8ad2 100644 --- a/docs/libcurl/curl_easy_getinfo.3 +++ b/docs/libcurl/curl_easy_getinfo.3 @@ -173,6 +173,17 @@ string holding the IP address of the most recent connection done with this \fBcurl\fP handle. This string may be IPv6 if that's enabled. Note that you get a pointer to a memory area that will be re-used at next request so you need to copy the string if you want to keep the information. (Added in 7.19.0) +.IP CURLINFO_PRIMARY_PORT +Pass a pointer to a long to receive the destination port of the most recent +connection done with this \fBcurl\fP handle. (Added in 7.xx.x) +.IP CURLINFO_LOCAL_IP +Pass a pointer to a char pointer to receive the pointer to a zero-terminated +string holding the local (source) IP address of the most recent connection done +with this \fBcurl\fP handle. This string may be IPv6 if that's enabled. The +same restrictions apply as to \fICURLINFO_PRIMARY_IP\fP. (Added in 7.xx.x) +.IP CURLINFO_LOCAL_PORT +Pass a pointer to a long to receive the local (source) port of the most recent +connection done with this \fBcurl\fP handle. (Added in 7.xx.x) .IP CURLINFO_COOKIELIST Pass a pointer to a 'struct curl_slist *' to receive a linked-list of all cookies cURL knows (expired ones, too). Don't forget to diff --git a/include/curl/curl.h b/include/curl/curl.h index 83ba078..b19828f 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1883,9 +1883,12 @@ typedef enum { CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, + CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, + CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, + CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, /* Fill in new entries below here! */ - CURLINFO_LASTONE = 39 + CURLINFO_LASTONE = 42 } CURLINFO; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as diff --git a/lib/connect.c b/lib/connect.c index 4adc7f3..51e6066 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -523,6 +523,51 @@ static bool trynextip(struct connectdata *conn, return TRUE; } +/* retrieves ip address and port from a sockaddr structure */ +static void getaddressinfo(struct sockaddr* sa, char* addr, + long* port) +{ + struct sockaddr_in* si = NULL; +#ifdef ENABLE_IPV6 + struct sockaddr_in6* si6 = NULL; +#endif + + switch (sa->sa_family) { + case AF_INET: + si = (struct sockaddr_in*) sa; + Curl_inet_ntop(sa->sa_family, &(si->sin_addr), addr, MAX_IPADR_LEN); + *port = ntohs(si->sin_port); + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + si6 = (struct sockaddr_in6*)sa; + Curl_inet_ntop(sa->sa_family, &(si6->sin6_addr), addr, MAX_IPADR_LEN); + *port = ntohs(si6->sin6_port); + break; +#endif + default: + addr[0] = '\0'; + *port = 0; + } +} + +/* retrieves the start/end point information of a socket of an established + connection */ +void Curl_updateconninfo(curl_socket_t sockfd, struct PureInfo* info) +{ + struct Curl_sockaddr_storage ssrem; + struct Curl_sockaddr_storage ssloc; + + socklen_t len; + len = sizeof(struct Curl_sockaddr_storage); + + getpeername(sockfd, (struct sockaddr*) &ssrem, &len); + getsockname(sockfd, (struct sockaddr*) &ssloc, &len); + + getaddressinfo(&ssrem, info->ip, &(info->port)); + getaddressinfo(&ssloc, info->localIp, &(info->localPort)); +} + /* * Curl_is_connected() is used from the multi interface to check if the * firstsocket has connected. @@ -577,6 +622,8 @@ CURLcode Curl_is_connected(struct connectdata *conn, *connected = TRUE; Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ Curl_verboseconnect(conn); + Curl_updateconninfo(sockfd, &(data->info)); + return CURLE_OK; } /* nope, not connected for real */ @@ -693,6 +740,7 @@ void Curl_sndbufset(curl_socket_t sockfd) #endif + /* singleipconnect() connects to the given IP only, and it may return without having connected if used from the multi interface. */ static curl_socket_t @@ -866,6 +914,9 @@ singleipconnect(struct connectdata *conn, /* we are connected, awesome! */ *connected = TRUE; /* this is a true connect */ infof(data, "connected\n"); + + Curl_updateconninfo(sockfd, &(data->info)); + return sockfd; } else if(WAITCONN_TIMEOUT == rc) diff --git a/lib/connect.h b/lib/connect.h index 36ea4f6..49cc977 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -68,4 +68,6 @@ void Curl_sndbufset(curl_socket_t sockfd); #define Curl_sndbufset(y) #endif +void Curl_updateconninfo(curl_socket_t sockfd, struct PureInfo* info); + #endif diff --git a/lib/getinfo.c b/lib/getinfo.c index 7a0ed71..6e4bb23 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -66,6 +66,12 @@ CURLcode Curl_initinfo(struct SessionHandle *data) info->header_size = 0; info->request_size = 0; info->numconnects = 0; + + strcpy(info->ip, ""); + info->port=0; + strcpy(info->localIp, ""); + info->localPort=0; + return CURLE_OK; } @@ -224,6 +230,19 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) /* Return the ip address of the most recent (primary) connection */ *param_charp = data->info.ip; break; + /* Return the (remote) port of the most recent (primary) connection */ + case CURLINFO_PRIMARY_PORT: + *param_longp = data->info.port; + break; + /* Return the source/local ip address of the most recent (primary) + connection */ + case CURLINFO_LOCAL_IP: + *param_charp = data->info.localIp; + break; + /* Return the local port of the most recent (primary) connection */ + case CURLINFO_LOCAL_PORT: + *param_longp = data->info.localPort; + break; case CURLINFO_CERTINFO: /* Return the a pointer to the certinfo struct. Not really an slist pointer but we can pretend it is here */ diff --git a/lib/url.c b/lib/url.c index 4d1632b..1bf7df2 100644 --- a/lib/url.c +++ b/lib/url.c @@ -5030,6 +5030,7 @@ static CURLcode setup_conn(struct connectdata *conn, conn->bits.tcpconnect = TRUE; *protocol_done = TRUE; Curl_verboseconnect(conn); + Curl_updateconninfo(conn->sock[FIRSTSOCKET], &(data->info)); } /* Stop the loop now */ break; diff --git a/lib/urldata.h b/lib/urldata.h index 9db0640..8325453 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -911,6 +911,12 @@ struct PureInfo { char ip[MAX_IPADR_LEN]; /* this buffer gets the numerical ip version stored at the connect *attempt* so it will get the last tried connect IP even on failures */ + long port; /* the remote port the last connection was established to */ + char localIp[MAX_IPADR_LEN]; /* this buffer gets the numerical (local) ip + stored from where the last connection was + established */ + long localPort; /* the local (src) port the last connection + originated from */ struct curl_certinfo certs; /* info about the certs, only populated in OpenSSL builds. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */