/***************************************************************************** SCL: A simple client Copyright (C) Neil Robertson 2003-2008 Last update: 20080410 This is a simple TCP/UDP/SCTP client for IP4 and IP6 and it also supports unix domain sockets. It might not work properly when connecting to some login shells as it does not support key processing negotiation. Default protocol is TCP. The SCTP part will currently only compile under Linux. This program can send to a multicast group using UDP but it won't recieve from it since it doesn't join the group using the IP_ADD_MEMBERSHIP setsockopt option. To compile: cc scl.c [-D IP6] [-D SCTP] [-lsocket -lnsl] *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERSION "20080410" #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif #define BUFFSIZE 1000 #define DEFAULT_PORT "23" #define UNRESOLVED (char *)"" #define CONTROL_RSQB 29 #define SB_IS 0 #define SB_SEND 1 #define SOPT_ECHO 1 #define SOPT_SGA 3 #define SOPT_TERMINAL 24 #define SOPT_NAWS 31 #define SOPT_XDISPLAY 35 #define PRINT_SUBSEND(O,S) \ if (do_teldump) \ printf("TELOPT SEND: %u (%s) subopt %u (%s)\n", \ O,telopt_str[O - OPT_SE],S,suboptName(S)); enum telopts { OPT_SE=240, OPT_NOP, OPT_MARK, OPT_BRK, OPT_IP, OPT_AO, OPT_AYT, OPT_EC, OPT_EL, OPT_GA, OPT_SB, OPT_WILL, OPT_WONT, OPT_DO, OPT_DONT, OPT_IAC }; char *telopt_str[] = { "SE", "NOP", "MARK", "BRK", "IP", "AO", "AYT", "EC", "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC" }; /* Function prototypes */ void parseCmdLine(int argc, char **argv); void init(); void doConnect(); void mainloop(); void sendBuffer(); void printBuffer(); void hexdump(u_char *buff, int len, int recvd); void telopt(u_char *s,int *i); void teloptWill(u_char subopt); void teloptWont(u_char subopt); void teloptDo(u_char subopt); void teloptDont(u_char subopt); void teloptSubneg(u_char *s,int *i); void sendNaws(); void sendTerminal(); void sendDisplay(); void sendOptReply(u_char opt,u_char subopt); void sendTermSize(int sig); char *suboptName(int subopt); void writeSock(u_char *data, int len); void rawOn(); void echoOn(); void canonicalOn(); void doExit(int sig); /* Global defs */ struct termios term_settings; int sock; int len; int do_raw; int force_echo; int force_linemode; int select_stdin; int sockdomain; int socktype; int protocol; int port; int lport; int kasecs; int nonl; int do_hexdump; int do_teldump; int kalen; int echo; int using_telopt; u_char optout[500]; u_char buff[BUFFSIZE*2+1]; u_char quit_char; char unixpath[110]; char *host; char *portstr; char *kastr; char *xdisplay; /*********************************** START **********************************/ int main(int argc,char **argv) { parseCmdLine(argc,argv); init(); echoOn(); doConnect(); if (do_raw) rawOn(); if (force_linemode) canonicalOn(); mainloop(); } /*** Read stuff on command line ***/ void parseCmdLine(int argc, char **argv) { int i,o; char *opt[] = { "ip6", "tcp", "udp", "sctp", "uxs", "uxd", "fe", "flm", "lp", "ka", "kastr", "qc", "noraw", "nonl", "hexdump", "teldump", "ver" }; enum { OPT_IP6, OPT_TCP, OPT_UDP, OPT_SCTP, OPT_UXS, OPT_UXD, OPT_FE, OPT_FLM, OPT_LP, OPT_KA, OPT_KASTR, OPT_QC, OPT_NORAW, OPT_NONL, OPT_HEXDUMP, OPT_TELDUMP, OPT_VER, OPT_END }; if (argc < 2) goto USAGE; #ifdef IP6 portstr = DEFAULT_PORT; #else port = atoi(DEFAULT_PORT); #endif lport = 0; force_echo = 0; force_linemode = 0; host = NULL; select_stdin = 1; sockdomain = AF_INET; socktype = SOCK_STREAM; protocol = IPPROTO_TCP; unixpath[0] = '\0'; kasecs = 0; kastr = NULL; kalen = 0; do_raw = 1; nonl = 0; do_hexdump = 0; do_teldump = 0; quit_char = CONTROL_RSQB; /* Go through arguments */ for(i=1;i < argc;++i) { if (argv[i][0] != '-') { if (!host) host=argv[i]; else { #ifdef IP6 if (strcmp(portstr,DEFAULT_PORT)) { printf("Unexpected argument '%s'.\n",argv[i]); exit(1); } portstr = argv[i]; #else if (port != atoi(DEFAULT_PORT)) { printf("Unexpected argument '%s'.\n",argv[i]); exit(1); } if ((port = atoi(argv[i])) < 1 || port > 65535) { puts("Invalid port number."); exit(1); } #endif } continue; } for(o=0;o < OPT_END;++o) if (!strcmp(argv[i]+1,opt[o])) break; if (o == OPT_END) goto USAGE; switch(o) { case OPT_IP6: #ifdef IP6 sockdomain = AF_INET6; break; #else puts("IP6 not supported in this build"); exit(1); #endif case OPT_TCP: protocol = IPPROTO_TCP; break; case OPT_UDP: socktype = SOCK_DGRAM; protocol = IPPROTO_UDP; break; case OPT_SCTP: #ifdef SCTP protocol = IPPROTO_SCTP; break; #else puts("SCTP not supported in this build."); exit(1); #endif case OPT_UXS: case OPT_UXD: if (i == argc - 1) goto USAGE; strcpy(unixpath,argv[++i]); sockdomain = AF_UNIX; socktype = (o == OPT_UXS ? SOCK_STREAM : SOCK_DGRAM); protocol = 0; break; case OPT_FE: force_echo = 1; break; case OPT_FLM: force_linemode = 1; break; case OPT_LP: if (i == argc-1) goto USAGE; if ((lport = atoi(argv[++i])) < 1 || lport > 65535) { puts("Invalid local port number."); exit(1); } break; case OPT_KA: if (i == argc-1) goto USAGE; if ((kasecs = atoi(argv[++i])) < 1) { puts("Invalid keepalive value."); exit(1); } break; case OPT_KASTR: if (i == argc-1) goto USAGE; kastr = argv[++i]; if ((kalen = strlen(kastr)) < 1) { puts("Invalid keepalive string."); exit(1); } break; case OPT_QC: if (i == argc-1) goto USAGE; quit_char = atoi(argv[++i]); if (!quit_char) { puts("Invalid quit character."); exit(1); } break; case OPT_NORAW: do_raw = 0; break; case OPT_NONL: nonl = 1; break; case OPT_HEXDUMP: do_hexdump = 1; break; case OPT_TELDUMP: do_teldump = 1; break; case OPT_VER: printf("SCL version %s\n",VERSION); exit(0); default: goto USAGE; } } if (socktype == -1 || (!host && sockdomain != AF_UNIX) || (host && sockdomain == AF_UNIX)) goto USAGE; if (protocol == SOCK_DGRAM && (force_echo || force_linemode)) { printf("The UDP and force echo or force linemode options are mutually exclusive.\n"); exit(1); } return; USAGE: printf("Usage: %s\n" " | -tcp/-udp/-sctp | -uxs/-uxd \n" " : TCP, UDP, SCTP, UNIX domain stream/datagram socket.\n" " Default is TCP and host must be specified\n" " [] : Remote port. Default is %s.\n" " [-ip6] : Use IPv6.\n" " [-fe] : Force echoing.\n" " [-flm] : Force line mode.\n" " [-lp ] : Local port.\n" " [-ka ] : Send keepalive string every seconds after\n" " you last sent data. Useful for some MUDs and chat\n" " systems.\n" " [-kastr ] : Sets keepalive string. Default is '\\r\\n'.\n" " [-qc <1 - 255>] : Sets quit character ascii code.\n" " [-noraw] : Don't put terminal in raw mode (^C etc will kill\n" " the client instead of being sent to the server).\n" " [-nonl] : Don't send \\r or \\n with data. Note: this also\n" " affects kastr so if kastr is just \\r\\n it will\n" " not be sent!\n" " [-hexdump] : Hexdump all data received.\n" " [-teldump] : Dump telnet opcodes sent and received.\n" " [-ver] : Print version then exit.\n", argv[0],DEFAULT_PORT); exit(1); } /*** Get started ***/ void init() { using_telopt = 0; xdisplay = getenv("DISPLAY"); if (xdisplay && !strlen(xdisplay)) xdisplay = NULL; tcgetattr(0,&term_settings); /* Store current keyboard settings */ } /*** Set up socket ***/ void doConnect() { #ifdef IP6 struct sockaddr_in6 bind_addr; struct addrinfo hints; struct addrinfo *res; char ipnum[50]; #else struct sockaddr_in con_addr; struct sockaddr_in bind_addr; struct hostent *hp; char **ptr; #endif struct sockaddr_un con_path; char *proto; char *name; int ret; int on; /* Set up the socket */ if ((sock=socket(sockdomain,socktype,protocol)) == -1) { perror("socket()"); exit(1); } /* Check for unix domain */ if (sockdomain == AF_UNIX) { bzero(&con_path,sizeof(con_path)); con_path.sun_family = AF_UNIX; strcpy(con_path.sun_path,unixpath); printf("Trying %s ...\n",unixpath); if (connect(sock,(struct sockaddr *)&con_path,sizeof(con_path)) == -1) { perror("connect()"); exit(1); } goto CONNECTED; } /* Do this or we can't send to a broadcast address. Don't check return value since if it doesn't work then screw it */ on = 1; setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on)); /* Bind to local port if required */ if (lport) { bzero((char *)&bind_addr,sizeof(bind_addr)); #ifdef IP6 bind_addr.sin6_family = AF_INET6; bind_addr.sin6_flowinfo = 0; /* Not used yet */ bind_addr.sin6_port = htons(lport); bind_addr.sin6_addr = in6addr_any; #else bind_addr.sin_family = AF_INET; bind_addr.sin_addr.s_addr = INADDR_ANY; bind_addr.sin_port = htons(lport); #endif if (bind( sock, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) == -1) { perror("bind()"); exit(1); } } proto = (protocol == IPPROTO_TCP ? "TCP" : (protocol == IPPROTO_UDP ? "UDP" : "SCTP")); ret = -1; /* Resolve address then do connect */ #ifdef IP6 res = NULL; bzero((char *)&hints,sizeof(hints)); hints.ai_flags = AI_NUMERICHOST; hints.ai_family = sockdomain; hints.ai_socktype = socktype; if (getaddrinfo(host,portstr,&hints,&res)) { hints.ai_flags = AI_CANONNAME; if (getaddrinfo(host,portstr,&hints,&res)) { printf("Can't resolve hostname '%s'.\n",host); exit(1); } name = res->ai_canonname ? res->ai_canonname : UNRESOLVED; /* Go through all addresses */ for(;res;res=res->ai_next) { printf("Trying %s (%s) %s port %s...\n", inet_ntop( sockdomain, sockdomain == AF_INET6 ? (void *)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr : (void *)&((struct sockaddr_in *)res->ai_addr)->sin_addr, ipnum, sizeof(ipnum)), name,proto,portstr); if ((ret = connect(sock,res->ai_addr,res->ai_addrlen)) == -1) perror("connect()"); else break; } if (ret == -1) exit(1); } else { /* Numeric address given */ printf("Trying %s (%s) %s port %s...\n", inet_ntop( sockdomain, sockdomain == AF_INET6 ? (void *)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr : (void *)&((struct sockaddr_in *)res->ai_addr)->sin_addr, ipnum, sizeof(ipnum)), UNRESOLVED,proto,portstr); if (connect(sock,res->ai_addr,res->ai_addrlen) == -1) { perror("connect()"); exit(1); } } #else /* IP4 */ bzero((char *)&con_addr,sizeof(con_addr)); con_addr.sin_family = AF_INET; con_addr.sin_port = htons(port); if ((con_addr.sin_addr.s_addr=inet_addr(host)) == -1) { /* DNS name given */ if (!(hp = gethostbyname(host))) { printf("Can't resolve hostname '%s'.\n",host); exit(1); } name = hp->h_name ? hp->h_name : UNRESOLVED; /* Try all addresses in turn */ for(ptr=hp->h_addr_list;*ptr;++ptr) { memcpy( (char *)&con_addr.sin_addr.s_addr, *ptr, hp->h_length); printf("Trying %s (%s) %s port %d...\n", inet_ntoa(con_addr.sin_addr),name,proto,port); if ((ret=connect( sock, (struct sockaddr *)&con_addr, sizeof(con_addr))) == -1) perror("connect()"); else break; } if (ret == -1) exit(1); } else { /* Numeric address given */ printf("Trying %s (%s) %s port %d...\n", inet_ntoa(con_addr.sin_addr),UNRESOLVED,proto,port); if (connect( sock, (struct sockaddr *)&con_addr,sizeof(con_addr)) == -1) { perror("connect()"); exit(1); } } #endif CONNECTED: puts("*** Connected ***"); if (do_raw) { if (quit_char < 32) printf("Quit character is '^%c' (plus newline if in line mode).\n",quit_char + 'A' - 1); else printf("Quit character is '%c' (plus newline if in line mode).\n",quit_char); } /* Signals */ signal(SIGINT,doExit); signal(SIGQUIT,doExit); signal(SIGTERM,doExit); #ifdef TIOCGWINSZ signal(SIGWINCH,sendTermSize); #endif } /*** Do the business ***/ void mainloop() { struct timeval tv1,tv2,tvs; fd_set mask; /* Set up keepalive stuff if required */ if (kasecs) { tvs.tv_sec = kasecs; tvs.tv_usec = 0; gettimeofday(&tv1,NULL); tv1.tv_sec += kasecs; } /** Main loop **/ while(1) { /* select on stdin (bit 0) and the socket */ FD_ZERO(&mask); if (select_stdin) FD_SET(0,&mask); FD_SET(sock,&mask); switch(select(FD_SETSIZE,&mask,0,0,kasecs ? &tvs : NULL)) { case -1: continue; case 0: if (kasecs) { tvs.tv_sec = kasecs; tvs.tv_usec = 0; gettimeofday(&tv1,NULL); tv1.tv_sec += kasecs; } if (kastr) writeSock((u_char *)kastr,kalen); if (!nonl) writeSock((u_char *)"\r\n",2); if (echo) { if (nonl) { if (kastr) write(1,kastr,strlen(kastr)); } else printf("%s\r\n",kastr ? kastr : ""); } continue; } /* See if data on stdin. */ if (FD_ISSET(0,&mask)) { sendBuffer(); /* Reset keepalive */ if (kasecs) { gettimeofday(&tv1,NULL); tv1.tv_sec += kasecs; } } else if (kasecs) { /* If doing keepalive see how many seconds would be left */ gettimeofday(&tv2,NULL); tvs.tv_sec = tv1.tv_sec - tv2.tv_sec; if (tvs.tv_sec < 0) tvs.tv_sec = 0; tvs.tv_usec = 0; } /* See if data on socket */ if (FD_ISSET(sock,&mask)) { if ((len=read(sock,buff,BUFFSIZE)) < 1) doExit(0); /* Only check for telopt stuff if using TCP */ if (socktype == SOCK_STREAM) printBuffer(); else { buff[len]='\0'; write(1,buff,len); } } } } /*** Red off stdin and write out to buffer **/ void sendBuffer() { u_char *s,*s2,*s3; /* If length is zero then stdin has closed. This can happen if we're piping or redirecting something into stdin on the command line */ if ((len = read(0,buff,BUFFSIZE)) < 1) { select_stdin = 0; return; } buff[len]='\0'; for(s=buff;s < buff+len;++s) { if (do_raw && *s == quit_char) doExit(1); s2 = s+1; if (nonl) { /* Remove newlines. This is useful for testing ascii protocols that use length to delimit data boundaries, not newlines. */ if (*s == '\r' || *s == '\n') { /* Shift data up one char */ for(s2=s;*(s2+1);++s2) *s2 = *(s2+1); *s2 = '\0'; --len; } } else /* Make sure we always have \r\n */ if (*s == '\r' && *s2 == '\n') ++s; else if (*s == '\n' && *s2 =='\r') { *s = '\r'; *s2 = '\n'; ++s; } else if (*s == '\n' || *s == '\r') { /* Shift chars up by 1 */ for(s3=buff+len+1;s3 != s2;--s3) *s3 = *(s3 - 1); *s = '\r'; *s2 = '\n'; ++s; ++len; } } if (len) writeSock(buff,len); } /*** Print out the buffer or call the telopt function ***/ void printBuffer() { int i; if (do_hexdump) hexdump(buff,len,1); for(i=0;i < len;) { if (buff[i] == OPT_IAC && len > 2) telopt(buff+i+1,&i); else { if (!do_hexdump) write(1,buff+i,1); ++i; } } } /*** Print out the data we've received from the client ***/ void hexdump(u_char *buff, int len, int recvd) { int start,i; printf("\n%s packet length: %d\n",recvd ? "RECEIVED" : "SENT",len); puts("---------------------------- BEGIN ----------------------------"); puts(" 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9"); for(start=0;start < len;start=i) { printf("%04X %05d: ",start,start); /* Print hex part of line */ for(i=start;i < start+10;++i) { if (i < len) printf("%02X ",buff[i]); else printf(" "); } /* Print ascii part */ printf(": "); for(i=start;i < start+10 && i < len;++i) printf("%c ",(buff[i] < 32 || buff[i] > 127) ? '.' : buff[i]); putchar('\n'); } puts("----------------------------- END -----------------------------"); } /**************************** TELOPT FUNCTIONS ******************************/ /*** Main telopt function. If we don't support at least the recognition and negative replies to telopt requests then we can't connect to a unix telnetd since it'll just sit and wait for replies forever. ***/ void telopt(u_char *s,int *i) { u_char subopt = *(s+1); if (do_teldump) printf("TELOPT RECV: %u (%s) subopt %u (%s)\n", *s,telopt_str[*s - OPT_SE],subopt,suboptName(subopt)); using_telopt = 1; switch(*s) { case OPT_NOP: case OPT_MARK: case OPT_BRK: case OPT_IP: case OPT_AO: case OPT_AYT: case OPT_EC: case OPT_EL: case OPT_GA: /* Ignore */ (*i) += 2; return; case OPT_SB: teloptSubneg(s+1,i); return; case OPT_WILL: teloptWill(subopt); break; case OPT_WONT: teloptWont(subopt); break; case OPT_DO : teloptDo(subopt); break; case OPT_DONT: teloptDont(subopt); break; case OPT_IAC: /* Print char 255 */ putchar(OPT_IAC); (*i) += 2; return; default: /* God knows what this could be */ (*i) += 2; return; } (*i) += 3; } /*** WILL reply ***/ void teloptWill(u_char subopt) { struct termios tio; switch(subopt) { case SOPT_ECHO: if (force_echo) { sendOptReply(OPT_DONT,subopt); return; } /* Switch echoing to screen off */ echo = 0; tcgetattr(0,&tio); tio.c_lflag &= ~ECHO; tcsetattr(0,TCSANOW,&tio); break; case SOPT_SGA: if (force_linemode) { sendOptReply(OPT_DONT,subopt); return; } /* Switch canonical mode off */ tcgetattr(0,&tio); tio.c_lflag &= ~ICANON; tio.c_cc[VTIME] = 0; tio.c_cc[VMIN] = 1; tcsetattr(0,TCSANOW,&tio); break; default: sendOptReply(OPT_DONT,subopt); return; } sendOptReply(OPT_DO,subopt); } /*** WONT reply ****/ void teloptWont(u_char subopt) { switch(subopt) { case SOPT_ECHO: if (!force_echo) echoOn(); break; case SOPT_SGA: if (!force_linemode) canonicalOn(); } sendOptReply(OPT_DONT,subopt); } /*** DO reply ***/ void teloptDo(u_char subopt) { switch(subopt) { case SOPT_TERMINAL: /* Request to send terminal type comes in a sub option command from the server, here we just agree to do it */ sendOptReply(OPT_WILL,SOPT_TERMINAL); break; case SOPT_XDISPLAY: /* As above we only acknowledge (or not if X display not set) */ sendOptReply(xdisplay ? OPT_WILL : OPT_WONT,SOPT_XDISPLAY); break; case SOPT_NAWS: /* Send window info immediately */ sendNaws(); break; default: sendOptReply(OPT_WONT,subopt); } } /*** DONT reply ***/ void teloptDont(u_char subopt) { sendOptReply(OPT_WONT,subopt); } /*** Print out any sub negotiation received from server unless its a request for terminal type ***/ void teloptSubneg(u_char *s, int *i) { int cnt; int pos; u_char type; for(cnt=0,pos=0;*s != OPT_SE && cnt < len;++s,++cnt) { switch(cnt) { case 0: type = *s; switch(type) { case SOPT_TERMINAL: case SOPT_XDISPLAY: ++pos; } break; case 1: if (*s == SB_SEND) ++pos; break; case 2: if (*s == OPT_IAC) ++pos; } } (*i) += (3 + cnt); if (pos != 3) return; /* If we got a terminal request then send it */ switch(type) { case SOPT_TERMINAL: sendTerminal(); break; case SOPT_XDISPLAY: sendDisplay(); break; } } /*** Send window size info ***/ void sendNaws() { /* Send will reply them send window size info immediately after */ sendOptReply(OPT_WILL,SOPT_NAWS); sendTermSize(0); } /*** Send terminal info. Just set to standard vt100 if env var not set ***/ void sendTerminal() { char *term; if (!(term = getenv("TERM")) || !strlen(term)) term="vt100"; PRINT_SUBSEND(OPT_SB,SOPT_TERMINAL); sprintf((char *)optout,"%c%c%c%c%s%c%c", OPT_IAC,OPT_SB,SOPT_TERMINAL,SB_IS,term,OPT_IAC,OPT_SE); writeSock(optout,6+strlen(term)); } /*** Send the X windows display ***/ void sendDisplay() { /* Should never be request if null but just in case */ if (!xdisplay) return; PRINT_SUBSEND(OPT_SB,SOPT_XDISPLAY); sprintf((char *)optout,"%c%c%c%c%s%c%c", OPT_IAC,OPT_SB,SOPT_XDISPLAY,SB_IS,xdisplay,OPT_IAC,OPT_SE); writeSock(optout,6+strlen(xdisplay)); } /*** Send will/wont/do/dont type reply ***/ void sendOptReply(u_char opt,u_char subopt) { PRINT_SUBSEND(opt,subopt); sprintf((char *)optout,"%c%c%c",OPT_IAC,opt,subopt); writeSock(optout,3); } /*** Get and send the current terminal size ***/ void sendTermSize(int sig) { #ifdef TIOCGWINSZ struct winsize ws; #endif uint16_t width; uint16_t height; u_char w1,w2; u_char h1,h2; u_char *p; /* This is the only asychronous telopt function so do this check */ if (!using_telopt) return; width = 80; height = 25; #ifdef TIOCGWINSZ if (ioctl(1,TIOCGWINSZ,&ws)==-1) perror("ioctl"); else { width = ws.ws_col; height = ws.ws_row; } signal(SIGWINCH,sendTermSize); #endif PRINT_SUBSEND(OPT_SB,SOPT_NAWS); sprintf((char *)optout,"%c%c%c",OPT_IAC,OPT_SB,SOPT_NAWS); /* Still need to double up 255s bizzarly given this is essentially a fixed size packet. Hey ho... */ w1 = (width & 0xFF00) >> 8; w2 = width & 0x00FF; h1 = (height & 0xFF00) >> 8; h2 = height & 0x00FF; p = optout + 3; *p++ = w1; if (w1 == 255) *p++ = 255; *p++ = w2; if (w2 == 255) *p++ = 255; *p++ = h1; if (h1 == 255) *p++ = 255; *p++ = h2; if (h2 == 255) *p++ = 255; *p++ = OPT_IAC; *p++ = OPT_SE; writeSock(optout,(int)(p - optout)); } /*** Return name of the sub option ***/ char *suboptName(int subopt) { switch(subopt) { case SOPT_ECHO: return "ECHO"; case SOPT_SGA: return "SGA"; case SOPT_TERMINAL: return "TERMINAL"; case SOPT_NAWS: return "NAWS"; case SOPT_XDISPLAY: return "XDISPLAY"; /* A few others not used here but some of which seem to get sent by the unix telnetd */ case 34: return "LINEMODE"; case 36: return "ENV"; case 37: return "AUTH"; case 38: return "ENCRYPT"; case 39: return "NEWENV"; } return "unknown"; } /***************************** MISCELLANIOUS *******************************/ /*** Write to the socket and do optional hexdump ***/ void writeSock(u_char *data, int len) { if (do_hexdump) hexdump(data,len,0); write(sock,data,len); } /*** Switch to raw mode ***/ void rawOn() { struct termios tio; tcgetattr(0,&tio); tio.c_lflag &= ~ISIG; tio.c_iflag &= ~(IXON | ISTRIP); tcsetattr(0,TCSANOW,&tio); } /*** Switch keyboard echoing on ***/ void echoOn() { struct termios tio; echo = 1; tcgetattr(0,&tio); tio.c_lflag |= ECHO; tcsetattr(0,TCSANOW,&tio); } /*** Switch canonical mode on ***/ void canonicalOn() { struct termios tio; /* Switch canonical mode back on */ tcgetattr(0,&tio); tio.c_lflag |= ICANON; tcsetattr(0,TCSANOW,&tio); } /*** Set echoing back on and quit ***/ void doExit(int sig) { /* Reset terminal to start state and exit */ tcsetattr(0,TCSANOW,&term_settings); printf("\n*** Connection closed by %s ***\n",sig ? "client" : "server"); exit(0); }