gopher: Implement secure gopher protocol.

This commit introduces a "gophers" handler inside the gopher protocol if
USE_SSL is defined. This protocol is no different than the usual gopher
prococol, with the added TLS encapsulation upon connecting. The protocol
has been adopted in the gopher community, and many people have enabled
TLS in their gopher daemons like geomyidae(8), and clients, like clic(1)
and hurl(1).

I have not implemented test units for this protocol because my knowledge
of Perl is sub-par. However, for someone more knowledgeable it might be
fairly trivial, because the same test that tests the plain gopher
protocol can be used for "gophers" just by adding a TLS listener.

Signed-off-by: parazyd <parazyd@dyne.org>

Closes #6208
This commit is contained in:
parazyd 2020-11-15 18:46:06 +01:00 committed by Daniel Stenberg
parent be8c94da78
commit a1f06f32b8
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
5 changed files with 62 additions and 0 deletions

View File

@ -5111,6 +5111,9 @@ if test "x$CURL_DISABLE_TFTP" != "x1"; then
fi
if test "x$CURL_DISABLE_GOPHER" != "x1"; then
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS GOPHER"
if test "x$SSL_ENABLED" = "x1"; then
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS GOPHERS"
fi
fi
if test "x$CURL_DISABLE_MQTT" != "x1"; then
SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS MQTT"

View File

@ -33,6 +33,7 @@
#include "gopher.h"
#include "select.h"
#include "strdup.h"
#include "vtls/vtls.h"
#include "url.h"
#include "escape.h"
#include "warnless.h"
@ -46,6 +47,10 @@
*/
static CURLcode gopher_do(struct connectdata *conn, bool *done);
#ifdef USE_SSL
static CURLcode gopher_connect(struct connectdata *conn, bool *done);
static CURLcode gopher_connecting(struct connectdata *conn, bool *done);
#endif
/*
* Gopher protocol handler.
@ -75,6 +80,46 @@ const struct Curl_handler Curl_handler_gopher = {
PROTOPT_NONE /* flags */
};
#ifdef USE_SSL
const struct Curl_handler Curl_handler_gophers = {
"GOPHERS", /* scheme */
ZERO_NULL, /* setup_connection */
gopher_do, /* do_it */
ZERO_NULL, /* done */
ZERO_NULL, /* do_more */
gopher_connect, /* connect_it */
gopher_connecting, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
PORT_GOPHER, /* defport */
CURLPROTO_GOPHER, /* protocol */
CURLPROTO_GOPHER, /* family */
PROTOPT_SSL /* flags */
};
static CURLcode gopher_connect(struct connectdata *conn, bool *done)
{
(void)conn;
(void)done;
return CURLE_OK;
}
static CURLcode gopher_connecting(struct connectdata *conn, bool *done)
{
CURLcode result = Curl_ssl_connect(conn, FIRSTSOCKET);
if(result)
connclose(conn, "Failed TLS connection");
*done = TRUE;
return result;
}
#endif
static CURLcode gopher_do(struct connectdata *conn, bool *done)
{
CURLcode result = CURLE_OK;
@ -127,6 +172,11 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
k = curlx_uztosz(len);
for(;;) {
/* Break out of the loop if the selector is empty because OpenSSL and/or
LibreSSL fail with errno 0 if this is the case. */
if(strlen(sel) < 1)
break;
result = Curl_write(conn, sockfd, sel, k, &amount);
if(!result) { /* Which may not have written it all! */
result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount);

View File

@ -24,6 +24,9 @@
#ifndef CURL_DISABLE_GOPHER
extern const struct Curl_handler Curl_handler_gopher;
#ifdef USE_SSL
extern const struct Curl_handler Curl_handler_gophers;
#endif
#endif
#endif /* HEADER_CURL_GOPHER_H */

View File

@ -251,6 +251,9 @@ static const struct Curl_handler * const protocols[] = {
#ifndef CURL_DISABLE_GOPHER
&Curl_handler_gopher,
#ifdef USE_SSL
&Curl_handler_gophers,
#endif
#endif
#ifdef USE_LIBRTMP

View File

@ -274,6 +274,9 @@ static const char * const protocols[] = {
#ifndef CURL_DISABLE_GOPHER
"gopher",
#endif
#if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER)
"gophers",
#endif
#ifndef CURL_DISABLE_HTTP
"http",
#endif