aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--RELEASE-NOTES7
-rw-r--r--include/curl/curl.h20
-rw-r--r--lib/connect.c37
-rw-r--r--lib/url.c139
-rw-r--r--lib/urldata.h3
6 files changed, 142 insertions, 69 deletions
diff --git a/CHANGES b/CHANGES
index 67c69c28d..803bf0f85 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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? */
diff --git a/lib/url.c b/lib/url.c
index c91d062fe..0571fd651 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -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: */