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