diff --git a/NEWS b/NEWS index ab23f73d..7af8673f 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,8 @@ includes the changes listed under "ELinks 0.11.4.GIT now" below. JS_CallFunction, which can crash if given a closure. * critical bug 1031: Use the same JSRuntime for both user SMJS and scripts on web pages, to work around SpiderMonkey bug 378918. +* bug 1040: Blacklist servers that don't support TLS. This reduces + SSL errors especially in HTTP POST requests using GnuTLS. * minor bug 951: SpiderMonkey scripting objects used to prevent ELinks from removing files from the memory cache diff --git a/src/network/socket.c b/src/network/socket.c index 701df867..aac3bf14 100644 --- a/src/network/socket.c +++ b/src/network/socket.c @@ -49,6 +49,7 @@ #include "network/ssl/socket.h" #include "osdep/osdep.h" #include "osdep/getifaddrs.h" +#include "protocol/http/blacklist.h" #include "protocol/protocol.h" #include "protocol/uri.h" #include "util/error.h" @@ -65,6 +66,7 @@ struct connect_info { void *dnsquery; /* Pointer to DNS query info. */ int port; /* Which port to bind to. */ int ip_family; /* If non-zero, force to IP version. */ + struct uri *uri; /* For updating the blacklist. */ }; @@ -104,6 +106,7 @@ init_connection_info(struct uri *uri, struct socket *socket, connect_info->ip_family = uri->ip_family; connect_info->triedno = -1; connect_info->addr = NULL; + connect_info->uri = get_uri_reference(uri); return connect_info; } @@ -118,6 +121,7 @@ done_connection_info(struct socket *socket) if (connect_info->dnsquery) kill_dns_request(&connect_info->dnsquery); mem_free_if(connect_info->addr); + done_uri(connect_info->uri); mem_free_set(&socket->connect_info, NULL); } @@ -258,6 +262,11 @@ make_connection(struct socket *socket, struct uri *uri, /* XXX: Keep here and not in init_connection_info() to make * complete_connect_socket() work from the HTTP implementation. */ socket->need_ssl = get_protocol_need_ssl(uri->protocol); + if (!socket->set_no_tls) { + enum blacklist_flags flags = get_blacklist_flags(uri); + socket->no_tls = ((flags & SERVER_BLACKLIST_NO_TLS) != 0); + socket->set_no_tls = 1; + } debug_transfer_log("\nCONNECTION: ", -1); debug_transfer_log(host, -1); @@ -425,6 +434,20 @@ complete_connect_socket(struct socket *socket, struct uri *uri, { struct connect_info *connect_info = socket->connect_info; + if (connect_info && connect_info->uri) { + /* Remember whether the server supported TLS or not. + * Then the next request can immediately use the right + * protocol. This is important for HTTP POST requests + * because it is not safe to silently retry them. The + * uri parameter is normally NULL here so don't use it. */ + if (socket->no_tls) + add_blacklist_entry(connect_info->uri, + SERVER_BLACKLIST_NO_TLS); + else + del_blacklist_entry(connect_info->uri, + SERVER_BLACKLIST_NO_TLS); + } + /* This is a special case used by the HTTP implementation to acquire an * SSL link for handling CONNECT requests. */ if (!connect_info) { diff --git a/src/network/socket.h b/src/network/socket.h index 411376f7..fc598ff1 100644 --- a/src/network/socket.h +++ b/src/network/socket.h @@ -97,6 +97,7 @@ struct socket { unsigned int protocol_family:1; /* EL_PF_INET, EL_PF_INET6 */ unsigned int need_ssl:1; /* If the socket needs SSL support */ unsigned int no_tls:1; /* Internal SSL flag. */ + unsigned int set_no_tls:1; /* Was the blacklist checked yet? */ unsigned int duplex:1; /* Allow simultaneous reads & writes. */ }; diff --git a/src/network/ssl/socket.c b/src/network/ssl/socket.c index eabd8a3f..5e6eb4d8 100644 --- a/src/network/ssl/socket.c +++ b/src/network/ssl/socket.c @@ -107,7 +107,7 @@ ssl_want_read(struct socket *socket) break; default: - socket->no_tls = 1; + socket->no_tls = !socket->no_tls; socket->ops->retry(socket, S_SSL_ERROR); } } @@ -189,7 +189,7 @@ ssl_connect(struct socket *socket) default: if (ret != SSL_ERROR_NONE) { /* DBG("sslerr %s", gnutls_strerror(ret)); */ - socket->no_tls = 1; + socket->no_tls = !socket->no_tls; } connect_socket(socket, S_SSL_ERROR); diff --git a/src/protocol/http/blacklist.h b/src/protocol/http/blacklist.h index 3b9246e3..28465cfa 100644 --- a/src/protocol/http/blacklist.h +++ b/src/protocol/http/blacklist.h @@ -8,6 +8,7 @@ enum blacklist_flags { SERVER_BLACKLIST_NONE = 0, SERVER_BLACKLIST_HTTP10 = 1, SERVER_BLACKLIST_NO_CHARSET = 2, + SERVER_BLACKLIST_NO_TLS = 4, }; void add_blacklist_entry(struct uri *, enum blacklist_flags);