Browse Source

Added support for reverse telnet (#1920)

* Added support for reverse telnet

* Fix issues with first command being ignored

* Fix incorrect client creation

* Integrate PR 1927
master
Niek van der Maas 5 years ago
committed by Max Prokhorov
parent
commit
f3b35567d4
2 changed files with 104 additions and 21 deletions
  1. +8
    -0
      code/espurna/config/general.h
  2. +96
    -21
      code/espurna/telnet.ino

+ 8
- 0
code/espurna/config/general.h View File

@ -130,6 +130,13 @@
#define TELNET_SERVER TELNET_SERVER_ASYNC // Can be either TELNET_SERVER_ASYNC (using ESPAsyncTCP) or TELNET_SERVER_WIFISERVER (using WiFiServer) #define TELNET_SERVER TELNET_SERVER_ASYNC // Can be either TELNET_SERVER_ASYNC (using ESPAsyncTCP) or TELNET_SERVER_WIFISERVER (using WiFiServer)
#endif #endif
// Enable this flag to add support for reverse telnet (+800 bytes)
// This is useful to telnet to a device behind a NAT or firewall
// To use this feature, start a listen server on a publicly reachable host with e.g. "ncat -vlp <port>" and use the MQTT reverse telnet command to connect
#ifndef TELNET_REVERSE_SUPPORT
#define TELNET_REVERSE_SUPPORT 0
#endif
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// TERMINAL // TERMINAL
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -1068,6 +1075,7 @@
#define MQTT_TOPIC_IRIN "irin" #define MQTT_TOPIC_IRIN "irin"
#define MQTT_TOPIC_IROUT "irout" #define MQTT_TOPIC_IROUT "irout"
#define MQTT_TOPIC_OTA "ota" #define MQTT_TOPIC_OTA "ota"
#define MQTT_TOPIC_TELNET_REVERSE "telnet_reverse"
// Light module // Light module
#define MQTT_TOPIC_CHANNEL "channel" #define MQTT_TOPIC_CHANNEL "channel"


+ 96
- 21
code/espurna/telnet.ino View File

@ -43,6 +43,58 @@ void _telnetWebSocketOnConnected(JsonObject& root) {
#endif #endif
#if TELNET_REVERSE_SUPPORT
void _telnetReverse(const char * host, uint16_t port) {
DEBUG_MSG_P(PSTR("[TELNET] Connecting to reverse telnet on %s:%d\n"), host, port);
unsigned char i;
for (i = 0; i < TELNET_MAX_CLIENTS; i++) {
if (!_telnetClients[i] || !_telnetClients[i]->connected()) {
#if TELNET_SERVER == TELNET_SERVER_WIFISERVER
_telnetClients[i] = std::make_unique<WiFiClient>();
#else // TELNET_SERVER_ASYNC
_telnetClients[i] = std::make_unique<AsyncClient>();
#endif
if (_telnetClients[i]->connect(host, port)) {
return _telnetNotifyConnected(i);
} else {
DEBUG_MSG_P(PSTR("[TELNET] Error connecting reverse telnet\n"));
return _telnetDisconnect(i);
}
}
}
//no free/disconnected spot so reject
if (i == TELNET_MAX_CLIENTS) {
DEBUG_MSG_P(PSTR("[TELNET] Failed too connect - too many clients connected\n"));
}
}
#if MQTT_SUPPORT
void _telnetReverseMQTTCallback(unsigned int type, const char * topic, const char * payload) {
if (type == MQTT_CONNECT_EVENT) {
mqttSubscribe(MQTT_TOPIC_TELNET_REVERSE);
} else if (type == MQTT_MESSAGE_EVENT) {
String t = mqttMagnitude((char *) topic);
if (t.equals(MQTT_TOPIC_TELNET_REVERSE)) {
String pl = String(payload);
int col = pl.indexOf(':');
if (col != -1) {
String host = pl.substring(0, col);
uint16_t port = pl.substring(col + 1).toInt();
_telnetReverse(host.c_str(), port);
} else {
DEBUG_MSG_P(PSTR("[TELNET] Incorrect reverse telnet value given, use the form \"host:ip\""));
}
}
}
}
#endif
#endif
void _telnetDisconnect(unsigned char clientId) { void _telnetDisconnect(unsigned char clientId) {
// ref: we are called from onDisconnect, async is already stopped // ref: we are called from onDisconnect, async is already stopped
#if TELNET_SERVER == TELNET_SERVER_WIFISERVER #if TELNET_SERVER == TELNET_SERVER_WIFISERVER
@ -127,6 +179,28 @@ void _telnetNotifyConnected(unsigned char i) {
DEBUG_MSG_P(PSTR("[TELNET] Client #%u connected\n"), i); DEBUG_MSG_P(PSTR("[TELNET] Client #%u connected\n"), i);
#if TELNET_SERVER == TELNET_SERVER_ASYNC
_telnetClients[i]->onAck([i](void *s, AsyncClient *c, size_t len, uint32_t time) {
}, 0);
_telnetClients[i]->onData([i](void *s, AsyncClient *c, void *data, size_t len) {
_telnetData(i, data, len);
}, 0);
_telnetClients[i]->onDisconnect([i](void *s, AsyncClient *c) {
_telnetDisconnect(i);
}, 0);
_telnetClients[i]->onError([i](void *s, AsyncClient *c, int8_t error) {
DEBUG_MSG_P(PSTR("[TELNET] Error %s (%d) on client #%u\n"), c->errorToString(error), error, i);
}, 0);
_telnetClients[i]->onTimeout([i](void *s, AsyncClient *c, uint32_t time) {
DEBUG_MSG_P(PSTR("[TELNET] Timeout on client #%u at %lu\n"), i, time);
c->close();
}, 0);
#endif
// If there is no terminal support automatically dump info and crash data // If there is no terminal support automatically dump info and crash data
#if TERMINAL_SUPPORT == 0 #if TERMINAL_SUPPORT == 0
info(); info();
@ -203,7 +277,7 @@ void _telnetLoop() {
char data[TERMINAL_BUFFER_SIZE]; char data[TERMINAL_BUFFER_SIZE];
size_t len = _telnetClients[i]->available(); size_t len = _telnetClients[i]->available();
unsigned int r = _telnetClients[i]->readBytes(data, min(sizeof(data), len)); unsigned int r = _telnetClients[i]->readBytes(data, min(sizeof(data), len));
_telnetData(i, data, r); _telnetData(i, data, r);
} }
} }
@ -238,26 +312,6 @@ void _telnetNewClient(AsyncClient* client) {
_telnetClients[i] = std::unique_ptr<AsyncClient>(client); _telnetClients[i] = std::unique_ptr<AsyncClient>(client);
_telnetClients[i]->onAck([i](void *s, AsyncClient *c, size_t len, uint32_t time) {
}, 0);
_telnetClients[i]->onData([i](void *s, AsyncClient *c, void *data, size_t len) {
_telnetData(i, data, len);
}, 0);
_telnetClients[i]->onDisconnect([i](void *s, AsyncClient *c) {
_telnetDisconnect(i);
}, 0);
_telnetClients[i]->onError([i](void *s, AsyncClient *c, int8_t error) {
DEBUG_MSG_P(PSTR("[TELNET] Error %s (%d) on client #%u\n"), c->errorToString(error), error, i);
}, 0);
_telnetClients[i]->onTimeout([i](void *s, AsyncClient *c, uint32_t time) {
DEBUG_MSG_P(PSTR("[TELNET] Timeout on client #%u at %lu\n"), i, time);
c->close();
}, 0);
_telnetNotifyConnected(i); _telnetNotifyConnected(i);
return; return;
} }
@ -312,6 +366,27 @@ void telnetSetup() {
.onKeyCheck(_telnetWebSocketOnKeyCheck); .onKeyCheck(_telnetWebSocketOnKeyCheck);
#endif #endif
#if TELNET_REVERSE_SUPPORT
#if MQTT_SUPPORT
mqttRegister(_telnetReverseMQTTCallback);
#endif
#if TERMINAL_SUPPORT
terminalRegisterCommand(F("TELNET.REVERSE"), [](Embedis* e) {
if (e->argc < 3) {
terminalError(F("Wrong arguments. Usage: TELNET.REVERSE <host> <port>"));
return;
}
String host = String(e->argv[1]);
uint16_t port = String(e->argv[2]).toInt();
terminalOK();
_telnetReverse(host.c_str(), port);
});
#endif
#endif
espurnaRegisterReload(_telnetConfigure); espurnaRegisterReload(_telnetConfigure);
_telnetConfigure(); _telnetConfigure();


Loading…
Cancel
Save