From owner-svn-src-stable-10@FreeBSD.ORG Tue Dec 9 11:50:52 2014 Return-Path: Delivered-To: svn-src-stable-10@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id AC517D41; Tue, 9 Dec 2014 11:50:52 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 9774B900; Tue, 9 Dec 2014 11:50:52 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id sB9Boqob011653; Tue, 9 Dec 2014 11:50:52 GMT (envelope-from trasz@FreeBSD.org) Received: (from trasz@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id sB9Bop6x011646; Tue, 9 Dec 2014 11:50:51 GMT (envelope-from trasz@FreeBSD.org) Message-Id: <201412091150.sB9Bop6x011646@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: trasz set sender to trasz@FreeBSD.org using -f From: Edward Tomasz Napierala Date: Tue, 9 Dec 2014 11:50:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r275642 - stable/10/usr.sbin/ctld X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 09 Dec 2014 11:50:52 -0000 Author: trasz Date: Tue Dec 9 11:50:50 2014 New Revision: 275642 URL: https://svnweb.freebsd.org/changeset/base/275642 Log: MFC r274308: Add support for sending redirections to iSCSI target. MFC r274309: Fix several nits in redirection handling - don't use wrong CSG, and avoid use-after-free. Sponsored by: The FreeBSD Foundation Modified: stable/10/usr.sbin/ctld/ctl.conf.5 stable/10/usr.sbin/ctld/ctld.c stable/10/usr.sbin/ctld/ctld.h stable/10/usr.sbin/ctld/login.c stable/10/usr.sbin/ctld/parse.y stable/10/usr.sbin/ctld/token.l Directory Properties: stable/10/ (props changed) Modified: stable/10/usr.sbin/ctld/ctl.conf.5 ============================================================================== --- stable/10/usr.sbin/ctld/ctl.conf.5 Tue Dec 9 11:12:24 2014 (r275641) +++ stable/10/usr.sbin/ctld/ctl.conf.5 Tue Dec 9 11:50:50 2014 (r275642) @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd November 8, 2014 +.Dd November 9, 2014 .Dt CTL.CONF 5 .Os .Sh NAME @@ -218,6 +218,17 @@ An IPv4 or IPv6 address and port to list .\".It Ic listen-iser Ar address .\"An IPv4 or IPv6 address and port to listen on for incoming connections .\"using iSER (iSCSI over RDMA) protocol. +.It Ic redirect Aq Ar address +IPv4 or IPv6 address to redirect initiators to. +When configured, all initiators attempting to connect to portal +belonging to this +.Sy portal-group +will get redirected using "Target moved temporarily" login response. +Redirection happens before authentication and any +.Sy initiator-name +or +.Sy initiator-portal +checks are skipped. .El .Ss target Context .Bl -tag -width indent @@ -296,6 +307,11 @@ The default portal group is .Qq Ar default , which makes the target available on TCP port 3260 on all configured IPv4 and IPv6 addresses. +.It Ic redirect Aq Ar address +IPv4 or IPv6 address to redirect initiators to. +When configured, all initiators attempting to connect to this target +will get redirected using "Target moved temporarily" login response. +Redirection happens after successful authentication. .It Ic lun Ar number Create a .Sy lun Modified: stable/10/usr.sbin/ctld/ctld.c ============================================================================== --- stable/10/usr.sbin/ctld/ctld.c Tue Dec 9 11:12:24 2014 (r275641) +++ stable/10/usr.sbin/ctld/ctld.c Tue Dec 9 11:50:50 2014 (r275642) @@ -622,6 +622,7 @@ portal_group_delete(struct portal_group TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp) portal_delete(portal); free(pg->pg_name); + free(pg->pg_redirection); free(pg); } @@ -1000,6 +1001,22 @@ portal_group_set_filter(struct portal_gr return (0); } +int +portal_group_set_redirection(struct portal_group *pg, const char *addr) +{ + + if (pg->pg_redirection != NULL) { + log_warnx("cannot set redirection to \"%s\" for " + "portal-group \"%s\"; already defined", + addr, pg->pg_name); + return (1); + } + + pg->pg_redirection = checked_strdup(addr); + + return (0); +} + static bool valid_hex(const char ch) { @@ -1144,6 +1161,7 @@ target_delete(struct target *targ) TAILQ_FOREACH_SAFE(lun, &targ->t_luns, l_next, tmp) lun_delete(lun); free(targ->t_name); + free(targ->t_redirection); free(targ); } @@ -1160,6 +1178,22 @@ target_find(struct conf *conf, const cha return (NULL); } +int +target_set_redirection(struct target *target, const char *addr) +{ + + if (target->t_redirection != NULL) { + log_warnx("cannot set redirection to \"%s\" for " + "target \"%s\"; already defined", + addr, target->t_name); + return (1); + } + + target->t_redirection = checked_strdup(addr); + + return (0); +} + struct lun * lun_new(struct target *targ, int lun_id) { @@ -1486,10 +1520,15 @@ conf_verify(struct conf *conf) return (error); found = true; } - if (!found) { + if (!found && targ->t_redirection == NULL) { log_warnx("no LUNs defined for target \"%s\"", targ->t_name); } + if (found && targ->t_redirection != NULL) { + log_debugx("target \"%s\" contains luns, " + " but configured for redirection", + targ->t_name); + } } TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) { assert(pg->pg_name != NULL); @@ -1506,13 +1545,22 @@ conf_verify(struct conf *conf) if (targ->t_portal_group == pg) break; } - if (targ == NULL) { + if (pg->pg_redirection != NULL) { + if (targ != NULL) { + log_debugx("portal-group \"%s\" assigned " + "to target \"%s\", but configured " + "for redirection", + pg->pg_name, targ->t_name); + } + pg->pg_unassigned = false; + } else if (targ != NULL) { + pg->pg_unassigned = false; + } else { if (strcmp(pg->pg_name, "default") != 0) log_warnx("portal-group \"%s\" not assigned " "to any target", pg->pg_name); pg->pg_unassigned = true; - } else - pg->pg_unassigned = false; + } } TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) { if (ag->ag_name == NULL) Modified: stable/10/usr.sbin/ctld/ctld.h ============================================================================== --- stable/10/usr.sbin/ctld/ctld.h Tue Dec 9 11:12:24 2014 (r275641) +++ stable/10/usr.sbin/ctld/ctld.h Tue Dec 9 11:50:50 2014 (r275642) @@ -117,6 +117,7 @@ struct portal_group { int pg_discovery_filter; bool pg_unassigned; TAILQ_HEAD(, portal) pg_portals; + char *pg_redirection; uint16_t pg_tag; }; @@ -151,6 +152,7 @@ struct target { struct portal_group *t_portal_group; char *t_name; char *t_alias; + char *t_redirection; }; struct isns { @@ -301,6 +303,8 @@ int portal_group_add_listen(struct por const char *listen, bool iser); int portal_group_set_filter(struct portal_group *pg, const char *filter); +int portal_group_set_redirection(struct portal_group *pg, + const char *addr); int isns_new(struct conf *conf, const char *addr); void isns_delete(struct isns *is); @@ -312,6 +316,8 @@ struct target *target_new(struct conf * void target_delete(struct target *target); struct target *target_find(struct conf *conf, const char *name); +int target_set_redirection(struct target *target, + const char *addr); struct lun *lun_new(struct target *target, int lun_id); void lun_delete(struct lun *lun); Modified: stable/10/usr.sbin/ctld/login.c ============================================================================== --- stable/10/usr.sbin/ctld/login.c Tue Dec 9 11:12:24 2014 (r275641) +++ stable/10/usr.sbin/ctld/login.c Tue Dec 9 11:50:50 2014 (r275642) @@ -613,13 +613,72 @@ login_negotiate_key(struct pdu *request, } static void +login_redirect(struct pdu *request, const char *target_address) +{ + struct pdu *response; + struct iscsi_bhs_login_response *bhslr2; + struct keys *response_keys; + + response = login_new_response(request); + login_set_csg(response, login_csg(request)); + bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs; + bhslr2->bhslr_status_class = 0x01; + bhslr2->bhslr_status_detail = 0x01; + + response_keys = keys_new(); + keys_add(response_keys, "TargetAddress", target_address); + + keys_save(response_keys, response); + pdu_send(response); + pdu_delete(response); + keys_delete(response_keys); +} + +static bool +login_portal_redirect(struct connection *conn, struct pdu *request) +{ + const struct portal_group *pg; + + pg = conn->conn_portal->p_portal_group; + if (pg->pg_redirection == NULL) + return (false); + + log_debugx("portal-group \"%s\" configured to redirect to %s", + pg->pg_name, pg->pg_redirection); + login_redirect(request, pg->pg_redirection); + + return (true); +} + +static bool +login_target_redirect(struct connection *conn, struct pdu *request) +{ + const char *target_address; + + assert(conn->conn_portal->p_portal_group->pg_redirection == NULL); + + if (conn->conn_target == NULL) + return (false); + + target_address = conn->conn_target->t_redirection; + if (target_address == NULL) + return (false); + + log_debugx("target \"%s\" configured to redirect to %s", + conn->conn_target->t_name, target_address); + login_redirect(request, target_address); + + return (true); +} + +static void login_negotiate(struct connection *conn, struct pdu *request) { struct pdu *response; struct iscsi_bhs_login_response *bhslr2; struct keys *request_keys, *response_keys; int i; - bool skipped_security; + bool redirected, skipped_security; if (request == NULL) { log_debugx("beginning operational parameter negotiation; " @@ -629,6 +688,18 @@ login_negotiate(struct connection *conn, } else skipped_security = true; + /* + * RFC 3720, 10.13.5. Status-Class and Status-Detail, says + * the redirection SHOULD be accepted by the initiator before + * authentication, but MUST be be accepted afterwards; that's + * why we're doing it here and not earlier. + */ + redirected = login_target_redirect(conn, request); + if (redirected) { + log_debugx("initiator redirected; exiting"); + exit(0); + } + request_keys = keys_new(); keys_load(request_keys, request); @@ -680,6 +751,7 @@ login(struct connection *conn) struct portal_group *pg; const char *initiator_name, *initiator_alias, *session_type, *target_name, *auth_method; + bool redirected; /* * Handle the initial Login Request - figure out required authentication @@ -722,6 +794,12 @@ login(struct connection *conn) */ setproctitle("%s (%s)", conn->conn_initiator_addr, conn->conn_initiator_name); + redirected = login_portal_redirect(conn, request); + if (redirected) { + log_debugx("initiator redirected; exiting"); + exit(0); + } + initiator_alias = keys_find(request_keys, "InitiatorAlias"); if (initiator_alias != NULL) conn->conn_initiator_alias = checked_strdup(initiator_alias); Modified: stable/10/usr.sbin/ctld/parse.y ============================================================================== --- stable/10/usr.sbin/ctld/parse.y Tue Dec 9 11:12:24 2014 (r275641) +++ stable/10/usr.sbin/ctld/parse.y Tue Dec 9 11:50:50 2014 (r275642) @@ -61,7 +61,8 @@ extern void yyrestart(FILE *); %token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER %token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT %token LISTEN LISTEN_ISER LUN MAXPROC OPENING_BRACKET OPTION -%token PATH PIDFILE PORTAL_GROUP SEMICOLON SERIAL SIZE STR TARGET TIMEOUT +%token PATH PIDFILE PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR +%token TARGET TIMEOUT %union { @@ -338,6 +339,8 @@ portal_group_entry: portal_group_listen | portal_group_listen_iser + | + portal_group_redirect ; portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR @@ -393,6 +396,17 @@ portal_group_listen_iser: LISTEN_ISER ST } ; +portal_group_redirect: REDIRECT STR + { + int error; + + error = portal_group_set_redirection(portal_group, $2); + free($2); + if (error != 0) + return (1); + } + ; + target: TARGET target_name OPENING_BRACKET target_entries CLOSING_BRACKET { @@ -433,6 +447,8 @@ target_entry: | target_portal_group | + target_redirect + | target_lun ; @@ -635,6 +651,17 @@ target_portal_group: PORTAL_GROUP STR } ; +target_redirect: REDIRECT STR + { + int error; + + error = target_set_redirection(target, $2); + free($2); + if (error != 0) + return (1); + } + ; + target_lun: LUN lun_number OPENING_BRACKET lun_entries CLOSING_BRACKET { Modified: stable/10/usr.sbin/ctld/token.l ============================================================================== --- stable/10/usr.sbin/ctld/token.l Tue Dec 9 11:12:24 2014 (r275641) +++ stable/10/usr.sbin/ctld/token.l Tue Dec 9 11:50:50 2014 (r275642) @@ -72,6 +72,7 @@ isns-server { return ISNS_SERVER; } isns-period { return ISNS_PERIOD; } isns-timeout { return ISNS_TIMEOUT; } portal-group { return PORTAL_GROUP; } +redirect { return REDIRECT; } serial { return SERIAL; } size { return SIZE; } target { return TARGET; }