增加地域白名单
This commit is contained in:
parent
2e650b5893
commit
7a692a8d39
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp.errorSquiggles": "disabled",
|
||||||
|
"files.associations": {
|
||||||
|
"forward-tunnel.h": "c",
|
||||||
|
"cstdlib": "c"
|
||||||
|
}
|
||||||
|
}
|
14
Makefile
14
Makefile
@ -6,6 +6,11 @@ LIB = -lssh2 -pthread
|
|||||||
forward-tunnel = forward-tunnel
|
forward-tunnel = forward-tunnel
|
||||||
reverse-tunnel = reverse-tunnel
|
reverse-tunnel = reverse-tunnel
|
||||||
|
|
||||||
|
|
||||||
|
ip2region_SRC := ip2region/ip2region.c ip2region/xdb_searcher.c
|
||||||
|
ip2region_OBJS := $(ip2region_SRC:.c=.o)
|
||||||
|
ip2region_CFLAGS := -Os -g -Wall -I/ip2region
|
||||||
|
|
||||||
ifeq ($(shell uname -o), GNU/Linux)
|
ifeq ($(shell uname -o), GNU/Linux)
|
||||||
ifeq ($(shell lsb_release -si), Debian)
|
ifeq ($(shell lsb_release -si), Debian)
|
||||||
LIB += -static
|
LIB += -static
|
||||||
@ -17,7 +22,7 @@ endif
|
|||||||
|
|
||||||
all:forward-tunnel reverse-tunnel
|
all:forward-tunnel reverse-tunnel
|
||||||
|
|
||||||
forward-tunnel: forward-tunnel.o thpool.o
|
forward-tunnel: forward-tunnel.o thpool.o $(ip2region_OBJS)
|
||||||
$(CC) $(CFLAGS) -o $(forward-tunnel) $^ $(SSH2_LIB) $(LIB)
|
$(CC) $(CFLAGS) -o $(forward-tunnel) $^ $(SSH2_LIB) $(LIB)
|
||||||
$(STRIP) forward-tunnel
|
$(STRIP) forward-tunnel
|
||||||
|
|
||||||
@ -28,6 +33,9 @@ reverse-tunnel: reverse-tunnel.o
|
|||||||
.c.o:
|
.c.o:
|
||||||
$(CC) $(CFLAGS) -c $<
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
|
||||||
|
ip2region/%.o: ip2region/%.c
|
||||||
|
$(CC) $(ip2region_CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf *.o
|
rm -rf *.o $(ip2region_SRC:.c=.o)
|
||||||
rm reverse-tunnel forward-tunnel
|
rm -rf reverse-tunnel forward-tunnel
|
||||||
|
BIN
forward-tunnel
BIN
forward-tunnel
Binary file not shown.
120
forward-tunnel.c
120
forward-tunnel.c
@ -1,5 +1,6 @@
|
|||||||
#include "forward-tunnel.h"
|
#include "forward-tunnel.h"
|
||||||
#include "thpool.h"
|
#include "thpool.h"
|
||||||
|
#include "ip2region/ip2region.h"
|
||||||
|
|
||||||
const char *keyfile1 = "/home/aixiao/.ssh/id_rsa.pub";
|
const char *keyfile1 = "/home/aixiao/.ssh/id_rsa.pub";
|
||||||
const char *keyfile2 = "/home/aixiao/.ssh/id_rsa";
|
const char *keyfile2 = "/home/aixiao/.ssh/id_rsa";
|
||||||
@ -313,6 +314,56 @@ int get_threads()
|
|||||||
return threads;
|
return threads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 地域段白名单对比
|
||||||
|
int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
for (i = 1; i < WHITELIST_IP_NUM - 1; i++) {
|
||||||
|
if (strcmp(region_list[i], "\0") == 0) // 如果字符串为空就跳出循环
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//printf("%s %s\n", str, region_list[i]);
|
||||||
|
// 在str中查找region_list[i]
|
||||||
|
p = strstr(str, region_list[i]);
|
||||||
|
if (p != NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM])
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
char *result = NULL;
|
||||||
|
|
||||||
|
result = strtok(string, delims);
|
||||||
|
while (result != NULL) {
|
||||||
|
i++;
|
||||||
|
strcpy(whitelist_ip[i], result);
|
||||||
|
result = strtok(NULL, delims);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *_time()
|
||||||
|
{
|
||||||
|
char temp[BUFFER];
|
||||||
|
char *wday[] = { "0", "1", "2", "3", "4", "5", "6" };
|
||||||
|
time_t t;
|
||||||
|
struct tm *p;
|
||||||
|
time(&t);
|
||||||
|
p = localtime(&t); // 取得当地时间
|
||||||
|
|
||||||
|
memset(temp, 0, BUFFER);
|
||||||
|
snprintf(temp, BUFFER, "[%d/%02d/%02d %s %02d:%02d:%02d] ", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
|
||||||
|
|
||||||
|
return strdup(temp);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[], char **env)
|
int main(int argc, char *argv[], char **env)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
@ -429,12 +480,79 @@ int main(int argc, char *argv[], char **env)
|
|||||||
if (-1 == (nice_(-20)))
|
if (-1 == (nice_(-20)))
|
||||||
perror("nice_");
|
perror("nice_");
|
||||||
|
|
||||||
|
// IP地域
|
||||||
|
char *area = NULL;
|
||||||
|
char *xdb_path = "ip2region.xdb";
|
||||||
|
|
||||||
|
if (access(xdb_path, F_OK) == -1) { // 判断 ip2region 地址定位库是否存在
|
||||||
|
xdb_path = "ip2region/ip2region.xdb";
|
||||||
|
if (access(xdb_path, F_OK) == -1) {
|
||||||
|
printf("ip2region/ip2region.xdb DOESN'T EXIST!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
threadpool thpool = thpool_init(1024);
|
threadpool thpool = thpool_init(1024);
|
||||||
while (1) {
|
while (1) {
|
||||||
printf("%d\n", get_threads());
|
//printf("%d\n", get_threads());
|
||||||
|
|
||||||
int *forwardsock = (int *)malloc(sizeof(int)); // 分配内存空间保存线程编号
|
int *forwardsock = (int *)malloc(sizeof(int)); // 分配内存空间保存线程编号
|
||||||
*forwardsock = accept(listensock, (struct sockaddr *)&sin, &server_addr_len);
|
*forwardsock = accept(listensock, (struct sockaddr *)&sin, &server_addr_len);
|
||||||
|
|
||||||
|
// 获取客户端IP地址
|
||||||
|
struct sockaddr_in client_addr;
|
||||||
|
socklen_t client_addr_len = sizeof(client_addr);
|
||||||
|
if (getpeername(*forwardsock, (struct sockaddr *)&client_addr, &client_addr_len) == -1) {
|
||||||
|
perror("getpeername");
|
||||||
|
} else {
|
||||||
|
char client_ip[INET_ADDRSTRLEN];
|
||||||
|
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
|
||||||
|
//printf("Client IP address: %s\n", client_ip);
|
||||||
|
|
||||||
|
#if _REGION
|
||||||
|
{
|
||||||
|
char *t = _time();
|
||||||
|
|
||||||
|
area = ip2region(xdb_path, client_ip);
|
||||||
|
if (area == NULL) {
|
||||||
|
printf("ip2region解析地域错误\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 地域白名单
|
||||||
|
char region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
|
||||||
|
char REGION_LIST_COPY[WHITELIST_IP_NUM] = { 0 };
|
||||||
|
|
||||||
|
// 取环境变量
|
||||||
|
const char *REGION_ENV = getenv("REGION");
|
||||||
|
if (REGION_ENV != NULL) {
|
||||||
|
printf("REGION: %s\n", REGION_ENV);
|
||||||
|
strcpy(REGION_LIST_COPY, REGION_ENV);
|
||||||
|
} else {
|
||||||
|
strcpy(REGION_LIST_COPY, "中国 郑州 上海 内网");
|
||||||
|
}
|
||||||
|
printf("REGION_LIST : %s\n", REGION_LIST_COPY);
|
||||||
|
|
||||||
|
split_string(REGION_LIST_COPY, " ", region_list);
|
||||||
|
if (isregion(area, region_list) == 1) { // 返回1表示在白名单列表
|
||||||
|
printf(RED "%s 隧道Ip地址: %s, 属于地域白名单: %s\n" RESET, t, client_ip, area);
|
||||||
|
} else {
|
||||||
|
printf(RED "%s 隧道客户端Ip地址: %s, 不属于地域白名单地址: %s!!!\n" RESET, t, client_ip, area);
|
||||||
|
|
||||||
|
if (*forwardsock)
|
||||||
|
close(*forwardsock);
|
||||||
|
|
||||||
|
if (t)
|
||||||
|
free(t);
|
||||||
|
free(area);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 接受连接
|
// 接受连接
|
||||||
if (*forwardsock == -1) {
|
if (*forwardsock == -1) {
|
||||||
perror("accept");
|
perror("accept");
|
||||||
|
@ -37,6 +37,12 @@
|
|||||||
#define INADDR_NONE (in_addr_t)-1
|
#define INADDR_NONE (in_addr_t)-1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define RED "\033[31m"
|
||||||
|
#define RESET "\033[0m"
|
||||||
|
#define BUFFER 1024
|
||||||
|
#define WHITELIST_IP_NUM 1024
|
||||||
|
|
||||||
|
#define _REGION 1
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
BIN
forward-tunnel.o
BIN
forward-tunnel.o
Binary file not shown.
48
ip2region/ip2region.c
Normal file
48
ip2region/ip2region.c
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "xdb_searcher.h"
|
||||||
|
#include "ip2region.h"
|
||||||
|
|
||||||
|
char *ip2region(char *xdb_file, char *ip)
|
||||||
|
{
|
||||||
|
char *db_path = xdb_file;
|
||||||
|
xdb_vector_index_t *v_index;
|
||||||
|
xdb_searcher_t searcher;
|
||||||
|
char region_buffer[256];
|
||||||
|
//long s_time;
|
||||||
|
|
||||||
|
// 1、从 db_path 加载 VectorIndex 索引。
|
||||||
|
// 得到 v_index 做成全局缓存,便于后续反复使用。
|
||||||
|
// 注意:v_index 不需要每次都加载,建议在服务启动的时候加载一次,然后做成全局资源。
|
||||||
|
v_index = xdb_load_vector_index_from_file(db_path);
|
||||||
|
if (v_index == NULL) {
|
||||||
|
printf("failed to load vector index from `%s`\n", db_path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2、使用全局的 VectorIndex 变量创建带 VectorIndex 缓存的 xdb 查询对象
|
||||||
|
int err = xdb_new_with_vector_index(&searcher, db_path, v_index);
|
||||||
|
if (err != 0) {
|
||||||
|
printf("failed to create vector index cached searcher with errcode=%d\n", err);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3、调用 search API 查询
|
||||||
|
// 得到的 region 信息会存储到 region_buffer 里面,如果你自定义了数据,请确保给足 buffer 的空间。
|
||||||
|
//s_time = xdb_now();
|
||||||
|
err = xdb_search_by_string(&searcher, ip, region_buffer, sizeof(region_buffer));
|
||||||
|
if (err != 0) {
|
||||||
|
printf("failed search(%s) with errno=%d\n", ip, err);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
;
|
||||||
|
//printf("{region: %s, took: %dμs}", region_buffer, (int)(xdb_now() - s_time));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 备注:并发使用,没一个线程需要单独定义并且初始化一个 searcher 查询对象。
|
||||||
|
|
||||||
|
// 4、关闭 xdb 查询器,如果是要关闭服务,也需要释放 v_index 的内存。
|
||||||
|
xdb_close(&searcher);
|
||||||
|
xdb_close_vector_index(v_index);
|
||||||
|
|
||||||
|
return strdup(region_buffer);
|
||||||
|
}
|
8
ip2region/ip2region.h
Normal file
8
ip2region/ip2region.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef IP2REGION_H
|
||||||
|
#define IP2REGION_H
|
||||||
|
|
||||||
|
|
||||||
|
char *ip2region(char *xdb_file, char *ip);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
BIN
ip2region/ip2region.o
Normal file
BIN
ip2region/ip2region.o
Normal file
Binary file not shown.
BIN
ip2region/ip2region.xdb
Normal file
BIN
ip2region/ip2region.xdb
Normal file
Binary file not shown.
402
ip2region/xdb_searcher.c
Normal file
402
ip2region/xdb_searcher.c
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
// Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a Apache2.0-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// ---
|
||||||
|
// @Author Lion <chenxin619315@gmail.com>
|
||||||
|
// @Date 2022/06/27
|
||||||
|
|
||||||
|
#include "sys/time.h"
|
||||||
|
#include "xdb_searcher.h"
|
||||||
|
|
||||||
|
// internal function prototype define
|
||||||
|
XDB_PRIVATE(int) read(xdb_searcher_t *, long offset, char *, size_t length);
|
||||||
|
|
||||||
|
XDB_PRIVATE(int) xdb_new_base(xdb_searcher_t *xdb, const char *db_path, const xdb_vector_index_t *v_index, const xdb_content_t *c_buffer) {
|
||||||
|
memset(xdb, 0x00, sizeof(xdb_searcher_t));
|
||||||
|
|
||||||
|
// check the content buffer first
|
||||||
|
if (c_buffer != NULL) {
|
||||||
|
xdb->v_index = NULL;
|
||||||
|
xdb->content = c_buffer;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the xdb binary file
|
||||||
|
FILE *handle = fopen(db_path, "rb");
|
||||||
|
if (handle == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xdb->handle = handle;
|
||||||
|
xdb->v_index = v_index;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// xdb searcher new api define
|
||||||
|
XDB_PUBLIC(int) xdb_new_with_file_only(xdb_searcher_t *xdb, const char *db_path) {
|
||||||
|
return xdb_new_base(xdb, db_path, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(int) xdb_new_with_vector_index(xdb_searcher_t *xdb, const char *db_path, const xdb_vector_index_t *v_index) {
|
||||||
|
return xdb_new_base(xdb, db_path, v_index, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(int) xdb_new_with_buffer(xdb_searcher_t *xdb, const xdb_content_t *c_buffer) {
|
||||||
|
return xdb_new_base(xdb, NULL, NULL, c_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(void) xdb_close(void *ptr) {
|
||||||
|
xdb_searcher_t *xdb = (xdb_searcher_t *) ptr;
|
||||||
|
if (xdb->handle != NULL) {
|
||||||
|
fclose(xdb->handle);
|
||||||
|
xdb->handle = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- xdb searcher search api define
|
||||||
|
|
||||||
|
XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *xdb, const char *str_ip, char *region_buffer, size_t length) {
|
||||||
|
unsigned int ip = 0;
|
||||||
|
int errcode = xdb_check_ip(str_ip, &ip);
|
||||||
|
if (errcode != 0) {
|
||||||
|
return 10 + errcode;
|
||||||
|
} else {
|
||||||
|
return xdb_search(xdb, ip, region_buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(int) xdb_search(xdb_searcher_t *xdb, unsigned int ip, char *region_buffer, size_t length) {
|
||||||
|
int il0, il1, idx, err, l, h, m, data_len;
|
||||||
|
unsigned int s_ptr, e_ptr, p, sip, eip, data_ptr;
|
||||||
|
char vector_buffer[xdb_vector_index_size], segment_buffer[xdb_segment_index_size];
|
||||||
|
|
||||||
|
// reset the io counter
|
||||||
|
xdb->io_count = 0;
|
||||||
|
|
||||||
|
// locate the segment index block based on the vector index
|
||||||
|
il0 = ((int) (ip >> 24)) & 0xFF;
|
||||||
|
il1 = ((int) (ip >> 16)) & 0xFF;
|
||||||
|
idx = il0 * xdb_vector_index_cols * xdb_vector_index_size + il1 * xdb_vector_index_size;
|
||||||
|
if (xdb->v_index != NULL) {
|
||||||
|
s_ptr = xdb_get_uint(xdb->v_index->buffer, idx);
|
||||||
|
e_ptr = xdb_get_uint(xdb->v_index->buffer, idx + 4);
|
||||||
|
} else if (xdb->content != NULL) {
|
||||||
|
s_ptr = xdb_get_uint(xdb->content->buffer, xdb_header_info_length + idx);
|
||||||
|
e_ptr = xdb_get_uint(xdb->content->buffer, xdb_header_info_length + idx + 4);
|
||||||
|
} else {
|
||||||
|
err = read(xdb, xdb_header_info_length + idx, vector_buffer, sizeof(vector_buffer));
|
||||||
|
if (err != 0) {
|
||||||
|
return 10 + err;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_ptr = xdb_get_uint(vector_buffer, 0);
|
||||||
|
e_ptr = xdb_get_uint(vector_buffer, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("s_ptr=%u, e_ptr=%u\n", s_ptr, e_ptr);
|
||||||
|
// binary search to get the final region info
|
||||||
|
data_len = 0, data_ptr = 0;
|
||||||
|
l = 0, h = ((int) (e_ptr - s_ptr)) / xdb_segment_index_size;
|
||||||
|
while (l <= h) {
|
||||||
|
m = (l + h) >> 1;
|
||||||
|
p = s_ptr + m * xdb_segment_index_size;
|
||||||
|
|
||||||
|
// read the segment index item
|
||||||
|
err = read(xdb, p, segment_buffer, sizeof(segment_buffer));
|
||||||
|
if (err != 0) {
|
||||||
|
return 20 + err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode the data fields as needed
|
||||||
|
sip = xdb_get_uint(segment_buffer, 0);
|
||||||
|
if (ip < sip) {
|
||||||
|
h = m - 1;
|
||||||
|
} else {
|
||||||
|
eip = xdb_get_uint(segment_buffer, 4);
|
||||||
|
if (ip > eip) {
|
||||||
|
l = m + 1;
|
||||||
|
} else {
|
||||||
|
data_len = xdb_get_ushort(segment_buffer, 8);
|
||||||
|
data_ptr = xdb_get_uint(segment_buffer, 10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("data_len=%u, data_ptr=%u\n", data_len, data_ptr);
|
||||||
|
if (data_len == 0) {
|
||||||
|
region_buffer[0] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// buffer length checking
|
||||||
|
if (data_len >= length) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = read(xdb, data_ptr, region_buffer, data_len);
|
||||||
|
if (err != 0) {
|
||||||
|
return 30 + err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// auto append a NULL-end
|
||||||
|
region_buffer[data_len] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PRIVATE(int) read(xdb_searcher_t *xdb, long offset, char *buffer, size_t length) {
|
||||||
|
// check the xdb content cache first
|
||||||
|
if (xdb->content != NULL) {
|
||||||
|
memcpy(buffer, xdb->content->buffer + offset, length);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// seek to the offset
|
||||||
|
if (fseek(xdb->handle, offset, SEEK_SET) == -1) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xdb->io_count++;
|
||||||
|
if (fread(buffer, 1, length, xdb->handle) != length) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(int) xdb_get_io_count(xdb_searcher_t *xdb) {
|
||||||
|
return xdb->io_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- buffer load util functions
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_header_t *) xdb_load_header(FILE *handle) {
|
||||||
|
xdb_header_t *header;
|
||||||
|
unsigned int size = xdb_header_info_length;
|
||||||
|
|
||||||
|
// entry alloc
|
||||||
|
header = (xdb_header_t *) xdb_malloc(sizeof(xdb_header_t));
|
||||||
|
if (header == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek(handle, 0, SEEK_SET) == -1) {
|
||||||
|
xdb_free(header);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(header->buffer, 1,size, handle) != size) {
|
||||||
|
xdb_free(header);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill the fields
|
||||||
|
header->length = size;
|
||||||
|
header->version = (unsigned short) xdb_get_ushort(header->buffer, 0);
|
||||||
|
header->index_policy = (unsigned short) xdb_get_ushort(header->buffer, 2);
|
||||||
|
header->created_at = xdb_get_uint(header->buffer, 4);
|
||||||
|
header->start_index_ptr = xdb_get_uint(header->buffer, 8);
|
||||||
|
header->end_index_ptr = xdb_get_uint(header->buffer,12);
|
||||||
|
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_header_t *) xdb_load_header_from_file(const char *db_path) {
|
||||||
|
xdb_header_t *header;
|
||||||
|
FILE *handle = fopen(db_path, "rb");
|
||||||
|
if (handle == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
header = xdb_load_header(handle);
|
||||||
|
fclose(handle);
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(void) xdb_close_header(void *ptr) {
|
||||||
|
xdb_header_t *header = (xdb_header_t *) ptr;
|
||||||
|
if (header->length > 0) {
|
||||||
|
header->length = 0;
|
||||||
|
xdb_free(header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- vector index
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_vector_index_t *) xdb_load_vector_index(FILE *handle) {
|
||||||
|
xdb_vector_index_t *v_index;
|
||||||
|
unsigned int size = xdb_vector_index_length;
|
||||||
|
|
||||||
|
// seek to the vector index offset
|
||||||
|
if (fseek(handle, xdb_header_info_length, SEEK_SET) == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the buffer read
|
||||||
|
v_index = (xdb_vector_index_t *) xdb_malloc(sizeof(xdb_vector_index_t));
|
||||||
|
if (v_index == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
v_index->length = size;
|
||||||
|
if (fread(v_index->buffer, 1, size, handle) != size) {
|
||||||
|
xdb_free(v_index);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_vector_index_t *) xdb_load_vector_index_from_file(const char *db_path) {
|
||||||
|
xdb_vector_index_t *v_index;
|
||||||
|
FILE *handle = fopen(db_path, "rb");
|
||||||
|
if (handle == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
v_index = xdb_load_vector_index(handle);
|
||||||
|
fclose(handle);
|
||||||
|
return v_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(void) xdb_close_vector_index(void *ptr) {
|
||||||
|
xdb_vector_index_t *v_index = (xdb_vector_index_t *) ptr;
|
||||||
|
if (v_index->length > 0) {
|
||||||
|
v_index->length = 0;
|
||||||
|
xdb_free(v_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- content buffer
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_content_t *) xdb_load_content(FILE *handle) {
|
||||||
|
unsigned int size;
|
||||||
|
xdb_content_t *content;
|
||||||
|
|
||||||
|
// determine the file size
|
||||||
|
if (fseek(handle, 0, SEEK_END) == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = (unsigned int) ftell(handle);
|
||||||
|
if (fseek(handle, 0, SEEK_SET) == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the file read
|
||||||
|
content = (xdb_content_t *) xdb_malloc(sizeof(xdb_content_t));
|
||||||
|
if (content == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do the buffer alloc
|
||||||
|
content->buffer = (char *) xdb_malloc(size);
|
||||||
|
if (content->buffer == NULL) {
|
||||||
|
xdb_free(content);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the content into the buffer
|
||||||
|
content->length = size;
|
||||||
|
if (fread(content->buffer, 1, size, handle) != size) {
|
||||||
|
xdb_free(content);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_content_t *) xdb_load_content_from_file(const char *db_path) {
|
||||||
|
xdb_content_t *content;
|
||||||
|
FILE *handle = fopen(db_path, "rb");
|
||||||
|
if (handle == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
content = xdb_load_content(handle);
|
||||||
|
fclose(handle);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(void) xdb_close_content(void *ptr) {
|
||||||
|
xdb_content_t *content = (xdb_content_t *) ptr;
|
||||||
|
if (content->length > 0) {
|
||||||
|
content->length = 0;
|
||||||
|
xdb_free(content->buffer);
|
||||||
|
content->buffer = NULL;
|
||||||
|
xdb_free(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- End
|
||||||
|
|
||||||
|
// get unsigned long (4bytes) from a specified buffer start from the specified offset
|
||||||
|
XDB_PUBLIC(unsigned int) xdb_get_uint(const char *buffer, int offset) {
|
||||||
|
return (
|
||||||
|
((buffer[offset ]) & 0x000000FF) |
|
||||||
|
((buffer[offset+1] << 8) & 0x0000FF00) |
|
||||||
|
((buffer[offset+2] << 16) & 0x00FF0000) |
|
||||||
|
((buffer[offset+3] << 24) & 0xFF000000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get unsigned short (2bytes) from a specified buffer start from the specified offset
|
||||||
|
XDB_PUBLIC(int) xdb_get_ushort(const char *buffer, int offset) {
|
||||||
|
return (
|
||||||
|
((buffer[offset ]) & 0x000000FF) |
|
||||||
|
((buffer[offset+1] << 8) & 0x0000FF00)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// string ip to unsigned int
|
||||||
|
static int shiftIndex[4] = {24, 16, 8, 0};
|
||||||
|
XDB_PUBLIC(int) xdb_check_ip(const char *src_ip, unsigned int *dst_ip) {
|
||||||
|
char c;
|
||||||
|
int i, n, ip = 0;
|
||||||
|
const char *ptr = src_ip;
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
n = 0;
|
||||||
|
while (1) {
|
||||||
|
c = *ptr;
|
||||||
|
ptr++;
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
n *= 10;
|
||||||
|
n += c - '0';
|
||||||
|
} else if ((i < 3 && c == '.') || i == 3) {
|
||||||
|
// stopping at the '.' but ignore the tailing chars
|
||||||
|
// after the 3rd one (auto clean the tailing none-integer ?).
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0xFF) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip |= (n << shiftIndex[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst_ip = ip;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsigned int ip to string ip
|
||||||
|
XDB_PUBLIC(void) xdb_long2ip(unsigned int ip, char *buffer) {
|
||||||
|
sprintf(buffer, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, ip & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the middle ip of a and b
|
||||||
|
XDB_PUBLIC(unsigned int) xdb_mip(unsigned long a, unsigned long b) {
|
||||||
|
return (unsigned int) ((a + b) >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
XDB_PUBLIC(long) xdb_now() {
|
||||||
|
struct timeval c_time;
|
||||||
|
gettimeofday(&c_time, NULL);
|
||||||
|
return c_time.tv_sec * (int)1e6 + c_time.tv_usec;
|
||||||
|
}
|
149
ip2region/xdb_searcher.h
Normal file
149
ip2region/xdb_searcher.h
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
// Copyright 2022 The Ip2Region Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a Apache2.0-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// ---
|
||||||
|
// @Author Lion <chenxin619315@gmail.com>
|
||||||
|
// @Date 2022/06/27
|
||||||
|
|
||||||
|
#ifndef C_XDB_SEARCHER_H
|
||||||
|
#define C_XDB_SEARCHER_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if ( defined(WIN32) || defined(_WIN32) || defined(__WINDOWS_) || defined(WINNT) )
|
||||||
|
# define XDB_PUBLIC(type) extern __declspec(dllexport) type
|
||||||
|
# define XDB_PRIVATE(type) static type
|
||||||
|
# define XDB_WINDOWS
|
||||||
|
#elif ( defined(linux) || defined(_UNIX) )
|
||||||
|
# define XDB_PUBLIC(type) extern type
|
||||||
|
# define XDB_PRIVATE(type) static inline type
|
||||||
|
# define XDB_LINUX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define xdb_calloc( _blocks, _bytes ) calloc( _blocks, _bytes )
|
||||||
|
#define xdb_malloc( _bytes ) malloc( _bytes )
|
||||||
|
#define xdb_free( _ptr ) free( _ptr )
|
||||||
|
|
||||||
|
// public constants define
|
||||||
|
#define xdb_header_info_length 256
|
||||||
|
#define xdb_vector_index_rows 256
|
||||||
|
#define xdb_vector_index_cols 256
|
||||||
|
#define xdb_vector_index_size 8
|
||||||
|
#define xdb_segment_index_size 14
|
||||||
|
|
||||||
|
// cache of vector_index_row × vector_index_rows × vector_index_size
|
||||||
|
#define xdb_vector_index_length 524288
|
||||||
|
|
||||||
|
|
||||||
|
// --- buffer load util functions
|
||||||
|
|
||||||
|
// use the following buffer struct to wrap the binary buffer data
|
||||||
|
// since the buffer data could not be operated with the string API.
|
||||||
|
struct xdb_header {
|
||||||
|
unsigned short version;
|
||||||
|
unsigned short index_policy;
|
||||||
|
unsigned int created_at;
|
||||||
|
unsigned int start_index_ptr;
|
||||||
|
unsigned int end_index_ptr;
|
||||||
|
|
||||||
|
// the original buffer
|
||||||
|
unsigned int length;
|
||||||
|
char buffer[xdb_header_info_length];
|
||||||
|
};
|
||||||
|
typedef struct xdb_header xdb_header_t;
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_header_t *) xdb_load_header(FILE *);
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_header_t *) xdb_load_header_from_file(const char *);
|
||||||
|
|
||||||
|
XDB_PUBLIC(void) xdb_close_header(void *);
|
||||||
|
|
||||||
|
|
||||||
|
// --- vector index buffer
|
||||||
|
struct xdb_vector_index {
|
||||||
|
unsigned int length;
|
||||||
|
char buffer[xdb_vector_index_length];
|
||||||
|
};
|
||||||
|
typedef struct xdb_vector_index xdb_vector_index_t;
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_vector_index_t *) xdb_load_vector_index(FILE *);
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_vector_index_t *) xdb_load_vector_index_from_file(const char *);
|
||||||
|
|
||||||
|
XDB_PUBLIC(void) xdb_close_vector_index(void *);
|
||||||
|
|
||||||
|
|
||||||
|
// --- content buffer
|
||||||
|
struct xdb_content {
|
||||||
|
unsigned int length;
|
||||||
|
char *buffer;
|
||||||
|
};
|
||||||
|
typedef struct xdb_content xdb_content_t;
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_content_t *) xdb_load_content(FILE *);
|
||||||
|
|
||||||
|
XDB_PUBLIC(xdb_content_t *) xdb_load_content_from_file(const char *);
|
||||||
|
|
||||||
|
XDB_PUBLIC(void) xdb_close_content(void *);
|
||||||
|
|
||||||
|
// --- End buffer load
|
||||||
|
|
||||||
|
// xdb searcher structure
|
||||||
|
struct xdb_searcher_entry {
|
||||||
|
FILE *handle;
|
||||||
|
|
||||||
|
// header info
|
||||||
|
const char *header;
|
||||||
|
int io_count;
|
||||||
|
|
||||||
|
// vector index buffer cache.
|
||||||
|
// preload the vector index will reduce the number of IO operations
|
||||||
|
// thus speedup the search process.
|
||||||
|
const xdb_vector_index_t *v_index;
|
||||||
|
|
||||||
|
// content buffer.
|
||||||
|
// cache the whole xdb content.
|
||||||
|
const xdb_content_t *content;
|
||||||
|
};
|
||||||
|
typedef struct xdb_searcher_entry xdb_searcher_t;
|
||||||
|
|
||||||
|
// xdb searcher new api define
|
||||||
|
XDB_PUBLIC(int) xdb_new_with_file_only(xdb_searcher_t *, const char *);
|
||||||
|
|
||||||
|
XDB_PUBLIC(int) xdb_new_with_vector_index(xdb_searcher_t *, const char *, const xdb_vector_index_t *);
|
||||||
|
|
||||||
|
XDB_PUBLIC(int) xdb_new_with_buffer(xdb_searcher_t *, const xdb_content_t *);
|
||||||
|
|
||||||
|
XDB_PUBLIC(void) xdb_close(void *);
|
||||||
|
|
||||||
|
// xdb searcher search api define
|
||||||
|
XDB_PUBLIC(int) xdb_search_by_string(xdb_searcher_t *, const char *, char *, size_t);
|
||||||
|
|
||||||
|
XDB_PUBLIC(int) xdb_search(xdb_searcher_t *, unsigned int, char *, size_t);
|
||||||
|
|
||||||
|
XDB_PUBLIC(int) xdb_get_io_count(xdb_searcher_t *);
|
||||||
|
|
||||||
|
|
||||||
|
// get unsigned long (4bytes) from a specified buffer start from the specified offset with little-endian
|
||||||
|
XDB_PUBLIC(unsigned int) xdb_get_uint(const char *, int);
|
||||||
|
|
||||||
|
// get unsigned short (2bytes) from a specified buffer start from the specified offset with little-endian
|
||||||
|
XDB_PUBLIC(int) xdb_get_ushort(const char *, int);
|
||||||
|
|
||||||
|
// check the specified string ip and convert it to an unsigned int
|
||||||
|
XDB_PUBLIC(int) xdb_check_ip(const char *, unsigned int *);
|
||||||
|
|
||||||
|
// unsigned int ip to string ip
|
||||||
|
XDB_PUBLIC(void) xdb_long2ip(unsigned int, char *);
|
||||||
|
|
||||||
|
// get the middle ip of a and b
|
||||||
|
XDB_PUBLIC(unsigned int) xdb_mip(unsigned long, unsigned long);
|
||||||
|
|
||||||
|
// get the current time in microseconds
|
||||||
|
XDB_PUBLIC(long) xdb_now();
|
||||||
|
|
||||||
|
|
||||||
|
#endif //C_XDB_SEARCHER_H
|
BIN
ip2region/xdb_searcher.o
Normal file
BIN
ip2region/xdb_searcher.o
Normal file
Binary file not shown.
BIN
reverse-tunnel
BIN
reverse-tunnel
Binary file not shown.
150
reverse-tunnel.c
150
reverse-tunnel.c
@ -1,30 +1,11 @@
|
|||||||
/*
|
#include "reverse-tunnel.h"
|
||||||
* Example of SSH tunnel using libssh2.
|
#include <pthread.h>
|
||||||
*
|
|
||||||
* 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 <libssh2.h>
|
||||||
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.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 <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <stdlib.h>
|
||||||
#include <sys/select.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#ifndef INADDR_NONE
|
|
||||||
#define INADDR_NONE (in_addr_t)-1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const char *keyfile1 = "/home/aixiao/.ssh/id_rsa.pub";
|
const char *keyfile1 = "/home/aixiao/.ssh/id_rsa.pub";
|
||||||
const char *keyfile2 = "/home/aixiao/.ssh/id_rsa";
|
const char *keyfile2 = "/home/aixiao/.ssh/id_rsa";
|
||||||
@ -33,13 +14,18 @@ const char *password = "12345";
|
|||||||
|
|
||||||
const char *server_ip = "127.0.0.1";
|
const char *server_ip = "127.0.0.1";
|
||||||
|
|
||||||
const char *remote_listenhost = "0.0.0.0"; /* resolved by the remote server */
|
const char *remote_listenhost = "0.0.0.0"; /* 由远程服务器解析 */
|
||||||
int remote_wantport = 33;
|
int remote_wantport = 33;
|
||||||
int remote_listenport;
|
int remote_listenport;
|
||||||
|
|
||||||
const char *local_destip = "0.0.0.0";
|
const char *local_destip = "0.0.0.0";
|
||||||
int local_destport = 22;
|
int local_destport = 22;
|
||||||
|
|
||||||
|
struct tunnel_args {
|
||||||
|
LIBSSH2_CHANNEL *channel;
|
||||||
|
LIBSSH2_SESSION *session;
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
AUTH_NONE = 0,
|
AUTH_NONE = 0,
|
||||||
AUTH_PASSWORD,
|
AUTH_PASSWORD,
|
||||||
@ -56,28 +42,28 @@ int forward_tunnel(LIBSSH2_SESSION * session, LIBSSH2_CHANNEL * channel)
|
|||||||
char buf[16384];
|
char buf[16384];
|
||||||
int forwardsock = -1;
|
int forwardsock = -1;
|
||||||
|
|
||||||
fprintf(stdout, "Accepted remote connection. Connecting to local server %s:%d\n", local_destip, local_destport);
|
fprintf(stdout, "接受到远程连接。连接到本地服务器 %s:%d\n", local_destip, local_destport);
|
||||||
forwardsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
forwardsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
if (forwardsock == -1) {
|
if (forwardsock == -1) {
|
||||||
fprintf(stderr, "Error opening socket\n");
|
fprintf(stderr, "打开socket错误\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
sin.sin_family = AF_INET;
|
sin.sin_family = AF_INET;
|
||||||
sin.sin_port = htons(local_destport);
|
sin.sin_port = htons(local_destport);
|
||||||
if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(local_destip))) {
|
if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(local_destip))) {
|
||||||
fprintf(stderr, "Invalid local IP address\n");
|
fprintf(stderr, "无效的本地IP地址\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 == connect(forwardsock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in))) {
|
if (-1 == connect(forwardsock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in))) {
|
||||||
fprintf(stderr, "Failed to connect!\n");
|
fprintf(stderr, "连接失败!\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stdout, "Forwarding connection from remote %s:%d to local %s:%d\n", remote_listenhost, remote_listenport, local_destip, local_destport);
|
fprintf(stdout, "将连接从远程 %s:%d 转发到本地 %s:%d\n", remote_listenhost, remote_listenport, local_destip, local_destport);
|
||||||
|
|
||||||
/* Setting session to non-blocking IO */
|
/* 设置会话为非阻塞IO */
|
||||||
libssh2_session_set_blocking(session, 0);
|
libssh2_session_set_blocking(session, 0);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@ -87,23 +73,23 @@ int forward_tunnel(LIBSSH2_SESSION * session, LIBSSH2_CHANNEL * channel)
|
|||||||
tv.tv_usec = 100000;
|
tv.tv_usec = 100000;
|
||||||
rc = select(forwardsock + 1, &fds, NULL, NULL, &tv);
|
rc = select(forwardsock + 1, &fds, NULL, NULL, &tv);
|
||||||
if (-1 == rc) {
|
if (-1 == rc) {
|
||||||
fprintf(stderr, "Socket not ready!\n");
|
fprintf(stderr, "socket未准备好!\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
if (rc && FD_ISSET(forwardsock, &fds)) {
|
if (rc && FD_ISSET(forwardsock, &fds)) {
|
||||||
len = recv(forwardsock, buf, sizeof(buf), 0);
|
len = recv(forwardsock, buf, sizeof(buf), 0);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
fprintf(stderr, "Error reading from the forwardsock!\n");
|
fprintf(stderr, "从forwardsock读取时出错!\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
} else if (0 == len) {
|
} else if (0 == len) {
|
||||||
fprintf(stderr, "The local server at %s:%d disconnected!\n", local_destip, local_destport);
|
fprintf(stderr, "本地服务器 %s:%d 断开连接!\n", local_destip, local_destport);
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
wr = 0;
|
wr = 0;
|
||||||
do {
|
do {
|
||||||
i = libssh2_channel_write(channel, buf, len);
|
i = libssh2_channel_write(channel, buf, len);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
fprintf(stderr, "Error writing on the SSH channel: %d\n", i);
|
fprintf(stderr, "在SSH通道上写入时出错: %d\n", i);
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
wr += i;
|
wr += i;
|
||||||
@ -114,20 +100,20 @@ int forward_tunnel(LIBSSH2_SESSION * session, LIBSSH2_CHANNEL * channel)
|
|||||||
if (LIBSSH2_ERROR_EAGAIN == len)
|
if (LIBSSH2_ERROR_EAGAIN == len)
|
||||||
break;
|
break;
|
||||||
else if (len < 0) {
|
else if (len < 0) {
|
||||||
fprintf(stderr, "Error reading from the SSH channel: %d\n", (int)len);
|
fprintf(stderr, "从SSH通道读取时出错: %d\n", (int)len);
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
wr = 0;
|
wr = 0;
|
||||||
while (wr < len) {
|
while (wr < len) {
|
||||||
i = send(forwardsock, buf + wr, len - wr, 0);
|
i = send(forwardsock, buf + wr, len - wr, 0);
|
||||||
if (i <= 0) {
|
if (i <= 0) {
|
||||||
fprintf(stderr, "Error writing on the forwardsock!\n");
|
fprintf(stderr, "在forwardsock上写入时出错!\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
wr += i;
|
wr += i;
|
||||||
}
|
}
|
||||||
if (libssh2_channel_eof(channel)) {
|
if (libssh2_channel_eof(channel)) {
|
||||||
fprintf(stderr, "The remote client at %s:%d disconnected!\n", remote_listenhost, remote_listenport);
|
fprintf(stderr, "远程客户端 %s:%d 断开连接!\n", remote_listenhost, remote_listenport);
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,11 +121,21 @@ int forward_tunnel(LIBSSH2_SESSION * session, LIBSSH2_CHANNEL * channel)
|
|||||||
|
|
||||||
shutdown:
|
shutdown:
|
||||||
close(forwardsock);
|
close(forwardsock);
|
||||||
/* Setting the session back to blocking IO */
|
/* 将会话设置回阻塞IO */
|
||||||
libssh2_session_set_blocking(session, 1);
|
libssh2_session_set_blocking(session, 1);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *handle_tunnel(void *arg)
|
||||||
|
{
|
||||||
|
LIBSSH2_CHANNEL *channel = ((struct tunnel_args *)arg)->channel;
|
||||||
|
LIBSSH2_SESSION *session = ((struct tunnel_args *)arg)->session;
|
||||||
|
forward_tunnel(session, channel);
|
||||||
|
libssh2_channel_free(channel);
|
||||||
|
free(arg); // 释放为参数分配的内存
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int rc, i, auth = AUTH_NONE;
|
int rc, i, auth = AUTH_NONE;
|
||||||
@ -169,64 +165,67 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
rc = libssh2_init(0);
|
rc = libssh2_init(0);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
|
fprintf(stderr, "libssh2初始化失败 (%d)\n", rc);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connect to SSH server */
|
/* 连接到SSH服务器 */
|
||||||
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
if (sock == -1) {
|
if (sock == -1) {
|
||||||
fprintf(stderr, "Error opening socket\n");
|
fprintf(stderr, "打开socket错误\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sin.sin_family = AF_INET;
|
sin.sin_family = AF_INET;
|
||||||
if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(server_ip))) {
|
if (INADDR_NONE == (sin.sin_addr.s_addr = inet_addr(server_ip))) {
|
||||||
fprintf(stderr, "Invalid remote IP address\n");
|
fprintf(stderr, "无效的远程IP地址\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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a session instance */
|
int optval = 1;
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
|
||||||
|
{
|
||||||
|
perror("setsockopt");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sin.sin_port = htons(22); /* SSH端口 */
|
||||||
|
if (connect(sock, (struct sockaddr *)(&sin), sizeof(struct sockaddr_in)) != 0) {
|
||||||
|
fprintf(stderr, "连接失败!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 创建会话实例 */
|
||||||
session = libssh2_session_init();
|
session = libssh2_session_init();
|
||||||
if (!session) {
|
if (!session) {
|
||||||
fprintf(stderr, "Could not initialize the SSH session!\n");
|
fprintf(stderr, "无法初始化SSH会话!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
/* 启动会话。这将交换欢迎消息,交换密钥,并设置加密、压缩和MAC层 */
|
||||||
* and setup crypto, compression, and MAC layers
|
|
||||||
*/
|
|
||||||
rc = libssh2_session_handshake(session, sock);
|
rc = libssh2_session_handshake(session, sock);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
fprintf(stderr, "Error when starting up SSH session: %d\n", rc);
|
fprintf(stderr, "启动SSH会话时出错: %d\n", rc);
|
||||||
return -1;
|
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);
|
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||||
fprintf(stdout, "Fingerprint: ");
|
fprintf(stdout, "指纹: ");
|
||||||
for (i = 0; i < 20; i++)
|
for (i = 0; i < 20; i++)
|
||||||
fprintf(stdout, "%02X ", (unsigned char)fingerprint[i]);
|
fprintf(stdout, "%02X ", (unsigned char)fingerprint[i]);
|
||||||
fprintf(stdout, "\n");
|
fprintf(stdout, "\n");
|
||||||
|
|
||||||
/* check what authentication methods are available */
|
/* 检查可用的身份验证方法 */
|
||||||
userauthlist = libssh2_userauth_list(session, username, strlen(username));
|
userauthlist = libssh2_userauth_list(session, username, strlen(username));
|
||||||
fprintf(stderr, "Authentication methods: %s\n", userauthlist);
|
fprintf(stderr, "身份验证方法: %s\n", userauthlist);
|
||||||
if (strstr(userauthlist, "password"))
|
if (strstr(userauthlist, "password"))
|
||||||
auth |= AUTH_PASSWORD;
|
auth |= AUTH_PASSWORD;
|
||||||
if (strstr(userauthlist, "publickey"))
|
if (strstr(userauthlist, "publickey"))
|
||||||
auth |= AUTH_PUBLICKEY;
|
auth |= AUTH_PUBLICKEY;
|
||||||
|
|
||||||
/* check for options */
|
/* 检查选项 */
|
||||||
if (argc > 8) {
|
if (argc > 8) {
|
||||||
if ((auth & AUTH_PASSWORD) && !strcasecmp(argv[8], "-p"))
|
if ((auth & AUTH_PASSWORD) && !strcasecmp(argv[8], "-p"))
|
||||||
auth = AUTH_PASSWORD;
|
auth = AUTH_PASSWORD;
|
||||||
@ -236,42 +235,41 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (auth & AUTH_PASSWORD) {
|
if (auth & AUTH_PASSWORD) {
|
||||||
if (libssh2_userauth_password(session, username, password)) {
|
if (libssh2_userauth_password(session, username, password)) {
|
||||||
fprintf(stderr, "Authentication by password failed.\n");
|
fprintf(stderr, "密码认证失败。\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
} else if (auth & AUTH_PUBLICKEY) {
|
} else if (auth & AUTH_PUBLICKEY) {
|
||||||
if (libssh2_userauth_publickey_fromfile(session, username, keyfile1, keyfile2, password)) {
|
if (libssh2_userauth_publickey_fromfile(session, username, keyfile1, keyfile2, password)) {
|
||||||
fprintf(stderr, "\tAuthentication by public key failed!\n");
|
fprintf(stderr, "公钥认证失败!\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "\tAuthentication by public key succeeded.\n");
|
fprintf(stderr, "公钥认证成功。\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "No supported authentication methods found!\n");
|
fprintf(stderr, "未找到支持的认证方法!\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stdout, "Asking server to listen on remote %s:%d\n", remote_listenhost, remote_wantport);
|
fprintf(stdout, "请求服务器监听远程 %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_ex(session, NULL, remote_wantport, &remote_listenport, 2);
|
||||||
listener = libssh2_channel_forward_listen(session, remote_wantport);
|
|
||||||
if (!listener) {
|
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");
|
fprintf(stderr, "无法启动tcpip-forward监听器!\n" "(请注意,这可能是服务器的问题!请查看服务器日志。)\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stdout, "Server is listening on %s:%d\n", remote_listenhost, remote_listenport);
|
fprintf(stdout, "服务器正在监听 %s:%d\n", remote_listenhost, remote_listenport);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
fprintf(stdout, "Waiting for remote connection\n");
|
fprintf(stdout, "等待远程连接\n");
|
||||||
channel = libssh2_channel_forward_accept(listener);
|
channel = libssh2_channel_forward_accept(listener);
|
||||||
if (!channel) {
|
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");
|
fprintf(stderr, "libssh2_channel_forward_accept() 无法接受连接!\n" "(请注意,这可能是服务器的问题!请查看服务器日志。)\n");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
forward_tunnel(session, channel);
|
forward_tunnel(session, channel);
|
||||||
|
|
||||||
libssh2_channel_free(channel);
|
libssh2_channel_free(channel);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown:
|
shutdown:
|
||||||
@ -279,7 +277,7 @@ shutdown:
|
|||||||
libssh2_channel_free(channel);
|
libssh2_channel_free(channel);
|
||||||
if (listener)
|
if (listener)
|
||||||
libssh2_channel_forward_cancel(listener);
|
libssh2_channel_forward_cancel(listener);
|
||||||
libssh2_session_disconnect(session, "Client disconnecting normally");
|
libssh2_session_disconnect(session, "客户端正常断开连接");
|
||||||
libssh2_session_free(session);
|
libssh2_session_free(session);
|
||||||
close(sock);
|
close(sock);
|
||||||
libssh2_exit();
|
libssh2_exit();
|
||||||
|
20
reverse-tunnel.h
Normal file
20
reverse-tunnel.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#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 <pthread.h>
|
||||||
|
|
||||||
|
#ifndef INADDR_NONE
|
||||||
|
#define INADDR_NONE (in_addr_t)-1
|
||||||
|
#endif
|
BIN
reverse-tunnel.o
BIN
reverse-tunnel.o
Binary file not shown.
Loading…
Reference in New Issue
Block a user