telnet/demo_for_develop/telnet_server.c

550 lines
15 KiB
C
Raw Permalink Normal View History

2024-04-24 02:32:26 +00:00
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "telnet.h"
#define TELNET_PORT 223
#define RX_BUFFER_SIZE 1024
#define CMD_SIZE 1024
#define TEL_PROMPT "admin@telnet:~$ "
#define PASSWD "admin"
// extern void printp(char *format, ...);
// #define debug_print(fmt, ...) printp(fmt, ##__VA_ARGS__)
// #define debug_print(fmt...) printp(...)
#define debug_print(fmt, ...) printf(fmt, ##__VA_ARGS__)
typedef struct telnet_t
{
struct sockaddr_in server_addr;
int sock_server;
struct sockaddr_in client_addr;
int sock_client;
unsigned char rec_buff[RX_BUFFER_SIZE];
int rec_len;
unsigned char cmd_buff[CMD_SIZE];
int cmd_pos;
unsigned short win_width;
unsigned short win_height;
unsigned char cilent_type_name[10];
char cilent_type;
char *passwd;
char passwd_pos;
char *tel_prompt;
char init : 1;
char login_in : 1;
char tel_login_show : 1;
char f_echo : 1;
} telnet_t;
telnet_t telnet = {
.passwd = PASSWD,
.tel_prompt = TEL_PROMPT,
};
int telnet_init(telnet_t *tel, int port)
{
int telnet_addr_len = sizeof(struct sockaddr_in);
// server socket create
tel->sock_server = socket(AF_INET, SOCK_STREAM, 0);
if (tel->sock_server < 0)
{
debug_print("telnet: opening socket");
return -1;
}
// server socket set
int keepalive = 1;
if (setsockopt(tel->sock_server, SOL_SOCKET, SO_REUSEADDR, (void *)&keepalive, sizeof(keepalive)) < 0)
{
debug_print("telnet:set socket keepalive failed\n");
return -1;
}
// server socket bind and start listen
tel->server_addr.sin_family = AF_INET;
tel->server_addr.sin_port = htons(port);
tel->server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(tel->sock_server, (void *)&tel->server_addr, sizeof(tel->server_addr)))
{
debug_print("error: binding tcp socket ");
return -1;
}
if (listen(tel->sock_server, 1) == -1)
{
debug_print("error: listen");
return -1;
}
debug_print("telnet: telnet server init success\n");
tel->init = 1;
return 0;
}
#define send_will(buf, a) \
{ \
buf[0] = IAC; \
buf[1] = WILL; \
buf[2] = a; \
send(tel->sock_client, buf, 3, 0); \
};
#define send_wont(buf, a) \
{ \
buf[0] = IAC; \
buf[1] = WONT; \
buf[2] = a; \
send(tel->sock_client, buf, 3, 0); \
};
#define send_do(buf, a) \
{ \
buf[0] = IAC; \
buf[1] = DO; \
buf[2] = a; \
send(tel->sock_client, buf, 3, 0); \
};
#define send_dont(buf, a) \
{ \
buf[0] = IAC; \
buf[1] = DONT; \
buf[2] = a; \
send(tel->sock_client, buf, 3, 0); \
};
int read_terminal_type(telnet_t *tel)
{
unsigned char terminal[] = {IAC, SB, TELOPT_TTYPE, 1, IAC, SE};
send(tel->sock_client, terminal, sizeof(terminal), 0);
sleep(1);
tel->rec_len = recv(tel->sock_client, tel->rec_buff, RX_BUFFER_SIZE, 0);
if (tel->rec_len < 0)
{
debug_print("error \n");
return -1;
}
}
int telnet_config(telnet_t *tel)
{
if (tel->sock_client < 0)
{
return -1;
}
unsigned char cmd[3];
// send_dont(cmd, TELOPT_LINEMODE);
// send(tel->sock_client,"\033[7e",sizeof("\033[7e"),0);
// send_do(cmd, 24);
send_will(cmd, TELOPT_ECHO);
send_will(cmd, TELOPT_SGA);
send_wont(cmd, TELOPT_LINEMODE);
// unsigned char line_mode={IAC,SB,TELOPT_LINEMODE,1,0xf,IAC,SE};
// send(tel->sock_client,line_mode,sizeof(line_mode),0);
// 清理下之前的信息
// tel->rec_len = recv(tel->sock_client, tel->rec_buff, RX_BUFFER_SIZE, 0);
send_do(cmd, TELOPT_TTYPE);
// 获取下终端类型
unsigned char terminal[] = {IAC, SB, TELOPT_TTYPE, 1, IAC, SE};
send(tel->sock_client, terminal, sizeof(terminal), 0);
// send_wont(cmd, TELOPT_LINEMODE);
// send_dont(cmd, TELOPT_LINEMODE);
// send
// send
#if 0
/**
*
*/
unsigned char cmd[3];
send_do(cmd, 24);
send_do(cmd, 32);
send_do(cmd, 35);
send_do(cmd, 39);
tel->rec_len = recv(tel->sock_client, tel->rec_buff, RX_BUFFER_SIZE, 0);
tel->cilent_type = 0;
if (tel->rec_len < 0)
{
return -1;
}
else
{
if (tel->rec_len == 12)
{
int i = 0;
for (; i < 12; i++)
{
if (tel->rec_buff[i] == 32 && tel->rec_buff[i - 1] == WONT)
{
// busy client
tel->cilent_type = 1;
}
}
}
else
{
tel->cilent_type = 2;
}
}
// cilent_type = 3;
switch (tel->cilent_type)
{
case 0:
send_will(cmd, 3);
send_do(cmd, 1);
send_do(cmd, 31);
send_will(cmd, 5);
send_do(cmd, 33);
tel->rec_len = recv(tel->sock_client, tel->rec_buff, RX_BUFFER_SIZE, 0);
send_will(cmd, 1);
break;
case 1:
send_will(cmd, 3);
send_do(cmd, 1);
send_do(cmd, 31);
send_will(cmd, 5);
send_do(cmd, 33);
tel->rec_len = recv(tel->sock_client, tel->rec_buff, RX_BUFFER_SIZE, 0);
send_will(cmd, 1);
break;
case 2:
send_do(cmd, 31);
send_will(cmd, 1);
send_do(cmd, 3);
send_will(cmd, 3);
tel->rec_len = recv(tel->sock_client, tel->rec_buff, RX_BUFFER_SIZE, 0);
send_do(cmd, 1);
send_do(cmd, 31);
send_will(cmd, 5);
send_do(cmd, 33);
break;
case 3:
send_do(cmd, 31);
send_will(cmd, 3);
send_do(cmd, 1);
send_do(cmd, 31);
send_will(cmd, 5);
send_do(cmd, 33);
send_dont(cmd, 1);
tel->rec_len = recv(tel->sock_client, tel->rec_buff, RX_BUFFER_SIZE, 0);
send_dont(cmd, 1);
tel->rec_len = recv(tel->sock_client, tel->rec_buff, RX_BUFFER_SIZE, 0);
send_will(cmd, 1);
break;
default:
break;
}
return 0;
#endif
}
int telnet_cmd_handle(telnet_t *tel)
{
send(tel->sock_client, tel->cmd_buff, tel->cmd_pos, 0);
tel->cmd_pos = 0;
}
int telnet_shell_handle(telnet_t *tel, char c)
{
if (c == 13)
{
send(tel->sock_client, "\r\n", 2, 0);
telnet_cmd_handle(tel);
send(tel->sock_client, "\r\n", 2, 0);
// send(tel->sock_client,"123",3,0);
send(tel->sock_client, tel->tel_prompt, sizeof(TEL_PROMPT), 0);
// send(tel->sock_client, " ", 1, 0);
unsigned char clear_line[] = "\r\033[K";
send(tel->sock_client, clear_line, sizeof(clear_line), 0);
return;
}
else if (c == 0)
{
send(tel->sock_client, " ", 1, 0);
}
else if (c == 10)
{
send(tel->sock_client, " ", 1, 0);
}
else if (c == 9)
{
}
else
{
if (tel->cmd_pos < CMD_SIZE)
{
tel->cmd_buff[tel->cmd_pos++] = c;
send(tel->sock_client, &c, 1, 0);
send(tel->sock_client, " ", 1, 0);
}
else
{
send(tel->sock_client, " ", 2, 0);
}
}
}
int telnet_nor_handle(telnet_t *tel, char c)
{
if (tel->f_echo == 0)
{
char cmd[3] = {0x08, ' ', 0x08};
send(tel->sock_client, cmd, 3, 0);
}
if (tel->login_in == 0)
{
if (tel->tel_login_show == 0)
{
char cmd[] = "\033[?25l";
send(tel->sock_client, cmd, sizeof(cmd), 0);
tel->tel_login_show = 1;
}
// 无论如何回复一个空格
send(tel->sock_client, " ", 1, 0);
if (tel->passwd[tel->passwd_pos] == c)
{
tel->passwd_pos++;
if (tel->passwd[tel->passwd_pos] == '\0')
{
tel->login_in = 1;
tel->passwd_pos = 0;
send(tel->sock_client, "\r\nlogin success\r\n", 17, 0);
send(tel->sock_client, tel->tel_prompt, sizeof(TEL_PROMPT), 0);
if (tel->tel_login_show == 1)
{
char cmd[] = "\033[?25h";
send(tel->sock_client, cmd, sizeof(cmd), 0);
tel->tel_login_show = 0;
}
}
}
else
{
tel->passwd_pos = 0;
}
}
else
{
// telnet_shell_handle(tel, c);
// char see = 0;
telnet_shell_handle(tel, c);
}
}
int telnet_rec_handle(telnet_t *tel, unsigned char *c, int len)
{
#define MOD_NORMAL 0
#define MOD_IAC 1
#define MOD_WILL 2
#define MOD_WONT 3
#define MOD_DO 4
#define MOD_DONT 5
#define MOD_SB 6
int state = MOD_NORMAL;
for (int i = 0; i < len; i++)
{
switch (state)
{
case MOD_NORMAL:
if (c[i] == IAC)
{
state = MOD_IAC;
}
else
{
telnet_nor_handle(tel, c[i]);
}
break;
case MOD_IAC:
if (c[i] == IAC)
{
state = MOD_NORMAL;
// 2个IAC代表字符255也需要进行处理
telnet_nor_handle(tel, c[i]);
}
else if (c[i] == DO)
{
state = MOD_DO;
}
else if (c[i] == DONT)
{
state = MOD_DONT;
}
else if (c[i] == WILL)
{
state = MOD_WILL;
}
else if (c[i] == WONT)
{
state = MOD_WONT;
}
else if (c[i] == SB)
{
state = MOD_SB;
}
else
{
state = MOD_NORMAL;
telnet_nor_handle(tel, c[i]);
}
break;
case MOD_WILL:
debug_print("telnet: WILL %d\n", c[i]);
if (c[i] == TELOPT_NAWS)
{
if (c[i + 1] == IAC && c[i + 2] == SB && c[i + 3] == TELOPT_NAWS && c[i + 8] == IAC && c[i + 9] == SE)
{
tel->win_width = ((unsigned short)c[i + 4] << 8) + (unsigned short)c[i + 5];
tel->win_height = ((unsigned short)c[i + 6] << 8) + (unsigned short)c[i + 7];
i = i + 9;
debug_print("telnet: win_width = %d, win_height = %d\n", tel->win_width, tel->win_height);
}
}
state = MOD_NORMAL;
break;
case MOD_WONT:
debug_print("telnet: WONT %d\n", c[i]);
state = MOD_NORMAL;
break;
case MOD_DO:
debug_print("telnet: DO %d\n", c[i]);
state = MOD_NORMAL;
break;
case MOD_DONT:
if (c[i] == TELOPT_ECHO)
{
tel->f_echo = 0;
}
debug_print("telnet: DONT %d\n", c[i]);
state = MOD_NORMAL;
break;
case MOD_SB:
if (c[i] == TELOPT_TTYPE && c[i + 1] == 0)
{
i = i + 2;
int k = 0;
// 客户端类型
while (1)
{
if ((c[i] == IAC && c[i + 1] == SE) || i == len)
{
tel->cilent_type_name[k] = '\0';
printf("telnet: client type = %s\n", tel->cilent_type_name);
break;
}
if (i == len)
{
break;
}
tel->cilent_type_name[k] = c[i];
i++;
k++;
}
}
break;
}
}
}
int telnet_core(telnet_t *tel)
{
while (1)
{
if (tel->init == 0)
{
sleep(1);
continue;
}
debug_print("\ntelnet: waiting for connection\n");
while (1)
{
int addr_len = sizeof(tel->client_addr);
tel->sock_client = accept(tel->sock_server, (void *)&tel->client_addr, &addr_len);
if (tel->sock_client < 0)
{
sleep(1);
continue;
}
else
{
break;
}
}
debug_print("telnet: new telnet client(%s:%d) connection, switch console to telnet...\n", inet_ntoa(tel->client_addr.sin_addr), tel->client_addr.sin_port);
int ret = telnet_config(tel);
if (ret < 0)
{
debug_print("telnet: client disconnected\n");
close(tel->sock_client);
continue;
}
if (tel->login_in == 0)
{
send(tel->sock_client, "admin login: \r\n", 15, 0);
}
while (1)
{
// telnet_host_function();
tel->rec_len = recv(tel->sock_client, tel->rec_buff, RX_BUFFER_SIZE, 0);
// if (tel->rec_buff[0] == IAC && tel->rec_buff[1] != IAC)
// {
// telnet_config_back(tel);
// }
if (tel->rec_len > 0)
{
debug_print("telnet: recv_len = %d\n", tel->rec_len);
for (int i = 0; i < tel->rec_len; i++)
{
switch (tel->rec_buff[i])
{
case IAC:
debug_print("IAC,");
break;
case DO:
debug_print("DO,");
break;
case DONT:
debug_print("DONT,");
break;
case WILL:
debug_print("WILL,");
break;
case WONT:
debug_print("WONT,");
break;
case SB:
debug_print("SB,");
break;
case SE:
debug_print("SE,");
break;
default:
debug_print("%d,", tel->rec_buff[i]);
break;
}
}
debug_print("\n");
telnet_rec_handle(tel, tel->rec_buff, tel->rec_len);
}
else
{
debug_print("telnet: client disconnected\n");
tel->login_in = 0;
close(tel->sock_client);
break;
}
}
}
}
int main()
{
telnet_init(&telnet, TELNET_PORT);
telnet_core(&telnet);
return 0;
}