diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..07887f4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "C_Cpp.errorSquiggles": "disabled", + "files.associations": { + "forward-tunnel.h": "c", + "cstdlib": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 300725a..086aee1 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,11 @@ LIB = -lssh2 -pthread forward-tunnel = forward-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 lsb_release -si), Debian) LIB += -static @@ -17,7 +22,7 @@ endif 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) $(STRIP) forward-tunnel @@ -28,6 +33,9 @@ reverse-tunnel: reverse-tunnel.o .c.o: $(CC) $(CFLAGS) -c $< +ip2region/%.o: ip2region/%.c + $(CC) $(ip2region_CFLAGS) -c $< -o $@ + clean: - rm -rf *.o - rm reverse-tunnel forward-tunnel + rm -rf *.o $(ip2region_SRC:.c=.o) + rm -rf reverse-tunnel forward-tunnel diff --git a/forward-tunnel b/forward-tunnel index a800e59..b6e7ed3 100644 Binary files a/forward-tunnel and b/forward-tunnel differ diff --git a/forward-tunnel.c b/forward-tunnel.c index c70f471..5f0fbc9 100644 --- a/forward-tunnel.c +++ b/forward-tunnel.c @@ -1,5 +1,6 @@ #include "forward-tunnel.h" #include "thpool.h" +#include "ip2region/ip2region.h" const char *keyfile1 = "/home/aixiao/.ssh/id_rsa.pub"; const char *keyfile2 = "/home/aixiao/.ssh/id_rsa"; @@ -313,6 +314,56 @@ int get_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) { struct sockaddr_in sin; @@ -429,12 +480,79 @@ int main(int argc, char *argv[], char **env) if (-1 == (nice_(-20))) 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); while (1) { - printf("%d\n", get_threads()); + //printf("%d\n", get_threads()); int *forwardsock = (int *)malloc(sizeof(int)); // 分配内存空间保存线程编号 *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) { perror("accept"); @@ -447,7 +565,7 @@ int main(int argc, char *argv[], char **env) thpool_wait(thpool); thpool_destroy(thpool); shutdown: - + close(forwardsock); close(listensock); libssh2_exit(); diff --git a/forward-tunnel.h b/forward-tunnel.h index fbdc58d..c1cae02 100644 --- a/forward-tunnel.h +++ b/forward-tunnel.h @@ -34,9 +34,15 @@ #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 + #define INADDR_NONE (in_addr_t)-1 #endif +#define RED "\033[31m" +#define RESET "\033[0m" +#define BUFFER 1024 +#define WHITELIST_IP_NUM 1024 + +#define _REGION 1 #endif diff --git a/forward-tunnel.o b/forward-tunnel.o index 5392c67..152ed3f 100644 Binary files a/forward-tunnel.o and b/forward-tunnel.o differ diff --git a/ip2region/ip2region.c b/ip2region/ip2region.c new file mode 100644 index 0000000..9c93049 --- /dev/null +++ b/ip2region/ip2region.c @@ -0,0 +1,48 @@ +#include +#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); +} diff --git a/ip2region/ip2region.h b/ip2region/ip2region.h new file mode 100644 index 0000000..71e153d --- /dev/null +++ b/ip2region/ip2region.h @@ -0,0 +1,8 @@ +#ifndef IP2REGION_H +#define IP2REGION_H + + +char *ip2region(char *xdb_file, char *ip); + + +#endif diff --git a/ip2region/ip2region.o b/ip2region/ip2region.o new file mode 100644 index 0000000..a0b81c8 Binary files /dev/null and b/ip2region/ip2region.o differ diff --git a/ip2region/ip2region.xdb b/ip2region/ip2region.xdb new file mode 100644 index 0000000..9f6502b Binary files /dev/null and b/ip2region/ip2region.xdb differ diff --git a/ip2region/xdb_searcher.c b/ip2region/xdb_searcher.c new file mode 100644 index 0000000..6bcae3a --- /dev/null +++ b/ip2region/xdb_searcher.c @@ -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 +// @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; +} diff --git a/ip2region/xdb_searcher.h b/ip2region/xdb_searcher.h new file mode 100644 index 0000000..12808bc --- /dev/null +++ b/ip2region/xdb_searcher.h @@ -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 +// @Date 2022/06/27 + +#ifndef C_XDB_SEARCHER_H +#define C_XDB_SEARCHER_H + +#include +#include +#include + +#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 diff --git a/ip2region/xdb_searcher.o b/ip2region/xdb_searcher.o new file mode 100644 index 0000000..9128bc6 Binary files /dev/null and b/ip2region/xdb_searcher.o differ diff --git a/reverse-tunnel b/reverse-tunnel index 16387b7..316a416 100644 Binary files a/reverse-tunnel and b/reverse-tunnel differ diff --git a/reverse-tunnel.c b/reverse-tunnel.c index 39d1903..d886e92 100644 --- a/reverse-tunnel.c +++ b/reverse-tunnel.c @@ -1,30 +1,11 @@ -/* - * 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 "reverse-tunnel.h" +#include #include - -#include #include -#include -#include - -#include -#include -#include -#include #include -#include -#include - -#ifndef INADDR_NONE -#define INADDR_NONE (in_addr_t)-1 -#endif +#include +#include +#include const char *keyfile1 = "/home/aixiao/.ssh/id_rsa.pub"; const char *keyfile2 = "/home/aixiao/.ssh/id_rsa"; @@ -33,20 +14,25 @@ const char *password = "12345"; 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_listenport; const char *local_destip = "0.0.0.0"; int local_destport = 22; +struct tunnel_args { + LIBSSH2_CHANNEL *channel; + LIBSSH2_SESSION *session; +}; + enum { AUTH_NONE = 0, AUTH_PASSWORD, AUTH_PUBLICKEY }; -int forward_tunnel(LIBSSH2_SESSION * session, LIBSSH2_CHANNEL * channel) +int forward_tunnel(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel) { int i, rc = 0; struct sockaddr_in sin; @@ -56,28 +42,28 @@ int forward_tunnel(LIBSSH2_SESSION * session, LIBSSH2_CHANNEL * channel) char buf[16384]; 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); if (forwardsock == -1) { - fprintf(stderr, "Error opening socket\n"); + fprintf(stderr, "打开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"); + fprintf(stderr, "无效的本地IP地址\n"); goto shutdown; } if (-1 == connect(forwardsock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in))) { - fprintf(stderr, "Failed to connect!\n"); + fprintf(stderr, "连接失败!\n"); 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); while (1) { @@ -87,23 +73,23 @@ int forward_tunnel(LIBSSH2_SESSION * session, LIBSSH2_CHANNEL * channel) tv.tv_usec = 100000; rc = select(forwardsock + 1, &fds, NULL, NULL, &tv); if (-1 == rc) { - fprintf(stderr, "Socket not ready!\n"); + fprintf(stderr, "socket未准备好!\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"); + fprintf(stderr, "从forwardsock读取时出错!\n"); goto shutdown; } 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; } wr = 0; do { i = libssh2_channel_write(channel, buf, len); if (i < 0) { - fprintf(stderr, "Error writing on the SSH channel: %d\n", i); + fprintf(stderr, "在SSH通道上写入时出错: %d\n", i); goto shutdown; } wr += i; @@ -114,20 +100,20 @@ int forward_tunnel(LIBSSH2_SESSION * session, LIBSSH2_CHANNEL * channel) if (LIBSSH2_ERROR_EAGAIN == len) break; 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; } wr = 0; while (wr < len) { i = send(forwardsock, buf + wr, len - wr, 0); if (i <= 0) { - fprintf(stderr, "Error writing on the forwardsock!\n"); + fprintf(stderr, "在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); + fprintf(stderr, "远程客户端 %s:%d 断开连接!\n", remote_listenhost, remote_listenport); goto shutdown; } } @@ -135,11 +121,21 @@ int forward_tunnel(LIBSSH2_SESSION * session, LIBSSH2_CHANNEL * channel) shutdown: close(forwardsock); - /* Setting the session back to blocking IO */ + /* 将会话设置回阻塞IO */ libssh2_session_set_blocking(session, 1); 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 rc, i, auth = AUTH_NONE; @@ -169,64 +165,67 @@ int main(int argc, char *argv[]) rc = libssh2_init(0); if (rc != 0) { - fprintf(stderr, "libssh2 initialization failed (%d)\n", rc); + fprintf(stderr, "libssh2初始化失败 (%d)\n", rc); return 1; } - /* Connect to SSH server */ + /* 连接到SSH服务器 */ sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == -1) { - fprintf(stderr, "Error opening socket\n"); + fprintf(stderr, "打开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"); + fprintf(stderr, "无效的远程IP地址\n"); 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(); if (!session) { - fprintf(stderr, "Could not initialize the SSH session!\n"); + fprintf(stderr, "无法初始化SSH会话!\n"); return -1; } - /* ... start it up. This will trade welcome banners, exchange keys, - * and setup crypto, compression, and MAC layers - */ + /* 启动会话。这将交换欢迎消息,交换密钥,并设置加密、压缩和MAC层 */ + rc = libssh2_session_handshake(session, sock); if (rc) { - fprintf(stderr, "Error when starting up SSH session: %d\n", rc); + fprintf(stderr, "启动SSH会话时出错: %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: "); + fprintf(stdout, "指纹: "); 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); + fprintf(stderr, "身份验证方法: %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; @@ -236,42 +235,41 @@ int main(int argc, char *argv[]) if (auth & AUTH_PASSWORD) { if (libssh2_userauth_password(session, username, password)) { - fprintf(stderr, "Authentication by password failed.\n"); + fprintf(stderr, "密码认证失败。\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"); + fprintf(stderr, "公钥认证失败!\n"); goto shutdown; } - fprintf(stderr, "\tAuthentication by public key succeeded.\n"); + fprintf(stderr, "公钥认证成功。\n"); } else { - fprintf(stderr, "No supported authentication methods found!\n"); + fprintf(stderr, "未找到支持的认证方法!\n"); 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(session, remote_wantport); + listener = libssh2_channel_forward_listen_ex(session, NULL, remote_wantport, &remote_listenport, 2); 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; } - fprintf(stdout, "Server is listening on %s:%d\n", remote_listenhost, remote_listenport); + fprintf(stdout, "服务器正在监听 %s:%d\n", remote_listenhost, remote_listenport); while (1) { - fprintf(stdout, "Waiting for remote connection\n"); + fprintf(stdout, "等待远程连接\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"); + fprintf(stderr, "libssh2_channel_forward_accept() 无法接受连接!\n" "(请注意,这可能是服务器的问题!请查看服务器日志。)\n"); goto shutdown; } forward_tunnel(session, channel); - libssh2_channel_free(channel); + } shutdown: @@ -279,7 +277,7 @@ shutdown: libssh2_channel_free(channel); if (listener) libssh2_channel_forward_cancel(listener); - libssh2_session_disconnect(session, "Client disconnecting normally"); + libssh2_session_disconnect(session, "客户端正常断开连接"); libssh2_session_free(session); close(sock); libssh2_exit(); diff --git a/reverse-tunnel.h b/reverse-tunnel.h new file mode 100644 index 0000000..cd258e7 --- /dev/null +++ b/reverse-tunnel.h @@ -0,0 +1,20 @@ +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef INADDR_NONE + #define INADDR_NONE (in_addr_t)-1 +#endif diff --git a/reverse-tunnel.o b/reverse-tunnel.o index 96a8c1a..d9dfe1a 100644 Binary files a/reverse-tunnel.o and b/reverse-tunnel.o differ diff --git a/thpool.o b/thpool.o index 817e92a..270715b 100644 Binary files a/thpool.o and b/thpool.o differ