Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions examples/telnet_server/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# name of your application
APPLICATION = telnet_server

# If no BOARD is found in the environment, use this default:
BOARD ?= native

# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..

# Include packages that pull up and auto-init the link layer.
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
USEMODULE += netdev_default
USEMODULE += auto_init_gnrc_netif
# Activate ICMPv6 error messages
USEMODULE += gnrc_icmpv6_error
# Specify the mandatory networking modules for IPv6
USEMODULE += gnrc_ipv6_default
# Additional networking modules that can be dropped if not needed
USEMODULE += gnrc_icmpv6_echo
USEMODULE += netutils
# Add also the shell, some shell commands
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
# Include the telnet server
USEMODULE += stdio_telnet

# Enable faster re-connects
CFLAGS += -DCONFIG_GNRC_TCP_EXPERIMENTAL_DYN_MSL_EN=1

# Acknowledge that telnet is bad
I_UNDERSTAND_THAT_TELNET_IS_INSECURE = 1

# enable debug output via UART
FEATURES_OPTIONAL += periph_uart

# Optionally include DNS support. This includes resolution of names at an
# upstream DNS server and the handling of RDNSS options in Router Advertisements
# to auto-configure that upstream DNS server.
# USEMODULE += sock_dns # include DNS client
# USEMODULE += gnrc_ipv6_nib_dns # include RDNSS option handling

# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1

include $(RIOTBASE)/Makefile.include

# Set a custom channel if needed
include $(RIOTMAKE)/default-radio-settings.inc.mk
37 changes: 37 additions & 0 deletions examples/telnet_server/Makefile.ci
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
BOARD_INSUFFICIENT_MEMORY := \
arduino-duemilanove \
arduino-leonardo \
arduino-mega2560 \
arduino-nano \
arduino-uno \
atmega1284p \
atmega328p \
atmega328p-xplained-mini \
atxmega-a3bu-xplained \
bluepill-stm32f030c8 \
derfmega128 \
i-nucleo-lrwan1 \
mega-xplained \
microduino-corerf \
msb-430 \
msb-430h \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f042k6 \
nucleo-f303k8 \
nucleo-f334r8 \
nucleo-l011k4 \
nucleo-l031k6 \
nucleo-l053r8 \
samd10-xmini \
stk3200 \
slstk3400a \
stm32f030f4-demo \
stm32f0discovery \
stm32g0316-disco \
stm32l0538-disco \
telosb \
waspmote-pro \
z1 \
zigduino \
#
104 changes: 104 additions & 0 deletions examples/telnet_server/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright (C) 2021 ML!PA Consulting GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @ingroup examples
* @{
*
* @file
* @brief Example application for demonstrating the RIOT telnet server
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*
* @}
*/

#include <stdio.h>

#include "net/ipv6/addr.h"
#include "net/gnrc.h"
#include "net/gnrc/netif.h"
#include "net/telnet.h"
#include "shell.h"
#include "msg.h"

#define MAIN_QUEUE_SIZE (8)
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE];

static void _print_addr(void)
{
gnrc_netif_t *netif = NULL;
while ((netif = gnrc_netif_iter(netif))) {
ipv6_addr_t ipv6_addrs[CONFIG_GNRC_NETIF_IPV6_ADDRS_NUMOF];
int res = gnrc_netapi_get(netif->pid, NETOPT_IPV6_ADDR, 0, ipv6_addrs,
sizeof(ipv6_addrs));

if (res < 0) {
continue;
}
for (unsigned i = 0; i < (unsigned)(res / sizeof(ipv6_addr_t)); i++) {
char ipv6_addr[IPV6_ADDR_MAX_STR_LEN];

ipv6_addr_to_str(ipv6_addr, &ipv6_addrs[i], IPV6_ADDR_MAX_STR_LEN);
printf("My address is %s\n", ipv6_addr);
}
}
}

static void _print_motd(void)
{
puts("RIOT telnet example application");

puts("╔═══════════════════════════════════════════════════╗");
puts("║telnet is entirely unencrypted and unauthenticated.║");
puts("║Do not use this on public networks. ║");
puts("╚═══════════════════════════════════════════════════╝");
}

void telnet_cb_pre_connected(sock_tcp_t *sock)
{
sock_tcp_ep_t ep;
char addr_str[IPV6_ADDR_MAX_STR_LEN];

sock_tcp_get_local(sock, &ep);
ipv6_addr_to_str(addr_str, (ipv6_addr_t *)ep.addr.ipv6, sizeof(addr_str));

printf("%s connected\n", addr_str);
}

void telnet_cb_disconneced(void)
{
puts("disconnected");
}

void telnet_cb_connected(sock_tcp_t *sock)
{
(void)sock;
_print_motd();
}

int main(void)
{
/* we need a message queue for the thread running the shell in order to
* receive potentially fast incoming networking packets */
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE);

_print_motd();

/* print address so we can connect to it */
_print_addr();

/* start shell */
printf("All up, awaiting connection on port %u\n", CONFIG_TELNET_PORT);
printf("Local shell disabled");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);

/* should be never reached */
return 0;
}
13 changes: 13 additions & 0 deletions makefiles/dependency_resolution.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,17 @@ else
$(shell $(COLOR_ECHO) "$(COLOR_RED)Deprecated modules are in use:$(COLOR_RESET)"\
"$(DEPRECATED_MODULES_USED)" 1>&2)
endif

# Warn about telnet
ifneq (,$(filter auto_init_telnet,$(USEMODULE)))
ifneq (1,$(I_UNDERSTAND_THAT_TELNET_IS_INSECURE))
$(shell $(COLOR_ECHO) "$(COLOR_RED)Telnet will be started automatically, "\
"make sure you understand why this almost certainly "\
"is a REALLY BAD idea before proceeding!$(COLOR_RESET)" 1>&2)
$(error I_UNDERSTAND_THAT_TELNET_IS_INSECURE must be set to 1 to proceed)
else
$(shell $(COLOR_ECHO) "$(COLOR_YELLOW)Telnet will be started automatically,"\
"don't run this on public networks!$(COLOR_RESET)" 1>&2)
endif
endif
endif
1 change: 1 addition & 0 deletions makefiles/pseudomodules.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ PSEUDOMODULES += stdio_cdc_acm
PSEUDOMODULES += stdio_ethos
PSEUDOMODULES += stdio_nimble_debug
PSEUDOMODULES += stdio_uart_rx
PSEUDOMODULES += stdio_telnet
PSEUDOMODULES += stm32_eth
PSEUDOMODULES += stm32_eth_auto
PSEUDOMODULES += stm32_eth_link_up
Expand Down
6 changes: 6 additions & 0 deletions makefiles/stdio.inc.mk
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ STDIO_MODULES = \
stdio_rtt \
stdio_semihosting \
stdio_uart \
stdio_telnet \
#

ifneq (,$(filter newlib picolibc,$(USEMODULE)))
Expand Down Expand Up @@ -63,6 +64,11 @@ ifneq (,$(filter stdio_semihosting,$(USEMODULE)))
FEATURES_REQUIRED_ANY += cpu_core_cortexm|arch_riscv
endif

ifneq (,$(filter stdio_telnet,$(USEMODULE)))
DEFAULT_MODULE += auto_init_telnet
USEMODULE += telnet
endif

# enable stdout buffering for modules that benefit from sending out buffers in larger chunks
ifneq (,$(filter picolibc,$(USEMODULE)))
ifneq (,$(filter stdio_cdc_acm stdio_ethos slipdev_stdio stdio_semihosting,$(USEMODULE)))
Expand Down
3 changes: 3 additions & 0 deletions sys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ endif
ifneq (,$(filter cipher_modes,$(USEMODULE)))
DIRS += crypto/modes
endif
ifneq (,$(filter telnet,$(USEMODULE)))
DIRS += net/application_layer/telnet
endif
ifneq (,$(filter constfs,$(USEMODULE)))
DIRS += fs/constfs
endif
Expand Down
5 changes: 5 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,11 @@ ifneq (,$(filter sema_inv,$(USEMODULE)))
USEMODULE += atomic_utils
endif

ifneq (,$(filter telnet,$(USEMODULE)))
USEMODULE += pipe
USEMODULE += sock_tcp
endif

ifneq (,$(filter luid,$(USEMODULE)))
FEATURES_OPTIONAL += periph_cpuid
endif
Expand Down
6 changes: 6 additions & 0 deletions sys/auto_init/auto_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,12 @@ void auto_init(void)
gnrc_ipv6_auto_subnets_init();
}

if (IS_USED(MODULE_AUTO_INIT_TELNET)) {
LOG_DEBUG("auto_init TELNET server\n");
extern void telnet_server_start(void);
telnet_server_start();
}

if (IS_USED(MODULE_AUTO_INIT_MULTIMEDIA)) {
LOG_DEBUG("auto_init MULTIMEDIA\n");
if (IS_USED(MODULE_DFPLAYER)) {
Expand Down
95 changes: 95 additions & 0 deletions sys/include/net/telnet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (C) 2021 ML!PA Consulting GmbH
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/

/**
* @defgroup net_telnet basic Telnet server implementation
* @ingroup net_ipv6
* @brief Telnet server functions
* @{
*
* @file
* @brief minimal Telnet server ([RFC 854](https://tools.ietf.org/html/rfc854)) implementation
* @note This implementation only supports a single client and no options.
*
* @warning Telnet is entirely unencrypted! Do not use it on public networks.
* This is intended to aid debugging on networks that are isolated from the Internet.
*
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com>
*/
#ifndef NET_TELNET_H
#define NET_TELNET_H

#include "net/sock/tcp.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief The port for the Telnet server to listen on
*/
#ifndef CONFIG_TELNET_PORT
#define CONFIG_TELNET_PORT (23)
#endif

/**
* @brief Start the Telnet server thread
*
* @return 0 on success, error otherwise
*/
int telnet_server_start(void);

/**
* @brief Write data to the telnet client
*
* @param[in] buffer The buffer to send to the client
* @param[in] len The length of the buffer
*
* @return 0 on success, error otherwise
*/
int telnet_server_write(const void* buffer, size_t len);

/**
* @brief Read data from the telnet client, will block until data is available.
*
* @param[out] buffer The buffer to write data from the client
* @param[in] count Number of bytes to read
*
* @return number of bytes read, error otherwise
*/
int telnet_server_read(void* buffer, size_t count);

/**
* @brief Callback function that gets called when a telnet client connects
* but before stdio is redirected.
*
* @param[in] sock Socket of the client that just connected
* only use with @ref sock_tcp_get_local
*/
void telnet_cb_pre_connected(sock_tcp_t *sock);

/**
* @brief Callback function that gets called when a telnet client connects
* after stdio is redirected.
*
* @param[in] sock Socket of the client that just connected
* only use with @ref sock_tcp_get_local
*/
void telnet_cb_connected(sock_tcp_t *sock);

/**
* @brief Callback function that gets called after a telnet client disconnected.
*/
void telnet_cb_disconneced(void);

#ifdef __cplusplus
}
#endif

#endif /* NET_TELNET_H */
/** @} */
6 changes: 6 additions & 0 deletions sys/net/application_layer/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ rsource "asymcute/Kconfig"
rsource "emcute/Kconfig"

endmenu # MQTT-SN

menu "Telnet"

rsource "telnet/Kconfig"

endmenu # Telnet
Loading