Reconnect if the sts cap is encountered.
This commit is contained in:
parent
ade78e84f1
commit
9487bda9a0
@ -546,6 +546,8 @@ typedef struct server
|
||||
|
||||
GSList *favlist; /* list of channels & keys to join */
|
||||
|
||||
struct sts_profile *stsprofile; /* pending sts profile that caused a reconnect */
|
||||
|
||||
unsigned int motd_skipped:1;
|
||||
unsigned int connected:1;
|
||||
unsigned int connecting:1;
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "ctcp.h"
|
||||
#include "hexchatc.h"
|
||||
#include "chanopt.h"
|
||||
#include "sts.h"
|
||||
|
||||
|
||||
void
|
||||
@ -1728,6 +1729,7 @@ static const char * const supported_caps[] = {
|
||||
"setname",
|
||||
"invite-notify",
|
||||
"account-tag",
|
||||
/* "sts", Handled manually */
|
||||
|
||||
/* ZNC */
|
||||
"znc.in/server-time-iso",
|
||||
@ -1778,7 +1780,9 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
|
||||
char buffer[500]; /* buffer for requesting capabilities and emitting the signal */
|
||||
gboolean want_cap = FALSE; /* format the CAP REQ string based on previous capabilities being requested or not */
|
||||
char **extensions;
|
||||
int i;
|
||||
int i, stsvalue;
|
||||
GHashTable *stscap;
|
||||
const char *stsvaluestr;
|
||||
|
||||
if (g_str_has_prefix (extensions_str, "* "))
|
||||
{
|
||||
@ -1811,6 +1815,57 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
|
||||
value++;
|
||||
}
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
/** If the server has a STS profile then we should respect it. */
|
||||
if (!g_strcmp0 (extension, "sts"))
|
||||
{
|
||||
stscap = sts_parse_cap (value);
|
||||
if (serv->use_ssl)
|
||||
{
|
||||
/* Retrieve the duration; if its valid then store/update it. */
|
||||
stsvaluestr = (const char*) g_hash_table_lookup (stscap, "duration");
|
||||
if (stsvaluestr)
|
||||
{
|
||||
stsvalue = atoi (stsvaluestr);
|
||||
if (stsvalue > 0)
|
||||
sts_update_expiry(serv->hostname, stsvalue, serv->stsprofile);
|
||||
}
|
||||
} else
|
||||
{
|
||||
stsvaluestr = (const char*) g_hash_table_lookup (stscap, "port");
|
||||
if (stsvaluestr)
|
||||
{
|
||||
stsvalue = atoi (stsvaluestr);
|
||||
if (stsvalue > 0 && stsvalue < 65536)
|
||||
{
|
||||
/* We are connecting on plain text and have found a valid STS profile. */
|
||||
serv->stsprofile = sts_new ();
|
||||
strcpy (serv->stsprofile->host, serv->hostname);
|
||||
serv->stsprofile->port = stsvalue;
|
||||
|
||||
/* Reconfigure with the new port and security settings. */
|
||||
serv->port = serv->stsprofile->port;
|
||||
serv->accept_invalid_cert = FALSE;
|
||||
serv->use_ssl = TRUE;
|
||||
|
||||
/* We're reconnecting so don't request caps. */
|
||||
want_cap = FALSE;
|
||||
|
||||
/* Reconnect to the server. */
|
||||
EMIT_SIGNAL (XP_TE_STSREDIRNEW, serv->server_session, serv->hostname, NULL, NULL, NULL, 0);
|
||||
stsvalue = prefs.hex_net_reconnect_delay;
|
||||
prefs.hex_net_reconnect_delay = 0;
|
||||
serv->auto_reconnect (serv, TRUE, -1);
|
||||
prefs.hex_net_reconnect_delay = stsvalue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_destroy (stscap);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if the SASL password is set AND auth mode is set to SASL, request SASL auth */
|
||||
if (!g_strcmp0 (extension, "sasl") &&
|
||||
((serv->loginmethod == LOGIN_SASL && strlen (serv->password) != 0)
|
||||
@ -1842,6 +1897,28 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
|
||||
|
||||
g_strfreev (extensions);
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
/* Check up on the status of the STS profile. */
|
||||
if (!serv->waiting_on_cap && serv->ctx && serv->stsprofile)
|
||||
{
|
||||
|
||||
/* We have reconnected using SSL; is the profile complete? */
|
||||
if (serv->stsprofile->expiry)
|
||||
{
|
||||
/* The profile is fine; store it. */
|
||||
sts_store (serv->stsprofile);
|
||||
serv->stsprofile = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The profile redirected us to a broken server. We MUST block connection as per spec. */
|
||||
EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, "STS profile mismatch", NULL, NULL, NULL, 0);
|
||||
serv->disconnect (serv, TRUE, -1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (want_cap)
|
||||
{
|
||||
/* buffer + 9 = emit buffer without "CAP REQ :" */
|
||||
|
@ -3469,6 +3469,10 @@ cmd_server (struct session *sess, char *tbuf, char *word[], char *word_eol[])
|
||||
use_ssl_noverify = TRUE;
|
||||
offset++; /* args move up by 1 word */
|
||||
}
|
||||
|
||||
/** If the server was previously used by a failed STS connection then free the incomplete profile. */
|
||||
if (serv->stsprofile)
|
||||
g_clear_pointer (&serv->stsprofile, g_free);
|
||||
#endif
|
||||
|
||||
if (!parse_irc_url (word[2 + offset], &server_name, &port, &channel, &key, &use_ssl))
|
||||
|
@ -1757,6 +1757,7 @@ server_new (void)
|
||||
|
||||
serv->id = id++;
|
||||
serv->sok = -1;
|
||||
serv->stsprofile = NULL;
|
||||
strcpy (serv->nick, prefs.hex_irc_nick1);
|
||||
server_set_defaults (serv);
|
||||
|
||||
@ -1943,6 +1944,7 @@ server_free (server *serv)
|
||||
g_free (serv->bad_nick_prefixes);
|
||||
g_free (serv->last_away_reason);
|
||||
g_free (serv->encoding);
|
||||
g_free (serv->stsprofile);
|
||||
|
||||
g_iconv_close (serv->read_converter);
|
||||
g_iconv_close (serv->write_converter);
|
||||
|
@ -32,7 +32,7 @@ struct sts_profile *
|
||||
sts_find (const char* host)
|
||||
{
|
||||
time_t now;
|
||||
GList *next;
|
||||
GSList *next;
|
||||
struct sts_profile *nextprofile;
|
||||
|
||||
now = time (NULL);
|
||||
@ -71,7 +71,7 @@ sts_load (void)
|
||||
continue;
|
||||
}
|
||||
|
||||
profiles = g_slist_append (profiles, profile);
|
||||
sts_store (profile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,6 +87,26 @@ sts_new (void)
|
||||
return profile;
|
||||
}
|
||||
|
||||
GHashTable *
|
||||
sts_parse_cap (const char* cap)
|
||||
{
|
||||
char **entries, **currentry;
|
||||
char *value;
|
||||
GHashTable *table;
|
||||
|
||||
table = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
entries = g_strsplit (cap, ",", 0);
|
||||
for (currentry = entries; *currentry; ++currentry)
|
||||
{
|
||||
value = strchr (*currentry, '=');
|
||||
if (value)
|
||||
g_hash_table_insert (table, g_strndup (*currentry, value - *currentry), g_strdup (value + 1));
|
||||
}
|
||||
|
||||
g_free (entries);
|
||||
return table;
|
||||
}
|
||||
|
||||
void
|
||||
sts_save (void)
|
||||
{
|
||||
@ -101,7 +121,7 @@ sts_save (void)
|
||||
return; /* Filesystem not writable. */
|
||||
|
||||
now = time (NULL);
|
||||
for (next = profiles; next; next = profiles->next)
|
||||
for (next = profiles; next; next = next->next)
|
||||
{
|
||||
nextprofile = (struct sts_profile *)next->data;
|
||||
if (now >= nextprofile->expiry)
|
||||
@ -114,3 +134,18 @@ sts_save (void)
|
||||
|
||||
close (fh);
|
||||
}
|
||||
|
||||
void
|
||||
sts_store (struct sts_profile *profile)
|
||||
{
|
||||
profiles = g_slist_append (profiles, profile);
|
||||
}
|
||||
|
||||
void sts_update_expiry (const char *host, time_t newexpiry, struct sts_profile *incomplete_profile)
|
||||
{
|
||||
struct sts_profile *profile;
|
||||
|
||||
profile = incomplete_profile ? incomplete_profile : sts_find (host);
|
||||
if (profile)
|
||||
profile->expiry = time (NULL) + newexpiry;
|
||||
}
|
||||
|
@ -50,7 +50,16 @@ void sts_load (void);
|
||||
/* Creates a new empty STS profile. */
|
||||
struct sts_profile * sts_new (void);
|
||||
|
||||
/** Parses the key/value pairs from a STS cap into a hash table */
|
||||
GHashTable *sts_parse_cap (const char* cap);
|
||||
|
||||
/* Saves STS profiles to sts.conf */
|
||||
void sts_save (void);
|
||||
|
||||
/* Stores a new STS profile in the hash table */
|
||||
void sts_store (struct sts_profile *profile);
|
||||
|
||||
/* Updates the expiry time for a STS profile. */
|
||||
void sts_update_expiry (const char *host, time_t newexpiry, struct sts_profile *incomplete_profile);
|
||||
|
||||
#endif
|
||||
|
@ -790,6 +790,12 @@ pevt_stsredir_help
|
||||
%C29*%O$tUsing the previously saved STS profile for %C29$1%O
|
||||
n2
|
||||
|
||||
NEW STS Redirection
|
||||
XP_TE_STSREDIRNEW
|
||||
pevt_stsredir_help
|
||||
%C29*%O$tReconnecting using the new STS profile for %C29$1%O
|
||||
1
|
||||
|
||||
Stop Connection
|
||||
XP_TE_STOPCONNECT
|
||||
pevt_sconnect_help
|
||||
|
Loading…
Reference in New Issue
Block a user