mirror of
https://github.com/unrealircd/unrealircd.git
synced 2026-07-06 04:33:13 +02:00
Added support for the "Server Name Indication" (SNI) SSL/TLS extension.
See https://www.unrealircd.org/docs/Sni_block Requested in #4380 by Eman.
This commit is contained in:
@@ -107,6 +107,7 @@ extern ConfigItem_deny_dcc *Find_deny_dcc(char *name);
|
||||
extern ConfigItem_oper *Find_oper(char *name);
|
||||
extern ConfigItem_operclass *Find_operclass(char *name);
|
||||
extern ConfigItem_listen *Find_listen(char *ipmask, int port, int ipv6);
|
||||
extern ConfigItem_sni *Find_sni(char *name);
|
||||
extern ConfigItem_ulines *Find_uline(char *host);
|
||||
extern ConfigItem_except *Find_except(aClient *, short type);
|
||||
extern ConfigItem_tld *Find_tld(aClient *cptr);
|
||||
|
||||
@@ -97,6 +97,7 @@ typedef struct _configitem_drpass ConfigItem_drpass;
|
||||
typedef struct _configitem_ulines ConfigItem_ulines;
|
||||
typedef struct _configitem_tld ConfigItem_tld;
|
||||
typedef struct _configitem_listen ConfigItem_listen;
|
||||
typedef struct _configitem_sni ConfigItem_sni;
|
||||
typedef struct _configitem_allow ConfigItem_allow;
|
||||
typedef struct _configflag_allow ConfigFlag_allow;
|
||||
typedef struct _configitem_allow_channel ConfigItem_allow_channel;
|
||||
@@ -1159,6 +1160,14 @@ struct _configitem_listen {
|
||||
SSLOptions *ssl_options;
|
||||
};
|
||||
|
||||
struct _configitem_sni {
|
||||
ConfigItem_sni *prev, *next;
|
||||
ConfigFlag flag;
|
||||
char *name;
|
||||
SSL_CTX *ssl_ctx;
|
||||
SSLOptions *ssl_options;
|
||||
};
|
||||
|
||||
struct _configitem_vhost {
|
||||
ConfigItem *prev, *next;
|
||||
ConfigFlag flag;
|
||||
@@ -1339,6 +1348,7 @@ struct _configitem_offchans {
|
||||
char *topic;
|
||||
};
|
||||
|
||||
|
||||
#define HM_HOST 1
|
||||
#define HM_IPV4 2
|
||||
#define HM_IPV6 3
|
||||
|
||||
@@ -100,6 +100,7 @@ static int _conf_alias (ConfigFile *conf, ConfigEntry *ce);
|
||||
static int _conf_help (ConfigFile *conf, ConfigEntry *ce);
|
||||
static int _conf_offchans (ConfigFile *conf, ConfigEntry *ce);
|
||||
static int _conf_spamfilter (ConfigFile *conf, ConfigEntry *ce);
|
||||
static int _conf_sni (ConfigFile *conf, ConfigEntry *ce);
|
||||
|
||||
/*
|
||||
* Validation commands
|
||||
@@ -131,6 +132,7 @@ static int _test_alias (ConfigFile *conf, ConfigEntry *ce);
|
||||
static int _test_help (ConfigFile *conf, ConfigEntry *ce);
|
||||
static int _test_offchans (ConfigFile *conf, ConfigEntry *ce);
|
||||
static int _test_spamfilter (ConfigFile *conf, ConfigEntry *ce);
|
||||
static int _test_sni (ConfigFile *conf, ConfigEntry *ce);
|
||||
|
||||
/* This MUST be alphabetized */
|
||||
static ConfigCommand _ConfigCommands[] = {
|
||||
@@ -154,6 +156,7 @@ static ConfigCommand _ConfigCommands[] = {
|
||||
{ "oper", _conf_oper, _test_oper },
|
||||
{ "operclass", _conf_operclass, _test_operclass },
|
||||
{ "set", _conf_set, _test_set },
|
||||
{ "sni", _conf_sni, _test_sni },
|
||||
{ "spamfilter", _conf_spamfilter, _test_spamfilter },
|
||||
{ "tld", _conf_tld, _test_tld },
|
||||
{ "ulines", _conf_ulines, _test_ulines },
|
||||
@@ -288,6 +291,7 @@ ConfigItem_tld *conf_tld = NULL;
|
||||
ConfigItem_oper *conf_oper = NULL;
|
||||
ConfigItem_operclass *conf_operclass = NULL;
|
||||
ConfigItem_listen *conf_listen = NULL;
|
||||
ConfigItem_sni *conf_sni = NULL;
|
||||
ConfigItem_allow *conf_allow = NULL;
|
||||
ConfigItem_except *conf_except = NULL;
|
||||
ConfigItem_vhost *conf_vhost = NULL;
|
||||
@@ -1920,6 +1924,7 @@ void config_rehash()
|
||||
ConfigItem_alias *alias_ptr;
|
||||
ConfigItem_help *help_ptr;
|
||||
ConfigItem_offchans *of_ptr;
|
||||
ConfigItem_sni *sni;
|
||||
OperStat *os_ptr;
|
||||
ListStruct *next, *next2;
|
||||
aTKline *tk, *tk_next;
|
||||
@@ -2214,6 +2219,17 @@ void config_rehash()
|
||||
}
|
||||
conf_offchans = NULL;
|
||||
|
||||
/* Free sni { } blocks */
|
||||
for (sni = conf_sni; sni; sni = (ConfigItem_sni *)next)
|
||||
{
|
||||
next = (ListStruct *)sni->next;
|
||||
SSL_CTX_free(sni->ssl_ctx);
|
||||
free_ssl_options(sni->ssl_options);
|
||||
safefree(sni->name);
|
||||
MyFree(sni);
|
||||
}
|
||||
conf_sni = NULL;
|
||||
|
||||
for (i = 0; i < EXTCMODETABLESZ; i++)
|
||||
{
|
||||
if (iConf.modes_on_join.extparams[i])
|
||||
@@ -2607,6 +2623,24 @@ ConfigItem_listen *Find_listen(char *ipmask, int port, int ipv6)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Find a SNI match.
|
||||
* @param name The hostname to look for (eg: irc.xyz.com).
|
||||
*/
|
||||
ConfigItem_sni *Find_sni(char *name)
|
||||
{
|
||||
ConfigItem_sni *e;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
for (e = conf_sni; e; e = e->next)
|
||||
{
|
||||
if (!match(name, e->name))
|
||||
return e;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ConfigItem_ulines *Find_uline(char *host) {
|
||||
ConfigItem_ulines *ulines;
|
||||
|
||||
@@ -6208,6 +6242,68 @@ int _test_spamfilter(ConfigFile *conf, ConfigEntry *ce)
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
||||
int _test_sni(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
int errors = 0;
|
||||
ConfigEntry *cep, *sslconfig = NULL;
|
||||
|
||||
if (!ce->ce_vardata)
|
||||
{
|
||||
config_error("%s:%i: sni block needs a name, eg: sni irc.xyz.com {",
|
||||
ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
|
||||
errors++;
|
||||
}
|
||||
|
||||
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
||||
{
|
||||
if (!strcmp(cep->ce_varname, "ssl-options"))
|
||||
{
|
||||
test_sslblock(conf, cep, &errors);
|
||||
} else
|
||||
{
|
||||
config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
|
||||
"sni", cep->ce_varname);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
int _conf_sni(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
ConfigEntry *cep;
|
||||
ConfigEntry *sslconfig = NULL;
|
||||
char *name;
|
||||
ConfigItem_sni *sni = NULL;
|
||||
|
||||
name = ce->ce_vardata;
|
||||
if (!name)
|
||||
return 0;
|
||||
|
||||
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
|
||||
{
|
||||
if (!strcmp(cep->ce_varname, "ssl-options"))
|
||||
{
|
||||
sslconfig = cep;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sslconfig)
|
||||
return 0;
|
||||
|
||||
sni = MyMallocEx(sizeof(ConfigItem_listen));
|
||||
sni->name = strdup(name);
|
||||
sni->ssl_options = MyMallocEx(sizeof(SSLOptions));
|
||||
conf_sslblock(conf, sslconfig, sni->ssl_options);
|
||||
sni->ssl_ctx = init_ctx(sni->ssl_options, 1);
|
||||
AddListItem(sni, conf_sni);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int _conf_help(ConfigFile *conf, ConfigEntry *ce)
|
||||
{
|
||||
ConfigEntry *cep;
|
||||
|
||||
@@ -188,6 +188,19 @@ static int ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ssl_hostname_callback(SSL *ssl, int *unk, void *arg)
|
||||
{
|
||||
char *name = (char *)SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
|
||||
ConfigItem_sni *sni;
|
||||
|
||||
if (name && (sni = Find_sni(name)))
|
||||
{
|
||||
SSL_set_SSL_CTX(ssl, sni->ssl_ctx);
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
static void mylog(char *fmt, ...)
|
||||
{
|
||||
va_list vl;
|
||||
@@ -353,6 +366,11 @@ SSL_CTX *init_ctx(SSLOptions *ssloptions, int server)
|
||||
SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE|SSL_OP_SINGLE_DH_USE);
|
||||
}
|
||||
|
||||
if (server)
|
||||
{
|
||||
SSL_CTX_set_tlsext_servername_callback(ctx, ssl_hostname_callback);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
fail:
|
||||
SSL_CTX_free(ctx);
|
||||
|
||||
Reference in New Issue
Block a user