The branch main has been updated by jhb: URL: https://cgit.FreeBSD.org/src/commit/?id=ccb188268565a89c7f3649eccfd80e0fe7279e31
commit ccb188268565a89c7f3649eccfd80e0fe7279e31 Author: John Baldwin <j...@freebsd.org> AuthorDate: 2025-08-04 19:38:06 +0000 Commit: John Baldwin <j...@freebsd.org> CommitDate: 2025-08-04 19:38:06 +0000 ctld: Convert struct auth_portal to a C++ class Pull logic to parse a portal address string into a sockaddr and mask into a parse() method. Reimplement the logic using operations on C++ std::string's instead of C string parsing. Pull logic from inside the loop in auth_portal_find() to compare a candidate socket address against a portal into a matches() method. Use a std::list of auth_portal objects instead of a TAILQ in struct auth_group. Sponsored by: Chelsio Communications Pull Request: https://github.com/freebsd/freebsd-src/pull/1794 --- usr.sbin/ctld/ctld.cc | 190 +++++++++++++++++++++++--------------------------- usr.sbin/ctld/ctld.hh | 23 +++--- 2 files changed, 100 insertions(+), 113 deletions(-) diff --git a/usr.sbin/ctld/ctld.cc b/usr.sbin/ctld/ctld.cc index 3ddccbfdb20e..396b8db13323 100644 --- a/usr.sbin/ctld/ctld.cc +++ b/usr.sbin/ctld/ctld.cc @@ -51,6 +51,8 @@ #include <unistd.h> #include <cam/scsi/scsi_all.h> +#include <libutil++.hh> + #include "conf.h" #include "ctld.hh" #include "isns.hh" @@ -241,135 +243,127 @@ auth_name_check(const struct auth_group *ag, const char *initiator_name) } bool -auth_portal_new(struct auth_group *ag, const char *portal) +auth_portal::parse(const char *portal) { - struct auth_portal *ap; - char *net, *mask, *str, *tmp; - int len, dm, m; + std::string net(portal); + std::string mask; - ap = reinterpret_cast<struct auth_portal *>(calloc(1, sizeof(*ap))); - if (ap == NULL) - log_err(1, "calloc"); - ap->ap_auth_group = ag; - ap->ap_initiator_portal = checked_strdup(portal); - mask = str = checked_strdup(portal); - net = strsep(&mask, "/"); - if (net[0] == '[') { - net++; - len = strlen(net); + /* Split into 'net' (address) and 'mask'. */ + size_t pos = net.find('/'); + if (pos != net.npos) { + mask = net.substr(pos + 1); + if (mask.empty()) + return false; + net.resize(pos); + } + if (net.empty()) + return false; + + /* + * If 'net' starts with a '[', ensure it ends with a ']' and + * force interpreting the address as IPv6. + */ + bool brackets = net[0] == '['; + if (brackets) { + net.erase(0, 1); + + size_t len = net.length(); if (len < 2) - goto error; + return false; if (net[len - 1] != ']') - goto error; - net[len - 1] = 0; - } else if (net[0] == '\0') - goto error; - if (str[0] == '[' || strchr(net, ':') != NULL) { + return false; + net.resize(len - 1); + } + + /* Parse address from 'net' and set default mask. */ + if (brackets || net.find(':') != net.npos) { struct sockaddr_in6 *sin6 = - (struct sockaddr_in6 *)&ap->ap_sa; + (struct sockaddr_in6 *)&ap_sa; sin6->sin6_len = sizeof(*sin6); sin6->sin6_family = AF_INET6; - if (inet_pton(AF_INET6, net, &sin6->sin6_addr) <= 0) - goto error; - dm = 128; + if (inet_pton(AF_INET6, net.c_str(), &sin6->sin6_addr) <= 0) + return false; + ap_mask = sizeof(sin6->sin6_addr) * 8; } else { struct sockaddr_in *sin = - (struct sockaddr_in *)&ap->ap_sa; + (struct sockaddr_in *)&ap_sa; sin->sin_len = sizeof(*sin); sin->sin_family = AF_INET; - if (inet_pton(AF_INET, net, &sin->sin_addr) <= 0) - goto error; - dm = 32; - } - if (mask != NULL) { - if (mask[0] == '\0') - goto error; - m = strtol(mask, &tmp, 0); - if (m < 0 || m > dm || tmp[0] != 0) - goto error; - } else - m = dm; - ap->ap_mask = m; - free(str); - TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next); - return (true); - -error: - free(str); - free(ap); - log_warnx("incorrect initiator portal \"%s\"", portal); - return (false); -} + if (inet_pton(AF_INET, net.c_str(), &sin->sin_addr) <= 0) + return false; + ap_mask = sizeof(sin->sin_addr) * 8; + } -static void -auth_portal_delete(struct auth_portal *ap) -{ - TAILQ_REMOVE(&ap->ap_auth_group->ag_portals, ap, ap_next); + /* Parse explicit mask if present. */ + if (!mask.empty()) { + char *tmp; + long m = strtol(mask.c_str(), &tmp, 0); + if (m < 0 || m > ap_mask || tmp[0] != 0) + return false; + ap_mask = m; + } - free(ap->ap_initiator_portal); - free(ap); + return true; } bool -auth_portal_defined(const struct auth_group *ag) +auth_portal_new(struct auth_group *ag, const char *portal) { - if (TAILQ_EMPTY(&ag->ag_portals)) + auth_portal ap; + if (!ap.parse(portal)) { + log_warnx("invalid initiator portal \"%s\"", portal); return (false); + } + + ag->ag_portals.emplace_back(ap); return (true); } -const struct auth_portal * -auth_portal_find(const struct auth_group *ag, const struct sockaddr_storage *ss) +bool +auth_portal::matches(const struct sockaddr *sa) const { - const struct auth_portal *ap; const uint8_t *a, *b; int i; - uint8_t bmask; - TAILQ_FOREACH(ap, &ag->ag_portals, ap_next) { - if (ap->ap_sa.ss_family != ss->ss_family) - continue; - if (ss->ss_family == AF_INET) { - a = (const uint8_t *) - &((const struct sockaddr_in *)ss)->sin_addr; - b = (const uint8_t *) - &((const struct sockaddr_in *)&ap->ap_sa)->sin_addr; - } else { - a = (const uint8_t *) - &((const struct sockaddr_in6 *)ss)->sin6_addr; - b = (const uint8_t *) - &((const struct sockaddr_in6 *)&ap->ap_sa)->sin6_addr; - } - for (i = 0; i < ap->ap_mask / 8; i++) { - if (a[i] != b[i]) - goto next; - } - if (ap->ap_mask % 8) { - bmask = 0xff << (8 - (ap->ap_mask % 8)); - if ((a[i] & bmask) != (b[i] & bmask)) - goto next; - } - return (ap); -next: - ; - } + if (ap_sa.ss_family != sa->sa_family) + return (false); - return (NULL); + if (sa->sa_family == AF_INET) { + a = (const uint8_t *) + &((const struct sockaddr_in *)sa)->sin_addr; + b = (const uint8_t *) + &((const struct sockaddr_in *)&ap_sa)->sin_addr; + } else { + a = (const uint8_t *) + &((const struct sockaddr_in6 *)sa)->sin6_addr; + b = (const uint8_t *) + &((const struct sockaddr_in6 *)&ap_sa)->sin6_addr; + } + for (i = 0; i < ap_mask / 8; i++) { + if (a[i] != b[i]) + return (false); + } + if ((ap_mask % 8) != 0) { + uint8_t bmask = 0xff << (8 - (ap_mask % 8)); + if ((a[i] & bmask) != (b[i] & bmask)) + return (false); + } + return (true); } bool -auth_portal_check(const struct auth_group *ag, const struct sockaddr_storage *sa) +auth_portal_check(const struct auth_group *ag, + const struct sockaddr_storage *sa) { - - if (!auth_portal_defined(ag)) + if (ag->ag_portals.empty()) return (true); - if (auth_portal_find(ag, sa) == NULL) - return (false); - - return (true); + for (const auth_portal &ap : ag->ag_portals) + if (ap.matches((const struct sockaddr *)sa)) + return (true); + return (false); } static struct auth_group * @@ -381,7 +375,6 @@ auth_group_create(struct conf *conf, const char *name, char *label) if (name != NULL) ag->ag_name = checked_strdup(name); ag->ag_label = label; - TAILQ_INIT(&ag->ag_portals); ag->ag_conf = conf; TAILQ_INSERT_TAIL(&conf->conf_auth_groups, ag, ag_next); @@ -416,13 +409,8 @@ auth_group_new(struct conf *conf, struct target *target) void auth_group_delete(struct auth_group *ag) { - struct auth_portal *auth_portal, *auth_portal_tmp; - TAILQ_REMOVE(&ag->ag_conf->conf_auth_groups, ag, ag_next); - TAILQ_FOREACH_SAFE(auth_portal, &ag->ag_portals, ap_next, - auth_portal_tmp) - auth_portal_delete(auth_portal); free(ag->ag_label); free(ag->ag_name); delete ag; diff --git a/usr.sbin/ctld/ctld.hh b/usr.sbin/ctld/ctld.hh index 339793e90bf1..06b932a65453 100644 --- a/usr.sbin/ctld/ctld.hh +++ b/usr.sbin/ctld/ctld.hh @@ -41,6 +41,7 @@ #include <libiscsiutil.h> #include <libutil.h> +#include <list> #include <string> #include <string_view> #include <unordered_map> @@ -74,11 +75,12 @@ private: }; struct auth_portal { - TAILQ_ENTRY(auth_portal) ap_next; - struct auth_group *ap_auth_group; - char *ap_initiator_portal; + bool matches(const struct sockaddr *sa) const; + bool parse(const char *portal); + +private: struct sockaddr_storage ap_sa; - int ap_mask; + int ap_mask = 0; }; #define AG_TYPE_UNKNOWN 0 @@ -95,7 +97,7 @@ struct auth_group { int ag_type; std::unordered_map<std::string, auth> ag_auths; std::unordered_set<std::string> ag_names; - TAILQ_HEAD(, auth_portal) ag_portals; + std::list<auth_portal> ag_portals; }; struct portal { @@ -286,13 +288,10 @@ bool auth_name_new(struct auth_group *ag, bool auth_name_check(const struct auth_group *ag, const char *initiator_name); -bool auth_portal_new(struct auth_group *ag, - const char *initiator_portal); -bool auth_portal_defined(const struct auth_group *ag); -const struct auth_portal *auth_portal_find(const struct auth_group *ag, - const struct sockaddr_storage *sa); -bool auth_portal_check(const struct auth_group *ag, - const struct sockaddr_storage *sa); +bool auth_portal_new(struct auth_group *ag, + const char *initiator_portal); +bool auth_portal_check(const struct auth_group *ag, + const struct sockaddr_storage *sa); struct portal_group *portal_group_new(struct conf *conf, const char *name); void portal_group_delete(struct portal_group *pg);