From 1b52dee2d662280bb14028026198d02c5ccc9332 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 1 Mar 2022 22:51:03 +0100 Subject: [PATCH 1/4] net/gnrc: restore inclusion of net/gnrc/tcp.h This reverts d03175c2ae05054bada1598668279ea37a5b89d1 --- sys/net/gnrc/sock/include/sock_types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/net/gnrc/sock/include/sock_types.h b/sys/net/gnrc/sock/include/sock_types.h index a8bd85c3ecd3..6369914ec8ef 100644 --- a/sys/net/gnrc/sock/include/sock_types.h +++ b/sys/net/gnrc/sock/include/sock_types.h @@ -27,6 +27,8 @@ #include "mbox.h" #include "net/af.h" +#include "net/gnrc.h" +#include "net/gnrc/tcp.h" #include "net/gnrc/netreg.h" #ifdef SOCK_HAS_ASYNC #include "net/sock/async/types.h" From 2034fa510113531876e7a9926f41daab246bdf89 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 10 Aug 2021 17:37:22 +0200 Subject: [PATCH 2/4] sys/net/application_layer: add telnet server module --- makefiles/pseudomodules.inc.mk | 1 + makefiles/stdio.inc.mk | 6 + sys/Makefile | 3 + sys/Makefile.dep | 5 + sys/auto_init/auto_init.c | 6 + sys/include/net/telnet.h | 95 ++++++ sys/net/application_layer/Kconfig | 6 + sys/net/application_layer/telnet/Kconfig | 28 ++ sys/net/application_layer/telnet/Makefile | 1 + .../application_layer/telnet/stdio_telnet.c | 86 +++++ .../application_layer/telnet/telnet_server.c | 303 ++++++++++++++++++ 11 files changed, 540 insertions(+) create mode 100644 sys/include/net/telnet.h create mode 100644 sys/net/application_layer/telnet/Kconfig create mode 100644 sys/net/application_layer/telnet/Makefile create mode 100644 sys/net/application_layer/telnet/stdio_telnet.c create mode 100644 sys/net/application_layer/telnet/telnet_server.c diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index ef14d491be5b..2531e39681b3 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -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 diff --git a/makefiles/stdio.inc.mk b/makefiles/stdio.inc.mk index a5dd52867077..a6dbca1d6536 100644 --- a/makefiles/stdio.inc.mk +++ b/makefiles/stdio.inc.mk @@ -7,6 +7,7 @@ STDIO_MODULES = \ stdio_rtt \ stdio_semihosting \ stdio_uart \ + stdio_telnet \ # ifneq (,$(filter newlib picolibc,$(USEMODULE))) @@ -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))) diff --git a/sys/Makefile b/sys/Makefile index c1fa9b8f649a..2a008ed9759c 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -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 diff --git a/sys/Makefile.dep b/sys/Makefile.dep index edd4685321a5..c42d9da876a7 100644 --- a/sys/Makefile.dep +++ b/sys/Makefile.dep @@ -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 diff --git a/sys/auto_init/auto_init.c b/sys/auto_init/auto_init.c index 81dc5ea66547..f315c070999e 100644 --- a/sys/auto_init/auto_init.c +++ b/sys/auto_init/auto_init.c @@ -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)) { diff --git a/sys/include/net/telnet.h b/sys/include/net/telnet.h new file mode 100644 index 000000000000..fa02d288324e --- /dev/null +++ b/sys/include/net/telnet.h @@ -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 + */ +#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 */ +/** @} */ diff --git a/sys/net/application_layer/Kconfig b/sys/net/application_layer/Kconfig index 6118a0aa9cd5..3f690d17f2bb 100644 --- a/sys/net/application_layer/Kconfig +++ b/sys/net/application_layer/Kconfig @@ -21,3 +21,9 @@ rsource "asymcute/Kconfig" rsource "emcute/Kconfig" endmenu # MQTT-SN + +menu "Telnet" + +rsource "telnet/Kconfig" + +endmenu # Telnet diff --git a/sys/net/application_layer/telnet/Kconfig b/sys/net/application_layer/telnet/Kconfig new file mode 100644 index 000000000000..4d706a060c22 --- /dev/null +++ b/sys/net/application_layer/telnet/Kconfig @@ -0,0 +1,28 @@ +# 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. +# +menuconfig KCONFIG_USEMODULE_TELNET + bool "Configure telnet server" + depends on USEMODULE_TELNET + help + Configure telnet module using Kconfig. If not set default values and + CFLAGS will be used. + +if KCONFIG_USEMODULE_TELNET + +config TELNET_PORT + int "Server port" + default 23 + help + Server port, the default is the one specified in RFC 855. + +config TELNET_TCP_QUEUE_SIZE + int "TCP Queue Size" + default 1 + help + Maximum number of incoming TCP connections. + +endif # KCONFIG_USEMODULE_TELNET diff --git a/sys/net/application_layer/telnet/Makefile b/sys/net/application_layer/telnet/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/sys/net/application_layer/telnet/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/application_layer/telnet/stdio_telnet.c b/sys/net/application_layer/telnet/stdio_telnet.c new file mode 100644 index 000000000000..99e96b5ac9c1 --- /dev/null +++ b/sys/net/application_layer/telnet/stdio_telnet.c @@ -0,0 +1,86 @@ +/* + * 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 sys + * @{ + * + * @file + * @brief STDIO over Telnet implementation + * + * This file implements STDIO via a Telnet server with fallback UART output + * + * @author Benjamin Valentin + * + * @} + */ + +#include + +#include "board.h" +#include "kernel_defines.h" +#include "net/telnet.h" +#if IS_USED(MODULE_PERIPH_UART) +#include "stdio_uart.h" +#include "periph/uart.h" +#endif +#if IS_USED(MODULE_VFS) +#include "vfs.h" +#endif +#ifdef CPU_NATIVE +#include "native_internal.h" +#endif + +#define ENABLE_DEBUG 0 +#include "debug.h" + +static inline void _init_fallback(void) +{ +#if defined(STDIO_UART_DEV) && IS_USED(MODULE_PERIPH_UART) + uart_init(STDIO_UART_DEV, STDIO_UART_BAUDRATE, NULL, NULL); +#endif +} + +static inline int _write_fallback(const void* buffer, size_t len) +{ +#if defined(CPU_NATIVE) + real_write(STDOUT_FILENO, buffer, len); +#elif defined(STDIO_UART_DEV) && IS_USED(MODULE_PERIPH_UART) + uart_write(STDIO_UART_DEV, buffer, len); +#else + (void)buffer; +#endif + + return len; +} + +void stdio_init(void) +{ + _init_fallback(); + +#if IS_USED(MODULE_VFS) + vfs_bind_stdio(); +#endif +} + +ssize_t stdio_read(void* buffer, size_t count) +{ + return telnet_server_read(buffer, count); +} + +ssize_t stdio_write(const void* buffer, size_t len) +{ + int res = telnet_server_write(buffer, len); + + /* write to UART if no client is connected */ + if (res == -ENOTCONN) { + return _write_fallback(buffer, len); + } + + return res; +} diff --git a/sys/net/application_layer/telnet/telnet_server.c b/sys/net/application_layer/telnet/telnet_server.c new file mode 100644 index 000000000000..e27e76d4d823 --- /dev/null +++ b/sys/net/application_layer/telnet/telnet_server.c @@ -0,0 +1,303 @@ +/* + * 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. + */ + +/** + * @{ + * + * @file + * @brief Telnet server implementation + * + * @author Benjamin Valentin + * + * @} + */ + +#include +#include +#include "net/sock/tcp.h" +#include "net/telnet.h" +#include "pipe.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#ifndef CONFIG_TELNET_TCP_QUEUE_SIZE +#define CONFIG_TELNET_TCP_QUEUE_SIZE (1) +#endif + +static char _stdin_pipe_buf[16]; +static ringbuffer_t _stdin_ringbuffer; +static pipe_t _stdin_pipe; + +static sock_tcp_queue_t sock_queue; +static sock_tcp_t socks[CONFIG_TELNET_TCP_QUEUE_SIZE]; +static sock_tcp_t *client; + +static char telnet_stack[THREAD_STACKSIZE_DEFAULT]; + +#define SOCK_TCP_TIMEOUT_MS 50 + +enum { + TELNET_CMD_EOF = 236, + TELNET_CMD_SE = 240, + TELNET_CMD_NOP, + TELNET_CMD_DATA_MARK, + TELNET_CMD_BRK, + TELNET_CMD_IP, + TELNET_CMD_AO, + TELNET_CMD_AYT, + TELNET_CMD_EC, + TELNET_CMD_EL, + TELNET_CMD_GA, + TELNET_CMD_SB = 250, + TELNET_CMD_WILL, + TELNET_CMD_WONT, + TELNET_CMD_DO, + TELNET_CMD_DONT, + TELNET_CMD_IAC +}; + +enum { + TELNET_OPT_BINARY = 0, + TELNET_OPT_ECHO = 1, + TELNET_OPT_SUP_GO_AHEAD = 3, + TELNET_OPT_STATUS = 5, +}; + +static bool connected; +static mutex_t connected_mutex = MUTEX_INIT_LOCKED; +static mutex_t sock_mutex; + +__attribute__((weak)) +void telnet_cb_pre_connected(sock_tcp_t *sock) +{ + (void)sock; +} + +__attribute__((weak)) +void telnet_cb_connected(sock_tcp_t *sock) +{ + (void)sock; +} + +__attribute__((weak)) +void telnet_cb_disconneced(void) +{ +} + +static void _acquire(void) +{ + mutex_lock(&sock_mutex); +} + +static void _release(void) +{ + mutex_unlock(&sock_mutex); +} + +static void _connected(void) +{ + telnet_cb_pre_connected(client); + + connected = true; + mutex_unlock(&connected_mutex); + + telnet_cb_connected(client); +} + +static void _disconnect(void) +{ + mutex_trylock(&connected_mutex); + connected = false; + + telnet_cb_disconneced(); +} + +static int _write_buffer(const void* buffer, size_t len) +{ + int res = 0; + const char *buf = buffer; + _acquire(); + + while (len) { + /* telnet expects \r\n line endings */ + /* https://datatracker.ietf.org/doc/html/rfc5198#appendix-C */ + const char *nl = memchr(buf, '\n', len); + if (nl) { + const char cr = '\r'; + size_t before_nl = nl - buf; + + /* write string before \n */ + res = sock_tcp_write(client, buf, before_nl); + if (res < 0) { + break; + } + + /* insert \r */ + res = sock_tcp_write(client, &cr, 1); + if (res < 0) { + break; + } + + buf = nl; + len -= before_nl; + } + + res = sock_tcp_write(client, buf, len); + if (res < 0) { + break; + } + len -= res; + buf += res; + } + _release(); + + return res < 0 ? res : 0; +} + +static uint8_t _will(uint8_t option) +{ + switch (option) { + /* agree to suppress go-ahead packets */ + /* see RFC 858 */ + case TELNET_OPT_SUP_GO_AHEAD: return TELNET_CMD_DO; + } + + return TELNET_CMD_WONT; +} + +static void _process_cmd(uint8_t cmd, uint8_t option) +{ + DEBUG("cmd: %u, option: %u\n", cmd, option); + switch (cmd) { + case TELNET_CMD_WILL: + { + uint8_t reply[] = {TELNET_CMD_IAC, _will(option), option}; + _write_buffer(reply, sizeof(reply)); + break; + } + } +} + +static void *telnet_thread(void *arg) +{ + (void)arg; + + static uint8_t rx_buf[64]; + + while (1) { + ssize_t res = sock_tcp_accept(&sock_queue, &client, SOCK_NO_TIMEOUT); + if (res < 0) { + DEBUG("accept error: %s\n", strerror(-res)); + continue; + } + + DEBUG("connected\n"); + _connected(); + + bool is_cmd = false; + uint8_t is_option = 0; + while (1) { + _acquire(); + res = sock_tcp_read(client, rx_buf, sizeof(rx_buf), SOCK_TCP_TIMEOUT_MS); + _release(); + if (res == -ETIMEDOUT) { + continue; + } + + if (res < 0) { + break; + } + + for (int i = 0; i < res; ++i) { + uint8_t c = rx_buf[i]; + + if (is_cmd) { + is_cmd = false; + switch (c) { + case TELNET_CMD_IAC: + goto write; + case TELNET_CMD_EOF: + goto disco; + default: + is_option = c; + } + continue; + } + + if (is_option) { + _process_cmd(is_option, c); + is_option = 0; + continue; + } + + if (c == TELNET_CMD_IAC) { + is_cmd = true; + continue; + } + + if (c == 0) { + continue; + } +write: + pipe_write(&_stdin_pipe, &c, 1); + } + } +disco: + _disconnect(); + sock_tcp_disconnect(client); + + if (res < 0) { + DEBUG("telnet: read: %s\n", strerror(res)); + } + } + + return NULL; +} + +int telnet_server_write(const void* buffer, size_t len) +{ + if (connected) { + int res = _write_buffer(buffer, len); + return res ? res : (int)len; + } + return -ENOTCONN; +} + +int telnet_server_read(void* buffer, size_t count) +{ + /* block until a connection is established */ + mutex_lock(&connected_mutex); + int res = pipe_read(&_stdin_pipe, buffer, count); + if (connected) { + mutex_unlock(&connected_mutex); + } + return res; +} + +int telnet_server_start(void) +{ + sock_tcp_ep_t ep = SOCK_IPV6_EP_ANY; + ep.port = CONFIG_TELNET_PORT; + + int res = sock_tcp_listen(&sock_queue, &ep, socks, ARRAY_SIZE(socks), 0); + if (res) { + return res; + } + + /* init RX ringbuffer */ + ringbuffer_init(&_stdin_ringbuffer, _stdin_pipe_buf, sizeof(_stdin_pipe_buf)); + pipe_init(&_stdin_pipe, &_stdin_ringbuffer, NULL); + + /* initiate telnet server */ + thread_create(telnet_stack, sizeof(telnet_stack), + THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST, + telnet_thread, NULL, "telnet"); + + return 0; +} From c476abe16e4e7724001cebf2406c501225ea329e Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 10 Aug 2021 23:39:32 +0200 Subject: [PATCH 3/4] examples/telnet_server: add telnet server example --- examples/telnet_server/Makefile | 51 ++++++++++++++ examples/telnet_server/Makefile.ci | 37 ++++++++++ examples/telnet_server/main.c | 104 +++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 examples/telnet_server/Makefile create mode 100644 examples/telnet_server/Makefile.ci create mode 100644 examples/telnet_server/main.c diff --git a/examples/telnet_server/Makefile b/examples/telnet_server/Makefile new file mode 100644 index 000000000000..78de41dbbdc6 --- /dev/null +++ b/examples/telnet_server/Makefile @@ -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 diff --git a/examples/telnet_server/Makefile.ci b/examples/telnet_server/Makefile.ci new file mode 100644 index 000000000000..2fe8d222fb1d --- /dev/null +++ b/examples/telnet_server/Makefile.ci @@ -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 \ + # diff --git a/examples/telnet_server/main.c b/examples/telnet_server/main.c new file mode 100644 index 000000000000..41f6b7b97a13 --- /dev/null +++ b/examples/telnet_server/main.c @@ -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 + * + * @} + */ + +#include + +#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; +} From 2e46e4ad7d12c1cd811d7be861bb1101bf89392b Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 8 Sep 2021 22:12:00 +0200 Subject: [PATCH 4/4] makefiles: warn if telnet is used in auto-init mode --- makefiles/dependency_resolution.inc.mk | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/makefiles/dependency_resolution.inc.mk b/makefiles/dependency_resolution.inc.mk index 9e4e704b9ce4..b0264c07b470 100644 --- a/makefiles/dependency_resolution.inc.mk +++ b/makefiles/dependency_resolution.inc.mk @@ -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