From c990848d2fa23da190ce230011f54d84e08c36fa Mon Sep 17 00:00:00 2001 From: Bram Matthys Date: Sun, 14 Dec 2025 10:03:51 +0100 Subject: [PATCH] Make json_expand_security_groups() really expand all and reorder some. * Add some missing fields, such as destination, but mostly in the exclude- area where a bunch were missing (some of those are a bit far fetched, but hey, they exist, so should be shown if in use). * Re-order fields to more closely match the struct (still not 100%) * Extended fields, such as "account" and "country", now show up directly under the security group, just like the other fields, such as "reputation_score". This is also how they show up in the config file, so hide the the fact that internally in the struct it is stored differently. * Add a comment in SecurityGroup struct in include/struct.h to make it clear you have to add/update stuff at 7 places if you are adding something new. --- include/struct.h | 13 +++++++++ src/json.c | 69 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 62 insertions(+), 20 deletions(-) diff --git a/include/struct.h b/include/struct.h index 8c9d7596b..ffc79a873 100644 --- a/include/struct.h +++ b/include/struct.h @@ -2238,6 +2238,11 @@ typedef struct DynamicSetBlock { } DynamicSetBlock; #define SECURITYGROUPLEN 48 +/** Security groups can match users based on various criteria. + * See https://www.unrealircd.org/docs/Security-group_block + * We also use a SecurityGroup struct for Mask/Match items + * https://www.unrealircd.org/docs/Mask_item + */ struct SecurityGroup { SecurityGroup *prev, *next; int priority; @@ -2260,6 +2265,14 @@ struct SecurityGroup { CRuleNode *rule; /**< parsed crule */ NameList *destination; NameValuePrioList *extended; + // IMPORTANT: If you are adding anything: + // 1) Add the item here + // 2) Add an exclude_ item (further below) + // 3) Update test_match_item() in src/securitygroup.c + // 4) Update conf_match_item() in src/securitygroup.c + // 5) Update duplicate_security_group() in src/securitygroup.c + // 6) Update free_security_group() in src/securitygroup.c + // 7) Update json_expand_security_group() in src/json.c /* Exclude */ int exclude_identified; int exclude_reputation_score; diff --git a/src/json.c b/src/json.c index 368870d03..1dfd2a1f2 100644 --- a/src/json.c +++ b/src/json.c @@ -709,6 +709,26 @@ void json_expand_nvplist(json_t *parent, const char *key, NameValuePrioList *lis json_object_set_new(obj, n->name, json_string_unreal(n->value)); } +/** Expand a NameValuePrioList to a JSON object. + * @param parent The parent JSON object + * @param key The key name for the object + * @param list The name-value list to expand + */ +void json_expand_nvplist_prefix(json_t *parent, const char *prefix, NameValuePrioList *list) +{ + NameValuePrioList *n; + + if (!list) + return; + + for (n = list; n; n = n->next) + { + char buf[512]; + snprintf(buf, sizeof(buf), "%s%s", prefix, n->name); + json_object_set_new(parent, buf, json_string_unreal(n->value)); + } +} + /** Helper: Expand security group details to JSON */ void json_expand_security_group(json_t *j, const char *key, SecurityGroup *s, int detail) { @@ -729,6 +749,7 @@ void json_expand_security_group(json_t *j, const char *key, SecurityGroup *s, in { json_object_set_new(child, "name", json_string_unreal(s->name)); json_object_set_new(child, "priority", json_integer(s->priority)); + json_object_set_new(child, "public", json_boolean(s->public)); } if (detail == 0) @@ -737,36 +758,44 @@ void json_expand_security_group(json_t *j, const char *key, SecurityGroup *s, in /* Inclusion criteria */ if (s->identified) json_object_set_new(child, "identified", json_boolean(1)); + if (s->reputation_score != 0) + json_object_set_new(child, "reputation_score", json_integer(s->reputation_score)); + if (s->connect_time != 0) + json_object_set_new(child, "connect_time", json_integer(s->connect_time)); if (s->webirc) json_object_set_new(child, "webirc", json_boolean(1)); if (s->websocket) json_object_set_new(child, "websocket", json_boolean(1)); if (s->tls) json_object_set_new(child, "tls", json_boolean(1)); - if (s->reputation_score != 0) - json_object_set_new(child, "reputation_score", json_integer(s->reputation_score)); - if (s->connect_time != 0) - json_object_set_new(child, "connect_time", json_integer(s->connect_time)); - - /* Mask lists */ - json_expand_mask_list(child, "mask", s->mask); - json_expand_mask_list(child, "exclude_mask", s->exclude_mask); - - /* Name lists */ json_expand_name_list(child, "ip", s->ip); - json_expand_name_list(child, "exclude_ip", s->exclude_ip); - json_expand_name_list(child, "security_group", s->security_group); - json_expand_name_list(child, "exclude_security_group", s->exclude_security_group); + json_expand_mask_list(child, "mask", s->mask); json_expand_name_list(child, "server_port", s->server_port); - json_expand_name_list(child, "exclude_server_port", s->exclude_server_port); - - /* Extended criteria (account, realname, etc) */ - json_expand_nvplist(child, "extended", s->extended); - json_expand_nvplist(child, "exclude_extended", s->exclude_extended); - - /* Rules (as strings) */ + json_expand_name_list(child, "security_group", s->security_group); + json_expand_name_list(child, "destination", s->destination); + json_expand_nvplist_prefix(child, "", s->extended); if (s->prettyrule) json_object_set_new(child, "rule", json_string_unreal(s->prettyrule)); + + /* Exclusion criteria */ + if (s->exclude_identified) + json_object_set_new(child, "exclude_identified", json_boolean(1)); + if (s->exclude_reputation_score != 0) + json_object_set_new(child, "exclude_reputation_score", json_integer(s->exclude_reputation_score)); + if (s->exclude_connect_time != 0) + json_object_set_new(child, "exclude_connect_time", json_integer(s->exclude_connect_time)); + if (s->exclude_webirc) + json_object_set_new(child, "exclude_webirc", json_boolean(1)); + if (s->exclude_websocket) + json_object_set_new(child, "exclude_websocket", json_boolean(1)); + if (s->exclude_tls) + json_object_set_new(child, "exclude_tls", json_boolean(1)); + json_expand_name_list(child, "exclude_ip", s->exclude_ip); + json_expand_mask_list(child, "exclude_mask", s->exclude_mask); + json_expand_name_list(child, "exclude_server_port", s->exclude_server_port); + json_expand_name_list(child, "exclude_security_group", s->exclude_security_group); + json_expand_name_list(child, "exclude_destination", s->exclude_destination); + json_expand_nvplist_prefix(child, "exclude_", s->exclude_extended); if (s->exclude_prettyrule) json_object_set_new(child, "exclude_rule", json_string_unreal(s->exclude_prettyrule)); }