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);

Reply via email to