JSON-RPC: add server.connect API call

(directly connected server only at the moment)
This also cleans up the linking procedure (now) at 3 places,
to use find_link() and check_deny_link() everywhere.
This commit is contained in:
Bram Matthys 2023-01-11 16:54:22 +01:00
parent 0578346b12
commit d6833ae298
No known key found for this signature in database
GPG key ID: BF8116B163EAAE98
5 changed files with 111 additions and 30 deletions

View file

@ -149,6 +149,7 @@ extern ConfigItem_sni *find_sni(const char *name);
extern ConfigItem_ulines *find_uline(const char *host);
extern ConfigItem_tld *find_tld(Client *cptr);
extern ConfigItem_link *find_link(const char *servername);
extern ConfigItem_deny_link *check_deny_link(ConfigItem_link *link, int auto_connect);
extern ConfigItem_ban *find_ban(Client *, const char *host, short type);
extern ConfigItem_ban *find_banEx(Client *,const char *host, short type, short type2);
extern ConfigItem_vhost *find_vhost(const char *name);

View file

@ -3082,6 +3082,30 @@ ConfigItem_link *find_link(const char *servername)
return NULL;
}
/** Check if this link should be denied due to deny link { } configuration
* @param link The link block
* @param auto_connect Set this to 1 if this is called from auto connect code
* (it will then check both CRULE_AUTO + CRULE_ALL)
* set it to 0 otherwise (will not check CRULE_AUTO blocks).
* @returns The deny block if the server should be denied, or NULL if no deny block.
*/
ConfigItem_deny_link *check_deny_link(ConfigItem_link *link, int auto_connect)
{
ConfigItem_deny_link *d;
for (d = conf_deny_link; d; d = d->next)
{
if ((auto_connect == 0) && (d->flag.type == CRULE_AUTO))
continue;
if (unreal_mask_match_string(link->servername, d->mask) &&
crule_eval(d->rule))
{
return d;
}
}
return NULL;
}
/** Find a ban of type CONF_BAN_*, which is currently only
* CONF_BAN_SERVER, CONF_BAN_VERSION and CONF_BAN_REALNAME
*/

View file

@ -92,12 +92,7 @@ CMD_FUNC(cmd_connect)
return;
}
for (aconf = conf_link; aconf; aconf = aconf->next)
if (match_simple(parv[1], aconf->servername))
break;
/* Checked first servernames, then try hostnames. */
aconf = find_link(parv[1]);
if (!aconf)
{
sendnotice(client,
@ -114,15 +109,11 @@ CMD_FUNC(cmd_connect)
return;
}
/* Evaluate deny link */
for (deny = conf_deny_link; deny; deny = deny->next)
deny = check_deny_link(aconf, 0);
if (deny)
{
if (deny->flag.type == CRULE_ALL && unreal_mask_match_string(aconf->servername, deny->mask)
&& crule_eval(deny->rule))
{
sendnotice(client, "*** Connect: Disallowed by connection rule");
return;
}
sendnotice(client, "*** Connect: Disallowed by connection rule");
return;
}
unreal_log(ULOG_INFO, "link", "LINK_REQUEST", client,

View file

@ -18,6 +18,7 @@ ModuleHeader MOD_HEADER
RPC_CALL_FUNC(rpc_server_list);
RPC_CALL_FUNC(rpc_server_get);
RPC_CALL_FUNC(rpc_server_rehash);
RPC_CALL_FUNC(rpc_server_connect);
int rpc_server_rehash_log(int failure, json_t *rehash_log);
@ -51,6 +52,14 @@ MOD_INIT()
config_error("[rpc/server] Could not register RPC handler");
return MOD_FAILED;
}
memset(&r, 0, sizeof(r));
r.method = "server.connect";
r.call = rpc_server_connect;
if (!RPCHandlerAdd(modinfo->handle, &r))
{
config_error("[rpc/server] Could not register RPC handler");
return MOD_FAILED;
}
HookAdd(modinfo->handle, HOOKTYPE_REHASH_LOG, 0, rpc_server_rehash_log);
@ -180,3 +189,67 @@ int rpc_server_rehash_log(int failure, json_t *rehash_log)
}
return 0;
}
RPC_CALL_FUNC(rpc_server_connect)
{
json_t *result, *list, *item;
const char *server, *link_name;
Client *acptr;
ConfigItem_link *link;
ConfigItem_deny_link *deny;
OPTIONAL_PARAM_STRING("server", server);
if (server)
{
if (!(acptr = find_server(server, NULL)))
{
rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server not found");
return;
}
} else {
acptr = &me;
}
REQUIRE_PARAM_STRING("link", link_name);
if (acptr != &me)
{
/* Not supported atm */
result = json_boolean(0);
rpc_response(client, request, result);
json_decref(result);
return;
}
if (find_server_quick(link_name))
{
rpc_error(client, request, JSON_RPC_ERROR_ALREADY_EXISTS, "Server is already linked");
return;
}
link = find_link(link_name);
if (!link)
{
rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server with that name does not exist in any link block");
return;
}
if (!link->outgoing.hostname && !link->outgoing.file)
{
rpc_error(client, request, JSON_RPC_ERROR_NOT_FOUND, "Server with that name exists but is not configured as an OUTGOING server.");
return;
}
if (check_deny_link(link, 0))
{
rpc_error(client, request, JSON_RPC_ERROR_DENIED, "Server linking is denied via a deny link { } block");
return;
}
unreal_log(ULOG_INFO, "link", "LINK_REQUEST", client,
"CONNECT: Link to $link_block requested by $client",
log_data_link_block(link));
connect_server(link, client, NULL);
result = json_boolean(1);
rpc_response(client, request, result);
json_decref(result);
}

View file

@ -249,7 +249,6 @@ int server_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
int server_needs_linking(ConfigItem_link *aconf)
{
ConfigItem_deny_link *deny;
Client *client;
ConfigItem_class *class;
@ -278,9 +277,8 @@ int server_needs_linking(ConfigItem_link *aconf)
return 0; /* Class is full */
/* Check connect rules to see if we're allowed to try the link */
for (deny = conf_deny_link; deny; deny = deny->next)
if (unreal_mask_match_string(aconf->servername, deny->mask) && crule_eval(deny->rule))
return 0;
if (check_deny_link(aconf, 1))
return 0;
/* Yes, this server is a linking candidate */
return 1;
@ -872,7 +870,6 @@ CMD_FUNC(cmd_server)
int hop = 0;
char info[REALLEN + 61];
ConfigItem_link *aconf = NULL;
ConfigItem_deny_link *deny;
char *flags = NULL, *protocol = NULL, *inf = NULL, *num = NULL;
int incoming;
@ -992,18 +989,13 @@ CMD_FUNC(cmd_server)
strlcpy(client->info, info[0] ? info : "server", sizeof(client->info));
}
/* Process deny server { } restrictions */
for (deny = conf_deny_link; deny; deny = deny->next)
if (check_deny_link(aconf, 0))
{
if (deny->flag.type == CRULE_ALL && unreal_mask_match_string(servername, deny->mask)
&& crule_eval(deny->rule))
{
unreal_log(ULOG_ERROR, "link", "LINK_DENIED_DENY_LINK_BLOCK", client,
"Server link $servername rejected by deny link { } block.",
log_data_string("servername", servername));
exit_client(client, NULL, "Disallowed by connection rule");
return;
}
unreal_log(ULOG_ERROR, "link", "LINK_DENIED_DENY_LINK_BLOCK", client,
"Server link $servername rejected by deny link { } block.",
log_data_string("servername", servername));
exit_client(client, NULL, "Disallowed by connection rule");
return;
}
if (aconf->options & CONNECT_QUARANTINE)