diff options
-rw-r--r-- | CHANGES | 5 | ||||
-rw-r--r-- | RELEASE-NOTES | 7 | ||||
-rw-r--r-- | include/curl/curl.h | 20 | ||||
-rw-r--r-- | lib/connect.c | 37 | ||||
-rw-r--r-- | lib/url.c | 139 | ||||
-rw-r--r-- | lib/urldata.h | 3 |
6 files changed, 142 insertions, 69 deletions
@@ -7,6 +7,11 @@ Changelog Daniel S (3 October 2007) +- Alexey Pesternikov introduced CURLOPT_OPENSOCKETFUNCTION and + CURLOPT_OPENSOCKETDATA to set a callback that allows an application to + replace the socket() call used by libcurl. It basically allows the app to + change address, protocol or whatever of the socket. + - I renamed the CURLE_SSL_PEER_CERTIFICATE error code to CURLE_PEER_FAILED_VERIFICATION (standard CURL_NO_OLDIES style), and made this return code get used by the previous SSH MD5 fingerprint check in case diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 9c4e06381..93f8c6dc6 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -3,7 +3,7 @@ Curl and libcurl 7.17.1 Public curl release number: 102 Releases counted from the very beginning: 128 Available command line options: 121 - Available curl_easy_setopt() options: 145 + Available curl_easy_setopt() options: 147 Number of public functions in libcurl: 55 Amount of public web site mirrors: 42 Number of known libcurl bindings: 36 @@ -17,6 +17,8 @@ This release includes the following changes: o added --post301 and CURLOPT_POST301 o builds with c-ares 1.5.0 o added CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 and --hostpubmd5 + o renamed CURLE_SSL_PEER_CERTIFICATE to CURLE_PEER_FAILED_VERIFICATION + o added CURLOPT_OPENSOCKETFUNCTION and CURLOPT_OPENSOCKETDATA This release includes the following bugfixes: @@ -48,6 +50,7 @@ This release would not have looked like this without help, code, reports and advice from friends like these: Dan Fandrich, Michal Marek, Günter Knauf, Rob Crittenden, Immanuel Gregoire, - Mark Davies, Max Katsev, Philip Langdale, Alex Fishman, Johnny Luong + Mark Davies, Max Katsev, Philip Langdale, Alex Fishman, Johnny Luong, + Alexey Pesternikov, Yang Tse Thanks! (and sorry if I forgot to mention someone) diff --git a/include/curl/curl.h b/include/curl/curl.h index 52acc564a..37058254d 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -246,6 +246,19 @@ typedef int (*curl_sockopt_callback)(void *clientp, curl_socket_t curlfd, curlsocktype purpose); +struct Curl_sockaddr { + int family; + int socktype; + int protocol; + socklen_t addrlen; + struct sockaddr addr; +}; + +typedef curl_socket_t +(*curl_opensocket_callback)(void* clentp, + curlsocktype purpose, + struct Curl_sockaddr* address); + #ifndef CURL_NO_OLDIES /* not used since 7.10.8, will be removed in a future release */ typedef int (*curl_passwd_callback)(void *clientp, @@ -1135,6 +1148,13 @@ typedef enum { /* used by scp/sftp to verify the host's public key */ CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162), + /* Callback function for opening socket (instead of socket(2)). Optionally, + callback is able change the address or refuse to connect returning + CURL_SOCKET_BAD. The callback should have type + curl_opensocket_callback */ + CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163), + CINIT(OPENSOCKETDATA, OBJECTPOINT, 164), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/connect.c b/lib/connect.c index c8c82a1b7..b0615661f 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -677,14 +677,41 @@ singleipconnect(struct connectdata *conn, struct SessionHandle *data = conn->data; curl_socket_t sockfd; CURLcode res; - - sockfd = socket(ai->ai_family, conn->socktype, ai->ai_protocol); + /* + * Curl_sockaddr_storage, which is basically sockaddr_storage has a space + * for a largest possible struct sockaddr only. We should add some space for + * the other fields we are using. Hence the addr_storage size math. + */ + char addr_storage[sizeof(struct Curl_sockaddr)- + sizeof(struct sockaddr)+ + sizeof(struct Curl_sockaddr_storage)]; + struct Curl_sockaddr* addr=(struct Curl_sockaddr*)&addr_storage; + + addr->family=ai->ai_family; + addr->socktype=conn->socktype; + addr->protocol=ai->ai_protocol; + addr->addrlen=(ai->ai_addrlen<=sizeof(struct Curl_sockaddr_storage))? + ai->ai_addrlen:sizeof(struct Curl_sockaddr_storage); + memcpy(&addr->addr, ai->ai_addr, addr->addrlen); + + /* optionally use callback to get the socket */ + sockfd = (data->set.fopensocket)? + data->set.fopensocket(data->set.opensocket_client, CURLSOCKTYPE_IPCXN, + &addr): + socket(addr->family, addr->socktype, addr->protocol); if (sockfd == CURL_SOCKET_BAD) return CURL_SOCKET_BAD; *connected = FALSE; /* default is not connected */ - Curl_printable_address(ai, addr_buf, sizeof(addr_buf)); + /* FIXME: do we have Curl_printable_address-like with struct sockaddr* as + argument? */ + const void *iptoprint = &((const struct sockaddr_in*)(&addr->addr))->sin_addr; +#ifdef ENABLE_IPV6 + if(addr->family==AF_INET6) + iptoprint= &((const struct sockaddr_in6*)(&addr->addr))->sin6_addr; +#endif + Curl_inet_ntop(addr->family, iptoprint, addr_buf, sizeof(addr_buf)); infof(data, " Trying %s... ", addr_buf); if(data->set.tcp_nodelay) @@ -715,7 +742,7 @@ singleipconnect(struct connectdata *conn, /* Connect TCP sockets, bind UDP */ if(conn->socktype == SOCK_STREAM) - rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen); + rc = connect(sockfd, &addr->addr, addr->addrlen); else rc = 0; @@ -779,7 +806,7 @@ singleipconnect(struct connectdata *conn, */ CURLcode Curl_connecthost(struct connectdata *conn, /* context */ - const struct Curl_dns_entry *remotehost, /* use this one */ + const struct Curl_dns_entry *remotehost, curl_socket_t *sockconn, /* the connected socket */ Curl_addrinfo **addr, /* the one we used */ bool *connected) /* really connected? */ @@ -1813,6 +1813,21 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.sockopt_client = va_arg(param, void *); break; + case CURLOPT_OPENSOCKETFUNCTION: + /* + * open/create socket callback function: called instead of socket(), + * before connect() + */ + data->set.fopensocket = va_arg(param, curl_opensocket_callback); + break; + + case CURLOPT_OPENSOCKETDATA: + /* + * socket callback data pointer. Might be NULL. + */ + data->set.opensocket_client = va_arg(param, void *); + break; + case CURLOPT_SSL_SESSIONID_CACHE: data->set.ssl.sessionid = (bool)(0 != va_arg(param, long)); break; @@ -1838,7 +1853,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: /* - * Option to allow for the MD5 of the host public key to be checked + * Option to allow for the MD5 of the host public key to be checked * for validation purposes. */ result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], @@ -2449,20 +2464,20 @@ static CURLcode ConnectPlease(struct SessionHandle *data, switch(data->set.proxytype) { case CURLPROXY_SOCKS5: - result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, conn->host.name, - conn->remote_port, FIRSTSOCKET, conn); - break; + result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, conn->host.name, + conn->remote_port, FIRSTSOCKET, conn); + break; case CURLPROXY_HTTP: - /* do nothing here. handled later. */ - break; + /* do nothing here. handled later. */ + break; case CURLPROXY_SOCKS4: - result = Curl_SOCKS4(conn->proxyuser, conn->host.name, conn->remote_port, - FIRSTSOCKET, conn); - break; + result = Curl_SOCKS4(conn->proxyuser, conn->host.name, conn->remote_port, + FIRSTSOCKET, conn); + break; default: - failf(data, "unknown proxytype option given"); - result = CURLE_COULDNT_CONNECT; - break; + failf(data, "unknown proxytype option given"); + result = CURLE_COULDNT_CONNECT; + break; } } } @@ -2910,7 +2925,7 @@ static CURLcode setup_range(struct SessionHandle *data) * Setup connection internals specific to the requested protocol ***************************************************************/ static CURLcode setup_connection_internals(struct SessionHandle *data, - struct connectdata *conn) + struct connectdata *conn) { conn->socktype = SOCK_STREAM; /* most of them are TCP streams */ @@ -3237,17 +3252,17 @@ static char *detect_proxy(struct connectdata *conn) size_t namelen; char *endptr = strchr(conn->host.name, ':'); if(endptr) - namelen=endptr-conn->host.name; + namelen=endptr-conn->host.name; else - namelen=strlen(conn->host.name); + namelen=strlen(conn->host.name); if(strlen(nope) <= namelen) { - char *checkn= - conn->host.name + namelen - strlen(nope); - if(checkprefix(nope, checkn)) { - /* no proxy for this host! */ - break; - } + char *checkn= + conn->host.name + namelen - strlen(nope); + if(checkprefix(nope, checkn)) { + /* no proxy for this host! */ + break; + } } nope=strtok_r(NULL, ", ", &no_proxy_tok_buf); } @@ -3259,7 +3274,7 @@ static char *detect_proxy(struct connectdata *conn) /* Now, build <protocol>_proxy and check for such a one to use */ while(*protop) - *envp++ = (char)tolower((int)*protop++); + *envp++ = (char)tolower((int)*protop++); /* append _proxy */ strcpy(envp, "_proxy"); @@ -3280,29 +3295,29 @@ static char *detect_proxy(struct connectdata *conn) * arbitrarily redirected by any external attacker. */ if(!prox && !strequal("http_proxy", proxy_env)) { - /* There was no lowercase variable, try the uppercase version: */ - for(envp = proxy_env; *envp; envp++) - *envp = (char)toupper((int)*envp); - prox=curl_getenv(proxy_env); + /* There was no lowercase variable, try the uppercase version: */ + for(envp = proxy_env; *envp; envp++) + *envp = (char)toupper((int)*envp); + prox=curl_getenv(proxy_env); } if(prox && *prox) { /* don't count "" strings */ - proxy = prox; /* use this */ + proxy = prox; /* use this */ } else { - proxy = curl_getenv("all_proxy"); /* default proxy to use */ - if(!proxy) - proxy=curl_getenv("ALL_PROXY"); + proxy = curl_getenv("all_proxy"); /* default proxy to use */ + if(!proxy) + proxy=curl_getenv("ALL_PROXY"); } if(proxy && *proxy) { - long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING); + long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING); - if(conn->proxytype == CURLPROXY_HTTP) { - /* force this connection's protocol to become HTTP */ - conn->protocol = PROT_HTTP | bits; - conn->bits.httpproxy = TRUE; - } + if(conn->proxytype == CURLPROXY_HTTP) { + /* force this connection's protocol to become HTTP */ + conn->protocol = PROT_HTTP | bits; + conn->bits.httpproxy = TRUE; + } } } /* if (!nope) - it wasn't specified non-proxy */ } /* NO_PROXY wasn't specified or '*' */ @@ -3351,43 +3366,43 @@ static CURLcode parse_proxy(struct SessionHandle *data, proxypasswd[0] = 0; if(1 <= sscanf(proxyptr, - "%" MAX_CURL_USER_LENGTH_TXT"[^:]:" - "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", - proxyuser, proxypasswd)) { + "%" MAX_CURL_USER_LENGTH_TXT"[^:]:" + "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", + proxyuser, proxypasswd)) { CURLcode res = CURLE_OK; /* found user and password, rip them out. note that we are - unescaping them, as there is otherwise no way to have a - username or password with reserved characters like ':' in - them. */ + unescaping them, as there is otherwise no way to have a + username or password with reserved characters like ':' in + them. */ Curl_safefree(conn->proxyuser); conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); if(!conn->proxyuser) - res = CURLE_OUT_OF_MEMORY; + res = CURLE_OUT_OF_MEMORY; else { - Curl_safefree(conn->proxypasswd); - conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); + Curl_safefree(conn->proxypasswd); + conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); - if(!conn->proxypasswd) - res = CURLE_OUT_OF_MEMORY; + if(!conn->proxypasswd) + res = CURLE_OUT_OF_MEMORY; } if(CURLE_OK == res) { - conn->bits.proxy_user_passwd = TRUE; /* enable it */ - atsign = strdup(atsign+1); /* the right side of the @-letter */ - - if(atsign) { - free(proxy); /* free the former proxy string */ - proxy = proxyptr = atsign; /* now use this instead */ - } - else - res = CURLE_OUT_OF_MEMORY; + conn->bits.proxy_user_passwd = TRUE; /* enable it */ + atsign = strdup(atsign+1); /* the right side of the @-letter */ + + if(atsign) { + free(proxy); /* free the former proxy string */ + proxy = proxyptr = atsign; /* now use this instead */ + } + else + res = CURLE_OUT_OF_MEMORY; } if(res) { - free(proxy); /* free the allocated proxy string */ - return res; + free(proxy); /* free the allocated proxy string */ + return res; } } } @@ -3443,9 +3458,9 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, struct connectdata char proxypasswd[MAX_CURL_PASSWORD_LENGTH]=""; sscanf(data->set.str[STRING_PROXYUSERPWD], - "%" MAX_CURL_USER_LENGTH_TXT "[^:]:" - "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]", - proxyuser, proxypasswd); + "%" MAX_CURL_USER_LENGTH_TXT "[^:]:" + "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]", + proxyuser, proxypasswd); conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); if(!conn->proxyuser) @@ -3633,7 +3648,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, if(conn->bits.proxy_user_passwd) { result = parse_proxy_auth(data, conn); if (result != CURLE_OK) - return result; + return result; } /************************************************************* diff --git a/lib/urldata.h b/lib/urldata.h index 72bd0eb83..51844c4ba 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1328,6 +1328,9 @@ struct UserDefined { curl_ioctl_callback ioctl_func; /* function for I/O control */ curl_sockopt_callback fsockopt; /* function for setting socket options */ void *sockopt_client; /* pointer to pass to the socket options callback */ + curl_opensocket_callback fopensocket; /* function for checking/translating + the address and opening the socket */ + void* opensocket_client; /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */ /* function to convert from the network encoding: */ |