Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Secure tunnel with Multiplexing #78

Merged
merged 71 commits into from
Feb 23, 2023
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
fc2425c
Add connection_error_code and API to access it for error checking on …
sbSteveK Sep 20, 2022
04e8055
encoder/decoder refactor
sbSteveK Oct 3, 2022
98545b5
Secure Tunnel Multiplex WIP
sbSteveK Nov 23, 2022
da4a6bb
WIP on hold to work on mqtt5 canary
sbSteveK Dec 5, 2022
97f1731
more wip saves
sbSteveK Dec 5, 2022
6caf6d5
revamp api and operations
sbSteveK Jan 12, 2023
6ea5be8
refactored message handling
sbSteveK Jan 12, 2023
b7a5b00
continued implementation of operations and tasks
sbSteveK Jan 14, 2023
4f7d3c0
merged with current main
sbSteveK Jan 17, 2023
b1d85b3
stash
sbSteveK Jan 17, 2023
449195c
test connection
sbSteveK Jan 18, 2023
d7c4216
progress before removing channel and slot for websocket use
sbSteveK Jan 20, 2023
6dee25f
stable before checking slot
sbSteveK Jan 23, 2023
5b6f269
pings updated to work with secure tunnel
sbSteveK Jan 24, 2023
39dcd7f
cleanup
sbSteveK Jan 24, 2023
1ea9dbe
encoding WIP
sbSteveK Jan 26, 2023
16572d1
encoding of outbound messages
sbSteveK Jan 26, 2023
7ee40ae
cleaning up
sbSteveK Jan 26, 2023
ca98b92
clean up
sbSteveK Jan 27, 2023
968c684
more clean up
sbSteveK Jan 27, 2023
34a3fc0
merge with latest main
sbSteveK Jan 27, 2023
d75b11a
clean up
sbSteveK Jan 27, 2023
94082ac
stream reset added
sbSteveK Jan 30, 2023
8a452c8
logging of error added
sbSteveK Jan 30, 2023
c890820
handling of the on_connection_complete callback
sbSteveK Jan 31, 2023
ee05c21
typo
sbSteveK Jan 31, 2023
1b6a666
code review changes WIP
sbSteveK Feb 7, 2023
f3a3993
wip
sbSteveK Feb 7, 2023
e24924b
pr wip
sbSteveK Feb 8, 2023
8d42b5f
remove typedef
sbSteveK Feb 8, 2023
cedc949
pr wip
sbSteveK Feb 8, 2023
824c96a
serializer changes test
sbSteveK Feb 8, 2023
bfcff0e
serializer simplification
sbSteveK Feb 8, 2023
08c55e9
formatting
sbSteveK Feb 8, 2023
cb5eb9f
capacity check fix
sbSteveK Feb 8, 2023
55e7ebb
pr changes
sbSteveK Feb 8, 2023
9332167
logging
sbSteveK Feb 9, 2023
4c42d98
added logging
sbSteveK Feb 9, 2023
e687535
add error logging
sbSteveK Feb 10, 2023
abdd57f
add more logging
sbSteveK Feb 10, 2023
f548e39
fix log
sbSteveK Feb 10, 2023
0c70639
expand logging
sbSteveK Feb 10, 2023
611dc84
add connection_view for connection complete settings
sbSteveK Feb 10, 2023
0cb7f75
handle zero length service id edge case
sbSteveK Feb 10, 2023
959c682
report a failed connection attempt
sbSteveK Feb 13, 2023
442300c
actually pass along the error code
sbSteveK Feb 13, 2023
539da71
add an on_stopped callback
sbSteveK Feb 14, 2023
176e38b
give options_storage its allocator to use during cleanup
sbSteveK Feb 14, 2023
05d2604
added /bin files
sbSteveK Feb 15, 2023
82b3179
code review fixes wip
sbSteveK Feb 16, 2023
71a082f
use aws_byte_buf_write_to_capacity
sbSteveK Feb 16, 2023
96c1ad3
removed unused variable
sbSteveK Feb 16, 2023
04358b5
convert service ids to hash table
sbSteveK Feb 16, 2023
a731303
fix hash table for service ids
sbSteveK Feb 16, 2023
4cb2261
cleanup old service id
sbSteveK Feb 16, 2023
5e6c377
more cr fixes/changes
sbSteveK Feb 16, 2023
b28da64
add termination callback specific user data
sbSteveK Feb 17, 2023
0b6027c
vtable expanded for testing
sbSteveK Feb 20, 2023
c7accba
expand vtable for testing
sbSteveK Feb 20, 2023
35fe644
simplify websocket creation
sbSteveK Feb 20, 2023
2d9ee53
add encoding for service ids on outbound message
sbSteveK Feb 20, 2023
fa2b9de
fix for length on multiple service ids
sbSteveK Feb 20, 2023
8fbe49a
cr changes
sbSteveK Feb 21, 2023
c7b2adb
remove old tests
sbSteveK Feb 21, 2023
ec73eee
fix race condition
sbSteveK Feb 21, 2023
bde1c01
secure tunnel tests
sbSteveK Feb 22, 2023
3736917
Clean Up
sbSteveK Feb 22, 2023
99f35b0
unused test parameters (void)
sbSteveK Feb 22, 2023
f0bbb07
ignore specific warning
sbSteveK Feb 22, 2023
e7abc0d
add logging
sbSteveK Feb 22, 2023
0c3cd36
code review changes
sbSteveK Feb 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,5 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake"
include(CTest)
if (BUILD_TESTING)
add_subdirectory(tests)
add_subdirectory(bin/securetunnel)
endif ()
17 changes: 15 additions & 2 deletions include/aws/iotdevice/iotdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,21 @@ enum aws_iotdevice_error {
AWS_ERROR_IOTDEVICE_DEFENDER_PUBLISH_FAILURE,
AWS_ERROR_IOTDEVICE_DEFENDER_UNKNOWN_TASK_STATUS,

AWS_ERROR_IOTDEVICE_SECUTRE_TUNNELING_INVALID_STREAM,
AWS_ERROR_IOTDEVICE_SECUTRE_TUNNELING_INCORRECT_MODE,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_INVALID_STREAM,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_INCORRECT_MODE,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_BAD_SERVICE_ID,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_DATA_OPTIONS_VALIDATION,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_STREAM_OPTIONS_VALIDATION,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_SECURE_TUNNEL_TERMINATED,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_WEBSOCKET_TIMEOUT,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_PING_RESPONSE_TIMEOUT,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_OPERATION_FAILED_DUE_TO_DISCONNECTION,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_OPERATION_PROCESSING_FAILURE,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_OPERATION_FAILED_DUE_TO_OFFLINE_QUEUE_POLICY,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_UNEXPECTED_HANGUP,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_USER_REQUESTED_STOP,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_TERMINATED,
AWS_ERROR_IOTDEVICE_SECURE_TUNNELING_DECODE_FAILURE,

AWS_ERROR_END_IOTDEVICE_RANGE = AWS_ERROR_ENUM_END_RANGE(AWS_C_IOTDEVICE_PACKAGE_ID),
};
Expand Down
43 changes: 0 additions & 43 deletions include/aws/iotdevice/private/iotdevice_internals.h

This file was deleted.

223 changes: 198 additions & 25 deletions include/aws/iotdevice/private/secure_tunneling_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,59 +9,232 @@

#include <aws/common/condition_variable.h>
#include <aws/common/mutex.h>
#include <aws/common/task_scheduler.h>
#include <aws/http/proxy.h>
#include <aws/http/websocket.h>
#include <aws/io/socket.h>
#include <aws/io/tls_channel_handler.h>

/**
* The various states that the secure tunnel can be in. A secure tunnel has both a current state and a desired state.
* Desired state is only allowed to be one of {STOPPED, CONNECTED, TERMINATED}. The secure tunnel transitions states
* based on either
* (1) changes in desired state, or
* (2) external events.
*
* Most states are interruptible (in the sense of a change in desired state causing an immediate change in state) but
* CONNECTING cannot be interrupted due to waiting for an asynchronous callback (that has no
* cancel) to complete.
*/
enum aws_secure_tunnel_state {
/*
* The secure tunnel is not connected and not waiting for anything to happen.
*
* Next States:
* CONNECTING - if the user invokes Connect() on the secure tunnel
* TERMINATED - if the user releases the last ref count on the secure tunnel
*/
AWS_STS_STOPPED,

/*
* The secure tunnel is attempting to connect to a remote endpoint and establish a WebSocket upgrade. This state is
* not interruptible by any means other than WebSocket setup completion.
*
* Next States:
* CONNECTED - if WebSocket handshake is successful and desired state is still CONNECTED
* WEBSOCKET_SHUTDOWN - if the WebSocket completes setup with no error but desired state is not CONNECTED
* PENDING_RECONNECT - if the WebSocket fails to complete setup and desired state is still CONNECTED
* STOPPED - if the WebSocket fails to complete setup and desired state is not CONNECTED
*/
AWS_STS_CONNECTING,

/*
* The secure tunnel is ready to perform user-requested operations.
*
* Next States:
* WEBSOCKET_SHUTDOWN - desired state is no longer CONNECTED
* PENDING_RECONNECT - unexpected WebSocket shutdown completion and desired state still CONNECTED
* STOPPED - unexpected WebSocket shutdown completion and desired state no longer CONNECTED
*/
AWS_STS_CONNECTED,

/*
* The secure tunnel is attempting to shut down a WebSocket connection cleanly by finishing the current operation
* and then transmitting a STREAM RESET message to all open streams.
*
* Next States:
* WEBSOCKET_SHUTDOWN - on sucessful (or unsuccessful) disconnection
* PENDING_RECONNECT - unexpected WebSocket shutdown completion and desired state still CONNECTED
* STOPPED - unexpected WebSocket shutdown completion and desired state no longer CONNECTED
*/
AWS_STS_CLEAN_DISCONNECT,

/*
* The secure tunnel is waiting for the WebSocket to completely shut down. This state is not interruptible.
sbSteveK marked this conversation as resolved.
Show resolved Hide resolved
*
* Next States:
* PENDING_RECONNECT - the WebSocket has shut down and desired state is still CONNECTED
* STOPPED - the WebSocket has shut down and desired state is not CONNECTED
*/
AWS_STS_WEBSOCKET_SHUTDOWN,

/*
* The secure tunnel is waiting for the reconnect timer to expire before attempting to connect again.
*
* Next States:
* CONNECTING - the reconnect timer has expired and desired state is still CONNECTED
* STOPPED - desired state is no longer CONNECTED
*/
AWS_STS_PENDING_RECONNECT,

/*
* The secure tunnel is performing final shutdown and release of all resources. This state is only realized for
* a non-observable instant of time (transition out of STOPPED).
*/
AWS_STS_TERMINATED
};

struct data_tunnel_pair {
struct aws_byte_buf buf;
struct aws_byte_cursor cur;
const struct aws_secure_tunnel *secure_tunnel;
bool length_prefix_written;
};

struct aws_secure_tunnel_vtable {
int (*connect)(struct aws_secure_tunnel *secure_tunnel);
int (*send_data)(struct aws_secure_tunnel *secure_tunnel, const struct aws_byte_cursor *data);
int (*send_stream_start)(struct aws_secure_tunnel *secure_tunnel);
int (*send_stream_reset)(struct aws_secure_tunnel *secure_tunnel);
int (*close)(struct aws_secure_tunnel *secure_tunnel);
};
/*
* Secure tunnel configuration
*/
struct aws_secure_tunnel_options_storage {
struct aws_allocator *allocator;

/* backup */

struct aws_client_bootstrap *bootstrap;
struct aws_socket_options socket_options;
struct aws_http_proxy_options http_proxy_options;
struct aws_http_proxy_config *http_proxy_config;
struct aws_string *access_token;
struct aws_string *client_token;

struct aws_string *endpoint_host;

/* Stream related info */
int32_t stream_id;
struct aws_string *service_id_1;
int32_t service_id_1_stream_id;
struct aws_string *service_id_2;
int32_t service_id_2_stream_id;
struct aws_string *service_id_3;
int32_t service_id_3_stream_id;

/* Callbacks */
aws_secure_tunnel_message_received_fn *on_message_received;
aws_secure_tunneling_on_connection_complete_fn *on_connection_complete;
aws_secure_tunneling_on_connection_shutdown_fn *on_connection_shutdown;
aws_secure_tunneling_on_stream_start_fn *on_stream_start;
aws_secure_tunneling_on_stream_reset_fn *on_stream_reset;
aws_secure_tunneling_on_session_reset_fn *on_session_reset;
aws_secure_tunneling_on_stopped_fn *on_stopped;

struct aws_websocket_client_connection_options;
struct aws_websocket_send_frame_options;
aws_secure_tunneling_on_send_data_complete_fn *on_send_data_complete;
aws_secure_tunneling_on_termination_complete_fn *on_termination_complete;

struct aws_websocket_vtable {
int (*client_connect)(const struct aws_websocket_client_connection_options *options);
int (*send_frame)(struct aws_websocket *websocket, const struct aws_websocket_send_frame_options *options);
void (*close)(struct aws_websocket *websocket, bool free_scarce_resources_immediately);
void (*release)(struct aws_websocket *websocket);
void *user_data;
enum aws_secure_tunneling_local_proxy_mode local_proxy_mode;
};

struct aws_secure_tunnel_vtable {
/* aws_high_res_clock_get_ticks */
uint64_t (*get_current_time_fn)(void);
};

struct aws_secure_tunnel {
/* Static settings */
struct aws_allocator *alloc;
struct aws_secure_tunnel_options_storage *options_storage;
struct aws_secure_tunnel_options *options;
struct aws_allocator *allocator;
struct aws_ref_count ref_count;

struct aws_secure_tunnel_vtable *vtable;

/*
* Secure tunnel configuration
*/
struct aws_secure_tunnel_options_storage *config;

struct aws_tls_ctx *tls_ctx;
struct aws_tls_connection_options tls_con_opt;
struct aws_secure_tunnel_vtable vtable;
struct aws_websocket_vtable websocket_vtable;

struct aws_ref_count ref_count;
/*
* The recurrent task that runs all secure tunnel logic outside of external event callbacks. Bound to the secure
* tunnel's event loop.
*/
struct aws_task service_task;

/*
* Tracks when the secure tunnel's service task is next schedule to run. Is zero if the task is not scheduled to
* run or we are in the middle of a service (so technically not scheduled too).
*/
uint64_t next_service_task_run_time;

/* Used only during initial websocket setup. Otherwise, should be NULL */
/*
* True if the secure tunnel's service task is running. Used to skip service task reevaluation due to state changes
* while running the service task. Reevaluation will occur at the very end of the service.
*/
bool in_service;

/*
* Event loop all the secure tunnel's tasks will be pinned to, ensuring serialization and
* concurrency safety.
*/
struct aws_event_loop *loop;

/*
* What state is the secure tunnel working towards?
*/
enum aws_secure_tunnel_state desired_state;

/*
* What is the secure tunnel's current state?
*/
enum aws_secure_tunnel_state current_state;

/*
* handshake_request exists between the transform completion timepoint and the websocket setup callback.
*/
struct aws_http_message *handshake_request;

/* Dynamic data */
int32_t stream_id;

struct aws_websocket *websocket;

/* Stores what has been received but not processed */
struct aws_byte_buf received_data;

/* The secure tunneling endpoint ELB drops idle connect after 1 minute. We need to send a ping periodically to keep
* the connection */
/*
* When should the secure tunnel next attempt to reconnect? Only used by PENDING_RECONNECT state.
*/
uint64_t next_reconnect_time_ns;

/*
* How many consecutive reconnect failures have we experienced?
*/
uint64_t reconnect_count;

struct aws_linked_list queued_operations;
struct aws_secure_tunnel_operation *current_operation;

/*
* Is there a WebSocket message in transit (to the socket) that has not invoked its write completion callback yet?
* The secure tunnel implementation only allows one in-transit message at a time, and so if this is true, we don't
* send additional ones/
*/
bool pending_write_completion;

struct ping_task_context *ping_task_context;
/*
* When should the next PINGREQ be sent?
* The secure tunneling endpoint ELB drops idle connect after 1 minute. we need to send a ping periodically to keep
* the connection alive.
*/
uint64_t next_ping_time;
};

#endif /* AWS_IOTDEVICE_SECURE_TUNNELING_IMPL_H */
Loading