diff --git a/examples/coap-client.c b/examples/coap-client.c index 3ce9f7df..73835818 100644 --- a/examples/coap-client.c +++ b/examples/coap-client.c @@ -318,6 +318,7 @@ event_handler(coap_session_t *session COAP_UNUSED, case COAP_EVENT_OSCORE_DECODE_ERROR: case COAP_EVENT_WS_PACKET_SIZE: case COAP_EVENT_WS_CLOSED: + case COAP_EVENT_BAD_PACKET: quit = 1; break; case COAP_EVENT_DTLS_CONNECTED: @@ -331,7 +332,6 @@ event_handler(coap_session_t *session COAP_UNUSED, case COAP_EVENT_XMIT_BLOCK_FAIL: case COAP_EVENT_SERVER_SESSION_NEW: case COAP_EVENT_SERVER_SESSION_DEL: - case COAP_EVENT_BAD_PACKET: case COAP_EVENT_MSG_RETRANSMITTED: case COAP_EVENT_WS_CONNECTED: case COAP_EVENT_KEEPALIVE_FAILURE: @@ -357,7 +357,6 @@ nack_handler(coap_session_t *session COAP_UNUSED, switch (reason) { case COAP_NACK_TOO_MANY_RETRIES: case COAP_NACK_NOT_DELIVERABLE: - case COAP_NACK_RST: case COAP_NACK_TLS_FAILED: case COAP_NACK_WS_FAILED: case COAP_NACK_TLS_LAYER_FAILED: @@ -365,8 +364,15 @@ nack_handler(coap_session_t *session COAP_UNUSED, coap_log_err("cannot send CoAP pdu\n"); quit = 1; break; - case COAP_NACK_ICMP_ISSUE: + case COAP_NACK_RST: + coap_log_info("received RST pdu response\n"); + quit = 1; + break; case COAP_NACK_BAD_RESPONSE: + coap_log_info("received bad response pdu\n"); + quit = 1; + break; + case COAP_NACK_ICMP_ISSUE: default: ; } diff --git a/include/coap3/coap_net_internal.h b/include/coap3/coap_net_internal.h index 9aafb6c0..80ce3d4b 100644 --- a/include/coap3/coap_net_internal.h +++ b/include/coap3/coap_net_internal.h @@ -393,6 +393,16 @@ coap_pdu_t *coap_wellknown_response(coap_context_t *context, */ unsigned int coap_calc_timeout(coap_session_t *session, unsigned char r); +/** + * Check whether the pdu contains a valid code class + * + * @param session The CoAP session. + * @param pdu The PDU to check. + * + * @return @c 1 valid, @c 0 invalid. + */ +int coap_check_code_class(coap_session_t *session, coap_pdu_t *pdu); + /** * Sends a CoAP message to given peer. The memory that is * allocated for the pdu will be released by coap_send_internal(). diff --git a/include/coap3/coap_pdu_internal.h b/include/coap3/coap_pdu_internal.h index df2aa6d6..767036d7 100644 --- a/include/coap3/coap_pdu_internal.h +++ b/include/coap3/coap_pdu_internal.h @@ -100,7 +100,8 @@ #define COAP_PDU_IS_EMPTY(pdu) ((pdu)->code == 0) #define COAP_PDU_IS_REQUEST(pdu) (!COAP_PDU_IS_EMPTY(pdu) && (pdu)->code < 32) -#define COAP_PDU_IS_RESPONSE(pdu) ((pdu)->code >= 64 && (pdu)->code < 224) +/* Code 1.xx (32-63) and 6.xx (192-224) currently invalid */ +#define COAP_PDU_IS_RESPONSE(pdu) ((pdu)->code >= 64 && (pdu)->code < 192) #define COAP_PDU_IS_SIGNALING(pdu) ((pdu)->code >= 224) #define COAP_PDU_IS_PING(pdu) ((COAP_PDU_IS_EMPTY(pdu) && \ ((pdu)->type == COAP_MESSAGE_CON)) || \ diff --git a/src/coap_net.c b/src/coap_net.c index 3f636442..1bdad675 100644 --- a/src/coap_net.c +++ b/src/coap_net.c @@ -1076,6 +1076,34 @@ coap_client_delay_first(coap_session_t *session) { return 1; } +/* + * return 0 Invalid + * 1 Valid + */ +int +coap_check_code_class(coap_session_t *session, coap_pdu_t *pdu) { + + /* Check validity of sending code */ + switch (COAP_RESPONSE_CLASS(pdu->code)) { + case 0: /* Empty or request */ + case 2: /* Success */ + case 3: /* Reserved for future use */ + case 4: /* Client error */ + case 5: /* Server error */ + break; + case 7: /* Reliable signalling */ + if (COAP_PROTO_RELIABLE(session->proto)) + break; + /* Not valid if UDP */ + /* Fall through */ + case 1: /* Invalid */ + case 6: /* Invalid */ + default: + return 0; + } + return 1; +} + coap_mid_t coap_send(coap_session_t *session, coap_pdu_t *pdu) { coap_mid_t mid = COAP_INVALID_MID; @@ -1091,6 +1119,14 @@ coap_send(coap_session_t *session, coap_pdu_t *pdu) { assert(pdu); coap_lock_check_locked(session->context); + + /* Check validity of sending code */ + if (!coap_check_code_class(session, pdu)) { + coap_log_err("coap_send: Invalid PDU code (%d.%02d)\n", + COAP_RESPONSE_CLASS(pdu->code), + pdu->code & 0x1f); + goto error; + } pdu->session = session; #if COAP_CLIENT_SUPPORT if (session->type == COAP_SESSION_TYPE_CLIENT && @@ -1416,11 +1452,9 @@ send_it: #endif /* COAP_CLIENT_SUPPORT */ return mid; -#if COAP_CLIENT_SUPPORT error: coap_delete_pdu(pdu); return COAP_INVALID_MID; -#endif } coap_mid_t @@ -3222,6 +3256,14 @@ handle_request(coap_context_t *context, coap_session_t *session, coap_pdu_t *pdu coap_lock_callback(context, h(resource, session, pdu, query, response)); + /* Check validity of response code */ + if (!coap_check_code_class(session, response)) { + coap_log_warn("handle_request: Invalid PDU response code (%d.%02d)\n", + COAP_RESPONSE_CLASS(response->code), + response->code & 0x1f); + goto drop_it_no_debug; + } + /* Check if lg_xmit generated and update PDU code if so */ coap_check_code_lg_xmit(session, pdu, response, resource, query); @@ -3603,6 +3645,20 @@ coap_dispatch(coap_context_t *context, coap_session_t *session, pdu->session = session; coap_show_pdu(COAP_LOG_DEBUG, pdu); + /* Check validity of received code */ + if (!coap_check_code_class(session, pdu)) { + coap_log_info("coap_dispatch: Received invalid PDU code (%d.%02d)\n", + COAP_RESPONSE_CLASS(pdu->code), + pdu->code & 0x1f); + packet_is_bad = 1; + if (pdu->type == COAP_MESSAGE_CON) { + coap_send_message_type(session, pdu, COAP_MESSAGE_RST); + } + /* find message id in sendqueue to stop retransmission */ + coap_remove_from_queue(&context->sendqueue, session, pdu->mid, &sent); + goto cleanup; + } + coap_option_filter_clear(&opt_filter); #if COAP_OSCORE_SUPPORT @@ -3917,7 +3973,8 @@ coap_dispatch(coap_context_t *context, coap_session_t *session, } } } else { - coap_send_message_type(session, pdu, COAP_MESSAGE_RST); + if (pdu->type == COAP_MESSAGE_CON) + coap_send_message_type(session, pdu, COAP_MESSAGE_RST); } } } diff --git a/src/coap_resource.c b/src/coap_resource.c index 21123656..ba03d35c 100644 --- a/src/coap_resource.c +++ b/src/coap_resource.c @@ -1108,6 +1108,15 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r, coap_lock_callback(obs->session->context, h(r, obs->session, obs->pdu, query, response)); + /* Check validity of response code */ + if (!coap_check_code_class(obs->session, response)) { + coap_log_warn("handle_request: Invalid PDU response code (%d.%02d)\n", + COAP_RESPONSE_CLASS(response->code), + response->code & 0x1f); + coap_delete_pdu(response); + return; + } + /* Check if lg_xmit generated and update PDU code if so */ coap_check_code_lg_xmit(obs->session, obs->pdu, response, r, query); coap_delete_string(query);