123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663 |
- /*
- * telnet_server.c
- *
- * Created on: 24.11.2017
- * Author: balbekova
- */
- /* Standard includes. */
- #include <string.h>
- /* lwIP core includes */
- #include "lwip/opt.h"
- #include "lwip/sockets.h"
- /* FreeRTOS includes. */
- #include "FreeRTOS.h"
- #include "task.h"
- #include "fr_timers.h"
- /* Utils includes. */
- #include "FreeRTOS_CLI.h"
- #include "CLI_Commands.h"
- #include "telnet_server.h"
- #include "settings_api.h"
- #include "parameters.h"
- #include "control_symbol.h"
- #include "log.h"
- #include "web_params_api.h"
- /* Dimensions the buffer into which input characters are placed. */
- #define cmdMAX_INPUT_SIZE 144
- /* Repeat Login timeout, 1 seconds */
- #define REPEAT_SENSOR_INFO_TIME configTICK_RATE_HZ*1*1
- /* Set option to drop old connection if the new one is accepted */
- #define TCP_DROP_PREV_CONNECTION 0
- static portBASE_TYPE FreeRTOS_CLIAuthProcess( const int8_t * const pcCommandInput, int8_t * pcWriteBuffer );
- static portBASE_TYPE FreeRTOS_ChangePWDProcess( const int8_t * const pcCommandInput, int8_t * pcWriteBuffer );
- void SensorInfoTimerCallback(TimerHandle_t pxTimer);
- TimerHandle_t RepeatSensorInfoTimer;
- state_telnet_server_t telnetState = TELNET_AUTH;
- uint8_t id_change_pwd = 0;
- user_level_t telnet_code_auth = USER;
- static int32_t lClientFd;
- static int32_t lSocket;
- static int8_t *pcOutputString;
- static bool flagTelnetChange = false;
- static struct fd_set master_set, read_set, write_set;
- static int max_sd;
- static struct sockaddr_in sa;
- #ifdef HARDWARE_BT6708
- extern bool white_list_check(uint32_t check_remote_addr);
- static bool flagWhiteListTelnet = false;
- #endif
- /**
- * @brief Общая структура настроек
- */
- extern SETTINGS_t sSettings;
- /*-----------------------------------------------------------*/
- /* Stop server */
- static void stop_server(void) {
- /* Clean up all of the sockets that are open */
- for (int i = 0; i <= max_sd; ++i)
- {
- if (FD_ISSET(i, &master_set)) {
- DBG printf("Close sock %d\n", i);
- closesocket(i);
- FD_CLR(i, &master_set);
- }
- }
- DBG printf("Portgw stopped\n");
- }
- /* Start server */
- static bool start_server(uint16_t port)
- {
- int res;
- lSocket = socket(PF_INET, SOCK_STREAM, 0);
- if (lSocket < 0) {
- DBG printf("Socket create failed\r\n");
- return false;
- }
- res = fcntl(lSocket, F_SETFL, O_NONBLOCK);
- if (res < 0) {
- DBG printf("fcntl() failed");
- closesocket(lSocket);
- return false;
- }
- memset(&sa, 0, sizeof(struct sockaddr_in));
- sa.sin_family = AF_INET;
- sa.sin_addr.s_addr = IPADDR_ANY;
- sa.sin_port = htons(port);
- if (bind(lSocket, (struct sockaddr *)&sa, sizeof(sa)) == -1)
- {
- DBG printf("Bind to port %d failed\n", port);
- closesocket(lSocket);
- return false;
- }
- res = listen(lSocket, 20);
- if (res < 0) {
- DBG printf("Listen failed failed\r\n");
- closesocket(lSocket);
- return false;
- }
- FD_ZERO(&master_set);
- max_sd = lSocket;
- FD_SET(lSocket, &master_set);
- DBG printf("Port %d opened\n", port);
- return true;
- }
- void vBasicSocketsCommandInterpreterTask( void *pvParameters )
- {
- int32_t lBytes, lAddrLen = sizeof( struct sockaddr_in );
- struct sockaddr_in sLocalAddr;
- struct sockaddr_in client_addr;
- #ifdef HARDWARE_BT6708
- const int8_t * const pcWelcomeMessage = ( const int8_t * ) "BT6708 command server - connection accepted.\r\nlogin:";
- #else
- const int8_t * const pcWelcomeMessage = ( const int8_t * ) "BT6706 command server - connection accepted.\r\nlogin:";
- #endif
- static const int8_t * const pcEndOfCommandOutputString = ( int8_t * ) "\r\n[Нажмите клавишу ENTER для повторного выполнения предыдущей команды]\r\n>";
- int8_t cInChar, cInputIndex;
- static int8_t cInputString[ cmdMAX_INPUT_SIZE ] = { 0 }, cLastInputString[ cmdMAX_INPUT_SIZE ] = { 0 };
- portBASE_TYPE xReturned;
- int new_sd;
- int desc_ready, rc;
- struct timeval timeout;
- bool close_conn;
- uint16_t port;
- bool enabled;
- bool firstrun = true;
- #ifdef HARDWARE_BT6708
- struct sockaddr_in sa_temp;
- socklen_t len;
- #endif
- static int active_sd = -1;
- FD_ZERO(&master_set);
- timeout.tv_sec = 5;
- timeout.tv_usec = 0;
- ( void ) pvParameters;
- pcOutputString = FreeRTOS_CLIGetOutputBuffer();
- enabled = sSettings.sTelnet.TelnetEnable;
- port = ( uint16_t ) sSettings.sTelnet.port;
- while (1) {
- /* Check if network settings was changed */
- if ((sSettings.sTelnet.port != port) ||
- (sSettings.sTelnet.TelnetEnable != enabled) ||
- (firstrun))
- {
- if (!firstrun || sSettings.sTelnet.port != port) {
- /* Stop server */
- stop_server();
- }
- if (sSettings.sTelnet.TelnetEnable) {
- /* (Re)start server */
- if (!start_server(sSettings.sTelnet.port)) {
- DBG printf("Server start error\n");
- firstrun = true;
- vTaskDelay(5000);
- continue;
- }
- }
- else {
- /* Obtain the address of the output buffer. Note there is no mutual
- exclusion on this buffer as it is assumed only one command console
- interface will be used at any one time. */
- firstrun = true;
- vTaskDelay(5000);
- continue;
- }
- firstrun = false;
- port = sSettings.sTelnet.port;
- enabled = sSettings.sTelnet.TelnetEnable;
- }
- if (!enabled) {
- firstrun = true;
- vTaskDelay(5000);
- continue;
- }
- memcpy(&read_set, &master_set, sizeof(master_set));
- DBG printf("Waiting on select()...\n");
- rc = select(max_sd + 1, &read_set, NULL, NULL, &timeout);
- DBG printf(" select() returned %d\n", rc);
- if (rc < 0) {
- DBG printf(" select() failed\n");
- }
- if (rc == 0) {
- DBG printf(" select() timed out.\n");
- }
- /* One or more descriptors are readable. Need to \
- * determine which ones they are. */
- desc_ready = rc;
- for (int i=0; i <= max_sd && desc_ready > 0; ++i) {
- /*******************************************************/
- /* Check to see if this descriptor is ready */
- /*******************************************************/
- if (FD_ISSET(i, &read_set)) {
- /* A descriptor was found that was readable - one \
- * less has to be looked for. This is being done \
- * so that we can stop looking at the working set \
- * once we have found all of the descriptors that \
- * were ready. */
- desc_ready -= 1;
- /* Check to see if this is the listening socket */
- if (i == lSocket) {
- DBG printf(" Listening socket is readable\n");
- /* Accept all incoming connections that are */
- /* queued up on the listening socket before we */
- /* loop back and call select again. */
- do {
- /* Accept each incoming connection. If */
- /* accept fails with EWOULDBLOCK, then we */
- /* have accepted all of them. Any other */
- /* failure on accept will cause us to end the */
- /* server. */
- new_sd = accept(lSocket, NULL, NULL);
- if (new_sd < 0) {
- if (errno != EWOULDBLOCK) {
- DBG printf(" accept() failed\n");
- }
- break;
- }
- /* Add the new incoming connection to the */
- /* master read set */
- printf(" New incoming connection - %d\n", new_sd);
- FD_SET(new_sd, &master_set);
- if (new_sd > max_sd) {
- max_sd = new_sd;
- }
- #ifdef HARDWARE_BT6708
- lwip_getpeername(new_sd, &sa_temp, &len);
- flagWhiteListTelnet = white_list_check(sa_temp.sin_addr.s_addr);
- #endif
- recv( new_sd, cInputString, 27, 0 );
- telnetState = TELNET_AUTH;
- send( new_sd, pcWelcomeMessage, strlen( ( const char * ) pcWelcomeMessage ), 0 );
- cInputIndex = 0;
- memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
- #if TCP_DROP_PREV_CONNECTION
- /* Close previous active connection */
- if (active_sd != -1 && active_sd != new_sd) {
- DBG printf(" Close prev active connection %d\n", active_sd);
- close(active_sd);
- FD_CLR(active_sd, &master_set);
- if (active_sd == max_sd) {
- while (FD_ISSET(max_sd, &master_set) == false) {
- max_sd -= 1;
- }
- }
- }
- /* Mark new connection as active */
- active_sd = new_sd;
- DBG printf(" New active connection %d\n", active_sd);
- #endif
- /* Loop back up and accept another incoming */
- /* connection */
- } while (new_sd != -1);
- }
- /* This is not the listening socket, therefore an */
- /* existing connection must be readable */
- else {
- DBG printf(" Descriptor %d is readable\n", i);
- close_conn = false;
- /* Receive data on this connection until the */
- /* recv fails with EWOULDBLOCK. If any other */
- /* failure occurs, we will close the */
- /* connection. */
- if ((lBytes = recv(i, &cInChar, sizeof( cInChar ), 0 )) > 0) {
- if( lBytes > 0L )
- {
- if( cInChar == '\n' )
- {
- switch(telnetState){
- case TELNET_AUTH:
- if(FreeRTOS_CLIAuthProcess(cInputString, pcOutputString)){
- send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
- cInputIndex = 0;
- memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
- }
- else{
- /* Set lBytes to 0 to close the connection. */
- lBytes = 0L;
- }
- break;
- case TELNET_CMD:
- /* The input string has been terminated. Was the
- input a quit command? */
- if( strcmp( "quit", ( const char * ) cInputString ) == 0 )
- {
- /* Set lBytes to 0 to close the connection. */
- lBytes = 0L;
- }
- else
- {
- /* The input string was not a quit command.
- Pass the string to the command interpreter. */
- /* See if the command is empty, indicating that the last command is
- to be executed again. */
- if( cInputIndex == 0 )
- {
- strcpy( ( char * ) cInputString, ( char * ) cLastInputString );
- }
- /* Transmit a line separator, just to make the
- output easier to read. */
- lwip_send( lClientFd, "\r\n", strlen( "\r\n" ), 0 );
- do
- {
- /* Ensure there is not a string lingering in
- the output buffer. */
- pcOutputString[ 0 ] = 0x00;
- xReturned = FreeRTOS_CLIProcessCommand( cInputString, pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE );
- send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
- } while( xReturned != pdFALSE );
- if( strcmp( "sensor info", ( const char * ) cInputString ) == 0 ){
- strcpy( ( char * ) cLastInputString, ( char * ) cInputString );
- cInputIndex = 0;
- memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
- lClientFd = i;
- xTimerStart(RepeatSensorInfoTimer, 0);
- }
- else{
- /* All the strings generated by the input
- command have been sent. Clear the input
- string ready to receive the next command.
- Remember the command that was just processed
- first in case it is to be processed again. */
- strcpy( ( char * ) cLastInputString, ( char * ) cInputString );
- cInputIndex = 0;
- memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
- if(telnetState != TELNET_CHANGE_PWD)
- send( i, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
- }
- }
- break;
- case TELNET_CHANGE_PWD:
- FreeRTOS_ChangePWDProcess(cInputString, pcOutputString);
- send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
- cInputIndex = 0;
- memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
- break;
- }
- }
- else
- {
- if( cInChar == '\r' )
- {
- /* Ignore the character. */
- }
- else if( cInChar == '\b' )
- {
- /* Backspace was pressed. Erase the last
- character in the string - if any. */
- if( cInputIndex > 0 )
- {
- cInputIndex--;
- cInputString[ cInputIndex ] = '\0';
- }
- }
- else if( cInChar == '\t' ){
- /*FreeRTOS_CLICompleteCMDCommand(cInputString, pcOutputString);
- strcpy((char *)cInputString, (char *)pcOutputString);
- send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );*/
- }
- else
- {
- /* A character was entered. Add it to the string
- entered so far. When a \n is entered the complete
- string will be passed to the command interpreter. */
- if( cInputIndex < cmdMAX_INPUT_SIZE )
- {
- cInputString[ cInputIndex ] = cInChar;
- cInputIndex++;
- }
- if( strcmp( "\377\364\377\375\006", ( const char * ) cInputString ) == 0 ){
- xTimerStop(RepeatSensorInfoTimer, 0);
- cInputIndex = 0;
- memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
- cInputString[0] = 255;
- cInputString[1] = 251;
- cInputString[2] = 6;
- cInputString[3] = 255;
- cInputString[4] = 242;
- //if(telnetState != TELNET_CHANGE_PWD)
- //lwip_send( lClientFd, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
- send( i, cInputString, strlen( ( const char * ) cInputString ), 0 );
- memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
- if(telnetState != TELNET_CHANGE_PWD)
- send( i, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
- }
- }
- }
- }
- }
- if (lBytes < 0) {
- if (errno != EWOULDBLOCK){
- DBG printf(" recv() failed\n");
- close_conn = true;
- }
- }
- /* Check to see if the connection has been */
- /* closed by the client */
- if (lBytes == 0) {
- DBG printf(" Connection closed\n");
- close_conn = true;
- }
- /* If the close_conn flag was turned on, we need */
- /* to clean up this active connection. This */
- /* clean up process includes removing the */
- /* descriptor from the master set and */
- /* determining the new maximum descriptor value */
- /* based on the bits that are still turned on in */
- /* the master set. */
- if (close_conn) {
- closesocket(i);
- FD_CLR(i, &master_set);
- if (i == max_sd) {
- while (FD_ISSET(max_sd, &master_set) == false) {
- max_sd -= 1;
- }
- }
- }
- }
- }
- }
- }
- }
- void telnet_server_init(void) {
- vRegisterCLICommands();
- xTaskCreate(vBasicSocketsCommandInterpreterTask, ( char * ) "vBasicSocketsCommandInterpreterTask", 8*configMINIMAL_STACK_SIZE , NULL, tskIDLE_PRIORITY + 1, NULL);
- RepeatSensorInfoTimer = xTimerCreate("SensorInfoTmr", REPEAT_SENSOR_INFO_TIME, pdFALSE, ( void * ) 0, SensorInfoTimerCallback);
- }
- void SensorInfoTimerCallback(TimerHandle_t pxTimer) {
- portBASE_TYPE xReturned = pdTRUE;
- do
- {
- /* Ensure there is not a string lingering in
- the output buffer. */
- pcOutputString[ 0 ] = 0x00;
- xReturned = FreeRTOS_CLIProcessCommand( "sensor info", pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE );
- lwip_send( lClientFd, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
- } while( xReturned != pdFALSE );
- xTimerStart(RepeatSensorInfoTimer, 0);
- }
- static portBASE_TYPE FreeRTOS_CLIAuthProcess( const int8_t * const pcCommandInput, int8_t * pcWriteBuffer )
- {
- portBASE_TYPE xReturn = pdTRUE;
- uint32_t len;
- uint8_t valueLen, user_id;
- char WebPassword[MAX_WEB_PASSWD_LEN];
- char WebLogin[MAX_WEB_LOGIN_LEN];
- static uint8_t login_err = 0;
- static uint8_t telnet_state_auth = 0;
- static char login[ cmdMAX_INPUT_SIZE ] = { 0 };
- char password[ cmdMAX_INPUT_SIZE ] = { 0 };
- const int8_t * const pcPSWHeader = ( int8_t * ) "\r\npassword:";
- const int8_t * const pcLoginHeader = ( int8_t * ) "\r\nlogin:";
- memset(pcWriteBuffer, 0, configCOMMAND_INT_MAX_OUTPUT_SIZE);
- if(telnet_state_auth == 0){
- telnet_state_auth = 1;
- memset(login, 0, cmdMAX_INPUT_SIZE);
- len = strlen((char *)pcCommandInput);
- strncpy(login, (char *)pcCommandInput, len);
- strncpy( ( char * ) pcWriteBuffer, ( const char * ) pcPSWHeader, strlen( ( char * ) pcPSWHeader ) );
- xReturn = pdTRUE;
- }
- else{
- memset(name_login_telnet, 0, 50);
- telnet_state_auth = 0;
- memset(password, 0, cmdMAX_INPUT_SIZE);
- len = strlen((char *)pcCommandInput);
- strncpy(password, (char *)pcCommandInput, len);
- #ifdef HARDWARE_BT6708
- if(!flagWhiteListTelnet){
- xReturn = pdFALSE;
- }
- else
- #endif
- {
- for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) {
- GetUserLogin(user_id, WebLogin, &valueLen);
- GetUserPassword(user_id, WebPassword, &valueLen);
- /* Check login and password */
- if ((strncmp(WebLogin, login, MAX_WEB_LOGIN_LEN) == 0) &&
- (strncmp(WebPassword, password, MAX_WEB_PASSWD_LEN) == 0)) {
- /* Login and pass are valid */
- telnet_code_auth = user_id;
- login_err = 0;
- strcpy( ( char * ) pcWriteBuffer, "\r\nАвторизация успешно пройдена\r\n>" );
- telnetState = TELNET_CMD;
- xReturn = pdTRUE;
- break;
- }
- else{
- xReturn = pdFALSE;
- }
- }
- }
- if(xReturn == pdFALSE){
- if(login_err < 4){
- login_err ++;
- #ifdef HARDWARE_BT6708
- if(!flagWhiteListTelnet)
- strcpy( ( char * ) pcWriteBuffer, "\r\nДоступ запрешен! Ваш IP-адрес находится вне диапазона доверительных хостов\r\n" );
- else
- #endif
- strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка авторизации\r\n" );
- strncat( ( char * ) pcWriteBuffer, ( const char * ) pcLoginHeader, strlen( ( char * ) pcLoginHeader ) );
- xReturn = pdTRUE;
- }
- else{
- login_err = 0;
- xReturn = pdFALSE;
- }
- }
- switch (user_id) {
- case 0:
- snprintf(name_login_telnet, sizeof(name_login_telnet), "Администратор");
- break;
- case 1:
- snprintf(name_login_telnet, sizeof(name_login_telnet), "Пользователь");
- break;
- default:
- break;
- }
- log_event_data(LOG_LOGIN_TELNET, name_login_telnet);
- }
- return xReturn;
- }
- static portBASE_TYPE FreeRTOS_ChangePWDProcess( const int8_t * const pcCommandInput, int8_t * pcWriteBuffer )
- {
- portBASE_TYPE xReturn = pdTRUE;
- uint32_t len;
- static uint8_t telnet_state_change_pwd = 0;
- static char password[ MAX_WEB_LOGIN_LEN ] = { 0 };
- char password2[ MAX_WEB_LOGIN_LEN ] = { 0 };
- const int8_t * const pcNewPSWHeader = ( int8_t * ) "\r\nВведите повторно новый пароль:";
- memset(pcWriteBuffer, 0, configCOMMAND_INT_MAX_OUTPUT_SIZE);
- if(telnet_state_change_pwd == 0){
- telnet_state_change_pwd = 1;
- memset(password, 0, MAX_WEB_LOGIN_LEN);
- len = strlen((char *)pcCommandInput);
- if(len >= MAX_WEB_LOGIN_LEN){
- strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
- telnetState = TELNET_CMD;
- }
- else{
- if(!control_string_en_digit((char *)pcCommandInput, len)){
- strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
- telnetState = TELNET_CMD;
- }
- else{
- strncpy(password, (char *)pcCommandInput, len);
- strncpy( ( char * ) pcWriteBuffer, ( const char * ) pcNewPSWHeader, strlen( ( char * ) pcNewPSWHeader ) );
- }
- }
- }
- else{
- telnet_state_change_pwd = 0;
- memset(password2, 0, cmdMAX_INPUT_SIZE);
- len = strlen((char *)pcCommandInput);
- if(len >= MAX_WEB_LOGIN_LEN){
- strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
- telnetState = TELNET_CMD;
- }
- else{
- strncpy(password2, (char *)pcCommandInput, len);
- if (strncmp(password, password2, MAX_WEB_PASSWD_LEN) == 0) {
- memcpy(sSettings.sAuth[id_change_pwd].password, password, 11);
- telnet_act = true;
- HTTP_SaveSettings();
- log_event_data(LOG_PSW_CHANGE, name_login_telnet);
- strcpy( ( char * ) pcWriteBuffer, "\r\nПароль успешно изменен\r\n>" );
- telnetState = TELNET_CMD;
- xReturn = pdTRUE;
- }
- else{
- strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
- telnetState = TELNET_CMD;
- }
- }
- }
- return xReturn;
- }
|