diff options
-rw-r--r-- | usr.sbin/ctld/ctl.conf.5 | 4 | ||||
-rw-r--r-- | usr.sbin/ctld/ctld.c | 101 | ||||
-rw-r--r-- | usr.sbin/ctld/ctld.h | 7 | ||||
-rw-r--r-- | usr.sbin/ctld/login.c | 2 |
4 files changed, 97 insertions, 17 deletions
diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5 index e0d18aa..7abff86 100644 --- a/usr.sbin/ctld/ctl.conf.5 +++ b/usr.sbin/ctld/ctl.conf.5 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 20, 2014 +.Dd July 28, 2014 .Dt CTL.CONF 5 .Os .Sh NAME @@ -119,7 +119,7 @@ name. Otherwise, only initiators with names matching one of defined ones will be allowed to connect. .It Ic initiator-portal Ao Ar address Ac -Specifies iSCSI initiator portal - IPv4 or IPv6 address. +Specifies iSCSI initiator portal - IPv4 or IPv6 address or network. If not defined, there will be no restrictions based on initiator address. Otherwise, only initiators with addresses matching one of defined diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c index e2b9ebe..c14be21 100644 --- a/usr.sbin/ctld/ctld.c +++ b/usr.sbin/ctld/ctld.c @@ -34,6 +34,7 @@ #include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> +#include <arpa/inet.h> #include <assert.h> #include <ctype.h> #include <errno.h> @@ -319,14 +320,56 @@ const struct auth_portal * auth_portal_new(struct auth_group *ag, const char *portal) { struct auth_portal *ap; + char *net, *mask, *str, *tmp; + int len, dm, m; ap = calloc(1, sizeof(*ap)); if (ap == NULL) log_err(1, "calloc"); ap->ap_auth_group = ag; ap->ap_initator_portal = checked_strdup(portal); + mask = str = checked_strdup(portal); + net = strsep(&mask, "/"); + if (net[0] == '[') + net++; + len = strlen(net); + if (len == 0) + goto error; + if (net[len - 1] == ']') + net[len - 1] = 0; + if (strchr(net, ':') != NULL) { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *)&ap->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; + } else { + struct sockaddr_in *sin = + (struct sockaddr_in *)&ap->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) { + 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 (ap); + +error: + log_errx(1, "Incorrect initiator portal '%s'", portal); + return (NULL); } static void @@ -347,13 +390,39 @@ auth_portal_defined(const struct auth_group *ag) } const struct auth_portal * -auth_portal_find(const struct auth_group *ag, const char *portal) +auth_portal_find(const struct auth_group *ag, const struct sockaddr_storage *ss) { - const struct auth_portal *auth_portal; + const struct auth_portal *ap; + const uint8_t *a, *b; + int i; + uint8_t bmask; - TAILQ_FOREACH(auth_portal, &ag->ag_portals, ap_next) { - if (strcmp(auth_portal->ap_initator_portal, portal) == 0) - return (auth_portal); + 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: + ; } return (NULL); @@ -950,7 +1019,8 @@ lun_option_set(struct lun_option *lo, const char *value) } static struct connection * -connection_new(struct portal *portal, int fd, const char *host) +connection_new(struct portal *portal, int fd, const char *host, + const struct sockaddr *client_sa) { struct connection *conn; @@ -960,6 +1030,7 @@ connection_new(struct portal *portal, int fd, const char *host) conn->conn_portal = portal; conn->conn_socket = fd; conn->conn_initiator_addr = checked_strdup(host); + memcpy(&conn->conn_initiator_sa, client_sa, client_sa->sa_len); /* * Default values, from RFC 3720, section 12. @@ -1586,7 +1657,7 @@ wait_for_children(bool block) static void handle_connection(struct portal *portal, int fd, - const struct sockaddr *client_sa, socklen_t client_salen, bool dont_fork) + const struct sockaddr *client_sa, bool dont_fork) { struct connection *conn; int error; @@ -1621,7 +1692,7 @@ handle_connection(struct portal *portal, int fd, } pidfile_close(conf->conf_pidfh); - error = getnameinfo(client_sa, client_salen, + error = getnameinfo(client_sa, client_sa->sa_len, host, sizeof(host), NULL, 0, NI_NUMERICHOST); if (error != 0) log_errx(1, "getnameinfo: %s", gai_strerror(error)); @@ -1631,7 +1702,7 @@ handle_connection(struct portal *portal, int fd, log_set_peer_addr(host); setproctitle("%s", host); - conn = connection_new(portal, fd, host); + conn = connection_new(portal, fd, host, client_sa); set_timeout(conf); kernel_capsicate(); login(conn); @@ -1687,6 +1758,9 @@ main_loop(struct conf *conf, bool dont_fork) client_salen = sizeof(client_sa); kernel_accept(&connection_id, &portal_id, (struct sockaddr *)&client_sa, &client_salen); + if (client_salen < client_sa.ss_len) + log_errx(1, "salen %u < %u", + client_salen, client_sa.ss_len); log_debugx("incoming connection, id %d, portal id %d", connection_id, portal_id); @@ -1703,8 +1777,7 @@ main_loop(struct conf *conf, bool dont_fork) found: handle_connection(portal, connection_id, - (struct sockaddr *)&client_sa, client_salen, - dont_fork); + (struct sockaddr *)&client_sa, dont_fork); } else { #endif assert(proxy_mode == false); @@ -1731,9 +1804,13 @@ found: &client_salen); if (client_fd < 0) log_err(1, "accept"); + if (client_salen < client_sa.ss_len) + log_errx(1, "salen %u < %u", + client_salen, + client_sa.ss_len); handle_connection(portal, client_fd, (struct sockaddr *)&client_sa, - client_salen, dont_fork); + dont_fork); break; } } diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h index 323ef2c..98d612f 100644 --- a/usr.sbin/ctld/ctld.h +++ b/usr.sbin/ctld/ctld.h @@ -35,8 +35,8 @@ #include <sys/queue.h> #ifdef ICL_KERNEL_PROXY #include <sys/types.h> -#include <sys/socket.h> #endif +#include <sys/socket.h> #include <stdbool.h> #include <libutil.h> @@ -67,6 +67,8 @@ struct auth_portal { TAILQ_ENTRY(auth_portal) ap_next; struct auth_group *ap_auth_group; char *ap_initator_portal; + struct sockaddr_storage ap_sa; + int ap_mask; }; #define AG_TYPE_UNKNOWN 0 @@ -179,6 +181,7 @@ struct connection { char *conn_initiator_addr; char *conn_initiator_alias; uint8_t conn_initiator_isid[6]; + struct sockaddr_storage conn_initiator_sa; uint32_t conn_cmdsn; uint32_t conn_statsn; size_t conn_max_data_segment_length; @@ -235,7 +238,7 @@ const struct auth_portal *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 char *initiator_portal); + 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); diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c index b14b264..20ed464 100644 --- a/usr.sbin/ctld/login.c +++ b/usr.sbin/ctld/login.c @@ -954,7 +954,7 @@ login(struct connection *conn) } if (auth_portal_defined(ag)) { - if (auth_portal_find(ag, conn->conn_initiator_addr) == NULL) { + if (auth_portal_find(ag, &conn->conn_initiator_sa) == NULL) { login_send_error(request, 0x02, 0x02); log_errx(1, "initiator does not match allowed " "initiator portals"); |