#include "forward-tunnel.h" #include "thpool.h" const char *keyfile1 = "/home/aixiao/.ssh/id_rsa.pub"; const char *keyfile2 = "/home/aixiao/.ssh/id_rsa"; char *server_ssh_ip = "127.0.0.1"; int server_ssh_port = 22; char *server_ssh_user = "aixiao"; char *server_ssh_passwd = "123456"; const char *local_listenip = "0.0.0.0"; unsigned int local_listenport = 3306; char *remote_desthost = "0.0.0.0"; /* resolved by the server */ unsigned int remote_destport = 3306; enum { AUTH_NONE = 0, AUTH_PASSWORD, AUTH_PUBLICKEY }; void forward_tunnel(void *sock_) { int forwardsock = *(int *)sock_; int rc, i, auth = AUTH_NONE; struct sockaddr_in sin; const char *fingerprint; char *userauthlist; LIBSSH2_SESSION *session; LIBSSH2_CHANNEL *channel = NULL; const char *shost; unsigned int sport; fd_set fds; struct timeval tv; ssize_t len, wr; char buffer[16384]; int sock; bzero(buffer, 0); rc = libssh2_init(0); if (rc) { fprintf(stderr, "libssh2 initialization failed (%d)\n", rc); return; } /* Connect to SSH server */ sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == -1) { perror("socket"); return; } int optval = SO_REUSEADDR; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { perror("setsockopt"); return; } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(server_ssh_ip); if (INADDR_NONE == sin.sin_addr.s_addr) { perror("inet_addr"); return; } sin.sin_port = htons(server_ssh_port); if (connect(sock, (struct sockaddr *)(&sin), sizeof(struct sockaddr_in)) != 0) { fprintf(stderr, "failed to connect!\n"); return; } /* Create a session instance */ session = libssh2_session_init(); if (!session) { fprintf(stderr, "Could not initialize SSH session!\n"); return; } /* ... start it up. This will trade welcome banners, exchange keys, * and setup crypto, compression, and MAC layers */ rc = libssh2_session_handshake(session, sock); if (rc) { fprintf(stderr, "Error when starting up SSH session: %d\n", rc); return; } /* At this point we havn't yet authenticated. The first thing to do * is check the hostkey's fingerprint against our known hosts Your app * may have it hard coded, may go to a file, may present it to the * user, that's your call */ fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1); fprintf(stderr, "Fingerprint: "); for (i = 0; i < 20; i++) fprintf(stderr, "%02X ", (unsigned char)fingerprint[i]); fprintf(stderr, "\n"); /* check what authentication methods are available */ userauthlist = libssh2_userauth_list(session, server_ssh_user, strlen(server_ssh_user)); fprintf(stderr, "Authentication methods: %s\n", userauthlist); if (strstr(userauthlist, "password")) auth |= AUTH_PASSWORD; if (strstr(userauthlist, "publickey")) auth |= AUTH_PUBLICKEY; if (auth & AUTH_PASSWORD) { if (libssh2_userauth_password(session, server_ssh_user, server_ssh_passwd)) { fprintf(stderr, "Authentication by password failed.\n"); goto shutdown; } } else if (auth & AUTH_PUBLICKEY) { if (libssh2_userauth_publickey_fromfile(session, server_ssh_user, keyfile1, keyfile2, server_ssh_passwd)) { fprintf(stderr, "\tAuthentication by public key failed!\n"); goto shutdown; } fprintf(stderr, "\tAuthentication by public key succeeded.\n"); } else { fprintf(stderr, "No supported authentication methods found!\n"); goto shutdown; } shost = inet_ntoa(sin.sin_addr); sport = ntohs(sin.sin_port); fprintf(stderr, "Forwarding connection from %s:%d here to remote %s:%d\n", shost, sport, remote_desthost, remote_destport); channel = libssh2_channel_direct_tcpip_ex(session, remote_desthost, remote_destport, shost, sport); if (!channel) { fprintf(stderr, "Could not open the direct-tcpip channel!\n" "(Note that this can be a problem at the server!" " Please review the server logs.)\n"); goto shutdown; } /* Setting session to non-blocking IO */ libssh2_session_set_blocking(session, 0); while (1) { FD_ZERO(&fds); FD_SET(forwardsock, &fds); // 设置一个描述符 tv.tv_sec = 0; tv.tv_usec = 100000; rc = select(forwardsock + 1, &fds, NULL, NULL, &tv); if (-1 == rc) { // 返回-1表示出错 perror("select"); goto shutdown; } if (rc && FD_ISSET(forwardsock, &fds)) { // 测试某一个描述符返回值: 若fd在描述符集中则返回非0,否则返回0 len = read(forwardsock, buffer, sizeof(buffer)); if (len < 0) { perror("read"); goto shutdown; } else if (0 == len) { fprintf(stderr, "The client at %s:%d disconnected!\n", shost, sport); goto shutdown; } wr = 0; while (wr < len) { i = libssh2_channel_write(channel, buffer + wr, len - wr); if (LIBSSH2_ERROR_EAGAIN == i) { continue; } if (i < 0) { fprintf(stderr, "libssh2_channel_write: %d\n", i); goto shutdown; } wr += i; } } while (1) { len = libssh2_channel_read(channel, buffer, sizeof(buffer)); if (LIBSSH2_ERROR_EAGAIN == len) break; else if (len < 0) { fprintf(stderr, "libssh2_channel_read: %d", (int)len); goto shutdown; } wr = 0; while (wr < len) { i = write(forwardsock, buffer + wr, len - wr); if (i <= 0) { perror("write"); goto shutdown; } wr += i; } if (libssh2_channel_eof(channel)) { fprintf(stderr, "The server at %s:%d disconnected!\n", remote_desthost, remote_destport); goto shutdown; } } } shutdown: close(forwardsock); if (channel) libssh2_channel_free(channel); libssh2_session_set_blocking(session, 1); libssh2_session_disconnect(session, "Client disconnecting normally"); libssh2_session_free(session); close(sock); libssh2_exit(); return; } static char help_info(void) { int l; static const char name[] = "STunnel"; static const char subject[] = "SSH forward tunnel"; static const struct { const char *email; const char *version; } author = { "AIXIAO@AIXIAO.ME", "1.0", }; static const char usage[] = "Usage: [-d] [-rsplueh?]"; static const char *s_help[] = { "", "Options:", " -d : Background running", " -r : SSH Server IP", " -p : SSH Server Port (default: 22)", " -u : SSH Server User", " -e : SSH Server User Passwd", " -s : Remote Dest Port (default: 3306 1521)", " -l : Local_Listen Port", " -? -h : help information", "", "", 0 }; fprintf(stderr, " %s %s\n", name, subject); fprintf(stderr, "Author: %s\n", author.email); fprintf(stderr, "Version: %s\n", author.version); fprintf(stderr, "%s\n", usage); for (l = 0; s_help[l]; l++) { fprintf(stderr, "%s\n", s_help[l]); } BUILD("Compile、link.\n"); puts(""); return 0; } int nice_(int increment) { int oldprio = getpriority(PRIO_PROCESS, getpid()); printf("%d\n", oldprio); return setpriority(PRIO_PROCESS, getpid(), oldprio + increment); } int modif_argv(int argc, char *argv[]) { int i, j; // 加密参数(账号密码) for (i = 1; i < argc; i++) { if (0 == strcmp(argv[i], "-e") || 0 == strcmp(argv[i], "-u") || 0 == strcmp(argv[i], "-p")) { for (j = strlen(argv[i + 1]) - 1; j >= 0; j--) { argv[i + 1][j] = 'x'; } } } return 0; } int get_threads() { pid_t pid; char line[256]; char path[256]; int threads = 0; pid = getpid(); snprintf(path, sizeof(path), "/proc/%d/status", pid); FILE *file = fopen(path, "r"); if (file == NULL) { perror("Failed to open file"); return EXIT_FAILURE; } while (fgets(line, sizeof(line), file)) { if (strncmp(line, "Threads:", 8) == 0) { sscanf(line, "Threads:\t%d", &threads); break; } } return threads; } int main(int argc, char *argv[], char **env) { struct sockaddr_in sin; struct sockaddr_in server_addr; socklen_t server_addr_len; int sockopt = 1; int listensock = -1, forwardsock = -1; int _daemon = 0; int opt; char *p = NULL; char optstring[] = ":dr:s:p:l:u:e:h?"; while (-1 != (opt = getopt(argc, argv, optstring))) { switch (opt) { case 'd': _daemon = 1; break; case 'r': server_ssh_ip = strdup(optarg); break; case 's': p = strchr(optarg, ':'); if (p != NULL) { remote_destport = atoi(p + 1); *p = '\0'; remote_desthost = optarg; } else { if (NULL == (p = strchr(optarg, '.'))) { remote_destport = atoi(optarg); remote_desthost = "0.0.0.0"; } else { help_info(); exit(0); } } break; case 'p': server_ssh_port = atoi(optarg); break; case 'l': local_listenport = atoi(optarg); break; case 'u': server_ssh_user = strdup(optarg); break; case 'e': server_ssh_passwd = strdup(optarg);; break; case 'h': case '?': help_info(); exit(0); break; default: ; } } modif_argv(argc, argv); printf("SSH Server: %s:%d, Local listen: %s:%d, User&Passwd: [%s]['%s']\n", server_ssh_ip, remote_destport, local_listenip, local_listenport, server_ssh_user, server_ssh_passwd); listensock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (listensock == -1) { perror("socket"); return -1; } int optval = SO_REUSEADDR; if (setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { perror("setsockopt"); return -1; } sin.sin_family = AF_INET; sin.sin_port = htons(local_listenport); sin.sin_addr.s_addr = inet_addr(local_listenip); if (INADDR_NONE == sin.sin_addr.s_addr) { perror("inet_addr"); goto shutdown; } if (setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(sockopt)) < 0) { perror("setsockopt"); return -1; } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(local_listenport); server_addr.sin_addr.s_addr = INADDR_ANY; if (bind(listensock, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) { perror("bind"); goto shutdown; } if (listen(listensock, 500) < 0) { perror("listen"); goto shutdown; } fprintf(stderr, "Waiting for TCP connection on %s:%d ...\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); // 后台运行 if (_daemon == 1) { if (daemon(1, 1)) { perror("daemon"); return -1; } } // 进程优先级 if (-1 == (nice_(-20))) perror("nice_"); threadpool thpool = thpool_init(1024); while (1) { printf("%d\n", get_threads()); int *forwardsock = (int *)malloc(sizeof(int)); // 分配内存空间保存线程编号 *forwardsock = accept(listensock, (struct sockaddr *)&sin, &server_addr_len); // 接受连接 if (*forwardsock == -1) { perror("accept"); goto shutdown; } thpool_add_work(thpool, forward_tunnel, (void *)(uintptr_t) forwardsock); } thpool_wait(thpool); thpool_destroy(thpool); shutdown: close(forwardsock); close(listensock); libssh2_exit(); if (server_ssh_ip) free(server_ssh_ip); if (server_ssh_user) free(server_ssh_user); if (server_ssh_passwd) free(server_ssh_passwd); return 0; }