telnet/demo_for_develop/telnet_server.c

550 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}