add PPP_RAW protocol

This commit is contained in:
Martin Michelsen
2024-02-23 22:48:53 -08:00
parent a4f69f6ca3
commit 82004b05dc
5 changed files with 116 additions and 47 deletions
+82 -35
View File
@@ -135,28 +135,28 @@ IPStackSimulator::~IPStackSimulator() {
} }
} }
void IPStackSimulator::listen(const string& name, const string& socket_path, FrameInfo::LinkType link_type) { void IPStackSimulator::listen(const string& name, const string& socket_path, Protocol proto) {
int fd = ::listen(socket_path, 0, SOMAXCONN); int fd = ::listen(socket_path, 0, SOMAXCONN);
ip_stack_simulator_log.info("Listening on Unix socket %s on fd %d as %s", socket_path.c_str(), fd, name.c_str()); ip_stack_simulator_log.info("Listening on Unix socket %s on fd %d as %s", socket_path.c_str(), fd, name.c_str());
this->add_socket(name, fd, link_type); this->add_socket(name, fd, proto);
} }
void IPStackSimulator::listen(const string& name, const string& addr, int port, FrameInfo::LinkType link_type) { void IPStackSimulator::listen(const string& name, const string& addr, int port, Protocol proto) {
if (port == 0) { if (port == 0) {
this->listen(name, addr, link_type); this->listen(name, addr, proto);
} else { } else {
int fd = ::listen(addr, port, SOMAXCONN); int fd = ::listen(addr, port, SOMAXCONN);
string netloc_str = render_netloc(addr, port); string netloc_str = render_netloc(addr, port);
ip_stack_simulator_log.info("Listening on TCP interface %s on fd %d as %s", netloc_str.c_str(), fd, name.c_str()); ip_stack_simulator_log.info("Listening on TCP interface %s on fd %d as %s", netloc_str.c_str(), fd, name.c_str());
this->add_socket(name, fd, link_type); this->add_socket(name, fd, proto);
} }
} }
void IPStackSimulator::listen(const string& name, int port, FrameInfo::LinkType link_type) { void IPStackSimulator::listen(const string& name, int port, Protocol proto) {
this->listen(name, "", port, link_type); this->listen(name, "", port, proto);
} }
void IPStackSimulator::add_socket(const string& name, int fd, FrameInfo::LinkType link_type) { void IPStackSimulator::add_socket(const string& name, int fd, Protocol proto) {
unique_listener l( unique_listener l(
evconnlistener_new( evconnlistener_new(
this->base.get(), this->base.get(),
@@ -166,7 +166,7 @@ void IPStackSimulator::add_socket(const string& name, int fd, FrameInfo::LinkTyp
0, 0,
fd), fd),
evconnlistener_free); evconnlistener_free);
this->listening_sockets.emplace(piecewise_construct, forward_as_tuple(fd), forward_as_tuple(name, link_type, std::move(l))); this->listening_sockets.emplace(piecewise_construct, forward_as_tuple(fd), forward_as_tuple(name, proto, std::move(l)));
} }
uint32_t IPStackSimulator::connect_address_for_remote_address(uint32_t remote_addr) { uint32_t IPStackSimulator::connect_address_for_remote_address(uint32_t remote_addr) {
@@ -180,10 +180,10 @@ uint32_t IPStackSimulator::connect_address_for_remote_address(uint32_t remote_ad
} }
} }
IPStackSimulator::IPClient::IPClient(shared_ptr<IPStackSimulator> sim, FrameInfo::LinkType link_type, struct bufferevent* bev) IPStackSimulator::IPClient::IPClient(shared_ptr<IPStackSimulator> sim, Protocol protocol, struct bufferevent* bev)
: sim(sim), : sim(sim),
bev(bev, bufferevent_free), bev(bev, bufferevent_free),
link_type(link_type), protocol(protocol),
mac_addr(0), mac_addr(0),
ipv4_addr(0), ipv4_addr(0),
idle_timeout_event(event_new(sim->base.get(), -1, EV_TIMEOUT, &IPStackSimulator::IPClient::dispatch_on_idle_timeout, this), event_free) { idle_timeout_event(event_new(sim->base.get(), -1, EV_TIMEOUT, &IPStackSimulator::IPClient::dispatch_on_idle_timeout, this), event_free) {
@@ -256,7 +256,7 @@ void IPStackSimulator::on_listen_accept(struct evconnlistener* listener,
struct bufferevent* bev = bufferevent_socket_new(this->base.get(), fd, struct bufferevent* bev = bufferevent_socket_new(this->base.get(), fd,
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
auto c = make_shared<IPClient>(this->shared_from_this(), listening_socket->link_type, bev); auto c = make_shared<IPClient>(this->shared_from_this(), listening_socket->protocol, bev);
this->bev_to_client.emplace(make_pair(bev, c)); this->bev_to_client.emplace(make_pair(bev, c));
bufferevent_setcb(bev, &IPStackSimulator::dispatch_on_client_input, nullptr, bufferevent_setcb(bev, &IPStackSimulator::dispatch_on_client_input, nullptr,
@@ -300,24 +300,64 @@ void IPStackSimulator::on_client_input(struct bufferevent* bev) {
struct timeval tv = usecs_to_timeval(idle_timeout_usecs); struct timeval tv = usecs_to_timeval(idle_timeout_usecs);
event_add(c->idle_timeout_event.get(), &tv); event_add(c->idle_timeout_event.get(), &tv);
while (evbuffer_get_length(buf) >= 2) { switch (c->protocol) {
uint16_t frame_size; case Protocol::ETHERNET_TAPSERVER:
evbuffer_copyout(buf, &frame_size, 2); case Protocol::HDLC_TAPSERVER:
if (evbuffer_get_length(buf) < static_cast<size_t>(frame_size + 2)) { while (evbuffer_get_length(buf) >= 2) {
break; // No complete frame available; done for now uint16_t frame_size;
} evbuffer_copyout(buf, &frame_size, 2);
if (evbuffer_get_length(buf) < static_cast<size_t>(frame_size + 2)) {
break; // No complete frame available; done for now
}
evbuffer_drain(buf, 2); evbuffer_drain(buf, 2);
string frame(frame_size, '\0'); string frame(frame_size, '\0');
evbuffer_remove(buf, frame.data(), frame.size()); evbuffer_remove(buf, frame.data(), frame.size());
try { try {
this->on_client_frame(c, frame); this->on_client_frame(c, frame);
} catch (const exception& e) { } catch (const exception& e) {
if (ip_stack_simulator_log.warning("Failed to process frame: %s", e.what())) { if (ip_stack_simulator_log.warning("Failed to process frame: %s", e.what())) {
print_data(stderr, frame); print_data(stderr, frame);
}
}
} }
} break;
case Protocol::HDLC_RAW:
while (evbuffer_get_length(buf) >= 2) {
struct evbuffer_ptr res = evbuffer_search(buf, "\x7E", 1, nullptr);
if (res.pos < 0) {
break;
}
size_t start_offset = res.pos;
if (evbuffer_ptr_set(buf, &res, 1, EVBUFFER_PTR_ADD)) {
ip_stack_simulator_log.warning("Cannot advance search for end of frame");
break;
}
struct evbuffer_ptr end_res = evbuffer_search(buf, "\x7E", 1, &res);
if (end_res.pos < 0) {
break;
}
size_t frame_size = end_res.pos + 1 - start_offset;
if (start_offset) {
evbuffer_drain(buf, start_offset);
}
string frame(frame_size, '\0');
evbuffer_remove(buf, frame.data(), frame.size());
try {
this->on_client_frame(c, frame);
} catch (const exception& e) {
if (ip_stack_simulator_log.warning("Failed to process frame: %s", e.what())) {
print_data(stderr, frame);
}
}
}
break;
} }
} }
@@ -343,8 +383,8 @@ void IPStackSimulator::send_layer3_frame(shared_ptr<IPClient> c, FrameInfo::Prot
void IPStackSimulator::send_layer3_frame(shared_ptr<IPClient> c, FrameInfo::Protocol proto, const void* data, size_t size) const { void IPStackSimulator::send_layer3_frame(shared_ptr<IPClient> c, FrameInfo::Protocol proto, const void* data, size_t size) const {
struct evbuffer* out_buf = bufferevent_get_output(c->bev.get()); struct evbuffer* out_buf = bufferevent_get_output(c->bev.get());
switch (c->link_type) { switch (c->protocol) {
case FrameInfo::LinkType::ETHERNET: { case Protocol::ETHERNET_TAPSERVER: {
EthernetHeader ether; EthernetHeader ether;
ether.dest_mac = c->mac_addr; ether.dest_mac = c->mac_addr;
ether.src_mac = this->host_mac_address_bytes; ether.src_mac = this->host_mac_address_bytes;
@@ -376,7 +416,8 @@ void IPStackSimulator::send_layer3_frame(shared_ptr<IPClient> c, FrameInfo::Prot
break; break;
} }
case FrameInfo::LinkType::HDLC: { case Protocol::HDLC_TAPSERVER:
case Protocol::HDLC_RAW: {
HDLCHeader hdlc; HDLCHeader hdlc;
hdlc.start_sentinel1 = 0x7E; hdlc.start_sentinel1 = 0x7E;
hdlc.address = 0xFF; hdlc.address = 0xFF;
@@ -413,8 +454,10 @@ void IPStackSimulator::send_layer3_frame(shared_ptr<IPClient> c, FrameInfo::Prot
print_data(stderr, w.str()); print_data(stderr, w.str());
} }
le_uint16_t frame_size = escaped.size(); if (c->protocol == Protocol::HDLC_TAPSERVER) {
evbuffer_add(out_buf, &frame_size, 2); le_uint16_t frame_size = escaped.size();
evbuffer_add(out_buf, &frame_size, 2);
}
evbuffer_add(out_buf, escaped.data(), escaped.size()); evbuffer_add(out_buf, escaped.data(), escaped.size());
if (this->pcap_text_log_file) { if (this->pcap_text_log_file) {
this->log_frame(escaped); this->log_frame(escaped);
@@ -428,9 +471,13 @@ void IPStackSimulator::send_layer3_frame(shared_ptr<IPClient> c, FrameInfo::Prot
} }
void IPStackSimulator::on_client_frame(shared_ptr<IPClient> c, const string& frame) { void IPStackSimulator::on_client_frame(shared_ptr<IPClient> c, const string& frame) {
FrameInfo::LinkType link_type = (c->protocol == Protocol::ETHERNET_TAPSERVER)
? FrameInfo::LinkType::ETHERNET
: FrameInfo::LinkType::HDLC;
const string* effective_data = &frame; const string* effective_data = &frame;
string hdlc_unescaped_data; string hdlc_unescaped_data;
if (c->link_type == FrameInfo::LinkType::HDLC) { if (link_type == FrameInfo::LinkType::HDLC) {
hdlc_unescaped_data = unescape_hdlc_frame(frame); hdlc_unescaped_data = unescape_hdlc_frame(frame);
effective_data = &hdlc_unescaped_data; effective_data = &hdlc_unescaped_data;
} }
@@ -439,7 +486,7 @@ void IPStackSimulator::on_client_frame(shared_ptr<IPClient> c, const string& fra
} }
this->log_frame(*effective_data); this->log_frame(*effective_data);
FrameInfo fi(c->link_type, *effective_data); FrameInfo fi(link_type, *effective_data);
if (ip_stack_simulator_log.should_log(LogLevel::DEBUG)) { if (ip_stack_simulator_log.should_log(LogLevel::DEBUG)) {
string fi_header = fi.header_str(); string fi_header = fi.header_str();
ip_stack_simulator_log.debug("Frame header: %s", fi_header.c_str()); ip_stack_simulator_log.debug("Frame header: %s", fi_header.c_str());
@@ -1314,7 +1361,7 @@ void IPStackSimulator::send_pending_push_frame(shared_ptr<IPClient> c, IPClient:
} }
size_t bytes_to_send = min<size_t>(pending_bytes, conn.next_push_max_frame_size); size_t bytes_to_send = min<size_t>(pending_bytes, conn.next_push_max_frame_size);
if ((c->link_type == FrameInfo::LinkType::HDLC) && (bytes_to_send > 200)) { if ((c->protocol == Protocol::HDLC_TAPSERVER) && (bytes_to_send > 200)) {
// There is a bug in Dolphin's modem implementation (which I wrote, so it's // There is a bug in Dolphin's modem implementation (which I wrote, so it's
// my fault) that causes commands to be dropped when too much data is sent // my fault) that causes commands to be dropped when too much data is sent
// at once. To work around this, we only send up to 200 bytes in each push // at once. To work around this, we only send up to 200 bytes in each push
+15 -9
View File
@@ -16,15 +16,21 @@
class IPStackSimulator : public std::enable_shared_from_this<IPStackSimulator> { class IPStackSimulator : public std::enable_shared_from_this<IPStackSimulator> {
public: public:
enum class Protocol {
ETHERNET_TAPSERVER = 0,
HDLC_TAPSERVER,
HDLC_RAW,
};
IPStackSimulator( IPStackSimulator(
std::shared_ptr<struct event_base> base, std::shared_ptr<struct event_base> base,
std::shared_ptr<ServerState> state); std::shared_ptr<ServerState> state);
~IPStackSimulator(); ~IPStackSimulator();
void listen(const std::string& name, const std::string& socket_path, FrameInfo::LinkType link_type); void listen(const std::string& name, const std::string& socket_path, Protocol protocol);
void listen(const std::string& name, const std::string& addr, int port, FrameInfo::LinkType link_type); void listen(const std::string& name, const std::string& addr, int port, Protocol protocol);
void listen(const std::string& name, int port, FrameInfo::LinkType link_type); void listen(const std::string& name, int port, Protocol protocol);
void add_socket(const std::string& name, int fd, FrameInfo::LinkType link_type); void add_socket(const std::string& name, int fd, Protocol protocol);
static uint32_t connect_address_for_remote_address(uint32_t remote_addr); static uint32_t connect_address_for_remote_address(uint32_t remote_addr);
@@ -41,7 +47,7 @@ private:
std::weak_ptr<IPStackSimulator> sim; std::weak_ptr<IPStackSimulator> sim;
unique_bufferevent bev; unique_bufferevent bev;
FrameInfo::LinkType link_type; Protocol protocol;
uint32_t hdlc_escape_control_character_flags = 0xFFFFFFFF; uint32_t hdlc_escape_control_character_flags = 0xFFFFFFFF;
uint32_t hdlc_remote_magic_number = 0; uint32_t hdlc_remote_magic_number = 0;
parray<uint8_t, 6> mac_addr; // Only used for LinkType::ETHERNET parray<uint8_t, 6> mac_addr; // Only used for LinkType::ETHERNET
@@ -80,7 +86,7 @@ private:
unique_event idle_timeout_event; unique_event idle_timeout_event;
IPClient(std::shared_ptr<IPStackSimulator> sim, FrameInfo::LinkType link_type, struct bufferevent* bev); IPClient(std::shared_ptr<IPStackSimulator> sim, Protocol protocol, struct bufferevent* bev);
static void dispatch_on_idle_timeout(evutil_socket_t fd, short events, void* ctx); static void dispatch_on_idle_timeout(evutil_socket_t fd, short events, void* ctx);
void on_idle_timeout(); void on_idle_timeout();
@@ -88,12 +94,12 @@ private:
struct ListeningSocket { struct ListeningSocket {
std::string name; std::string name;
FrameInfo::LinkType link_type; Protocol protocol;
unique_listener listener; unique_listener listener;
ListeningSocket(const std::string& name, FrameInfo::LinkType link_type, unique_listener&& l) ListeningSocket(const std::string& name, Protocol protocol, unique_listener&& l)
: name(name), : name(name),
link_type(link_type), protocol(protocol),
listener(std::move(l)) {} listener(std::move(l)) {}
}; };
+8 -3
View File
@@ -2452,12 +2452,17 @@ Action a_run_server_replay_log(
for (const auto& it : state->ip_stack_addresses) { for (const auto& it : state->ip_stack_addresses) {
auto netloc = parse_netloc(it); auto netloc = parse_netloc(it);
string spec = (netloc.second == 0) ? ("T-IPS-" + netloc.first) : string_printf("T-IPS-%hu", netloc.second); string spec = (netloc.second == 0) ? ("T-IPS-" + netloc.first) : string_printf("T-IPS-%hu", netloc.second);
ip_stack_simulator->listen(spec, netloc.first, netloc.second, FrameInfo::LinkType::ETHERNET); ip_stack_simulator->listen(spec, netloc.first, netloc.second, IPStackSimulator::Protocol::ETHERNET_TAPSERVER);
} }
for (const auto& it : state->ppp_stack_addresses) { for (const auto& it : state->ppp_stack_addresses) {
auto netloc = parse_netloc(it); auto netloc = parse_netloc(it);
string spec = (netloc.second == 0) ? ("T-PPPS-" + netloc.first) : string_printf("T-PPPS-%hu", netloc.second); string spec = (netloc.second == 0) ? ("T-PPPST-" + netloc.first) : string_printf("T-PPPST-%hu", netloc.second);
ip_stack_simulator->listen(spec, netloc.first, netloc.second, FrameInfo::LinkType::HDLC); ip_stack_simulator->listen(spec, netloc.first, netloc.second, IPStackSimulator::Protocol::HDLC_TAPSERVER);
}
for (const auto& it : state->ppp_raw_addresses) {
auto netloc = parse_netloc(it);
string spec = (netloc.second == 0) ? ("T-PPPSR-" + netloc.first) : string_printf("T-PPPSR-%hu", netloc.second);
ip_stack_simulator->listen(spec, netloc.first, netloc.second, IPStackSimulator::Protocol::HDLC_RAW);
} }
} }
+10
View File
@@ -622,6 +622,16 @@ void ServerState::load_config_early() {
} }
} catch (const out_of_range&) { } catch (const out_of_range&) {
} }
try {
for (const auto& item : this->config_json.at("PPPRawListen").as_list()) {
if (item->is_int()) {
this->ppp_raw_addresses.emplace_back(string_printf("0.0.0.0:%" PRId64, item->as_int()));
} else {
this->ppp_raw_addresses.emplace_back(item->as_string());
}
}
} catch (const out_of_range&) {
}
try { try {
for (const auto& item : this->config_json.at("HTTPListen").as_list()) { for (const auto& item : this->config_json.at("HTTPListen").as_list()) {
if (item->is_int()) { if (item->is_int()) {
+1
View File
@@ -79,6 +79,7 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
uint16_t dns_server_port = 0; uint16_t dns_server_port = 0;
std::vector<std::string> ip_stack_addresses; std::vector<std::string> ip_stack_addresses;
std::vector<std::string> ppp_stack_addresses; std::vector<std::string> ppp_stack_addresses;
std::vector<std::string> ppp_raw_addresses;
std::vector<std::string> http_addresses; std::vector<std::string> http_addresses;
uint64_t client_ping_interval_usecs = 30000000; uint64_t client_ping_interval_usecs = 30000000;
uint64_t client_idle_timeout_usecs = 60000000; uint64_t client_idle_timeout_usecs = 60000000;