Skip to content

Commit

Permalink
Connection-ID: Support changing client IP addresses
Browse files Browse the repository at this point in the history
Support of RFC9146. Currently only Mbed TLS supported.

New function coap_context_set_cid_tuple_change() for a client to
force periodic source port changes to test out CID.

Configurable support for the client to use Connection-ID
assuming underlying DTLS library is configured for or supports it.
  • Loading branch information
mrdeep1 committed Jul 22, 2024
1 parent b75c784 commit 8b2fb39
Show file tree
Hide file tree
Showing 24 changed files with 238 additions and 51 deletions.
22 changes: 20 additions & 2 deletions examples/coap-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ static coap_uri_t proxy = { {0, NULL}, 0, {0, NULL}, {0, NULL}, 0 };
static int proxy_scheme_option = 0;
static int uri_host_option = 0;
static unsigned int ping_seconds = 0;
static int setup_cid = 0;

#define REPEAT_DELAY_MS 1000
static size_t repeat_count = 1;
Expand Down Expand Up @@ -510,7 +511,8 @@ usage(const char *program, const char *version) {
"\t\t[-E oscore_conf_file[,seq_file]] [-G count] [-H hoplimit]\n"
"\t\t[-K interval] [-N] [-O num,text] [-P scheme://address[:port]\n"
"\t\t[-T token] [-U] [-V num] [-X size]\n"
"\t\t[[-h match_hint_file] [-k key] [-u user] [-2]]\n"
"\t\t[[-d count]]\n"
"\t\t[[h match_hint_file] [-k key] [-u user] [-2]]\n"
"\t\t[[-c certfile] [-j keyfile] [-n] [-C cafile]\n"
"\t\t[-J pkcs11_pin] [-M raw_pk] [-R trust_casfile]] URI\n"
"\tURI can be an absolute URI or a URI prefixed with scheme and host\n\n"
Expand Down Expand Up @@ -576,6 +578,13 @@ usage(const char *program, const char *version) {
"\t-X size\t\tMaximum message size to use for TCP based connections\n"
"\t \t\t(default is 8388864). Maximum value of 2^32 -1\n"
,program, wait_seconds);
fprintf(stderr,
"DTLS Options (if supported by underlying (D)TLS library)\n"
"\t-d count\n"
"\t \t\tFor DTLS, enable use of Connection-ID. If count\n"
"\t \t\tis not 0, then the client will changes its source port\n"
"\t \t\tevery count packets to test CID\n"
);
fprintf(stderr,
"PSK Options (if supported by underlying (D)TLS library)\n"
"\t-h match_hint_file\n"
Expand Down Expand Up @@ -1408,6 +1417,7 @@ setup_pki(coap_context_t *ctx) {
dtls_pki.verify_peer_cert = verify_peer_cert;
}
dtls_pki.is_rpk_not_cert = is_rpk_not_cert;
dtls_pki.use_cid = setup_cid;
dtls_pki.validate_cn_call_back = verify_cn_callback;
if (proxy.host.length) {
snprintf(client_sni, sizeof(client_sni), "%*.*s", (int)proxy.host.length, (int)proxy.host.length,
Expand Down Expand Up @@ -1470,6 +1480,7 @@ setup_psk(const uint8_t *identity,
memset(&dtls_psk, 0, sizeof(dtls_psk));
dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;
dtls_psk.ec_jpake = ec_jpake;
dtls_psk.use_cid = setup_cid;
if (valid_ihs.count) {
dtls_psk.validate_ih_call_back = verify_ih_callback;
}
Expand Down Expand Up @@ -1658,6 +1669,7 @@ main(int argc, char **argv) {
uint8_t *data = NULL;
size_t data_len = 0;
coap_addr_info_t *info_list = NULL;
uint8_t cid_every = 0;
#ifndef _WIN32
struct sigaction sa;
#endif
Expand All @@ -1666,7 +1678,7 @@ main(int argc, char **argv) {
coap_startup();

while ((opt = getopt(argc, argv,
"a:b:c:e:f:h:j:k:l:m:no:p:q:rs:t:u:v:wA:B:C:E:G:H:J:K:L:M:NO:P:R:T:UV:X:2")) != -1) {
"a:b:c:d:e:f:h:j:k:l:m:no:p:q:rs:t:u:v:wA:B:C:E:G:H:J:K:L:M:NO:P:R:T:UV:X:2")) != -1) {
switch (opt) {
case 'a':
strncpy(node_str, optarg, NI_MAXHOST - 1);
Expand All @@ -1688,6 +1700,10 @@ main(int argc, char **argv) {
case 'R':
root_ca_file = optarg;
break;
case 'd':
cid_every = atoi(optarg);
setup_cid = 1;
break;
case 'e':
if (!cmdline_input(optarg, &payload))
payload.length = 0;
Expand Down Expand Up @@ -1908,6 +1924,8 @@ main(int argc, char **argv) {
coap_register_nack_handler(ctx, nack_handler);
if (the_token.length > COAP_TOKEN_DEFAULT_MAX)
coap_context_set_max_token_size(ctx, the_token.length);
if (cid_every)
coap_context_set_cid_tuple_change(ctx, cid_every);

session = get_session(ctx,
node_str[0] ? node_str : NULL,
Expand Down
12 changes: 8 additions & 4 deletions include/coap3/coap_dtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,12 @@ struct coap_dtls_pki_t {
uint8_t is_rpk_not_cert; /**< 1 is RPK instead of Public Certificate.
* If set, PKI key format type cannot be
* COAP_PKI_KEY_PEM */
uint8_t reserved[3]; /**< Reserved - must be set to 0 for
uint8_t use_cid; /**< 1 if DTLS Connection ID is to be
* used (Client only, server always enabled)
* if supported */
uint8_t reserved[2]; /**< Reserved - must be set to 0 for
future compatibility */
/* Size of 3 chosen to align to next
/* Size of 2 chosen to align to next
* parameter, so if newly defined option
* it can use one of the reserved slots so
* no need to change
Expand Down Expand Up @@ -453,9 +456,10 @@ typedef struct coap_dtls_cpsk_t {
/* Options to enable different TLS functionality in libcoap */
uint8_t ec_jpake; /**< Set to 1 if EC-JPAKE is to be used.
Currently Mbed TLS only */
uint8_t reserved[6]; /**< Reserved - must be set to 0 for
uint8_t use_cid; /**< Set to 1 if DTLS Connection ID is to be used */
uint8_t reserved[5]; /**< Reserved - must be set to 0 for
future compatibility */
/* Size of 6 chosen to align to next
/* Size of 5 chosen to align to next
* parameter, so if newly defined option
* it can use one of the reserverd slot so
* no need to change
Expand Down
2 changes: 1 addition & 1 deletion include/coap3/coap_dtls_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

/* For RFC9146 Connection ID support */
#ifndef COAP_DTLS_CID_LENGTH
#define COAP_DTLS_CID_LENGTH 6
#define COAP_DTLS_CID_LENGTH 8
#endif

typedef enum {
Expand Down
2 changes: 1 addition & 1 deletion include/coap3/coap_io_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ ssize_t coap_socket_send_pdu(coap_socket_t *sock, coap_session_t *session,
* @return The number of bytes written on success, or a value
* less than zero on error.
*/
ssize_t coap_socket_send(coap_socket_t *sock, const coap_session_t *session,
ssize_t coap_socket_send(coap_socket_t *sock, coap_session_t *session,
const uint8_t *data, size_t datalen);

/**
Expand Down
8 changes: 8 additions & 0 deletions include/coap3/coap_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,14 @@ COAP_API int coap_context_set_pki_root_cas(coap_context_t *context,
*/
void coap_context_set_keepalive(coap_context_t *context, unsigned int seconds);

/**
* Set the Connection ID client tuple frequency change for testing CIDs.
*
* @param context The coap_context_t object.
* @param every Change the client's source port @p every packets sent.
*/
void coap_context_set_cid_tuple_change(coap_context_t *context, uint8_t every);

/**
* Set the maximum token size (RFC8974).
*
Expand Down
3 changes: 3 additions & 0 deletions include/coap3/coap_net_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ struct coap_context_t {
uint8_t mcast_per_resource; /**< Mcast controlled on a per resource
basis */
#endif /* COAP_SERVER_SUPPORT */
#if COAP_CLIENT_SUPPORT
uint8_t testing_cids; /**< Change client's source port every testing_cids */
#endif /* COAP_CLIENT_SUPPORT */
uint32_t block_mode; /**< Zero or more COAP_BLOCK_ or'd options */
};

Expand Down
3 changes: 3 additions & 0 deletions include/coap3/coap_session_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,9 @@ struct coap_session_t {
been processed */
coap_response_t last_con_handler_res; /**< The result of calling the response handler
of the last CON */
#if COAP_SERVER_SUPPORT
coap_bin_const_t *client_cid; /**< Contains client CID or NULL */
#endif /* COAP_SERVER_SUPPORT */
};

#if COAP_SERVER_SUPPORT
Expand Down
1 change: 1 addition & 0 deletions libcoap-3.map
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ global:
coap_context_oscore_server;
coap_context_set_app_data;
coap_context_set_block_mode;
coap_context_set_cid_tuple_change;
coap_context_set_csm_max_message_size;
coap_context_set_csm_timeout;
coap_context_set_csm_timeout_ms;
Expand Down
1 change: 1 addition & 0 deletions libcoap-3.sym
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ coap_context_get_session_timeout
coap_context_oscore_server
coap_context_set_app_data
coap_context_set_block_mode
coap_context_set_cid_tuple_change
coap_context_set_csm_max_message_size
coap_context_set_csm_timeout
coap_context_set_csm_timeout_ms
Expand Down
1 change: 1 addition & 0 deletions man/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ install-man: install-man3 install-man5 install-man7
@echo ".so man3/coap_context.3" > coap_context_set_max_token_size.3
@echo ".so man3/coap_context.3" > coap_context_set_app_data.3
@echo ".so man3/coap_context.3" > coap_context_get_app_data.3
@echo ".so man3/coap_context.3" > coap_context_set_cid_tuple_change.3
@echo ".so man3/coap_deprecated.3" > coap_set_app_data.3
@echo ".so man3/coap_deprecated.3" > coap_get_app_data.3
@echo ".so man3/coap_deprecated.3" > coap_option_setb.3
Expand Down
10 changes: 10 additions & 0 deletions man/coap-client.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ SYNOPSIS
[*-K* interval] [*-L* value] [*-N*] [*-O* num,text]
[*-P* scheme://addr[:port]] [*-T* token] [*-U*] [*-V* num]
[*-X* size]
[*-d* value]
[[*-h* match_hint_file] [*-k* key] [*-u* user] [*-2*]]
[[*-c* certfile] [*-j* keyfile] [*-n*] [*-C* cafile]
[*-J* pkcs11_pin] [*-M* rpk_file] [*-R* trust_casfile]] URI
Expand Down Expand Up @@ -195,6 +196,15 @@ OPTIONS - General
Maximum message size to use for TCP based connections (default is 8388864).
Maximum value of 2^32 -1.

OPTIONS - DTLS
--------------
(If supported by underlying (D)TLS library)

*-d* count::
For DTLS, enable use of Connection-ID (RFC9176). If the count is not 0,
then the client will changes its source port every count packets to test
CID.

OPTIONS - PSK
-------------
(If supported by underlying (D)TLS library)
Expand Down
11 changes: 10 additions & 1 deletion man/coap_context.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ coap_context_set_csm_timeout_ms,
coap_context_get_csm_timeout_ms,
coap_context_set_max_token_size,
coap_context_set_app_data,
coap_context_get_app_data
coap_context_get_app_data,
coap_context_set_cid_tuple_change
- Work with CoAP contexts

SYNOPSIS
Expand Down Expand Up @@ -64,6 +65,8 @@ size_t _max_token_size_);*

*void *coap_context_get_app_data(const coap_context_t *_context_);*

*void coap_context_set_cid_tuple_change(coap_context_t *_context_context, uint8_t _every_);*

For specific (D)TLS library support, link with
*-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*,
*-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls*,
Expand Down Expand Up @@ -183,6 +186,12 @@ pointer for the _context_ which can then be retrieved at a later date.
The *coap_context_get_app_data*() function is used to retrieve the app_data
pointer previously defined by *coap_context_set_app_data*().

*Function: coap_context_set_cid_tuple_change()*

The *coap_context_set_cid_tuple_change*() function is used to define to a client
to force the client's port to change _every_ packets sent, providing the ability
to test a CID (RFC9146) enabled server.

RETURN VALUES
-------------
*coap_new_context*() returns a newly created context or
Expand Down
20 changes: 17 additions & 3 deletions man/coap_encryption.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,11 @@ typedef struct coap_dtls_cpsk_t {
uint8_t ec_jpake; /* Set to 1 if DC-JPAKE is to be used.
Currently Mbed TLS only */

uint8_t use_cid; /* Set to 1 if DTLS Connection ID is to be used.
Currently Mbed TLS only */

/* Options to enable different TLS functionality in libcoap */
uint8_t reserved[6]; /* Reserved - must be set to 0 for
uint8_t reserved[5]; /* Reserved - must be set to 0 for
future compatibility */

/** Identity Hint check callback function.
Expand Down Expand Up @@ -182,11 +185,16 @@ definition.
*version* is set to COAP_DTLS_CPSK_SETUP_VERSION. This will then allow
support for different versions of the coap_dtls_cpsk_t structure in the future.

*SECTION: PSK Server: coap_dtls_spsk_t: ec_jpake*
*SECTION: PSK Client: coap_dtls_cpsk_t: ec_jpake*

*ec_jpake* Set to 1 if EC-JPAKE negotiation is to be used. Currently only
supported by suitably compiled Mbed TLS library.

*SECTION: PSK Client: coap_dtls_cpsk_t: use_cid*

*use_cid* Set to 1 if the DTLS Client is to try to used Connection-ID.
Server is alwys enabled if support available.

*SECTION: PSK Client: coap_dtls_cpsk_t: Reserved*

*reserved* All must be set to 0. Future functionality updates will make use of
Expand Down Expand Up @@ -468,7 +476,10 @@ typedef struct coap_dtls_pki_t {
uint8_t is_rpk_not_cert; /* 1 is RPK instead of Public Certificate.
* If set, PKI key format type cannot be
* COAP_PKI_KEY_PEM */
uint8_t reserved[3]; /* Reserved - must be set to 0 for
uint8_t use_cid; /* 1 if DTLS Connection ID is to be
* used (Client only, server always enabled)
* if supported */
uint8_t reserved[2]; /* Reserved - must be set to 0 for
future compatibility */

/** CN check callback function
Expand Down Expand Up @@ -576,6 +587,9 @@ cert_chain_validation, cert_chain_verify_depth, check_cert_revocation,
allow_no_crl, allow_expired_crl, allow_bad_md_hash and
allow_short_rsa_length settings are all ignored.

*use_cid* Set to 1 if the DTLS Client is to try to used Connection-ID.
Server is alwys enabled if support available.

*SECTION: PKI/RPK: coap_dtls_pki_t: Reserved*

*reserved* All must be set to 0. Future functionality updates will make use of
Expand Down
6 changes: 6 additions & 0 deletions src/coap_gnutls.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,9 @@ coap_dtls_context_set_pki(coap_context_t *c_context,
coap_dtls_map_key_type_to_define(&g_context->setup_data, &key);
g_context->setup_data.pki_key = key;
g_context->psk_pki_enabled |= IS_PKI;
if (setup_data->use_cid) {
coap_log_warn("GnuTLS has no Connection-ID support\n");
}
return 1;
}

Expand Down Expand Up @@ -420,6 +423,9 @@ coap_dtls_context_set_cpsk(coap_context_t *c_context,
if (setup_data->ec_jpake) {
coap_log_warn("GnuTLS has no EC-JPAKE support\n");
}
if (setup_data->use_cid) {
coap_log_warn("GnuTLS has no Connection-ID support\n");
}
g_context->psk_pki_enabled |= IS_PSK;
return 1;
}
Expand Down
44 changes: 43 additions & 1 deletion src/coap_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -776,16 +776,58 @@ static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL;
#endif

#if !defined(RIOT_VERSION) && !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
#if COAP_CLIENT_SUPPORT
static uint32_t cid_track_counter;

static void
coap_test_cid_tuple_change(coap_session_t *session) {
if (session->type == COAP_SESSION_TYPE_CLIENT &&
session->state == COAP_SESSION_STATE_ESTABLISHED &&
COAP_PROTO_NOT_RELIABLE(session->proto) && session->context->testing_cids) {
if ((++cid_track_counter) % session->context->testing_cids == 0) {
coap_address_t local_if = session->addr_info.local;
uint16_t port = coap_address_get_port(&local_if);

port++;
coap_address_set_port(&local_if, port);

coap_socket_close(&session->sock);
session->sock.session = session;
if (!coap_socket_connect_udp(&session->sock, &local_if, &session->addr_info.remote,
port,
&session->addr_info.local,
&session->addr_info.remote)) {
coap_log_err("Tuple change for CID failed\n");
return;
#ifdef COAP_EPOLL_SUPPORT
} else {
coap_epoll_ctl_add(&session->sock,
EPOLLIN |
((session->sock.flags & COAP_SOCKET_WANT_CONNECT) ?
EPOLLOUT : 0),
__func__);
#endif /* COAP_EPOLL_SUPPORT */
}
session->sock.flags |= COAP_SOCKET_NOT_EMPTY | COAP_SOCKET_WANT_READ | COAP_SOCKET_BOUND;
}
}
}
#endif /* COAP_CLIENT_SUPPORT */

/*
* dgram
* return +ve Number of bytes written.
* -1 Error error in errno).
*/
ssize_t
coap_socket_send(coap_socket_t *sock, const coap_session_t *session,
coap_socket_send(coap_socket_t *sock, coap_session_t *session,
const uint8_t *data, size_t datalen) {
ssize_t bytes_written = 0;

#if COAP_CLIENT_SUPPORT
coap_test_cid_tuple_change(session);
#endif /* COAP_CLIENT_SUPPORT */

if (!coap_debug_send_packet()) {
bytes_written = (ssize_t)datalen;
} else if (sock->flags & COAP_SOCKET_CONNECTED) {
Expand Down
2 changes: 1 addition & 1 deletion src/coap_io_contiki.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ coap_socket_close(coap_socket_t *sock) {
* -1 Error error in errno).
*/
ssize_t
coap_socket_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data,
coap_socket_send(coap_socket_t *sock, coap_session_t *session, const uint8_t *data,
size_t datalen) {
ssize_t bytes_written = 0;

Expand Down
2 changes: 1 addition & 1 deletion src/coap_io_lwip.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ coap_socket_send_pdu(coap_socket_t *sock, coap_session_t *session,
* -1 Error error in errno).
*/
ssize_t
coap_socket_send(coap_socket_t *sock, const coap_session_t *session,
coap_socket_send(coap_socket_t *sock, coap_session_t *session,
const uint8_t *data, size_t data_len) {
struct pbuf *pbuf;
int err;
Expand Down
Loading

0 comments on commit 8b2fb39

Please sign in to comment.