#pragma once #include #include #include #include #include #include #include "IPFrameInfo.hh" #include "ProxyServer.hh" #include "Server.hh" #include "ServerState.hh" #include "Text.hh" class IPStackSimulator : public std::enable_shared_from_this { public: enum class Protocol { ETHERNET_TAPSERVER = 0, HDLC_TAPSERVER, HDLC_RAW, }; IPStackSimulator( std::shared_ptr base, std::shared_ptr state); ~IPStackSimulator(); 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, Protocol protocol); void listen(const std::string& name, int port, Protocol protocol); void add_socket(const std::string& name, int fd, Protocol protocol); static uint32_t connect_address_for_remote_address(uint32_t remote_addr); private: std::shared_ptr base; std::shared_ptr state; using unique_listener = std::unique_ptr; using unique_bufferevent = std::unique_ptr; using unique_evbuffer = std::unique_ptr; using unique_event = std::unique_ptr; struct IPClient { std::weak_ptr sim; unique_bufferevent bev; Protocol protocol; uint32_t hdlc_escape_control_character_flags = 0xFFFFFFFF; uint32_t hdlc_remote_magic_number = 0; parray mac_addr; // Only used for LinkType::ETHERNET uint32_t ipv4_addr; struct TCPConnection { std::weak_ptr client; // The PSO protocol begins with the server sending a command, but we // shouldn't send a PSH immediately after the SYN+ACK, so the connection // isn't handed to the Server object until after the 3-way handshake // (receive SYN, send SYN+ACK, receive ACK). This means server_bev is null // during the first part of the connection phase. unique_bufferevent server_bev; // TODO: Get rid of pending_data and just use server_bev's input buffer in // its place unique_evbuffer pending_data; unique_event resend_push_event; bool awaiting_first_ack; uint32_t server_addr; uint16_t server_port; uint16_t client_port; uint32_t next_client_seq; uint32_t acked_server_seq; size_t resend_push_usecs; size_t next_push_max_frame_size; size_t max_frame_size; size_t bytes_received; size_t bytes_sent; TCPConnection(); }; std::unordered_map tcp_connections; unique_event idle_timeout_event; IPClient(std::shared_ptr sim, Protocol protocol, struct bufferevent* bev); static void dispatch_on_idle_timeout(evutil_socket_t fd, short events, void* ctx); void on_idle_timeout(); }; struct ListeningSocket { std::string name; Protocol protocol; unique_listener listener; ListeningSocket(const std::string& name, Protocol protocol, unique_listener&& l) : name(name), protocol(protocol), listener(std::move(l)) {} }; std::unordered_map listening_sockets; std::unordered_map> bev_to_client; parray host_mac_address_bytes; parray broadcast_mac_address_bytes; FILE* pcap_text_log_file; void disconnect_client(struct bufferevent* bev); static uint64_t tcp_conn_key_for_connection(const IPClient::TCPConnection& conn); static uint64_t tcp_conn_key_for_client_frame(const IPv4Header& ipv4, const TCPHeader& tcp); static uint64_t tcp_conn_key_for_client_frame(const FrameInfo& fi); static std::string str_for_ipv4_netloc(uint32_t addr, uint16_t port); static std::string str_for_tcp_connection(std::shared_ptr c, const IPClient::TCPConnection& conn); static void dispatch_on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr* address, int socklen, void* ctx); void on_listen_accept(struct evconnlistener* listener, evutil_socket_t fd, struct sockaddr* address, int socklen); static void dispatch_on_listen_error(struct evconnlistener* listener, void* ctx); void on_listen_error(struct evconnlistener* listener); static void dispatch_on_client_input(struct bufferevent* bev, void* ctx); void on_client_input(struct bufferevent* bev); static void dispatch_on_client_error(struct bufferevent* bev, short events, void* ctx); void on_client_error(struct bufferevent* bev, short events); void send_layer3_frame(std::shared_ptr c, FrameInfo::Protocol proto, const std::string& data) const; void send_layer3_frame(std::shared_ptr c, FrameInfo::Protocol proto, const void* data, size_t size) const; void on_client_frame(std::shared_ptr c, const std::string& frame); void on_client_lcp_frame(std::shared_ptr c, const FrameInfo& fi); void on_client_pap_frame(std::shared_ptr c, const FrameInfo& fi); void on_client_ipcp_frame(std::shared_ptr c, const FrameInfo& fi); void on_client_arp_frame(std::shared_ptr c, const FrameInfo& fi); void on_client_udp_frame(std::shared_ptr c, const FrameInfo& fi); void on_client_tcp_frame(std::shared_ptr c, const FrameInfo& fi); static void dispatch_on_server_input(struct bufferevent* bev, void* ctx); void on_server_input(std::shared_ptr c, IPClient::TCPConnection& conn); static void dispatch_on_server_error(struct bufferevent* bev, short events, void* ctx); void on_server_error(std::shared_ptr c, IPClient::TCPConnection& conn, short events); static void dispatch_on_resend_push(evutil_socket_t, short, void* ctx); void send_pending_push_frame(std::shared_ptr c, IPClient::TCPConnection& conn, bool always_send); void send_tcp_frame( std::shared_ptr c, IPClient::TCPConnection& conn, uint16_t flags = 0, struct evbuffer* src_buf = nullptr, size_t src_bytes = 0); void open_server_connection( std::shared_ptr c, IPClient::TCPConnection& conn); void log_frame(const std::string& data) const; };