mirror of
https://github.com/brazilofmux/tinymux
synced 2026-08-13 00:23:11 -04:00
ganl: remove dead telnet_protocol_handler (Hydra-client parser, never built into the server path) (#793)
telnet_protocol_handler.cpp (1699 lines) + its header compiled into libganl but were never instantiated in netmux: the live protocol handler is RawPassthroughHandler (ganl_adapter.cpp:1414), which feeds raw bytes straight into the real server-side telnet NVT parser, mux/src/telnet.cpp:: process_input_helper. TelnetProtocolHandler was authored for an external "Hydra" telnet *client* (per its createClientProtocolContext "Hydra" API) and is referenced nowhere in this tree outside its own .cpp/.h and the Makefiles. Keeping it was an audit/maintenance hazard: it looks like the live telnet handler but isn't (a future change could wire it onto the data path assuming it is the tested parser), and it carries latent gaps that would matter only if activated (GMCP/MSSP/MXP subnegotiation falls through to default/ignored). Remove it from libganl: drop both files and their Makefile.am entries, regenerate Makefile.in. No #include of the header exists outside the deleted .cpp. Clean rebuild links libganl + netmux without it; smoke 1115/1115. The external Hydra project keeps its own copy; history preserves this one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d66953fb92
commit
537b155a20
4 changed files with 12 additions and 1952 deletions
|
|
@ -15,8 +15,7 @@ libganl_a_SOURCES = \
|
|||
src/openssl_transport.cpp \
|
||||
src/secure_transport_factory.cpp \
|
||||
src/select_network_engine.cpp \
|
||||
src/slave_spawn_posix.cpp \
|
||||
src/telnet_protocol_handler.cpp
|
||||
src/slave_spawn_posix.cpp
|
||||
|
||||
# Platform-specific source files
|
||||
if HAVE_EPOLL
|
||||
|
|
@ -42,5 +41,4 @@ noinst_HEADERS = \
|
|||
include/secure_transport.h \
|
||||
include/select_network_engine.h \
|
||||
include/session_manager.h \
|
||||
include/slave_spawn_posix.h \
|
||||
include/telnet_protocol_handler.h
|
||||
include/slave_spawn_posix.h
|
||||
|
|
|
|||
|
|
@ -122,8 +122,7 @@ am__libganl_a_SOURCES_DIST = src/connection.cpp src/io_buffer.cpp \
|
|||
src/network_address.cpp src/network_engine_factory.cpp \
|
||||
src/openssl_transport.cpp src/secure_transport_factory.cpp \
|
||||
src/select_network_engine.cpp src/slave_spawn_posix.cpp \
|
||||
src/telnet_protocol_handler.cpp src/epoll_network_engine.cpp \
|
||||
src/kqueue_network_engine.cpp
|
||||
src/epoll_network_engine.cpp src/kqueue_network_engine.cpp
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
@HAVE_EPOLL_TRUE@am__objects_1 = src/epoll_network_engine.$(OBJEXT)
|
||||
@HAVE_KQUEUE_TRUE@am__objects_2 = src/kqueue_network_engine.$(OBJEXT)
|
||||
|
|
@ -133,8 +132,7 @@ am_libganl_a_OBJECTS = src/connection.$(OBJEXT) \
|
|||
src/openssl_transport.$(OBJEXT) \
|
||||
src/secure_transport_factory.$(OBJEXT) \
|
||||
src/select_network_engine.$(OBJEXT) \
|
||||
src/slave_spawn_posix.$(OBJEXT) \
|
||||
src/telnet_protocol_handler.$(OBJEXT) $(am__objects_1) \
|
||||
src/slave_spawn_posix.$(OBJEXT) $(am__objects_1) \
|
||||
$(am__objects_2)
|
||||
libganl_a_OBJECTS = $(am_libganl_a_OBJECTS)
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
|
|
@ -161,8 +159,7 @@ am__depfiles_remade = src/$(DEPDIR)/connection.Po \
|
|||
src/$(DEPDIR)/openssl_transport.Po \
|
||||
src/$(DEPDIR)/secure_transport_factory.Po \
|
||||
src/$(DEPDIR)/select_network_engine.Po \
|
||||
src/$(DEPDIR)/slave_spawn_posix.Po \
|
||||
src/$(DEPDIR)/telnet_protocol_handler.Po
|
||||
src/$(DEPDIR)/slave_spawn_posix.Po
|
||||
am__mv = mv -f
|
||||
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
|
||||
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
|
||||
|
|
@ -234,6 +231,7 @@ ECHO_C = @ECHO_C@
|
|||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
ENGINE_SONAME_FLAG = @ENGINE_SONAME_FLAG@
|
||||
ETAGS = @ETAGS@
|
||||
EXEEXT = @EXEEXT@
|
||||
GREP = @GREP@
|
||||
|
|
@ -249,6 +247,10 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
|||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LD_HARDENING = @LD_HARDENING@
|
||||
LD_NOUNDEFINED = @LD_NOUNDEFINED@
|
||||
LD_RPATH_ORIGIN = @LD_RPATH_ORIGIN@
|
||||
LIBMUX_SONAME_FLAG = @LIBMUX_SONAME_FLAG@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LN_S = @LN_S@
|
||||
|
|
@ -350,8 +352,7 @@ libganl_a_SOURCES = src/connection.cpp src/io_buffer.cpp \
|
|||
src/network_address.cpp src/network_engine_factory.cpp \
|
||||
src/openssl_transport.cpp src/secure_transport_factory.cpp \
|
||||
src/select_network_engine.cpp src/slave_spawn_posix.cpp \
|
||||
src/telnet_protocol_handler.cpp $(am__append_1) \
|
||||
$(am__append_2)
|
||||
$(am__append_1) $(am__append_2)
|
||||
|
||||
# Header files (for distribution)
|
||||
noinst_HEADERS = \
|
||||
|
|
@ -368,8 +369,7 @@ noinst_HEADERS = \
|
|||
include/secure_transport.h \
|
||||
include/select_network_engine.h \
|
||||
include/session_manager.h \
|
||||
include/slave_spawn_posix.h \
|
||||
include/telnet_protocol_handler.h
|
||||
include/slave_spawn_posix.h
|
||||
|
||||
all: all-am
|
||||
|
||||
|
|
@ -429,8 +429,6 @@ src/select_network_engine.$(OBJEXT): src/$(am__dirstamp) \
|
|||
src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/slave_spawn_posix.$(OBJEXT): src/$(am__dirstamp) \
|
||||
src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/telnet_protocol_handler.$(OBJEXT): src/$(am__dirstamp) \
|
||||
src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/epoll_network_engine.$(OBJEXT): src/$(am__dirstamp) \
|
||||
src/$(DEPDIR)/$(am__dirstamp)
|
||||
src/kqueue_network_engine.$(OBJEXT): src/$(am__dirstamp) \
|
||||
|
|
@ -458,7 +456,6 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/secure_transport_factory.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/select_network_engine.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/slave_spawn_posix.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/telnet_protocol_handler.Po@am__quote@ # am--include-marker
|
||||
|
||||
$(am__depfiles_remade):
|
||||
@$(MKDIR_P) $(@D)
|
||||
|
|
@ -617,7 +614,6 @@ distclean: distclean-am
|
|||
-rm -f src/$(DEPDIR)/secure_transport_factory.Po
|
||||
-rm -f src/$(DEPDIR)/select_network_engine.Po
|
||||
-rm -f src/$(DEPDIR)/slave_spawn_posix.Po
|
||||
-rm -f src/$(DEPDIR)/telnet_protocol_handler.Po
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
|
@ -673,7 +669,6 @@ maintainer-clean: maintainer-clean-am
|
|||
-rm -f src/$(DEPDIR)/secure_transport_factory.Po
|
||||
-rm -f src/$(DEPDIR)/select_network_engine.Po
|
||||
-rm -f src/$(DEPDIR)/slave_spawn_posix.Po
|
||||
-rm -f src/$(DEPDIR)/telnet_protocol_handler.Po
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
|
|
|
|||
|
|
@ -1,234 +0,0 @@
|
|||
#ifndef GANL_TELNET_PROTOCOL_HANDLER_H
|
||||
#define GANL_TELNET_PROTOCOL_HANDLER_H
|
||||
|
||||
#include <protocol_handler.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <chrono> // For timeout tracking
|
||||
|
||||
namespace ganl {
|
||||
|
||||
// Telnet Options (ensure these values match your defines or an enum)
|
||||
enum class TelnetOption : unsigned char {
|
||||
BINARY = 0,
|
||||
ECHO = 1,
|
||||
SGA = 3,
|
||||
TTYPE = 24,
|
||||
EOR = 25,
|
||||
NAWS = 31,
|
||||
NEW_ENVIRON = 39,
|
||||
CHARSET = 42,
|
||||
STARTTLS = 46,
|
||||
MSSP = 70,
|
||||
GMCP = 201,
|
||||
UNKNOWN = 255
|
||||
};
|
||||
|
||||
// Telnet Commands (ensure these are correct)
|
||||
enum class TelnetCommand : unsigned char {
|
||||
SE = 240, NOP = 241, DM = 242, BRK = 243, IP = 244,
|
||||
AO = 245, AYT = 246, EC = 247, EL = 248, GA = 249,
|
||||
SB = 250, WILL = 251, WONT = 252, DO = 253, DONT = 254,
|
||||
IAC = 255
|
||||
};
|
||||
|
||||
// Negotiation mode: Server initiates offers, Client responds to them.
|
||||
enum class NegotiationMode { Server, Client };
|
||||
|
||||
class TelnetProtocolHandler : public ProtocolHandler {
|
||||
public:
|
||||
explicit TelnetProtocolHandler(bool offerStartTls = true);
|
||||
~TelnetProtocolHandler() override;
|
||||
|
||||
// Server-mode context (existing behavior).
|
||||
bool createProtocolContext(ConnectionHandle conn) override;
|
||||
|
||||
// Client-mode context: Hydra acts as a telnet client connecting
|
||||
// to a game server. Does not initiate negotiation — responds
|
||||
// to the server's WILL/DO offers instead.
|
||||
bool createClientProtocolContext(ConnectionHandle conn,
|
||||
uint16_t clientWidth = 80,
|
||||
uint16_t clientHeight = 24,
|
||||
const std::string& clientTtype = "Hydra");
|
||||
|
||||
void destroyProtocolContext(ConnectionHandle conn) override;
|
||||
|
||||
virtual bool canOfferStartTls() const { return offerStartTls_; }
|
||||
void setOfferStartTls(bool enabled) { offerStartTls_ = enabled; }
|
||||
void onNegotiationTimeout(ConnectionHandle conn); // Called by Connection
|
||||
|
||||
void startNegotiation(ConnectionHandle conn, IoBuffer& telnet_responses_out) override;
|
||||
bool processInput(ConnectionHandle conn, IoBuffer& decrypted_in,
|
||||
IoBuffer& app_data_out, IoBuffer& telnet_responses_out,
|
||||
bool consumeInput = true) override;
|
||||
bool formatOutput(ConnectionHandle conn, IoBuffer& app_data_in,
|
||||
IoBuffer& formatted_out, bool consumeInput = true) override;
|
||||
|
||||
NegotiationStatus getNegotiationStatus(ConnectionHandle conn) override;
|
||||
bool consumeStateChanges(ConnectionHandle conn,
|
||||
ProtocolState& outState,
|
||||
ProtocolStateChangeFlags& outFlags) override;
|
||||
|
||||
bool setEncoding(ConnectionHandle conn, EncodingType encoding) override;
|
||||
EncodingType getEncoding(ConnectionHandle conn) override;
|
||||
|
||||
ProtocolState getProtocolState(ConnectionHandle conn) override;
|
||||
void updateWidth(ConnectionHandle conn, uint16_t width) override;
|
||||
void updateHeight(ConnectionHandle conn, uint16_t height) override;
|
||||
|
||||
std::string getLastProtocolErrorString(ConnectionHandle conn) override;
|
||||
|
||||
bool isStartTlsNegotiated(ConnectionHandle conn);
|
||||
bool isReadyForApplication(ConnectionHandle conn);
|
||||
|
||||
protected:
|
||||
enum class ParserState { Normal, IAC, Command, Subnegotiation, Subnegotiation_IAC };
|
||||
|
||||
enum class OptionNegotiationState {
|
||||
Idle, SentWill, SentWont, SentDo, SentDont,
|
||||
ActiveWill, ActiveDo, RejectedWill, RejectedDo,
|
||||
ReceivedWill, ReceivedDo
|
||||
};
|
||||
|
||||
void handleTelnetStandaloneCommand(ConnectionHandle conn, TelnetCommand cmd, IoBuffer& telnet_responses_out);
|
||||
void handleTelnetOptionNegotiation(ConnectionHandle conn, TelnetCommand cmd, TelnetOption opt, IoBuffer& telnet_responses_out);
|
||||
void processSubnegotiationData(ConnectionHandle conn, TelnetOption opt, IoBuffer& telnet_responses_out);
|
||||
void sendTelnetCommand(IoBuffer& buffer, TelnetCommand cmd, TelnetOption opt);
|
||||
void updateNegotiationStatus(ConnectionHandle conn);
|
||||
|
||||
// Get the current state of an option negotiation
|
||||
OptionNegotiationState getOptionState(ConnectionHandle conn, TelnetOption opt) const;
|
||||
|
||||
private:
|
||||
static constexpr size_t kMaxInputBufferBytes = 8192;
|
||||
static constexpr size_t kMaxSubnegotiationBufferBytes = 4096;
|
||||
// A well-behaved client closes a subnegotiation (IAC SE) within a single
|
||||
// message. Bound it by wall-clock time as well as by buffer size so a
|
||||
// client that opens "IAC SB ... " and dribbles bytes without ever
|
||||
// sending IAC SE cannot pin the parser in the Subnegotiation state.
|
||||
static constexpr std::chrono::seconds kMaxSubnegotiationDuration{ 30 };
|
||||
static constexpr uint16_t kDefaultTerminalWidth = 80;
|
||||
static constexpr uint16_t kDefaultTerminalHeight = 24;
|
||||
static constexpr uint16_t kMaxTerminalDimension = 1000;
|
||||
static constexpr size_t kMaxTerminalTypeBytes = 256;
|
||||
|
||||
struct TelnetContext {
|
||||
NegotiationMode mode{ NegotiationMode::Server };
|
||||
|
||||
// Client-mode parameters (what Hydra reports to the game)
|
||||
uint16_t clientWidth{ 80 };
|
||||
uint16_t clientHeight{ 24 };
|
||||
std::string clientTtype{ "Hydra" };
|
||||
|
||||
ProtocolState state;
|
||||
std::vector<char> inputBuffer;
|
||||
bool sawCR{ false };
|
||||
|
||||
ParserState parserState{ ParserState::Normal };
|
||||
TelnetCommand lastCmd{ TelnetCommand::NOP };
|
||||
TelnetOption lastOpt{ TelnetOption::UNKNOWN };
|
||||
|
||||
std::vector<char> subnegotiationBuffer;
|
||||
// Set when the parser enters ParserState::Subnegotiation; used to
|
||||
// enforce kMaxSubnegotiationDuration.
|
||||
std::chrono::steady_clock::time_point subnegotiationStartTime;
|
||||
|
||||
NegotiationStatus currentNegotiationStatus{ NegotiationStatus::InProgress };
|
||||
bool negotiationTimedOut{ false };
|
||||
std::chrono::steady_clock::time_point negotiationStartTime;
|
||||
|
||||
std::map<TelnetOption, OptionNegotiationState> optionStates;
|
||||
|
||||
// --- Maps track our initial offers/requests ---
|
||||
std::map<TelnetOption, bool> weSentDo; // Tracks if we sent DO for a specific option
|
||||
std::map<TelnetOption, bool> weSentWill; // Tracks if we sent WILL for a specific option
|
||||
// --- Individual flags removed ---
|
||||
|
||||
// --- Flags indicating subnegotiation completion ---
|
||||
bool nawsDataReceived{ false };
|
||||
bool ttypeDataReceived{ false };
|
||||
bool newEnvironDataReceived{ false };
|
||||
bool charsetDataReceived{ false };
|
||||
bool charsetRequestPending{ false }; // RFC 2066: true while our REQUEST awaits reply
|
||||
bool startTlsWillReceived{ false }; // Set when client WILLs STARTTLS
|
||||
|
||||
std::string lastError;
|
||||
|
||||
ProtocolStateChangeFlags pendingStateChanges{ ProtocolStateChangeNone };
|
||||
|
||||
// Helper to check if an option's state is settled
|
||||
bool isStateSettled(TelnetOption opt) const {
|
||||
// Corrected lookup: use .count()/.at() for safety or rely on default construction
|
||||
auto it = optionStates.find(opt);
|
||||
if (it == optionStates.end()) {
|
||||
// If we never started negotiation for it (not in map), it's trivially settled.
|
||||
// Check if we *intended* to negotiate it via weSentDo/weSentWill maps.
|
||||
bool intended = (weSentDo.count(opt) && weSentDo.at(opt)) || (weSentWill.count(opt) && weSentWill.at(opt));
|
||||
return !intended || negotiationTimedOut; // Settled if not intended, or if intended but timed out
|
||||
}
|
||||
|
||||
|
||||
switch (it->second) {
|
||||
case OptionNegotiationState::ActiveWill:
|
||||
case OptionNegotiationState::ActiveDo:
|
||||
case OptionNegotiationState::RejectedWill:
|
||||
case OptionNegotiationState::RejectedDo:
|
||||
case OptionNegotiationState::ReceivedWill:
|
||||
case OptionNegotiationState::ReceivedDo:
|
||||
case OptionNegotiationState::SentWont:
|
||||
case OptionNegotiationState::SentDont:
|
||||
return true; // Final states are settled
|
||||
case OptionNegotiationState::Idle: // Should ideally not be in map if truly Idle, but handle defensively
|
||||
case OptionNegotiationState::SentWill:
|
||||
case OptionNegotiationState::SentDo:
|
||||
return negotiationTimedOut; // Pending states only settled if timed out
|
||||
}
|
||||
return false; // Should not happen
|
||||
}
|
||||
|
||||
// Returns true if encoding was changed, false otherwise.
|
||||
bool setEncoding(EncodingType newEncoding);
|
||||
|
||||
void setTelnetBinary(bool enabled);
|
||||
void setTelnetEcho(bool enabled);
|
||||
void setTelnetSGA(bool enabled);
|
||||
void setTelnetEOR(bool enabled);
|
||||
void setSupportsANSI(bool enabled);
|
||||
void setSupportsMXP(bool enabled);
|
||||
void setWidth(uint16_t width);
|
||||
void setHeight(uint16_t height);
|
||||
|
||||
void markStateChange(ProtocolStateChangeFlags flag) {
|
||||
pendingStateChanges |= flag;
|
||||
}
|
||||
};
|
||||
|
||||
std::map<ConnectionHandle, TelnetContext> contexts_;
|
||||
std::chrono::seconds negotiationTimeoutDuration_{ 10 }; // Configurable timeout
|
||||
bool offerStartTls_{true};
|
||||
|
||||
/**
|
||||
* Handle Telnet subnegotiation data
|
||||
*
|
||||
* Called when a complete IAC SB <option> ... IAC SE sequence is detected.
|
||||
* Derived classes can override this to handle specific options.
|
||||
*
|
||||
* @param conn The connection handle
|
||||
* @param option The telnet option code (e.g., NAWS, TTYPE)
|
||||
* @param subnegotiationData Buffer containing the raw data between SB and SE (excluding IAC escapes)
|
||||
* @param telnet_responses_out Buffer for any telnet responses to be sent
|
||||
*/
|
||||
virtual void handleTelnetSubnegotiation(ConnectionHandle conn,
|
||||
TelnetOption option,
|
||||
const IoBuffer& subnegotiationData,
|
||||
IoBuffer& telnet_responses_out)
|
||||
{
|
||||
// Base implementation is empty - derived classes can override
|
||||
// to handle application-specific telnet options
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ganl
|
||||
|
||||
#endif // GANL_TELNET_PROTOCOL_HANDLER_H
|
||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue