Skip to content

Commit

Permalink
Fix backward compatibility (#150)
Browse files Browse the repository at this point in the history
* add cli option for compatibility mode with various destination clients
  • Loading branch information
RogerZhongAWS committed Apr 25, 2024
1 parent 0a72168 commit 9eace74
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 14 deletions.
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,15 +233,20 @@ V1 local proxy: local proxy uses Sec-WebSocket-Protocol _aws.iot.securetunneling

V2 local proxy: local proxy uses Sec-WebSocket-Protocol _aws.iot.securetunneling-2.0_ when communicates with AWS IoT Tunneling Service.

V3 local proxy: local proxy uses Sec-WebSocket-Protocol _aws.iot.securetunneling-3.0_ when communicates with AWS IoT Tunneling Service.

Source local proxy: local proxy that runs in source mode.

Destination local proxy: local proxy that runs in destination mode.


### Multi-port tunneling feature support
Multi-port tunneling feature allows more than one stream multiplexed on same tunnel.
This feature is only supported with V2 local proxy. If you have some devices that on V1 local proxy, some on V2 local proxy, simply upgrade the local proxy on the source device to V2 local proxy. When V2 local proxy talks to V1 local proxy, the backward compatibility is maintained. For more details, please refer to section [backward compatibility](#backward-compatibility)

### Simultaneous TCP connections feature support
Simultaneous TCP is a feature that allows application layer (e.g. HTTP) protocols to open multiple TCP connections over a single stream.
This feature is only supported with V3 local proxy. If you have some devices that on V1/V2 local proxy, some on V3 local proxy, simply upgrade the local proxy on the source device to V3 local proxy. When V3 local proxy talks to V1/V2 local proxy, the backward compatibility is maintained as long as users specify `V1` or `V2` as the value for `destination-client-type`. For more details, please refer to section [backward compatibility](#backward-compatibility)

### Service identifier (Service ID)
If you need to use multi-port tunneling feature, service ID is needed to start local proxy. A service identifier will be used as the new format to specify the source listening port or destination service when start local proxy. The identifier is like an alias for the source listening port or destination service. For the format requirement of service ID, please refer to AWS public doc [services in DestinationConfig ](https://docs.aws.amazon.com/iot/latest/apireference/API_iot-secure-tunneling_DestinationConfig.html). There is no restriction on how this service ID should be named, as long as it can help uniquely identifying a connection or stream.

Expand Down Expand Up @@ -327,6 +332,16 @@ Example 3:

In this example, no service ID is used. Backward compatibility is supported.

V3 local proxy is able to communicate with V1 and V2 local proxy if only one connection/stream needs to be established over the tunnel. When connecting to older versions, you will need to pass the `destination-client-type` CLI arg if and only if starting the localproxy in source mode. The same rules listed above still apply when connecting over V1.

Example when targeting a V1 destination, like Device Client of the Greengrass Secure Tunneling Component:

./localproxy -s 3333 --destination-client-type V1 -v 6 -r us-east-1

Example when targeting a V2 destination:

./localproxy -s 3333 --destination-client-type V2 -v 6 -r us-east-1

### HTTP proxy Support

The local proxy relies on the HTTP tunneling mechanism described by the [HTTP/1.1 specification](https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.6). To comply with the specifications, your web proxy must allow devices to use the CONNECT method. For more details on how that works and how configure it properly, Please refer to "[Configure local proxy for devices that use web proxy](https://docs.aws.amazon.com/iot/latest/developerguide/configure-local-proxy-web-proxy.html)"
Expand Down Expand Up @@ -450,6 +465,9 @@ Specifies the verbosity of the output. Value must be between 0-255, however mean
**-m/--mode [argvalue]**
Specifies the mode local proxy will run. Accepted values are: src, source, dst, destination.

**-y/--destination-client-type [argvalue]**
Specifies the backward compatibility mode the local proxy will run when opening a source connection to an older destination client. Currently supported values are: V1, V2. The localproxy will assume the destination to be V3 if no/invalid value is passed.

**--config-dir [argvalue]**
Specifies the configuration directory where service identifier mappings are configured. If this parameter is not specified, local proxy will read configuration files from default directory _./config_, under the file path where `localproxy` binary are located.

Expand Down
19 changes: 6 additions & 13 deletions src/TcpAdapterProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,7 @@ namespace aws { namespace iot { namespace securedtunneling {
std::int32_t stream_id = static_cast<std::int32_t>(message.streamid());
uint32_t connection_id = static_cast<uint32_t>(message.connectionid());

// backward compatibility: set connection id to 1 if first received a message with no connection id (id value will be 0)
// backward compatibility: set is_v2_message_format to true if receives no connection id
if (!connection_id)
{
BOOST_LOG_SEV(log, info) << "reverting to v2 message format";
Expand Down Expand Up @@ -1257,14 +1257,6 @@ namespace aws { namespace iot { namespace securedtunneling {
throw std::runtime_error("Wrong configurations detected in local proxy. Please starts local proxy with right sets of service ids.");
}

/**
* Set flag to mark local proxy will communicate using local proxy v1 message format.
* local proxy v1 message format: 1 service id. It can be a empty string when open tunnel with no service in destination config.
*/
if (service_id_list.size() == 1)
{
tac.adapter_config.is_v1_message_format = true;
}
/**
* Build serviceId <-> endpoint mapping if not done yet.
* Case1: Configuration is provided through configuration files. Upon receiving service ids, search through
Expand Down Expand Up @@ -1365,7 +1357,7 @@ namespace aws { namespace iot { namespace securedtunneling {
std::int32_t stream_id = static_cast<std::int32_t>(message.streamid());
uint32_t connection_id = static_cast<uint32_t>(message.connectionid());

// backward compatibility: set connection id to 1 if first received a message with no connection id (id value will be 0)
// backward compatibility: set is_v2_message_format to true if receives no connection id
if (!connection_id)
{
BOOST_LOG_SEV(log, info) << "reverting to v2 message format";
Expand Down Expand Up @@ -1468,7 +1460,7 @@ namespace aws { namespace iot { namespace securedtunneling {

BOOST_LOG_SEV(log, trace) << "Forwarding message to tcp socket with connection id: " << connection_id;

// backward compatibility: set connection id to 1 if first received a message with no connection id (id value will be 0)
// backward compatibility: set is_v2_message_format to true if receives no connection id
if (!connection_id)
{
BOOST_LOG_SEV(log, info) << "reverting to v2 message format";
Expand Down Expand Up @@ -1599,7 +1591,7 @@ namespace aws { namespace iot { namespace securedtunneling {
{
BOOST_LOG_SEV(log, trace) << "Processing data message";

// backward compatibility: set connection id to 1 if first received a message with no connection id (id value will be 0)
// backward compatibility: set is_v2_message_format to true if receives no connection id
if (!connection_id)
{
BOOST_LOG_SEV(log, info) << "reverting to v2 message format";
Expand Down Expand Up @@ -2036,12 +2028,13 @@ namespace aws { namespace iot { namespace securedtunneling {

uint32_t new_connection_id = ++server->highest_connection_id;

// backward compatibility: set connection id to 1 if simultaneous connections is not enabled
// backward compatibility: set connection id to 0 if simultaneous connections is not enabled
if (tac.adapter_config.is_v2_message_format || tac.adapter_config.is_v1_message_format)
{
BOOST_LOG_SEV(log, info) << "Falling back to older protocol, setting new connection id to 0";
new_connection_id = 0;
}

BOOST_LOG_SEV(log, info) << "creating tcp connection id " << new_connection_id;

if (server->connectionId_to_tcp_connection_map.find(new_connection_id) == server->connectionId_to_tcp_connection_map.end() &&
Expand Down
20 changes: 20 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ bool process_cli(int argc, char ** argv, LocalproxyConfig &cfg, ptree &settings,
("config", value<string>(), "Use the supplied configuration file to apply CLI args. Actual CLI args override the contents of this file")
("verbose,v", value<std::uint16_t>()->default_value(4), "Logging level to standard out. [0, 255] (0=off, 1=fatal, 2=error, 3=warning, 4=info, 5=debug, >=6=trace)")
("mode,m", value<string>(), "The mode local proxy will run: src(source) or dst(destination)")
("destination-client-type,y", value<string>(), "Specify the value V1 or V2 to run the localproxy in compatibility mode with older clients. This should only be used when running localproxy in source mode.")
("config-dir", value<string>(), "Set the configuration directory where service identifier mappings are stored. If not specified, will read mappings from default directory ./config (same directory where local proxy binary is running)")
;
store(parse_command_line(argc, argv, cliargs_desc), vm);
Expand Down Expand Up @@ -305,6 +306,25 @@ bool process_cli(int argc, char ** argv, LocalproxyConfig &cfg, ptree &settings,
}
}

if (vm.count("destination-client-type"))
{
string type = vm["destination-client-type"].as<string>();
if (type == "V1")
{
BOOST_LOG_TRIVIAL(info) << "setting source protocol to V1";
cfg.is_v1_message_format = true;
}
else if (type == "V2")
{
BOOST_LOG_TRIVIAL(info) << "setting source protocol to V2";
cfg.is_v2_message_format = true;
}
else
{
BOOST_LOG_TRIVIAL(warning) << "unknown value for destination-client-type, assuming default protocol V3.";
}
}

/** Invalid input combination for: -s, -d and --mode
* 1. -s and -d should NOT used together
* 2. -s and mode value is dst/destination should NOT used together
Expand Down

0 comments on commit 9eace74

Please sign in to comment.