20230324
This commit is contained in:
commit
250a958832
26
Makefile
Normal file
26
Makefile
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
CROSS_COMPILE ?=
|
||||||
|
CC := $(CROSS_COMPILE)gcc
|
||||||
|
STRIP := $(CROSS_COMPILE)strip
|
||||||
|
CFLAGS = -Wall -g -O3
|
||||||
|
LIB = -lssh2 -pthread
|
||||||
|
OBJ = tunnel
|
||||||
|
|
||||||
|
SSH2_LIB := $(shell pkg-config --static --libs --cflags libssh2)
|
||||||
|
|
||||||
|
|
||||||
|
all:forward-tunnel reverse-tunnel
|
||||||
|
|
||||||
|
forward-tunnel: forward-tunnel.o
|
||||||
|
$(CC) $(CFLAGS) -o forward-tunnel $^ $(SSH2_LIB) $(LIB)
|
||||||
|
$(STRIP) forward-tunnel
|
||||||
|
|
||||||
|
reverse-tunnel: reverse-tunnel.o
|
||||||
|
$(CC) $(CFLAGS) -o reverse-tunnel $^ $(SSH2_LIB) $(LIB)
|
||||||
|
$(STRIP) reverse-tunnel
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf *.o
|
||||||
|
rm reverse-tunnel forward-tunnel
|
30
README.md
Normal file
30
README.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# libssh2_tunnel
|
||||||
|
|
||||||
|
Linux libssh2 正向隧道
|
||||||
|
|
||||||
|
# build
|
||||||
|
git clone https://git.aixiao.me/aixiao/libssh2-tunnel.git
|
||||||
|
cd libssh2-tunnel
|
||||||
|
make clean; make
|
||||||
|
|
||||||
|
# test
|
||||||
|
root@NIUYULING:/mnt/c/Users/niuyuling/Desktop/libssh2-tunnel# ./forward-tunnel -h
|
||||||
|
STunnel SSH forward tunnel
|
||||||
|
Author: AIXIAO@AIXIAO.ME
|
||||||
|
Version: 1.0
|
||||||
|
Usage: [-d] [-rsplueh?]
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
Mar 24 2023 17:46:41 Compile、link.
|
||||||
|
|
||||||
|
root@NIUYULING:/mnt/c/Users/niuyuling/Desktop/libssh2-tunnel#
|
391
forward-tunnel.c
Normal file
391
forward-tunnel.c
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
#include "forward-tunnel.h"
|
||||||
|
|
||||||
|
|
||||||
|
const char *keyfile1 = "/home/aixiao/.ssh/id_rsa.pub";
|
||||||
|
const char *keyfile2 = "/home/aixiao/.ssh/id_rsa";
|
||||||
|
|
||||||
|
char *server_ssh_ip = "47.108.253.59";
|
||||||
|
int server_ssh_port = 22;
|
||||||
|
char *server_ssh_user = "root";
|
||||||
|
char *server_ssh_passwd = "123456";
|
||||||
|
|
||||||
|
const char *local_listenip = "0.0.0.0";
|
||||||
|
unsigned int local_listenport = 3009;
|
||||||
|
|
||||||
|
const 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 *p)
|
||||||
|
{
|
||||||
|
|
||||||
|
int forwardsock = *(int *)p;
|
||||||
|
|
||||||
|
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 NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect to SSH server */
|
||||||
|
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (sock == -1) {
|
||||||
|
perror("socket");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 NULL;
|
||||||
|
}
|
||||||
|
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 NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a session instance */
|
||||||
|
session = libssh2_session_init();
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
fprintf(stderr, "Could not initialize SSH session!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... 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 NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static char help_info(void)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
int l;
|
||||||
|
for (l = 0; s_help[l]; l++) {
|
||||||
|
fprintf(stderr, "%s\n", s_help[l]);
|
||||||
|
}
|
||||||
|
|
||||||
|
BUILD("Compile、link.\n");
|
||||||
|
puts("");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_is = 0;
|
||||||
|
int opt;
|
||||||
|
|
||||||
|
|
||||||
|
char optstring[] = ":dr:s:p:l:u:e:h?";
|
||||||
|
while (-1 != (opt = getopt(argc, argv, optstring))) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'd':
|
||||||
|
daemon_is = 1;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
server_ssh_ip = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
remote_destport = atoi(optarg);
|
||||||
|
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:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 1024) < 0) {
|
||||||
|
perror("listen");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Waiting for TCP connection on %s:%d...\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
|
||||||
|
|
||||||
|
pthread_t thread_id = 0;
|
||||||
|
sigset_t signal_mask;
|
||||||
|
sigemptyset(&signal_mask);
|
||||||
|
sigaddset(&signal_mask, SIGPIPE); // 忽略PIPE信号
|
||||||
|
if (pthread_sigmask(SIG_BLOCK, &signal_mask, NULL) != 0) {
|
||||||
|
printf("block sigpipe error\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (daemon_is == 1) {
|
||||||
|
if (daemon(1, 1)) {
|
||||||
|
perror("daemon");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
server_addr_len = sizeof(server_addr);
|
||||||
|
forwardsock = accept(listensock, (struct sockaddr *)&sin, &server_addr_len);
|
||||||
|
if (forwardsock == -1) {
|
||||||
|
perror("accept");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_create(&thread_id, NULL, &forward_tunnel, (void *)&forwardsock);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_join(thread_id, NULL);
|
||||||
|
pthread_exit(NULL);
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
24
forward-tunnel.h
Normal file
24
forward-tunnel.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef FORWARD_TUNNEL
|
||||||
|
#define FORWARD_TUNNEL
|
||||||
|
|
||||||
|
#include <libssh2.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#define BUILD(fmt...) do { fprintf(stderr,"%s %s ",__DATE__,__TIME__); fprintf(stderr, ##fmt); } while(0)
|
||||||
|
#ifndef INADDR_NONE
|
||||||
|
#define INADDR_NONE (in_addr_t)-1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
287
reverse-tunnel.c
Normal file
287
reverse-tunnel.c
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
/*
|
||||||
|
* Example of SSH tunnel using libssh2.
|
||||||
|
*
|
||||||
|
* This code was based on the 'tcpip-forward.c' example:
|
||||||
|
* https://github.com/libssh2/libssh2/blob/master/example/tcpip-forward.c
|
||||||
|
*
|
||||||
|
* Author: marianafranco (https://github.com/marianafranco)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libssh2.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
|
||||||
|
#ifndef INADDR_NONE
|
||||||
|
#define INADDR_NONE (in_addr_t)-1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *keyfile1 = "/home/username/.ssh/id_rsa.pub";
|
||||||
|
const char *keyfile2 = "/home/username/.ssh/id_rsa";
|
||||||
|
const char *username = "root";
|
||||||
|
const char *password = "12345";
|
||||||
|
|
||||||
|
const char *server_ip = "47.240.75.93";
|
||||||
|
|
||||||
|
const char *remote_listenhost = "0.0.0.0"; /* resolved by the remote server */
|
||||||
|
int remote_wantport = 33;
|
||||||
|
int remote_listenport;
|
||||||
|
|
||||||
|
const char *local_destip = "0.0.0.0";
|
||||||
|
int local_destport = 22;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
AUTH_NONE = 0,
|
||||||
|
AUTH_PASSWORD,
|
||||||
|
AUTH_PUBLICKEY
|
||||||
|
};
|
||||||
|
|
||||||
|
int forward_tunnel(LIBSSH2_SESSION * session, LIBSSH2_CHANNEL * channel)
|
||||||
|
{
|
||||||
|
int i, rc = 0;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
fd_set fds;
|
||||||
|
struct timeval tv;
|
||||||
|
ssize_t len, wr;
|
||||||
|
char buf[16384];
|
||||||
|
int forwardsock = -1;
|
||||||
|
|
||||||
|
fprintf(stdout, "Accepted remote connection. Connecting to local server %s:%d\n", local_destip, local_destport);
|
||||||
|
forwardsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (forwardsock == -1) {
|
||||||
|
fprintf(stderr, "Error opening socket\n");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_port = htons(local_destport);
|
||||||
|
if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(local_destip))) {
|
||||||
|
fprintf(stderr, "Invalid local IP address\n");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == connect(forwardsock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in))) {
|
||||||
|
fprintf(stderr, "Failed to connect!\n");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "Forwarding connection from remote %s:%d to local %s:%d\n", remote_listenhost, remote_listenport, local_destip, local_destport);
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
fprintf(stderr, "Socket not ready!\n");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
if (rc && FD_ISSET(forwardsock, &fds)) {
|
||||||
|
len = recv(forwardsock, buf, sizeof(buf), 0);
|
||||||
|
if (len < 0) {
|
||||||
|
fprintf(stderr, "Error reading from the forwardsock!\n");
|
||||||
|
goto shutdown;
|
||||||
|
} else if (0 == len) {
|
||||||
|
fprintf(stderr, "The local server at %s:%d disconnected!\n", local_destip, local_destport);
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
wr = 0;
|
||||||
|
do {
|
||||||
|
i = libssh2_channel_write(channel, buf, len);
|
||||||
|
if (i < 0) {
|
||||||
|
fprintf(stderr, "Error writing on the SSH channel: %d\n", i);
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
wr += i;
|
||||||
|
} while (i > 0 && wr < len);
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
len = libssh2_channel_read(channel, buf, sizeof(buf));
|
||||||
|
if (LIBSSH2_ERROR_EAGAIN == len)
|
||||||
|
break;
|
||||||
|
else if (len < 0) {
|
||||||
|
fprintf(stderr, "Error reading from the SSH channel: %d\n", (int)len);
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
wr = 0;
|
||||||
|
while (wr < len) {
|
||||||
|
i = send(forwardsock, buf + wr, len - wr, 0);
|
||||||
|
if (i <= 0) {
|
||||||
|
fprintf(stderr, "Error writing on the forwardsock!\n");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
wr += i;
|
||||||
|
}
|
||||||
|
if (libssh2_channel_eof(channel)) {
|
||||||
|
fprintf(stderr, "The remote client at %s:%d disconnected!\n", remote_listenhost, remote_listenport);
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown:
|
||||||
|
close(forwardsock);
|
||||||
|
/* Setting the session back to blocking IO */
|
||||||
|
libssh2_session_set_blocking(session, 1);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int rc, i, auth = AUTH_NONE;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
const char *fingerprint;
|
||||||
|
char *userauthlist;
|
||||||
|
LIBSSH2_SESSION *session;
|
||||||
|
LIBSSH2_LISTENER *listener = NULL;
|
||||||
|
LIBSSH2_CHANNEL *channel = NULL;
|
||||||
|
|
||||||
|
int sock = -1;
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
server_ip = argv[1];
|
||||||
|
if (argc > 2)
|
||||||
|
username = argv[2];
|
||||||
|
if (argc > 3)
|
||||||
|
password = argv[3];
|
||||||
|
if (argc > 4)
|
||||||
|
remote_listenhost = argv[4];
|
||||||
|
if (argc > 5)
|
||||||
|
remote_wantport = atoi(argv[5]);
|
||||||
|
if (argc > 6)
|
||||||
|
local_destip = argv[6];
|
||||||
|
if (argc > 7)
|
||||||
|
local_destport = atoi(argv[7]);
|
||||||
|
|
||||||
|
rc = libssh2_init(0);
|
||||||
|
if (rc != 0) {
|
||||||
|
fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect to SSH server */
|
||||||
|
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (sock == -1) {
|
||||||
|
fprintf(stderr, "Error opening socket\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(server_ip))) {
|
||||||
|
fprintf(stderr, "Invalid remote IP address\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sin.sin_port = htons(22); /* SSH port */
|
||||||
|
if (connect(sock, (struct sockaddr *)(&sin), sizeof(struct sockaddr_in)) != 0) {
|
||||||
|
fprintf(stderr, "Failed to connect!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a session instance */
|
||||||
|
session = libssh2_session_init();
|
||||||
|
if (!session) {
|
||||||
|
fprintf(stderr, "Could not initialize the SSH session!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ... 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 -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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(stdout, "Fingerprint: ");
|
||||||
|
for (i = 0; i < 20; i++)
|
||||||
|
fprintf(stdout, "%02X ", (unsigned char)fingerprint[i]);
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
|
/* check what authentication methods are available */
|
||||||
|
userauthlist = libssh2_userauth_list(session, username, strlen(username));
|
||||||
|
fprintf(stderr, "Authentication methods: %s\n", userauthlist);
|
||||||
|
if (strstr(userauthlist, "password"))
|
||||||
|
auth |= AUTH_PASSWORD;
|
||||||
|
if (strstr(userauthlist, "publickey"))
|
||||||
|
auth |= AUTH_PUBLICKEY;
|
||||||
|
|
||||||
|
/* check for options */
|
||||||
|
if (argc > 8) {
|
||||||
|
if ((auth & AUTH_PASSWORD) && !strcasecmp(argv[8], "-p"))
|
||||||
|
auth = AUTH_PASSWORD;
|
||||||
|
if ((auth & AUTH_PUBLICKEY) && !strcasecmp(argv[8], "-k"))
|
||||||
|
auth = AUTH_PUBLICKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth & AUTH_PASSWORD) {
|
||||||
|
if (libssh2_userauth_password(session, username, password)) {
|
||||||
|
fprintf(stderr, "Authentication by password failed.\n");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
} else if (auth & AUTH_PUBLICKEY) {
|
||||||
|
if (libssh2_userauth_publickey_fromfile(session, username, keyfile1, keyfile2, password)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "Asking server to listen on remote %s:%d\n", remote_listenhost, remote_wantport);
|
||||||
|
|
||||||
|
//listener = libssh2_channel_forward_listen_ex(session, NULL, remote_wantport, &remote_listenport, 1);
|
||||||
|
listener = libssh2_channel_forward_listen(session, remote_wantport);
|
||||||
|
if (!listener) {
|
||||||
|
fprintf(stderr, "Could not start the tcpip-forward listener!\n" "(Note that this can be a problem at the server!" " Please review the server logs.)\n");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stdout, "Server is listening on %s:%d\n", remote_listenhost, remote_listenport);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
fprintf(stdout, "Waiting for remote connection\n");
|
||||||
|
channel = libssh2_channel_forward_accept(listener);
|
||||||
|
if (!channel) {
|
||||||
|
fprintf(stderr, "Could not accept connection!\n" "(Note that this can be a problem at the server!" " Please review the server logs.)\n");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
forward_tunnel(session, channel);
|
||||||
|
|
||||||
|
libssh2_channel_free(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown:
|
||||||
|
if (channel)
|
||||||
|
libssh2_channel_free(channel);
|
||||||
|
if (listener)
|
||||||
|
libssh2_channel_forward_cancel(listener);
|
||||||
|
libssh2_session_disconnect(session, "Client disconnecting normally");
|
||||||
|
libssh2_session_free(session);
|
||||||
|
close(sock);
|
||||||
|
libssh2_exit();
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user