Add netmasks support to initiator-portal option.

MFC after:	2 weeks
This commit is contained in:
Alexander Motin 2014-07-28 12:47:09 +00:00
parent 56e397023c
commit 073edb1c91
4 changed files with 92 additions and 17 deletions

View File

@ -27,7 +27,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd July 20, 2014 .Dd July 28, 2014
.Dt CTL.CONF 5 .Dt CTL.CONF 5
.Os .Os
.Sh NAME .Sh NAME
@ -119,7 +119,7 @@ name.
Otherwise, only initiators with names matching one of defined Otherwise, only initiators with names matching one of defined
ones will be allowed to connect. ones will be allowed to connect.
.It Ic initiator-portal Ao Ar address Ac .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 If not defined, there will be no restrictions based on initiator
address. address.
Otherwise, only initiators with addresses matching one of defined Otherwise, only initiators with addresses matching one of defined

View File

@ -34,6 +34,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
@ -319,14 +320,56 @@ const struct auth_portal *
auth_portal_new(struct auth_group *ag, const char *portal) auth_portal_new(struct auth_group *ag, const char *portal)
{ {
struct auth_portal *ap; struct auth_portal *ap;
char *net, *mask, *str, *tmp;
int len, dm, m;
ap = calloc(1, sizeof(*ap)); ap = calloc(1, sizeof(*ap));
if (ap == NULL) if (ap == NULL)
log_err(1, "calloc"); log_err(1, "calloc");
ap->ap_auth_group = ag; ap->ap_auth_group = ag;
ap->ap_initator_portal = checked_strdup(portal); 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); TAILQ_INSERT_TAIL(&ag->ag_portals, ap, ap_next);
return (ap); return (ap);
error:
log_errx(1, "Incorrect initiator portal '%s'", portal);
return (NULL);
} }
static void static void
@ -347,13 +390,34 @@ auth_portal_defined(const struct auth_group *ag)
} }
const struct auth_portal * 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;
uint8_t *a, *b, bmask;
int i;
TAILQ_FOREACH(auth_portal, &ag->ag_portals, ap_next) { TAILQ_FOREACH(ap, &ag->ag_portals, ap_next) {
if (strcmp(auth_portal->ap_initator_portal, portal) == 0) if (ap->ap_sa.ss_family != ss->ss_family)
return (auth_portal); continue;
if (ss->ss_family == AF_INET) {
a = (uint8_t *)&((struct sockaddr_in *)ss)->sin_addr;
b = (uint8_t *)&((struct sockaddr_in *)&ap->ap_sa)->sin_addr;
} else {
a = (uint8_t *)&((struct sockaddr_in6 *)ss)->sin6_addr;
b = (uint8_t *)&((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); return (NULL);
@ -950,7 +1014,8 @@ lun_option_set(struct lun_option *lo, const char *value)
} }
static struct connection * 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; struct connection *conn;
@ -960,6 +1025,7 @@ connection_new(struct portal *portal, int fd, const char *host)
conn->conn_portal = portal; conn->conn_portal = portal;
conn->conn_socket = fd; conn->conn_socket = fd;
conn->conn_initiator_addr = checked_strdup(host); 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. * Default values, from RFC 3720, section 12.
@ -1586,7 +1652,7 @@ wait_for_children(bool block)
static void static void
handle_connection(struct portal *portal, int fd, 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; struct connection *conn;
int error; int error;
@ -1621,7 +1687,7 @@ handle_connection(struct portal *portal, int fd,
} }
pidfile_close(conf->conf_pidfh); 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); host, sizeof(host), NULL, 0, NI_NUMERICHOST);
if (error != 0) if (error != 0)
log_errx(1, "getnameinfo: %s", gai_strerror(error)); log_errx(1, "getnameinfo: %s", gai_strerror(error));
@ -1631,7 +1697,7 @@ handle_connection(struct portal *portal, int fd,
log_set_peer_addr(host); log_set_peer_addr(host);
setproctitle("%s", host); setproctitle("%s", host);
conn = connection_new(portal, fd, host); conn = connection_new(portal, fd, host, client_sa);
set_timeout(conf); set_timeout(conf);
kernel_capsicate(); kernel_capsicate();
login(conn); login(conn);
@ -1687,6 +1753,9 @@ main_loop(struct conf *conf, bool dont_fork)
client_salen = sizeof(client_sa); client_salen = sizeof(client_sa);
kernel_accept(&connection_id, &portal_id, kernel_accept(&connection_id, &portal_id,
(struct sockaddr *)&client_sa, &client_salen); (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", log_debugx("incoming connection, id %d, portal id %d",
connection_id, portal_id); connection_id, portal_id);
@ -1703,8 +1772,7 @@ main_loop(struct conf *conf, bool dont_fork)
found: found:
handle_connection(portal, connection_id, handle_connection(portal, connection_id,
(struct sockaddr *)&client_sa, client_salen, (struct sockaddr *)&client_sa, dont_fork);
dont_fork);
} else { } else {
#endif #endif
assert(proxy_mode == false); assert(proxy_mode == false);
@ -1731,9 +1799,13 @@ main_loop(struct conf *conf, bool dont_fork)
&client_salen); &client_salen);
if (client_fd < 0) if (client_fd < 0)
log_err(1, "accept"); 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, handle_connection(portal, client_fd,
(struct sockaddr *)&client_sa, (struct sockaddr *)&client_sa,
client_salen, dont_fork); dont_fork);
break; break;
} }
} }

View File

@ -35,8 +35,8 @@
#include <sys/queue.h> #include <sys/queue.h>
#ifdef ICL_KERNEL_PROXY #ifdef ICL_KERNEL_PROXY
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h>
#endif #endif
#include <sys/socket.h>
#include <stdbool.h> #include <stdbool.h>
#include <libutil.h> #include <libutil.h>
@ -67,6 +67,8 @@ struct auth_portal {
TAILQ_ENTRY(auth_portal) ap_next; TAILQ_ENTRY(auth_portal) ap_next;
struct auth_group *ap_auth_group; struct auth_group *ap_auth_group;
char *ap_initator_portal; char *ap_initator_portal;
struct sockaddr_storage ap_sa;
int ap_mask;
}; };
#define AG_TYPE_UNKNOWN 0 #define AG_TYPE_UNKNOWN 0
@ -179,6 +181,7 @@ struct connection {
char *conn_initiator_addr; char *conn_initiator_addr;
char *conn_initiator_alias; char *conn_initiator_alias;
uint8_t conn_initiator_isid[6]; uint8_t conn_initiator_isid[6];
struct sockaddr_storage conn_initiator_sa;
uint32_t conn_cmdsn; uint32_t conn_cmdsn;
uint32_t conn_statsn; uint32_t conn_statsn;
size_t conn_max_data_segment_length; 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); const char *initiator_portal);
bool auth_portal_defined(const struct auth_group *ag); bool auth_portal_defined(const struct auth_group *ag);
const struct auth_portal *auth_portal_find(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); struct portal_group *portal_group_new(struct conf *conf, const char *name);
void portal_group_delete(struct portal_group *pg); void portal_group_delete(struct portal_group *pg);

View File

@ -954,7 +954,7 @@ login(struct connection *conn)
} }
if (auth_portal_defined(ag)) { 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); login_send_error(request, 0x02, 0x02);
log_errx(1, "initiator does not match allowed " log_errx(1, "initiator does not match allowed "
"initiator portals"); "initiator portals");