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$
.\"
.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

View File

@ -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,34 @@ 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;
uint8_t *a, *b, bmask;
int i;
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 = (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);
@ -950,7 +1014,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 +1025,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 +1652,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 +1687,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 +1697,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 +1753,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 +1772,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 +1799,13 @@ main_loop(struct conf *conf, bool dont_fork)
&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;
}
}

View File

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

View File

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