git: ccb188268565 - main - ctld: Convert struct auth_portal to a C++ class
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 04 Aug 2025 19:46:44 UTC
The branch main has been updated by jhb:
URL: https://cgit.FreeBSD.org/src/commit/?id=ccb188268565a89c7f3649eccfd80e0fe7279e31
commit ccb188268565a89c7f3649eccfd80e0fe7279e31
Author: John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2025-08-04 19:38:06 +0000
Commit: John Baldwin <jhb@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);