Setup the message bridge key sharing services
This implements 2 new services that will be used to share the active
SCTP authentication key. For context, if SCTP authentication is wanted,
then we will need a way to securely distribute a shared key across every
node. We use gRPC to distribute the key.
* message_bridge_auth_server
This service should only run in one node. It generates a 128-bit
random-key during initialization. It sets up the gRPC service using
mutual-TLS authentication.
* message_bridge_auth_client
This service will run in every node. It listens for requests
in /aos aos.message_bridge.SctpConfigRequest and requests the
active key from the gRPC server which gets propagated into /aos
aos.message_bridge.SctpConfig. message_bridge reads this value and sets
the authentication key (previous change in relation).
These have some additional side-effects:
* This change also forces us to bring in an appropriate version of GRPC,
which itself forces updates to protobuf and other dependencies. We
take the opportunity to remove the protobuf subtree in favor of
a more sanitized import in the WORKSPACE.
* The various upgrades also upgraded our version of buildifier,
which now performs more aggressive linting.
* Our version of abseil was upgraded, which now forces you to only
have access to const references to things stored in absl::btree_set's
(see https://github.com/abseil/abseil-cpp/commit/a74b796ab3f114f6991479c9ad9e4c1a0dad3a4b).
Change-Id: I870b8f93451056e011cefa3cdf3c5dc01c19a6f9
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
Signed-off-by: Adam Snaider <adsnaider@gmail.com>
diff --git a/aos/network/BUILD b/aos/network/BUILD
index e8dd75f..7a8ceb5 100644
--- a/aos/network/BUILD
+++ b/aos/network/BUILD
@@ -3,6 +3,9 @@
load("//aos:flatbuffers.bzl", "cc_static_flatbuffer")
load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
load("@com_github_google_flatbuffers//:typescript.bzl", "flatbuffer_ts_library")
+load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library")
+load("@rules_cc//cc:defs.bzl", "cc_proto_library")
+load("@rules_proto//proto:defs.bzl", "proto_library")
package(default_visibility = ["//visibility:public"])
@@ -137,6 +140,36 @@
visibility = ["//visibility:public"],
)
+proto_library(
+ name = "message_bridge_auth_proto",
+ srcs = [
+ "message_bridge_auth.proto",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = [":__pkg__"],
+)
+
+cc_proto_library(
+ name = "message_bridge_auth_proto_cc",
+ target_compatible_with = ["@platforms//os:linux"],
+ visibility = ["//visibility:public"],
+ deps = [
+ ":message_bridge_auth_proto",
+ ],
+)
+
+cc_grpc_library(
+ name = "message_bridge_auth_proto_grpc_cc",
+ srcs = [
+ ":message_bridge_auth_proto",
+ ],
+ grpc_only = True,
+ target_compatible_with = ["@platforms//os:linux"],
+ deps = [
+ ":message_bridge_auth_proto_cc",
+ ],
+)
+
cc_library(
name = "team_number",
srcs = [
@@ -173,10 +206,6 @@
hdrs = [
"sctp_lib.h",
],
- copts = [
- # The casts required to read datastructures from sockets trip -Wcast-align.
- "-Wno-cast-align",
- ],
target_compatible_with = ["@platforms//os:linux"],
deps = [
"//aos:unique_malloc_ptr",
@@ -214,9 +243,6 @@
hdrs = [
"sctp_server.h",
],
- copts = [
- "-Wno-cast-align",
- ],
target_compatible_with = ["@platforms//os:linux"],
deps = [
":sctp_lib",
@@ -285,9 +311,6 @@
hdrs = [
"message_bridge_server_lib.h",
],
- copts = [
- "-Wno-cast-align",
- ],
target_compatible_with = ["@platforms//os:linux"],
deps = [
":connect_fbs",
@@ -334,9 +357,6 @@
hdrs = [
"sctp_client.h",
],
- copts = [
- "-Wno-cast-align",
- ],
target_compatible_with = ["@platforms//os:linux"],
deps = [
":sctp_lib",
@@ -370,9 +390,6 @@
hdrs = [
"message_bridge_client_lib.h",
],
- copts = [
- "-Wno-cast-align",
- ],
target_compatible_with = ["@platforms//os:linux"],
deps = [
":connect_fbs",
@@ -397,9 +414,6 @@
srcs = [
"message_bridge_client.cc",
],
- copts = [
- "-Wno-cast-align",
- ],
target_compatible_with = ["@platforms//os:linux"],
deps = [
":message_bridge_client_lib",
@@ -413,6 +427,68 @@
],
)
+cc_library(
+ name = "message_bridge_auth_server_lib",
+ srcs = [
+ "message_bridge_auth_server_lib.cc",
+ ],
+ hdrs = [
+ "message_bridge_auth_server_lib.h",
+ ],
+ deps = [
+ ":message_bridge_auth_proto_cc",
+ ":message_bridge_auth_proto_grpc_cc",
+ "//aos/logging",
+ "//aos/util:file",
+ "@com_github_grpc_grpc//:grpc++",
+ "@com_google_absl//absl/strings",
+ ],
+)
+
+cc_library(
+ name = "message_bridge_auth_client_lib",
+ srcs = [
+ "message_bridge_auth_client_lib.cc",
+ ],
+ hdrs = [
+ "message_bridge_auth_client_lib.h",
+ ],
+ deps = [
+ ":message_bridge_auth_proto_grpc_cc",
+ ":message_bridge_client_fbs",
+ ":message_bridge_server_fbs",
+ ":sctp_config_fbs",
+ ":sctp_config_request_fbs",
+ "//aos/events:event_loop",
+ "//aos/logging",
+ "//aos/util:file",
+ "@com_github_grpc_grpc//:grpc++",
+ "@com_google_absl//absl/strings",
+ ],
+)
+
+cc_test(
+ name = "message_bridge_auth_test",
+ srcs = [
+ "message_bridge_auth_test.cc",
+ ],
+ data = [
+ ":message_bridge_auth_test_config",
+ ],
+ deps = [
+ ":message_bridge_auth_client_lib",
+ ":message_bridge_auth_server_lib",
+ "//aos:configuration",
+ "//aos/events:simulated_event_loop",
+ "//aos/logging",
+ "//aos/testing:googletest",
+ "//aos/testing:path",
+ "//aos/util:file",
+ "@com_github_grpc_grpc//:grpc++",
+ "@com_google_absl//absl/strings",
+ ],
+)
+
aos_config(
name = "message_bridge_test_combined_timestamps_common_config",
src = "message_bridge_test_combined_timestamps_common.json",
@@ -431,6 +507,17 @@
)
aos_config(
+ name = "message_bridge_auth_test_config",
+ src = "message_bridge_auth_test.json",
+ flatbuffers = [
+ ":sctp_config_fbs",
+ ":sctp_config_request_fbs",
+ ],
+ target_compatible_with = ["@platforms//os:linux"],
+ deps = ["//aos/events:aos_config"],
+)
+
+aos_config(
name = "message_bridge_test_common_config",
src = "message_bridge_test_common.json",
flatbuffers = [
@@ -772,7 +859,6 @@
srcs = [
"sctp_perf.cc",
],
- copts = ["-Wno-cast-align"],
deps = [
":sctp_client",
":sctp_server",
diff --git a/aos/network/message_bridge_auth.proto b/aos/network/message_bridge_auth.proto
new file mode 100644
index 0000000..178c51d
--- /dev/null
+++ b/aos/network/message_bridge_auth.proto
@@ -0,0 +1,16 @@
+syntax = "proto3";
+
+package aos.message_bridge;
+
+message SctpKeyResponse {
+ // Active SCTP authentication key.
+ bytes key = 1;
+}
+
+message SctpKeyRequest {}
+
+service SctpConfigService {
+ // Returns the active SCTP authentication key that should be used
+ // across nodes in message bridge.
+ rpc GetActiveKey(SctpKeyRequest) returns (SctpKeyResponse) {}
+}
diff --git a/aos/network/message_bridge_auth_client_lib.cc b/aos/network/message_bridge_auth_client_lib.cc
new file mode 100644
index 0000000..3b71632
--- /dev/null
+++ b/aos/network/message_bridge_auth_client_lib.cc
@@ -0,0 +1,62 @@
+#include "aos/network/message_bridge_auth_client_lib.h"
+
+#include <vector>
+
+#include "glog/logging.h"
+
+#include "aos/events/event_loop.h"
+#include "aos/network/message_bridge_auth.grpc.pb.h"
+#include "aos/network/message_bridge_client_generated.h"
+#include "aos/network/message_bridge_server_generated.h"
+#include "aos/network/sctp_config_generated.h"
+#include "aos/network/sctp_config_request_generated.h"
+#include "aos/util/file.h"
+#include "grpc/grpc.h"
+#include "grpcpp/channel.h"
+
+namespace aos::message_bridge::auth {
+
+namespace {
+using ::grpc::Channel;
+using ::grpc::ClientContext;
+using ::grpc::Status;
+} // namespace
+
+MessageBridgeAuthClient::MessageBridgeAuthClient(
+ EventLoop *const event_loop, std::shared_ptr<Channel> channel)
+ : sender_(event_loop->MakeSender<SctpConfig>("/aos")),
+ client_(SctpConfigService::NewStub(channel)) {
+ event_loop->MakeWatcher("/aos", [this](const SctpConfigRequest &stats) {
+ if (stats.request_key()) {
+ VLOG(1) << "Got SCTP authentication request from /aos";
+ SendKey();
+ }
+ });
+}
+
+void MessageBridgeAuthClient::SendKey() {
+ std::vector<uint8_t> key(GetSctpKey());
+ if (key.empty()) {
+ return;
+ }
+ Sender<SctpConfig>::Builder sender = sender_.MakeBuilder();
+ auto fb_key = sender.fbb()->CreateVector(std::move(key));
+ auto builder = sender.MakeBuilder<SctpConfig>();
+ builder.add_key(fb_key);
+ sender.CheckOk(sender.Send(builder.Finish()));
+}
+
+std::vector<uint8_t> MessageBridgeAuthClient::GetSctpKey() {
+ ClientContext context;
+ SctpKeyRequest request;
+ SctpKeyResponse response;
+ Status status = client_->GetActiveKey(&context, request, &response);
+ if (!status.ok()) {
+ LOG_EVERY_N(ERROR, 50)
+ << "Unable to retreive active SCTP authentication key from server";
+ return {};
+ }
+
+ return std::vector<uint8_t>(response.key().begin(), response.key().end());
+}
+} // namespace aos::message_bridge::auth
diff --git a/aos/network/message_bridge_auth_client_lib.h b/aos/network/message_bridge_auth_client_lib.h
new file mode 100644
index 0000000..2ff6d1c
--- /dev/null
+++ b/aos/network/message_bridge_auth_client_lib.h
@@ -0,0 +1,37 @@
+#ifndef AOS_NETWORK_MESSAGE_BRIGE_AUTH_CLIENT_LIB_H_
+#define AOS_NETWORK_MESSAGE_BRIGE_AUTH_CLIENT_LIB_H_
+
+#include "aos/events/event_loop.h"
+#include "aos/network/message_bridge_auth.grpc.pb.h"
+#include "aos/network/sctp_config_generated.h"
+#include "grpcpp/channel.h"
+
+namespace aos::message_bridge::auth {
+
+// See the explanation of underlying the architecture in
+// aos/network/message_bridge_auth_server_lib.h.
+
+// This class propagates the SCTP authentication key from the gRPC server to
+// message bridge. It listens to requests in the /aos SctpConfigRequest channel
+// and sends responses to /aos SctpConfig channel.
+class MessageBridgeAuthClient {
+ public:
+ MessageBridgeAuthClient(EventLoop *const event_loop,
+ std::shared_ptr<grpc::Channel> channel);
+
+ // Gets the key from the gRPC channel and sends it to the /aos SctpConfig
+ // channel.
+ void SendKey();
+
+ private:
+ // Gets the active SCTP key from the authentication server.
+ //
+ // Returns an empty vector on failure.
+ std::vector<uint8_t> GetSctpKey();
+
+ Sender<SctpConfig> sender_;
+ const std::unique_ptr<SctpConfigService::Stub> client_;
+};
+} // namespace aos::message_bridge::auth
+
+#endif // AOS_NETWORK_MESSAGE_BRIGE_AUTH_CLIENT_LIB_H_
diff --git a/aos/network/message_bridge_auth_server_lib.cc b/aos/network/message_bridge_auth_server_lib.cc
new file mode 100644
index 0000000..6a9dc7e
--- /dev/null
+++ b/aos/network/message_bridge_auth_server_lib.cc
@@ -0,0 +1,44 @@
+#include "aos/network/message_bridge_auth_server_lib.h"
+
+#include <cstdio>
+#include <fstream>
+
+#include "glog/logging.h"
+
+#include "grpc/grpc.h"
+#include "grpcpp/server_context.h"
+
+namespace aos::message_bridge::auth {
+
+namespace {
+
+using ::grpc::ServerContext;
+using ::grpc::Status;
+
+constexpr int kSctpKeySize = 16;
+
+std::string GenerateSecureRandomSequence(size_t count) {
+ std::ifstream rng("/dev/random", std::ios::in | std::ios::binary);
+ CHECK(rng) << "Unable to open /dev/random";
+ std::string out(count, 0);
+ rng.read(out.data(), count);
+ CHECK(rng) << "Couldn't read from random device";
+ rng.close();
+ return out;
+}
+} // namespace
+
+// This class implements the SctpConfigService. It securely generates an SCTP
+// authentication key and sends it to the clients that request it.
+SctpConfigServer::SctpConfigServer()
+ : active_key_(GenerateSecureRandomSequence(kSctpKeySize)) {}
+
+Status SctpConfigServer::GetActiveKey(ServerContext * /*context*/,
+ const SctpKeyRequest * /*request*/,
+ SctpKeyResponse *response) {
+ VLOG(1) << "Got request for SCTP authentication key";
+ response->set_key(active_key_);
+ return Status::OK;
+}
+
+} // namespace aos::message_bridge::auth
diff --git a/aos/network/message_bridge_auth_server_lib.h b/aos/network/message_bridge_auth_server_lib.h
new file mode 100644
index 0000000..acd5817
--- /dev/null
+++ b/aos/network/message_bridge_auth_server_lib.h
@@ -0,0 +1,48 @@
+#ifndef AOS_NETWORK_MESSAGE_BRIGE_AUTH_SERVER_LIB_H_
+#define AOS_NETWORK_MESSAGE_BRIGE_AUTH_SERVER_LIB_H_
+
+#include <string>
+
+#include "aos/network/message_bridge_auth.grpc.pb.h"
+#include "aos/network/message_bridge_auth.pb.h"
+#include "grpc/grpc.h"
+
+namespace aos::message_bridge::auth {
+
+// We use two services to share the active SCTP authentication key. For context,
+// if SCTP authentication is wanted, then we will need a way to securely
+// distribute a shared key across all the nodes. We use gRPC to distribute the
+// key.
+//
+// * message_bridge_auth_server
+//
+// This service should only run on a single node. It generates an n-bit
+// random-key during initialization. The server and client should use a mutal
+// authenticated channel. Without mutual authentication, anyone would be able to
+// acquire the authentication key which would defeat the purpose.
+//
+// * message_bridge_auth_client
+//
+// This service will run on all nodes. It listens for requests in /aos
+// aos.message_bridge.SctpConfigRequest and requests the active key from the
+// gRPC server which gets propagated into /aos aos.message_bridge.SctpConfig.
+// message_bridge reads this value and sets the authentication key (previous
+// change in relation).
+
+// This class implements the SctpConfigService. It securely generates an SCTP
+// authentication key and sends it to the clients that request it.
+class SctpConfigServer final : public SctpConfigService::Service {
+ public:
+ SctpConfigServer();
+
+ grpc::Status GetActiveKey(grpc::ServerContext *context,
+ const SctpKeyRequest *_request,
+ SctpKeyResponse *response) override;
+
+ private:
+ std::string active_key_;
+};
+
+} // namespace aos::message_bridge::auth
+
+#endif // AOS_NETWORK_MESSAGE_BRIGE_AUTH_SERVER_LIB_H_
diff --git a/aos/network/message_bridge_auth_test.cc b/aos/network/message_bridge_auth_test.cc
new file mode 100644
index 0000000..a360bdf
--- /dev/null
+++ b/aos/network/message_bridge_auth_test.cc
@@ -0,0 +1,123 @@
+#include <chrono>
+#include <memory>
+#include <thread>
+
+#include "gmock/gmock-matchers.h"
+#include "gtest/gtest.h"
+
+#include "aos/configuration.h"
+#include "aos/events/simulated_event_loop.h"
+#include "aos/network/message_bridge_auth_client_lib.h"
+#include "aos/network/message_bridge_auth_server_lib.h"
+#include "aos/network/sctp_config_generated.h"
+#include "aos/network/sctp_config_request_generated.h"
+#include "aos/testing/path.h"
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "grpcpp/channel.h"
+#include "grpcpp/create_channel.h"
+#include "grpcpp/server_builder.h"
+
+namespace aos::message_bridge::auth::testing {
+namespace {
+
+using ::aos::testing::ArtifactPath;
+using ::grpc::Channel;
+using ::grpc::Server;
+using ::grpc::ServerBuilder;
+using ::testing::ElementsAreArray;
+using ::testing::Not;
+
+using namespace ::std::chrono_literals;
+
+void RunServer() {
+ std::string server_address("127.0.0.1:1234");
+ SctpConfigServer service;
+ ServerBuilder builder;
+ builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+ builder.RegisterService(&service);
+ std::unique_ptr<Server> auth_server(builder.BuildAndStart());
+ auth_server->Wait();
+}
+
+std::shared_ptr<Channel> MakeAuthClientChannel() {
+ std::string server_address = "127.0.0.1:1234";
+ std::shared_ptr<Channel> channel(
+ grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials()));
+ // Give 10s deadline to connect to server or bail.
+ CHECK(channel->WaitForConnected(std::chrono::system_clock::now() + 10s))
+ << "Couldn't connect to auth server.";
+ return channel;
+}
+
+class MessageBridgeAuthTest : public ::testing::Test {
+ public:
+ MessageBridgeAuthTest()
+ : config_(aos::configuration::ReadConfig(
+ ArtifactPath("aos/network/message_bridge_auth_test_config.json"))),
+ event_loop_factory_(&config_.message()),
+ client_event_loop_(event_loop_factory_.MakeEventLoop("client")),
+ auth_client_(client_event_loop_.get(), MakeAuthClientChannel()),
+ mock_event_loop_(event_loop_factory_.MakeEventLoop("mock")),
+ request_key_sender_(
+ mock_event_loop_->MakeSender<SctpConfigRequest>("/aos")) {}
+
+ static void SetUpTestSuite() { std::thread(RunServer).detach(); }
+
+ private:
+ FlatbufferDetachedBuffer<Configuration> config_;
+ SimulatedEventLoopFactory event_loop_factory_;
+ std::unique_ptr<EventLoop> client_event_loop_;
+ MessageBridgeAuthClient auth_client_;
+
+ protected:
+ void RequestAuthKey() {
+ LOG(INFO) << "Requesting auth key";
+ auto sender = request_key_sender_.MakeBuilder();
+ auto builder = sender.MakeBuilder<SctpConfigRequest>();
+ builder.add_request_key(true);
+ sender.CheckOk(sender.Send(builder.Finish()));
+ }
+
+ void RunFor(distributed_clock::duration duration) {
+ event_loop_factory_.RunFor(duration);
+ }
+
+ std::unique_ptr<EventLoop> mock_event_loop_;
+ Sender<SctpConfigRequest> request_key_sender_;
+};
+
+// The "obvious" test for the message bridge authentication server/client.
+//
+// It spins up the server (done once for the entire test suite), creates a
+// client, and checks that we propagate the key from the server into the
+// appropriate AOS channel upon an a key request.
+TEST_F(MessageBridgeAuthTest, SmokeTest) {
+ // How many times we receive a new key.
+ int key_count = 0;
+ std::vector<uint8_t> auth_key;
+ mock_event_loop_->MakeWatcher("/aos", [&](const SctpConfig &config) {
+ if (config.has_key()) {
+ key_count++;
+ if (auth_key.empty()) {
+ auth_key.assign(config.key()->begin(), config.key()->end());
+ }
+ LOG(INFO) << "Got new auth key";
+ // Key shouldn't change as we are running on the same server.
+ EXPECT_THAT(auth_key,
+ ElementsAreArray(config.key()->begin(), config.key()->end()));
+ }
+ });
+
+ RunFor(1000ms);
+ RequestAuthKey();
+ RunFor(1000ms);
+ RequestAuthKey();
+ RunFor(1000ms);
+ EXPECT_FALSE(auth_key.empty());
+ // We requested the key twice, we should get it back twice.
+ EXPECT_EQ(key_count, 2);
+}
+
+} // namespace
+} // namespace aos::message_bridge::auth::testing
diff --git a/aos/network/message_bridge_auth_test.json b/aos/network/message_bridge_auth_test.json
new file mode 100644
index 0000000..8ebdda0
--- /dev/null
+++ b/aos/network/message_bridge_auth_test.json
@@ -0,0 +1,32 @@
+{
+ "channels": [
+ {
+ "name": "/aos",
+ "type": "aos.logging.LogMessageFbs",
+ "frequency": 200,
+ "num_senders": 20,
+ "max_size": 2048
+ },
+ {
+ "name": "/aos",
+ "type": "aos.timing.Report",
+ "frequency": 50,
+ "num_senders": 20,
+ "max_size": 2048
+ },
+ {
+ "name": "/aos",
+ "type": "aos.message_bridge.SctpConfig",
+ "frequency": 10,
+ "num_senders": 1,
+ "max_size": 256
+ },
+ {
+ "name": "/aos",
+ "type": "aos.message_bridge.SctpConfigRequest",
+ "frequency": 1,
+ "num_senders": 2,
+ "max_size": 32
+ }
+ ]
+}
diff --git a/aos/network/message_bridge_client_lib.cc b/aos/network/message_bridge_client_lib.cc
index 34f578e..bb233a9 100644
--- a/aos/network/message_bridge_client_lib.cc
+++ b/aos/network/message_bridge_client_lib.cc
@@ -19,6 +19,11 @@
#include "aos/unique_malloc_ptr.h"
#include "aos/util/file.h"
+// The casts required to read datastructures from sockets trip - Wcast - align.
+#ifdef __clang
+#pragma clang diagnostic ignored "-Wcast-align"
+#endif
+
DECLARE_bool(use_sctp_authentication);
// This application receives messages from another node and re-publishes them on
diff --git a/aos/network/message_bridge_server_lib.cc b/aos/network/message_bridge_server_lib.cc
index 35c8afe..4f582e7 100644
--- a/aos/network/message_bridge_server_lib.cc
+++ b/aos/network/message_bridge_server_lib.cc
@@ -17,6 +17,11 @@
#include "aos/network/sctp_server.h"
#include "aos/network/timestamp_channel.h"
+// The casts required to read datastructures from sockets trip - Wcast - align.
+#ifdef __clang
+#pragma clang diagnostic ignored "-Wcast-align"
+#endif
+
// For retrying sends on reliable channels, we will do an additive backoff
// strategy where we start at FLAGS_min_retry_period_ms and then add
// kRetryAdditivePeriod every time the retry fails, up until
diff --git a/aos/network/sctp_lib.cc b/aos/network/sctp_lib.cc
index 0922d6b..99a7f09 100644
--- a/aos/network/sctp_lib.cc
+++ b/aos/network/sctp_lib.cc
@@ -17,6 +17,11 @@
#include "aos/util/file.h"
+// The casts required to read datastructures from sockets trip - Wcast - align.
+#ifdef __clang
+#pragma clang diagnostic ignored "-Wcast-align"
+#endif
+
DEFINE_string(interface, "", "network interface");
DEFINE_bool(disable_ipv6, false, "disable ipv6");
DEFINE_int32(rmem, 0, "If nonzero, set rmem to this size.");
diff --git a/aos/network/sctp_perf.cc b/aos/network/sctp_perf.cc
index 5201f47..db762de 100644
--- a/aos/network/sctp_perf.cc
+++ b/aos/network/sctp_perf.cc
@@ -9,6 +9,11 @@
#include "aos/network/sctp_lib.h"
#include "aos/network/sctp_server.h"
+// The casts required to read datastructures from sockets trip - Wcast - align.
+#ifdef __clang
+#pragma clang diagnostic ignored "-Wcast-align"
+#endif
+
DEFINE_string(config, "aos_config.json", "Path to the config.");
DEFINE_uint32(port, 1323, "Port to run the sctp test on");
DEFINE_uint32(payload_size, 1000, "Size of data to send in bytes");