summaryrefslogtreecommitdiffstats
path: root/src/server/iscsi.c
diff options
context:
space:
mode:
authorSebastian Vater2025-08-19 10:36:01 +0200
committerSebastian Vater2025-08-19 10:36:01 +0200
commit196c02500f9f52ddd2fd4aca16fc83a8972f91f0 (patch)
tree2a1335d3930865af41af484a08246bceec19582a /src/server/iscsi.c
parentFinished iSCSI login handling. Also fixed some bugs and simplified certain st... (diff)
downloaddnbd3-196c02500f9f52ddd2fd4aca16fc83a8972f91f0.tar.gz
dnbd3-196c02500f9f52ddd2fd4aca16fc83a8972f91f0.tar.xz
dnbd3-196c02500f9f52ddd2fd4aca16fc83a8972f91f0.zip
Added iSCSI NOP-In and NOP-Out implementation for keep alive. Also increased memory size alignment to 16 bytes for safe manipulation of integer values in order to prevent buffer overflows for key and value pair handling. Finally, again fixed some bugs.
Diffstat (limited to 'src/server/iscsi.c')
-rw-r--r--src/server/iscsi.c114
1 files changed, 96 insertions, 18 deletions
diff --git a/src/server/iscsi.c b/src/server/iscsi.c
index 51b9c7d..bfda85b 100644
--- a/src/server/iscsi.c
+++ b/src/server/iscsi.c
@@ -43,7 +43,7 @@
* @see https://www.rfc-editor.org/rfc/rfc7143
*/
-/// iSCSI connection key and value pair lookup table.
+/// iSCSI connection negotation key and value pair lookup table.
static const iscsi_key_value_pair_lut_entry iscsi_connection_key_value_pair_lut[] = {
{ (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_HEADER_DIGEST, (uint8_t *) "None", (uint8_t *) "CRC32C\0None\0", ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_LIST, 0L },
{ (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_DATA_DIGEST, (uint8_t *) "None", (uint8_t *) "CRC32C\0None\0", ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_LIST, 0L },
@@ -61,7 +61,7 @@ static const iscsi_key_value_pair_lut_entry iscsi_connection_key_value_pair_lut[
{ NULL, NULL, NULL, ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_INVALID, 0L }
};
-/// iSCSI session key and value pair lookup table.
+/// iSCSI session negotation key and value pair lookup table.
static const iscsi_key_value_pair_lut_entry iscsi_session_key_value_pair_lut[] = {
{ (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_MAX_CONNECTIONS, (uint8_t *) "1", (uint8_t *) "1\065535\0", ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_NUM_MIN, ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_DISCOVERY_IGNORE },
{ (uint8_t *) ISCSI_LOGIN_AUTH_SESSION_TEXT_KEY_SEND_TARGETS, (uint8_t *) "", (uint8_t *) "\0", ISCSI_TEXT_KEY_VALUE_PAIR_TYPE_DECLARATIVE, ISCSI_TEXT_KEY_VALUE_PAIR_FLAGS_SPECIAL_HANDLING },
@@ -1179,7 +1179,7 @@ iscsi_bhs_packet *iscsi_append_ahs_packet(iscsi_bhs_packet *packet_data, const u
const uint32_t old_pkt_size = (const uint32_t) sizeof(struct iscsi_bhs_packet) + (packet_data->total_ahs_len << 2UL);
const uint32_t new_pkt_size = (uint32_t) (old_pkt_size + iscsi_align(ahs_len, ISCSI_ALIGN_SIZE));
- if ( new_pkt_size > (sizeof(struct iscsi_bhs_packet) + 1020UL) ) {
+ if ( new_pkt_size > (sizeof(struct iscsi_bhs_packet) + ISCSI_MAX_AHS_SIZE) ) {
logadd( LOG_ERROR, "iscsi_append_ahs_packet: Total numer of AHS packet size exceeds 255 DWORDs" );
return NULL;
@@ -1938,7 +1938,7 @@ static int iscsi_parse_text_key_value_pair(iscsi_hashmap *pairs, const uint8_t *
return -1L;
}
- uint8_t *hash_val = (uint8_t *) malloc( iscsi_align(val_len + 1UL, ISCSI_HASHMAP_KEY_ALIGN) );
+ uint8_t *hash_val = (uint8_t *) malloc( iscsi_align(val_len + 1UL, ISCSI_HASHMAP_VALUE_ALIGN) );
if ( hash_val == NULL ) {
logadd( LOG_ERROR, "iscsi_parse_text_key_value_pair: Out of memory allocating memory for value string" );
@@ -2100,7 +2100,7 @@ static int iscsi_add_key_value_pair(iscsi_hashmap *key_value_pairs, const uint8_
}
const uint val_len = (uint) strlen( (char *) value ) + 1;
- uint8_t *hash_val = (uint8_t *) malloc( iscsi_align(val_len, ISCSI_HASHMAP_KEY_ALIGN) );
+ uint8_t *hash_val = (uint8_t *) malloc( iscsi_align(val_len, ISCSI_HASHMAP_VALUE_ALIGN) );
if ( hash_val == NULL ) {
logadd( LOG_ERROR, "iscsi_add_key_value_pair: Out of memory allocating string value" );
@@ -2144,7 +2144,7 @@ static int iscsi_update_key_value_pair(iscsi_hashmap *key_value_pairs, const uin
}
const uint val_len = (uint) strlen( (char *) value ) + 1;
- uint8_t *hash_val = (uint8_t *) malloc( iscsi_align(val_len, ISCSI_HASHMAP_KEY_ALIGN) );
+ uint8_t *hash_val = (uint8_t *) malloc( iscsi_align(val_len, ISCSI_HASHMAP_VALUE_ALIGN) );
if ( hash_val == NULL ) {
logadd( LOG_ERROR, "iscsi_update_key_value_pair: Out of memory allocating string value" );
@@ -3063,6 +3063,7 @@ iscsi_connection *iscsi_connection_create(iscsi_portal *portal, const int sock)
conn->data_digest = 0L;
conn->pdu_processing = NULL;
conn->login_response_pdu = NULL;
+ conn->id = 0L;
conn->sock = sock;
conn->pdu_recv_state = ISCSI_CONNECT_PDU_RECV_STATE_WAIT_PDU_READY;
conn->flags = 0L;
@@ -3653,7 +3654,7 @@ int iscsi_negotiate_key_value_pair_callback(uint8_t *key, const size_t key_size,
max_burst_len = (rc < 0) ? ISCSI_SESSION_DEFAULT_MAX_BURST_LEN : (uint) atol( (char *) max_burst_len_val );
- if ( (first_burst_len < 16777215) && (first_burst_len > max_burst_len) )
+ if ( (first_burst_len < ISCSI_MAX_DS_SIZE) && (first_burst_len > max_burst_len) )
sprintf( (char *) value, "%d", first_burst_len );
}
@@ -3901,7 +3902,7 @@ static int iscsi_connection_update_key_value_pairs(iscsi_connection *conn)
else if ( recv_buf_len > 8192 )
recv_buf_len = 8192UL;
- recv_buf_len += (uint) (sizeof(struct iscsi_bhs_packet) + 1020UL + conn->header_digest + conn->data_digest); // BHS + maximum AHS size + header and data digest overhead
+ recv_buf_len += (uint) (sizeof(struct iscsi_bhs_packet) + ISCSI_MAX_AHS_SIZE + conn->header_digest + conn->data_digest); // BHS + maximum AHS size + header and data digest overhead
recv_buf_len <<= 2UL; // Receive up to four streams at once.
setsockopt( conn->sock, SOL_SOCKET, SO_RCVBUF, &recv_buf_len, sizeof(recv_buf_len)); // Not being able to set the buffer is NOT fatal, so ignore error.
@@ -4570,20 +4571,20 @@ static int iscsi_connection_handle_reject(iscsi_connection *conn, iscsi_pdu *pdu
iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn );
if ( response_pdu == NULL ) {
- logadd( LOG_ERROR, "iscsi_pdu_create: Out of memory while allocating iSCSI reject response PDU" );
+ logadd( LOG_ERROR, "iscsi_connection_handle_reject: Out of memory while allocating iSCSI reject response PDU" );
- return -1L;
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
}
const uint32_t ds_len = (uint32_t) sizeof(struct iscsi_bhs_packet) + ((uint32_t) pdu->bhs_pkt->total_ahs_len << 2UL) + conn->header_digest;
- iscsi_reject_packet *reject_pkt = (iscsi_reject_packet *) iscsi_append_ds_packet( pdu->bhs_pkt, conn->header_digest, ds_len, conn->data_digest );
+ iscsi_reject_packet *reject_pkt = (iscsi_reject_packet *) iscsi_append_ds_packet( response_pdu->bhs_pkt, conn->header_digest, ds_len, conn->data_digest );
if ( reject_pkt == NULL ) {
- logadd( LOG_ERROR, "iscsi_pdu_create: Out of memory while allocating iSCSI reject packet data" );
+ logadd( LOG_ERROR, "iscsi_connection_handle_reject: Out of memory while allocating iSCSI reject packet data" );
iscsi_connection_pdu_destroy( response_pdu );
- return -1L;
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
}
response_pdu->bhs_pkt = (iscsi_bhs_packet *) reject_pkt;
@@ -4620,7 +4621,7 @@ static int iscsi_connection_handle_reject(iscsi_connection *conn, iscsi_pdu *pdu
iscsi_connection_pdu_write( conn, response_pdu, NULL, NULL );
- return 0L;
+ return ISCSI_CONNECT_PDU_READ_OK;
}
/**
@@ -4706,9 +4707,23 @@ static int iscsi_connection_pdu_header_handle_login_req(iscsi_connection *conn,
*/
static int iscsi_connection_pdu_header_handle_nop_out(iscsi_connection *conn, iscsi_pdu *pdu)
{
- // TODO: Implement opcode.
+ if ( conn->session->type == ISCSI_SESSION_TYPE_DISCOVERY )
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
- return 0;
+ if ( pdu->ds_len > ISCSI_DEFAULT_MAX_RECV_DS_LEN )
+ return iscsi_connection_handle_reject( conn, pdu, ISCSI_REJECT_REASON_PROTOCOL_ERR );
+
+ iscsi_nop_out_packet *nop_out_pkt = (iscsi_nop_out_packet *) pdu->bhs_pkt;
+ const uint32_t init_task_tag = iscsi_get_be32(nop_out_pkt->init_task_tag);
+ const uint32_t target_xfer_tag = iscsi_get_be32(nop_out_pkt->target_xfer_tag);
+
+ if ( (target_xfer_tag != 0xFFFFFFFFUL) && (target_xfer_tag != conn->id) )
+ return iscsi_connection_handle_reject( conn, pdu, ISCSI_REJECT_REASON_INVALID_PDU_FIELD ); // TODO: Check if this is the correct error code.
+
+ if ( (init_task_tag == 0xFFFFFFFFUL) && (nop_out_pkt->opcode & 0x40) == 0 )
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+
+ return 0L;
}
/**
@@ -4950,9 +4965,72 @@ static int iscsi_connection_pdu_header_handle(iscsi_connection *conn, iscsi_pdu
*/
static int iscsi_connection_pdu_data_handle_nop_out(iscsi_connection *conn, iscsi_pdu *pdu)
{
- // TODO: Implement opcode.
+ iscsi_nop_out_packet *nop_out_pkt = (iscsi_nop_out_packet *) pdu->bhs_pkt;
+ uint32_t ds_len = pdu->ds_len;
- return 0L;
+ if ( ds_len > conn->max_recv_ds_len )
+ ds_len = conn->max_recv_ds_len;
+
+ const uint64_t lun = iscsi_get_be64(nop_out_pkt->lun);
+ const uint32_t init_task_tag = iscsi_get_be32(nop_out_pkt->init_task_tag);
+
+ conn->flags &= ~ISCSI_CONNECT_FLAGS_NOP_OUTSTANDING;
+
+ if ( init_task_tag == 0xFFFFFFFFUL )
+ return ISCSI_CONNECT_PDU_READ_OK;
+
+ iscsi_pdu *response_pdu = iscsi_connection_pdu_create( conn );
+
+ if ( response_pdu == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_pdu_data_handle_nop_out: Out of memory while allocating iSCSI NOP-In response PDU" );
+
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+
+ iscsi_nop_in_packet *nop_in_pkt = (iscsi_nop_in_packet *) iscsi_append_ds_packet( response_pdu->bhs_pkt, conn->header_digest, ds_len, conn->data_digest );
+
+ if ( nop_in_pkt == NULL ) {
+ logadd( LOG_ERROR, "iscsi_connection_pdu_data_handle_nop_out: Out of memory while allocating iSCSI NOP-In packet data" );
+
+ iscsi_connection_pdu_destroy( response_pdu );
+
+ return ISCSI_CONNECT_PDU_READ_ERR_FATAL;
+ }
+
+ response_pdu->bhs_pkt = (iscsi_bhs_packet *) nop_in_pkt;
+
+ if ( conn->header_digest != 0 ) {
+ response_pdu->header_digest = (iscsi_header_digest *) (((iscsi_bhs_packet *) nop_in_pkt) + 1);
+ response_pdu->header_digest_size = conn->header_digest;
+ }
+
+ response_pdu->ds_cmd_data = (iscsi_ds_cmd_data *) (((uint8_t *) nop_in_pkt) + sizeof(struct iscsi_bhs_packet) + conn->header_digest);
+ response_pdu->ds_len = ds_len;
+
+ if ( conn->data_digest != 0 ) {
+ response_pdu->data_digest = (iscsi_data_digest *) (((uint8_t *) response_pdu->ds_cmd_data) + iscsi_align(ds_len, ISCSI_ALIGN_SIZE));
+ response_pdu->data_digest_size = conn->data_digest;
+ }
+
+ nop_in_pkt->opcode = ISCSI_SERVER_NOP_IN;
+ nop_in_pkt->flags = -0x80;
+ iscsi_put_be24( (uint8_t *) &nop_in_pkt->ds_len, ds_len );
+ iscsi_put_be64( (uint8_t *) &nop_in_pkt->lun, lun );
+ nop_in_pkt->target_xfer_tag = 0xFFFFFFFFUL;
+ iscsi_put_be32( (uint8_t *) &nop_in_pkt->init_task_tag, init_task_tag );
+ iscsi_put_be32( (uint8_t *) &nop_in_pkt->stat_sn, conn->stat_sn++ );
+
+ if ( (nop_out_pkt->opcode & 0x40) == 0 )
+ conn->session->max_cmd_sn++;
+
+ iscsi_put_be32( (uint8_t *) &nop_in_pkt->exp_cmd_sn, conn->session->exp_cmd_sn );
+ iscsi_put_be32( (uint8_t *) &nop_in_pkt->max_cmd_sn, conn->session->max_cmd_sn );
+
+ iscsi_connection_pdu_write( conn, response_pdu, NULL, NULL );
+
+ // conn->nop_in_last = iscsi_get_ticks();
+
+ return ISCSI_CONNECT_PDU_READ_OK;
}
/**