diff --git a/SCTP_SocketAPI_Status.md b/SCTP_SocketAPI_Status.md index bc1c9aa7a1dc3f2eda063364130cdfdbbdc6f474..fa76244c3fae986bc51c8903771b15abdaae3da2 100644 --- a/SCTP_SocketAPI_Status.md +++ b/SCTP_SocketAPI_Status.md @@ -30,6 +30,9 @@ For Linux the following tables are based on [sctp.h](https://github.com/sctp/lks |`SCTP_SENDER_DRY_EVENT` | [RFC6458](https://tools.ietf.org/html/rfc6458#section-6.1.9) | [RFC4960](https://tools.ietf.org/html/rfc4960) | supported | supported | supported | |`SCTP_NOTIFICATIONS_STOPPED_EVENT` | [RFC6458](https://tools.ietf.org/html/rfc6458#section-6.1.10) | [RFC4960](https://tools.ietf.org/html/rfc4960) | supported | unsupported | unsupported | |`SCTP_SEND_FAILED_EVENT` | [RFC6458](https://tools.ietf.org/html/rfc6458#section-6.1.10) | [RFC4960](https://tools.ietf.org/html/rfc4960) | supported | unsupported | supported | +|`SCTP_STREAM_RESET_EVENT` | [RFC6525](https://tools.ietf.org/html/rfc6525#section-6.1.1) | [RFC6525](https://tools.ietf.org/html/rfc6525) | supported | unsupported | supported | +|`SCTP_ASSOC_RESET_EVENT` | [RFC6525](https://tools.ietf.org/html/rfc6525#section-6.1.2) | [RFC6525](https://tools.ietf.org/html/rfc6525) | supported | unsupported | supported | +|`SCTP_STREAM_CHANGE_EVENT` | [RFC6525](https://tools.ietf.org/html/rfc6525#section-6.1.3) | [RFC6525](https://tools.ietf.org/html/rfc6525) | supported | unsupported | supported | ## SCTP Socket Options |Name | API Spec | Protocol Spec | packetdrill | Linux | FreeBSD | @@ -74,6 +77,10 @@ For Linux the following tables are based on [sctp.h](https://github.com/sctp/lks |`SCTP_AUTH_KEY` | [RFC6458](https://tools.ietf.org/html/rfc6458#section-8.3.3) | [RFC4895](https://tools.ietf.org/html/rfc4895) | unsupported | supported | supported | |`SCTP_AUTH_DEACTIVATE_KEY` | [RFC6458](https://tools.ietf.org/html/rfc6458#section-8.3.4) | [RFC4895](https://tools.ietf.org/html/rfc4895) | unsupported | unsupported | supported | |`SCTP_AUTH_DELETE_KEY` | [RFC6458](https://tools.ietf.org/html/rfc6458#section-8.3.5) | [RFC4895](https://tools.ietf.org/html/rfc4895) | unsupported | supported | supported | +|`SCTP_ENABLE_STREAM_RESET` | [RFC6525](https://tools.ietf.org/html/rfc6525#page-28) | [RFC6525](https://tools.ietf.org/html/rfc6525) | supported | unsupported | supported | +|`SCTP_RESET_STREAMS` | [RFC6525](https://tools.ietf.org/html/rfc6525#page-29) | [RFC6525](https://tools.ietf.org/html/rfc6525) | supported | unsupported | supported | +|`SCTP_RESET_ASSOC` | [RFC6525](https://tools.ietf.org/html/rfc6525#section-6.3.2) | [RFC6525](https://tools.ietf.org/html/rfc6525) | supported | unsupported | supported | +|`SCTP_ADD_STREAMS` | [RFC6525](https://tools.ietf.org/html/rfc6525#page-30) | [RFC6525](https://tools.ietf.org/html/rfc6525) | supported | unsupported | supported | ## SCTP Functions diff --git a/gtests/net/packetdrill/parser.y b/gtests/net/packetdrill/parser.y index ecb74c63b45917a779c0e47f583cb8ec877f2c97..ab4268807a8cad6c0ea62b98dd0e657c0fde87e6 100644 --- a/gtests/net/packetdrill/parser.y +++ b/gtests/net/packetdrill/parser.y @@ -674,7 +674,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <chunk_list_item> sctp_shutdown_complete_chunk_spec %type <chunk_list_item> sctp_i_data_chunk_spec %type <chunk_list_item> sctp_pad_chunk_spec sctp_reconfig_chunk_spec -%type <parameter_list> opt_parameter_list_spec sctp_parameter_list_spec sctp_reconfig_parameter_list_spec +%type <parameter_list> opt_parameter_list_spec sctp_parameter_list_spec %type <parameter_list_item> sctp_parameter_spec %type <parameter_list_item> sctp_generic_parameter_spec %type <parameter_list_item> sctp_heartbeat_information_parameter_spec @@ -688,7 +688,7 @@ static struct tcp_option *new_tcp_fast_open_option(const char *cookie_string, %type <parameter_list_item> sctp_ecn_capable_parameter_spec %type <parameter_list_item> sctp_supported_extensions_parameter_spec %type <parameter_list_item> sctp_adaptation_indication_parameter_spec -%type <parameter_list_item> sctp_pad_parameter_spec sctp_reconfig_parameter_spec +%type <parameter_list_item> sctp_pad_parameter_spec %type <parameter_list_item> outgoing_ssn_reset_request incoming_ssn_reset_request %type <parameter_list_item> reconfig_response ssn_tsn_reset_request generic_reconfig_request %type <parameter_list_item> add_outgoing_streams_request add_incoming_streams_request @@ -1734,27 +1734,6 @@ opt_result | RESULT '=' ELLIPSIS { $$ = -1; } ; -sctp_reconfig_parameter_list_spec -: sctp_reconfig_parameter_spec { - $$ = sctp_parameter_list_new(); - sctp_parameter_list_append($$, $1); -} -| sctp_reconfig_parameter_list_spec ',' sctp_reconfig_parameter_spec { - $$ = $1; - sctp_parameter_list_append($1, $3); -} -; - -sctp_reconfig_parameter_spec -: outgoing_ssn_reset_request { $$ = $1; } -| incoming_ssn_reset_request { $$ = $1; } -| ssn_tsn_reset_request { $$ = $1; } -| reconfig_response { $$ = $1; } -| add_outgoing_streams_request { $$ = $1; } -| add_incoming_streams_request { $$ = $1; } -| generic_reconfig_request { $$ = $1; } -; - opt_sender_next_tsn : SENDER_NEXT_TSN '=' INTEGER { if (!is_valid_u32($3)) { @@ -1849,11 +1828,8 @@ generic_reconfig_request ; sctp_reconfig_chunk_spec -: RECONFIG '[' opt_flags ',' sctp_reconfig_parameter_list_spec ']' { - $$ = sctp_reconfig_chunk_new($3, $5); -} -| RECONFIG '[' opt_flags ']' { - $$ = sctp_reconfig_chunk_new($3, NULL); +: RECONFIG '[' opt_flags opt_parameter_list_spec ']' { + $$ = sctp_reconfig_chunk_new($3, $4); } ; @@ -1884,6 +1860,13 @@ sctp_parameter_spec | sctp_supported_extensions_parameter_spec { $$ = $1; } | sctp_adaptation_indication_parameter_spec { $$ = $1; } | sctp_pad_parameter_spec { $$ = $1; } +| outgoing_ssn_reset_request { $$ = $1; } +| incoming_ssn_reset_request { $$ = $1; } +| ssn_tsn_reset_request { $$ = $1; } +| reconfig_response { $$ = $1; } +| add_outgoing_streams_request { $$ = $1; } +| add_incoming_streams_request { $$ = $1; } +| generic_reconfig_request { $$ = $1; } ; opt_parameter_type diff --git a/gtests/net/packetdrill/run_packet.c b/gtests/net/packetdrill/run_packet.c index 0df2fc2e0c27796bbfe02de963b676b1ae4ea4e3..56fd664b00fbcb57afc1a4cb433206c71185fb1f 100644 --- a/gtests/net/packetdrill/run_packet.c +++ b/gtests/net/packetdrill/run_packet.c @@ -661,7 +661,6 @@ static int map_inbound_sctp_packet( reflect_v_tag = false; contains_init_chunk = false; - /* Map the TSNs and the initiate tags in the INIT and INIT-ACK chunk */ for (chunk = sctp_chunks_begin(live_packet, &iter, error); chunk != NULL; @@ -741,7 +740,7 @@ static int map_inbound_sctp_packet( break; case SCTP_RECONFIG_CHUNK_TYPE: reconfig = (struct sctp_reconfig_chunk *)chunk; - if (reconfig->length > sizeof(struct sctp_reconfig_chunk)) { + if (htons(reconfig->length) >= sizeof(struct sctp_reconfig_chunk) + 4) { struct sctp_parameter *parameter; struct sctp_parameters_iterator iter; int parameters_length = ntohs(reconfig->length) - sizeof(struct sctp_reconfig_chunk); @@ -753,29 +752,41 @@ static int map_inbound_sctp_packet( case SCTP_OUTGOING_SSN_RESET_REQUEST_PARAMETER_TYPE: { struct sctp_outgoing_ssn_reset_request_parameter *reset; reset = (struct sctp_outgoing_ssn_reset_request_parameter *)parameter; - reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); - reset->respsn = htonl(ntohl(reset->respsn) + local_diff); - reset->last_tsn = htonl(ntohl(reset->last_tsn) + remote_diff); + if (htons(reset->length) >= 8) { + reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + } + if (htons(reset->length) >= 12) { + reset->respsn = htonl(ntohl(reset->respsn) + local_diff); + } + if (htons(reset->length) >= 16) { + reset->last_tsn = htonl(ntohl(reset->last_tsn) + remote_diff); + } break; } case SCTP_INCOMING_SSN_RESET_REQUEST_PARAMETER_TYPE: { struct sctp_incoming_ssn_reset_request_parameter *reset; reset = (struct sctp_incoming_ssn_reset_request_parameter *)parameter; - reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + if (htons(reset->length) >= 8) { + reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + } break; } case SCTP_SSN_TSN_RESET_REQUEST_PARAMETER_TYPE: { struct sctp_ssn_tsn_reset_request_parameter *reset; reset = (struct sctp_ssn_tsn_reset_request_parameter *)parameter; - reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + if (htons(reset->length) >= 8) { + reset->reqsn = htonl(ntohl(reset->reqsn) + remote_diff); + } break; } case SCTP_RECONFIG_RESPONSE_PARAMETER_TYPE: { struct sctp_reconfig_response_parameter *response; response = (struct sctp_reconfig_response_parameter *)parameter; response->respsn = htonl(htonl(response->respsn) + local_diff); - if (htons(response->length) == sizeof(struct sctp_reconfig_response_parameter)) { + if (htons(response->length) >= 16) { response->receiver_next_tsn = htonl(htonl(response->receiver_next_tsn) + local_diff); + } + if (htons(response->length) >= 20) { response->sender_next_tsn = htonl(htonl(response->sender_next_tsn) + remote_diff); } break; @@ -783,13 +794,17 @@ static int map_inbound_sctp_packet( case SCTP_ADD_OUTGOING_STREAMS_REQUEST_PARAMETER_TYPE: { struct sctp_add_outgoing_streams_request_parameter *request; request = (struct sctp_add_outgoing_streams_request_parameter *)parameter; - request->reqsn = htonl(htonl(request->reqsn) + remote_diff); + if (htons(request->length) >= 8) { + request->reqsn = htonl(htonl(request->reqsn) + remote_diff); + } break; } case SCTP_ADD_INCOMING_STREAMS_REQUEST_PARAMETER_TYPE: { struct sctp_add_incoming_streams_request_parameter *request; request = (struct sctp_add_incoming_streams_request_parameter *)parameter; - request->reqsn = htonl(htonl(request->reqsn) + remote_diff); + if (htons(request->length) >= 8) { + request->reqsn = htonl(htonl(request->reqsn) + remote_diff); + } break; } default: diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index c69ca7beff1af76abf7cdc2b1cbd6a532ea28dba..ad3c651012dbd2ea561ffdd2e917a2e9e3477389 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -3360,6 +3360,30 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, } break; } +#endif +#ifdef SCTP_RESET_STREAMS + case EXPR_SCTP_RESET_STREAMS: + live_optval = malloc(sizeof(struct sctp_reset_streams)); + live_optlen = (socklen_t)sizeof(struct sctp_reset_streams); + if (get_sctp_assoc_t(val_expression->value.sctp_reset_streams->srs_assoc_id, + &((struct sctp_reset_streams *)live_optval)->srs_assoc_id, + error)) { + free(live_optval); + return STATUS_ERR; + } + break; +#endif +#ifdef SCTP_ADD_STREAMS + case EXPR_SCTP_ADD_STREAMS: + live_optval = malloc(sizeof(struct sctp_add_streams)); + live_optlen = (socklen_t)sizeof(struct sctp_add_streams); + if (get_sctp_assoc_t(val_expression->value.sctp_add_streams->sas_assoc_id, + &((struct sctp_add_streams *)live_optval)->sas_assoc_id, + error)) { + free(live_optval); + return STATUS_ERR; + } + break; #endif case EXPR_LIST: s32_bracketed_arg(args, 3, &script_optval, error); @@ -3491,6 +3515,16 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, case EXPR_SCTP_AUTHCHUNKS: result = check_sctp_authchunks(val_expression->value.sctp_authchunks, live_optval, error); break; +#endif +#ifdef SCTP_RESET_STREAMS + case EXPR_SCTP_RESET_STREAMS: + // SCTP_RESET_STREAMS should not be a successfull option + break; +#endif +#ifdef SCTP_ADD_STREAMS + case EXPR_SCTP_ADD_STREAMS: + // SCTP_ADD_STREAMS should not be a successfull option + break; #endif case EXPR_LIST: if (*(int*)live_optval != script_optval) { diff --git a/gtests/net/packetdrill/sctp_chunk_to_string.c b/gtests/net/packetdrill/sctp_chunk_to_string.c index ab647ae7de6e5d3307cc4a937aa8288be64404ae..5ef8e002c213442b32b6d6ae63c979f602d2a0e8 100644 --- a/gtests/net/packetdrill/sctp_chunk_to_string.c +++ b/gtests/net/packetdrill/sctp_chunk_to_string.c @@ -328,6 +328,12 @@ static int sctp_outgoing_ssn_reset_request_parameter_to_string( int len; length = ntohs(parameter->length); + if (length < sizeof(struct sctp_outgoing_ssn_reset_request_parameter)) { + fputs("invalid OUTGOING_SSN_RESET_REQUEST parameter", s); + asprintf(error, "OUTGOING_SSN_RESET_REQUEST parameter illegal (length=%u)", + length); + return STATUS_ERR; + } reqsn = ntohl(parameter->reqsn); respsn = ntohl(parameter->respsn); last_tsn = ntohl(parameter->last_tsn); @@ -358,10 +364,16 @@ static int sctp_incoming_ssn_reset_request_parameter_to_string( int len; length = ntohs(parameter->length); + if (length < sizeof(struct sctp_incoming_ssn_reset_request_parameter)) { + fputs("invalid INCOMING_SSN_RESET_REQUEST parameter", s); + asprintf(error, "INCOMING_SSN_RESET_REQUEST parameter illegal (length=%u)", + length); + return STATUS_ERR; + } reqsn = ntohl(parameter->reqsn); fputs("INCOMING_SSN_RESET[", s); fprintf(s, "len=%hu, ", length); - fprintf(s, "req_sn=%u ,", reqsn); + fprintf(s, "req_sn=%u, ", reqsn); fputs("sids=[", s); for(len = 0; len < ((length-8)/sizeof(u16)); len++) { u16 sid; @@ -383,6 +395,12 @@ static int sctp_ssn_tsn_reset_request_parameter_to_string( u32 reqsn; length = ntohs(parameter->length); + if (length != sizeof(struct sctp_ssn_tsn_reset_request_parameter)) { + fputs("invalid SSN_TSN_RESET_REQUEST parameter", s); + asprintf(error, "SSN_TSN_RESET_REQUEST parameter illegal (length=%u)", + length); + return STATUS_ERR; + } reqsn = ntohl(parameter->reqsn); fputs("SSN_TSN_RESET[", s); @@ -404,6 +422,14 @@ static int sctp_reconfig_response_parameter_to_string( u32 receiver_next_tsn; length = ntohs(parameter->length); + // filter correct length + if ((length != sizeof(struct sctp_reconfig_response_parameter)) && + (length != sizeof(struct sctp_reconfig_response_parameter) - 8)) { + fputs("invalid RECONFIG_RESPONSE parameter", s); + asprintf(error, "RECONFIG_RESPONSE parameter illegal (length=%u)", + length); + return STATUS_ERR; + } respsn = ntohl(parameter->respsn); result = ntohl(parameter->result); @@ -429,15 +455,24 @@ static int sctp_add_outgoing_streams_request_parameter_to_string( u16 length; u32 reqsn; u16 number_of_new_streams; + u16 reserved; length = ntohs(parameter->length); + if (length != sizeof(struct sctp_add_outgoing_streams_request_parameter)) { + fputs("invalid ADD_OUTGOING_STREAMS_REQUEST parameter", s); + asprintf(error, "ADD_OUTGOING_STREAMS_REQUEST parameter illegal (length=%u)", + length); + return STATUS_ERR; + } reqsn = ntohl(parameter->reqsn); number_of_new_streams = ntohs(parameter->number_of_new_streams); + reserved = ntohs(parameter->reserved); fputs("ADD_OUTGOING_STREAMS[", s); fprintf(s, "len=%hu, ", length); fprintf(s, "req_sn=%u, ", reqsn); - fprintf(s, "number_of_new_streams=%hu", number_of_new_streams); + fprintf(s, "number_of_new_streams=%hu, ", number_of_new_streams); + fprintf(s, "reserved=%hu", reserved); fputs("]", s); return STATUS_OK; } @@ -450,15 +485,24 @@ static int sctp_add_incoming_streams_request_parameter_to_string( u16 length; u32 reqsn; u16 number_of_new_streams; + u16 reserved; length = ntohs(parameter->length); + if (length != sizeof(struct sctp_add_incoming_streams_request_parameter)) { + fputs("invalid ADD_INCOMING_STREAMS_REQUEST parameter", s); + asprintf(error, "ADD_INCOMING_STREAMS_REQUEST parameter illegal (length=%u)", + length); + return STATUS_ERR; + } reqsn = ntohl(parameter->reqsn); number_of_new_streams = ntohs(parameter->number_of_new_streams); + reserved = ntohs(parameter->reserved); fputs("ADD_INCOMING_STREAMS[", s); fprintf(s, "len=%hu, ", length); fprintf(s, "req_sn=%u, ", reqsn); - fprintf(s, "number_of_new_streams=%hu", number_of_new_streams); + fprintf(s, "number_of_new_streams=%hu, ", number_of_new_streams); + fprintf(s, "reserved=%hu", reserved); fputs("]", s); return STATUS_OK; } @@ -1554,12 +1598,15 @@ static int sctp_reconfig_chunk_to_string( char **error) { u16 length; - int result, parameters_length; + int result = STATUS_OK; + int parameters_length; struct sctp_parameter *parameter; struct sctp_parameters_iterator iter; length = ntohs(chunk->length); - if (length < sizeof(struct sctp_reconfig_chunk)) { + if (length < sizeof(struct sctp_reconfig_chunk) || + (length > sizeof(struct sctp_reconfig_chunk) && + length < sizeof(struct sctp_reconfig_chunk) + 4)) { asprintf(error, "RECONFIG chunk too short (length=%u)", length); return STATUS_ERR; } @@ -1567,21 +1614,23 @@ static int sctp_reconfig_chunk_to_string( fputs("RECONFIG[", s); fprintf(s, "flgs=0x%02x, ", chunk->flags); fprintf(s, "len=%u", length); - - for (parameter = sctp_parameters_begin(chunk->parameter, - parameters_length, - &iter, error); - parameter != NULL; - parameter = sctp_parameters_next(&iter, error)) { - fputs(", ", s); - if (*error != NULL) - break; - result = sctp_parameter_to_string(s, parameter, error); - if (result != STATUS_OK) - break; + + if (length >= sizeof(struct sctp_reconfig_chunk) + 4) { + for (parameter = sctp_parameters_begin(chunk->parameter, + parameters_length, + &iter, error); + parameter != NULL; + parameter = sctp_parameters_next(&iter, error)) { + fputs(", ", s); + if (*error != NULL) + break; + result = sctp_parameter_to_string(s, parameter, error); + if (result != STATUS_OK) + break; + } } fputs("]", s); - return STATUS_OK; + return result; } static int sctp_unknown_chunk_to_string(FILE *s, diff --git a/gtests/net/packetdrill/sctp_packet.h b/gtests/net/packetdrill/sctp_packet.h index 7581f207e72d32e1df27900dd80f5416d09657b8..01922281002eb68be2b2e7a26de9f6803bc744e5 100644 --- a/gtests/net/packetdrill/sctp_packet.h +++ b/gtests/net/packetdrill/sctp_packet.h @@ -1,4 +1,3 @@ - /* * Copyright 2015 Michael Tuexen *