模拟telnet协议C语言客户端程序
程序员文章站
2022-05-09 11:31:25
首先要了解telnet协议,一下两篇blog给了我初步的思路 https://www.cnblogs.com/liang ling/p/5833489.html 这篇有比较基础的介绍 以及IAC命令含义解释 https://www.cnblogs.com/image eye/archive/2012 ......
首先要了解telnet协议,一下两篇blog给了我初步的思路
https://www.cnblogs.com/liang-ling/p/5833489.html 这篇有比较基础的介绍 以及iac命令含义解释
https://www.cnblogs.com/image-eye/archive/2012/03/28/2421726.html 这篇就很能抓住重点 另外这位博主使用的是c# 写的程序十分完整 我这里关于iac指令处理有部分是直接借鉴他的程序 因此注释都没有修改仍然使用的是他的注释
以上两篇大致看过之后 就可以了解本次po出来的程序了 内容较为朴素
utils.h
#ifndef __utils__h #define __utils__h #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <malloc.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <stdarg.h> #include <fcntl.h> #include <fcntl.h> #include <sys/poll.h> #include <signal.h> #include <sys/wait.h> typedef signed long int ssize_t; typedef unsigned long int size_t; ssize_t readn(int fd, void *vptr,size_t n); ssize_t writen(int fd, const void *vptr, size_t n); ssize_t readline(int fd,void *vptr,size_t maxlen); #endif
utils.c
#include"utils.h" ssize_t readn(int fd, void *vptr,size_t n) { size_t nleft; ssize_t nread; char *ptr; ptr = vptr; nleft = n; while(nleft >0) { if((nread = read(fd,ptr,nleft))<0) { if(errno == eintr)//error:为eagain,表示在非阻塞下,此时无数据到达,立即返回。 nread = 0; //error:为eintr,表示被信号中断了。 else return (-1); } else if(nread == 0) break; else /* do nothing */ nleft -= nread; ptr += nread; } return n-nleft;//实际读了多少字节 } ssize_t writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while(nleft > 0) { if((nwritten = write(fd,ptr,nleft)) < 0) { if(nwritten <0 && errno == eintr) { nwritten = 0; } else return (-1); } else if(nwritten == 0) break; else //nwritten > 0 { /*do nothing*/ } nleft = nleft - nwritten; ptr = ptr + nwritten; } return (n- nleft);//实际写了多少字节 } ssize_t readline(int fd,void *vptr,size_t maxlen) { ssize_t n =0,rc; char c,*ptr; ptr = vptr; while(1) { if((rc = read(fd,&c,1)) == 1) { *ptr++ = c; n++; if(c == '\n') break; } else if (rc == 0) { *ptr = '\0'; return (n -1); } else { if(errno == eintr) continue; else return (-1); } } *ptr = '\0'; return n; }
telnet.h
#ifndef __telnet__h #define __telnet__h //<iac cmd op > #define iac 255 //command word #define nul 0 #define bel 7 #define bs 8 #define ht 9 #define lf 10 #define vt 11 #define ff 12 #define cr 13 #define se 240 #define nop 241 #define dm 242 #define brk 243 #define ip 244 #define ao 245 #define ayt 246 #define ec 247 #define el 248 #define ga 249 #define sb 250 #define will 251 #define wont 252 #define do 253 #define dont 254 typedef unsigned char uint8; typedef unsigned int uint32; //operation options typedef enum tagoperation_options { topt_bin = 0, topt_echo = 1, topt_recn = 2, topt_supp = 3 }operation_options; uint32 get_every_frame(uint8* recvbuf,uint32 len,uint8* sendbuf,uint32 sendlen); #endif
telnet.c
#include"telnet.h" #include<string.h> #include<stdio.h> #define maxline 1024 #define send 1 #define is 0 static uint32 handle_telnetcmd_from_server(uint8* buf,uint32 len,uint8* resp,uint32 n); static uint32 process_every_frame(uint8* startbyte,uint8* endbyte,uint8* sendbuf,uint32 startsendbyte); uint32 get_every_frame(uint8* recvbuf,uint32 len,uint8* sendbuf,uint32 sendlen) { uint32 i =0,n=0,sum =0; //uint8* p = sendbuf; uint8* prear = &recvbuf[len]; uint8* startbyte = recvbuf; uint8* endbyte = recvbuf; printf("-sum-receivelen----%d-------\n",len); printf("receive :<*"); for(i =0 ;i<len;i++) { printf("%x*",recvbuf[i]); } printf("*>\n"); while(startbyte != prear) { if(*startbyte == iac) { sum = sum + n; switch(*(++endbyte)) { /*fa 250 */case sb:while(*(++endbyte) != se){};n = process_every_frame(startbyte,endbyte,sendbuf,sum);break; /*fb 251 */case will:endbyte +=2;n = process_every_frame(startbyte,endbyte,sendbuf,sum);break; /*fc 252 */case wont:endbyte +=2;n = process_every_frame(startbyte,endbyte,sendbuf,sum);break; /*fd 253 */case do:endbyte +=2;n = process_every_frame(startbyte,endbyte,sendbuf,sum);break; /*fe 254 */case dont:endbyte +=2;n = process_every_frame(startbyte,endbyte,sendbuf,sum);break; /* 240 */case se:break; /* sss */default : break; } } startbyte = endbyte; } if(sum > sendlen) { printf("--error3---sum > maxline-----\n"); } printf("--------------sum is %d ----\n",sum); return sum; } static uint32 process_every_frame(uint8* startbyte,uint8* endbyte,uint8* sendbuf,uint32 startsendbyte) { uint8 n = 0 ; uint8* pstartbyte = startbyte; while(pstartbyte != endbyte) { n++; pstartbyte++; } return handle_telnetcmd_from_server(startbyte,n,&sendbuf[startsendbyte],maxline); } static uint32 handle_telnetcmd_from_server(uint8* buf,uint32 len,uint8* resp,uint32 n) { uint32 i =0; uint8 *p = resp; operation_options optioncode; uint8 cmdcode,ch; uint32 resplen =0; memset(resp,0,len); //first display cmd from server in string printf("--receivelen----%d-------\n",len); printf("receive :<*"); for(i =0 ;i<len;i++) { printf("%x*",buf[i]); } printf("*>\n"); if(len < 3) { printf("iac command length is %d less then 3\n",len); return -1; } //获得命令码 cmdcode = buf[1]; //获得选项码 optioncode = buf[2]; //response requests from server *p = iac; resplen++; if(optioncode == topt_echo || optioncode == topt_supp) { if (cmdcode == do) { //我设置我应答的命令码为 251(will) 即为支持 回显或抑制继续进行 ch = will; *(++p) = ch; *(++p)= optioncode; resplen += 2; } //如果命令码为 254(dont) else if (cmdcode == dont) { //我设置我应答的命令码为 252(wont) 即为我也会"拒绝启动" 回显或抑制继续进行 ch = wont; *(++p)= ch; *(++p)= optioncode; resplen += 2; } //如果命令码为251(will) else if (cmdcode == will) { //我设置我应答的命令码为 253(do) 即为我认可你使用回显或抑制继续进行 ch = do; *(++p)= ch; *(++p)= optioncode; resplen += 2; //break; } //如果接受到的命令码为251(wont) else if (cmdcode == wont) { //应答 我也拒绝选项请求回显或抑制继续进行 ch = dont; *(++p)= ch; *(++p)= optioncode; resplen += 2; // break; } //如果接受到250(sb,标志子选项开始) else if (cmdcode == sb) { /* * 因为启动了子标志位,命令长度扩展到了4字节, * 取最后一个标志字节为选项码 * 如果这个选项码字节为1(send) * 则回发为 250(sb子选项开始) + 获取的第二个字节 + 0(is) + 255(标志位iac) + 240(se子选项结束) */ ch = buf[3]; if (ch == send) { ch = sb; *(++p)= ch; *(++p)= optioncode; *(++p)= is; *(++p)= iac; *(++p)= se; resplen += 5; } else { printf("ch != send\n"); } } else { /* do nothing */ } } else/* 如果选项码不是1 或者3 */ { // 底下一系列代表,无论你发那种请求,我都不干 if (cmdcode == do) { ch = wont; *(++p)= ch; *(++p)= optioncode; resplen += 2; } else if (cmdcode == dont) { ch = wont; *(++p)= ch; *(++p)= optioncode; resplen += 2; } else if (cmdcode == will) { ch = dont; *(++p)= ch; *(++p)= optioncode; resplen += 2; } else if (cmdcode == wont) { ch = dont; *(++p)= ch; *(++p)= optioncode; resplen += 2; } else { /* do nothing */ } } printf("--resplen---%d-------\n",resplen); printf("response :<*"); for(i =0 ;i<resplen;i++) { printf("%x*",resp[i]); } printf("*>\n"); if(n < resplen ) { printf("error n < resplen !!! \n"); } if(resplen < 3 ) { printf("resplen < 3 \n"); } return resplen; }
client.c
//gcc client.c -o client #include"utils.h" #include"telnet.h" #define ip_address "127.0.0.1" #define ip_port 23 #define serv_port 3333 #define maxline 1024 typedef struct sockaddr sa; void str_cli(file *fp,uint32 sockfd); uint32 max(uint32 a,uint32 b); void err_exit(char* s); uint32 main(uint32 argc,uint32 **argv) { uint32 sockfd,isready=0; struct sockaddr_in servaddr; uint32 hname[128]; sockfd = socket(af_inet,sock_stream,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family = af_inet; servaddr.sin_port = htons(ip_port); servaddr.sin_addr.s_addr = inet_addr(ip_address); printf("servaddr: ip is %s, port is %d\n",inet_ntoa(servaddr.sin_addr), ntohs(servaddr.sin_port)); while(connect(sockfd,(sa*)&servaddr,sizeof(servaddr))){}; printf("connect has been ready\n"); str_cli(stdin,sockfd); exit(0); return 0; } void err_exit(char* s) { perror(s); exit(exit_failure); } void info_print(char* s) { printf("%s",s); } uint32 max(uint32 a,uint32 b) { return (a>b?a:b); } void str_cli(file *fp,uint32 sockfd) { uint32 maxfdp1,nready;//stdineof; fd_set rset; uint8 buf[maxline]; uint8 respbuff[maxline] = {0};; uint32 resplen; uint32 n; uint8 echo_cmd[] = {0xff,0xfb,0x01}; //stdineof = 0; fd_zero(&rset); writen(sockfd,echo_cmd,3); for(;;) { //if(stdineof == 0) fd_set(fileno(fp),&rset); fd_set(sockfd,&rset); maxfdp1 = max(fileno(fp),sockfd)+1; nready = select(maxfdp1,&rset,null,null,null); if(nready < 0) { err_exit("error!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } if(fd_isset(sockfd,&rset)) { memset(buf,0,maxline); if((n = read(sockfd,buf,maxline))==0) { err_exit("str_cli:server termination prematurely"); } buf[n] = '\0'; //printf("fd_isset(sockfd,&rset)-------------%s\n",buf); if(buf[0] == iac) { memset(respbuff,0,maxline); resplen = get_every_frame(buf,n,respbuff,maxline); writen(sockfd,respbuff,resplen); } else { writen(fileno(stdout),(char *)buf,n); } //writen(fileno(stdout),buf,n); } if(fd_isset(fileno(fp),&rset)) { memset(buf,0,maxline); if((n = readline(fileno(fp),(char *)buf,maxline)) == 0) { //stdineof = 1;//此时碰到eof 并且马上要发生fin序列 所以标准输入不可读了 shutdown(sockfd,shut_wr); fd_clr(fileno(fp),&rset); info_print("nothing input!"); continue; } else if(n >0) { /* do nothing */ } else { err_exit("some error occurred "); } //printf("fd_isset(fileno(fp),&rset)----%d--\n",n); //memset(buf,0,maxline); writen(sockfd,(char *)buf,n); } } }
makefile
all:client_telnet @echo "" @echo "this is telnet client compile......." @echo "" client_telnet:client.o utils.o telnet.o gcc -g -o client_telnet client.o utils.o telnet.o client.o:client.c utils.h telnet.h gcc -g -c client.c utils.o:utils.c utils.h gcc -g -c utils.c telnet.o:telnet.c telnet.h gcc -g -c telnet.c clean : -rm client.o utils.o telnet.o client_telnet
以上为本次程序使用的源码 程序在linux系统上运行方式为 ./client_telnet
然后是运行截图如此下:
以上
上一篇: 傻瓜生的
下一篇: 厉害孩子怪问父亲憋到内伤