18 Commits

Author SHA1 Message Date
staylightblow8
3fb01ce735 Update version.h 2022-06-30 14:01:39 +08:00
staylightblow8
f14562b26b Delete xfrpc.conf 2022-06-30 14:00:25 +08:00
staylightblow8
d4f35909c5 Delete xfrpc.init 2022-06-30 14:00:18 +08:00
staylightblow8
1ee2b1ff56 Delete Makefile 2022-06-30 13:59:55 +08:00
staylightblow8
cab6e8a20f Update README.md 2022-06-28 17:58:25 +08:00
staylightblow8
e53f8e1c94 Update README.md 2022-06-15 09:50:10 +08:00
staylightblow8
23819fcb44 Update README.md 2022-06-14 09:51:19 +08:00
staylightblow8
51930c855f Update CONTRIBUTING.md 2022-06-13 11:30:55 +08:00
Dengfeng Liu
690a6f4feb fix: interval ping process
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-06-08 11:09:34 +08:00
Dengfeng Liu
56e4020969 feat: heartbeat_timeout process
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-06-07 15:18:37 +08:00
Dengfeng Liu
e06a9a40a3 fix: parse proxy response error when remote_address is domain
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-06-07 14:20:27 +08:00
Dengfeng Liu
767d2859f9 feat: when xfrpc disconnected from frps, it should reconnect repeatly
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-06-07 10:08:38 +08:00
Dengfeng Liu
fa0a273865 Merge branch 'master' of https://github.com/liudf0716/xfrpc 2022-06-06 15:27:56 +08:00
Dengfeng Liu
030a7b8784 fix: when reconnect frps should send proxy conf again
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-06-06 15:26:36 +08:00
staylightblow8
d2cd54d831 Update README.md 2022-06-06 15:13:25 +08:00
Dengfeng Liu
9c90f6b5cd Merge branch 'master' of https://github.com/liudf0716/xfrpc 2022-06-05 17:39:27 +08:00
Dengfeng Liu
d1e2f549a7 fix: fix the following bug
when xfrpc connected frps, then stop frps and start frps
the bug happen

Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-06-05 17:26:20 +08:00
staylightblow8
ffa9e1ad97 Update README.md 2022-06-01 16:36:56 +08:00
13 changed files with 127 additions and 238 deletions

View File

@@ -27,7 +27,7 @@ If you want to contribute to [xfrpc](https://github.com/liudf0716/xfrpc), please
6. Commit and push your changes, then make a pull request from Github.
git commit --signoff
git push -f
git push
7. Awaiting review, if accepted, merged!

View File

@@ -18,6 +18,9 @@ the following table is detail compatible feature:
| tcpmux | Yes | Yes |
| http | Yes | Yes |
| https | Yes | Yes |
| subdomain | No | Yes |
| use_encryption | No | Yes |
| use_compression | No | Yes |
| udp | No | Yes |
| p2p | No | Yes |
| xtcp | No | Yes |
@@ -76,7 +79,7 @@ sequenceDiagram
```
## Compile
## Compile on Ubuntu 20.04.3 LTS
xfrp need [libevent](https://github.com/libevent/libevent) [openssl-dev](https://github.com/openssl/openssl) and [json-c](https://github.com/json-c/json-c) support
@@ -97,6 +100,14 @@ cmake ..
make
```
## Compile on OpenWrt
xfrpc was recruited by openwrt community since version 1.04.515
anyway I highly recommend you to use latest version
in order to compile xfrpc in openwrt sdk environment, you should firstly `make menuconfig`, then select `Network --> Web Servers/Proxies ---> xfrpc`
## Quick start
**before using xfrpc, you should get frps server: [frps](https://github.com/fatedier/frp/releases)**
@@ -132,7 +143,17 @@ local_port = 22
remote_port = 6128
```
+ xfrpc http
+ xfrpc http&https
compare with supporting tcp, supporting http&https need to add vhost_http_port&vhost_https_port in frps.ini as the following
```
# frps.ini
[common]
bind_port = 7000
vhost_http_port = 80
vhost_https_port = 443
```
```
# xfrpc_mini.ini
@@ -140,10 +161,15 @@ remote_port = 6128
server_addr = x.x.x.x
server_port = 7000
[web]
[http]
type = http
local_port = 80
custom_domains = www.example.com
[https]
type = https
local_port = 443
custom_domains = www.example.com
```
+ Run in debug mode
@@ -158,6 +184,10 @@ xfrpc -c frpc_mini.ini -f -d 7
xfrpc -c frpc_mini.ini -d 0
```
## Openwrt UI
If running xfrpc in openwrt box, [luci-app-xfrpc](https://github.com/liudf0716/luci-app-xfrpc) is a good choice
## How to contribute our project
See [CONTRIBUTING](https://github.com/liudf0716/xfrpc/blob/master/CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
@@ -184,8 +214,12 @@ QQ群 [331230369](https://jq.qq.com/?_wv=1027&k=47QGEhL)
![微信打赏](https://user-images.githubusercontent.com/1182593/169465249-db1b495e-078e-4cab-91fc-96dab3320b06.png)
<!--
## 广告
想学习OpenWrt开发但是摸不着门道自学没毅力基础太差怕太难学不会跟着佐大学OpenWrt开发入门培训班助你能学有所成
报名地址https://forgotfun.org/2018/04/openwrt-training-2018.html
-->

View File

@@ -209,7 +209,7 @@ new_proxy_client()
struct proxy_client *client = calloc(1, sizeof(struct proxy_client));
assert(client);
client->stream_id = get_next_session_id();
client->send_window = 128*1024;
client->send_window = 200*1024;
client->stream_state = INIT;
HASH_ADD_INT(all_pc, stream_id, client);

View File

@@ -363,7 +363,7 @@ static void init_common_conf(struct common_conf *config)
assert(config->log_level);
config->log_max_days = 3;
config->heartbeat_interval = 30;
config->heartbeat_timeout = 60;
config->heartbeat_timeout = 90;
config->tcp_mux = 1;
config->user = NULL;
config->server_ip = NULL;

View File

@@ -35,6 +35,7 @@
#include <json-c/json.h>
#include <syslog.h>
#include <unistd.h>
#include <time.h>
#include "debug.h"
#include "client.h"
@@ -53,10 +54,13 @@
static struct control *main_ctl;
static int clients_conn_signel = 0;
static int is_login = 0;
static time_t pong_time = 0;
static void sync_new_work_connection(struct bufferevent *bev, uint32_t sid);
static void recv_cb(struct bufferevent *bev, void *ctx);
static void clear_main_control();
static void start_base_connect();
static void keep_control_alive();
static int
is_client_connected()
@@ -179,8 +183,7 @@ ping()
static void
sync_new_work_connection(struct bufferevent *bev, uint32_t sid)
{
struct bufferevent *bout = bev;
assert(bout);
assert(bev);
/* send new work session regist request to frps*/
struct work_conn *work_c = new_work_conn();
@@ -230,32 +233,25 @@ set_ticker_ping_timer(struct event *timeout)
event_add(timeout, &tv);
}
static void
set_tcp_mux_ping_timer(struct event *timeout)
{
struct timeval tv;
evutil_timerclear(&tv);
tv.tv_sec = 60;
event_add(timeout, &tv);
}
static void
hb_sender_cb(evutil_socket_t fd, short event, void *arg)
{
debug(LOG_DEBUG, "hb_sender_cb");
if (is_client_connected()) {
debug(LOG_DEBUG, "ping frps");
ping(NULL);
}
set_ticker_ping_timer(main_ctl->ticker_ping);
}
static void
tcp_mux_hb_sender_cb(evutil_socket_t fd, short event, void *arg)
{
tcp_mux_send_ping(main_ctl->connect_bev, main_ctl->tcp_mux_ping_id++);
set_tcp_mux_ping_timer(main_ctl->tcp_mux_ping_event);
struct common_conf *c_conf = get_common_config();
time_t current_time = time(NULL);
int interval = current_time - pong_time;
if (pong_time && interval > c_conf->heartbeat_timeout) {
debug(LOG_INFO, " interval [%d] greater than heartbeat_timeout [%d]", interval, c_conf->heartbeat_timeout);
clear_main_control();
run_control();
return;
}
}
// return: 0: raw succeed 1: raw failed
@@ -327,7 +323,7 @@ handle_enc_msg(const uint8_t *enc_msg, int ilen, uint8_t **out)
uint8_t *dec_msg = NULL;
size_t len = decrypt_data(buf, ilen, get_main_decoder(), &dec_msg);
*out = dec_msg;
debug(LOG_DEBUG, "dec out len %d ", len);
//debug(LOG_DEBUG, "dec out len %d ", len);
return len;
}
@@ -356,7 +352,7 @@ handle_control_work(const uint8_t *buf, int len, void *ctx)
debug(LOG_DEBUG, "cmd_type is %c data is %s", cmd_type, msg->data);
switch(cmd_type) {
case TypeReqWorkConn:
debug(LOG_DEBUG, "TypeReqWorkConn cmd");
//debug(LOG_DEBUG, "TypeReqWorkConn cmd");
if (! is_client_connected()) {
start_proxy_services();
client_connected(1);
@@ -364,7 +360,7 @@ handle_control_work(const uint8_t *buf, int len, void *ctx)
new_client_connect();
break;
case TypeNewProxyResp:
debug(LOG_DEBUG, "TypeNewProxyResp cmd");
debug(LOG_DEBUG, "TypeNewProxyResp cmd ");
struct new_proxy_response *npr = new_proxy_resp_unmarshal((const char *)msg->data);
if (npr == NULL) {
debug(LOG_ERR, "new proxy response buffer unmarshal faild!");
@@ -411,6 +407,8 @@ handle_control_work(const uint8_t *buf, int len, void *ctx)
break;
case TypePong:
//debug(LOG_DEBUG, "receive pong from frps");
pong_time = time(NULL);
break;
default:
debug(LOG_INFO, "command type dont support: ctx is %d", ctx?1:0);
@@ -512,50 +510,40 @@ connect_event_cb (struct bufferevent *bev, short what, void *ctx)
static int retry_times = 1;
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
if (retry_times >= 100) {
debug(LOG_ERR,
"have retry connect to xfrp server for %d times, exit!",
debug(LOG_INFO,
"have retry connect to xfrp server for %d times, exit?",
retry_times);
exit(0);
}
sleep(retry_times);
sleep(2);
retry_times++;
debug(LOG_ERR, "error: connect server [%s:%d] failed %s",
c_conf->server_addr,
c_conf->server_port,
strerror(errno));
clear_main_control();
start_base_connect();
run_control();
} else if (what & BEV_EVENT_CONNECTED) {
retry_times = 0;
tcp_mux_send_win_update_syn(bev, main_ctl->stream_id);
login();
keep_control_alive();
}
}
static void
keep_control_alive()
{
debug(LOG_DEBUG, "start keep_control_alive");
main_ctl->ticker_ping = evtimer_new(main_ctl->connect_base, hb_sender_cb, NULL);
if ( !main_ctl->ticker_ping) {
debug(LOG_ERR, "Ping Ticker init failed!");
return;
}
pong_time = time(NULL);
set_ticker_ping_timer(main_ctl->ticker_ping);
}
static void
keep_control_tcp_mux_alive()
{
struct common_conf *c_conf = get_common_config();
if (!c_conf->tcp_mux) return;
main_ctl->tcp_mux_ping_event = evtimer_new(main_ctl->connect_base, tcp_mux_hb_sender_cb, NULL);
assert(main_ctl->tcp_mux_ping_event);
set_tcp_mux_ping_timer(main_ctl->tcp_mux_ping_event);
}
static void
server_dns_cb(int event_code, struct evutil_addrinfo *addr, void *ctx)
{
@@ -582,7 +570,7 @@ server_dns_cb(int event_code, struct evutil_addrinfo *addr, void *ctx)
}
}
void
static void
start_base_connect()
{
struct common_conf *c_conf = get_common_config();
@@ -686,7 +674,7 @@ send_enc_msg_frp_server(struct bufferevent *bev,
uint8_t *enc_msg = NULL;
size_t olen = encrypt_data((uint8_t *)req_msg, msg_len+sizeof(struct msg_hdr), get_main_encoder(), &enc_msg);
assert(olen > 0);
debug(LOG_DEBUG, "encrypt_data length %d", olen);
//debug(LOG_DEBUG, "encrypt_data length %d", olen);
tcp_mux_send_data(bout, sid, olen);
@@ -825,6 +813,10 @@ clear_main_control()
if (main_ctl->ticker_ping) evtimer_del(main_ctl->ticker_ping);
if (main_ctl->tcp_mux_ping_event) evtimer_del(main_ctl->tcp_mux_ping_event);
clear_all_proxy_client();
free_evp_cipher_ctx();
client_connected(0);
pong_time = 0;
is_login = 0;
}
void
@@ -843,8 +835,6 @@ void
run_control()
{
start_base_connect();
keep_control_alive();
keep_control_tcp_mux_alive();
}

View File

@@ -49,8 +49,6 @@ struct control {
void connect_eventcb(struct bufferevent *bev, short events, void *ptr);
void start_base_connect();
void init_main_control();
void run_control();

View File

@@ -43,6 +43,46 @@ static const char *default_salt = "frp";
static const size_t block_size = 16;
static struct frp_coder *main_encoder = NULL;
static struct frp_coder *main_decoder = NULL;
static EVP_CIPHER_CTX *enc_ctx = NULL;
static EVP_CIPHER_CTX *dec_ctx = NULL;
static void
free_frp_coder(struct frp_coder *coder)
{
free(coder->salt);
free(coder->privilege_token);
free(coder);
}
static void
free_all_frp_coder()
{
if (main_encoder) {
free_frp_coder(main_encoder);
main_encoder = NULL;
}
if (main_decoder) {
free_frp_coder(main_decoder);
main_decoder = NULL;
}
}
void
free_evp_cipher_ctx()
{
free_all_frp_coder();
if (enc_ctx) {
EVP_CIPHER_CTX_free(enc_ctx);
enc_ctx = NULL;
}
if (dec_ctx) {
EVP_CIPHER_CTX_free(dec_ctx);
dec_ctx = NULL;
}
}
size_t
get_block_size()
@@ -56,7 +96,7 @@ new_coder(const char *privilege_token, const char *salt)
struct frp_coder *enc = calloc(sizeof(struct frp_coder), 1);
assert(enc);
enc->privilege_token = privilege_token ? strdup(privilege_token):"\0";
enc->privilege_token = privilege_token ? strdup(privilege_token):strdup("\0");
enc->salt = strdup(salt);
encrypt_key(enc->privilege_token, strlen(enc->privilege_token), enc->salt, enc->key, block_size);
encrypt_iv(enc->iv, block_size);
@@ -175,11 +215,11 @@ encrypt_data(const uint8_t *src_data, size_t srclen, struct frp_coder *encoder,
assert(outbuf);
*ret = outbuf;
static EVP_CIPHER_CTX *ctx = NULL;
if (!ctx) {
ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(ctx, EVP_aes_128_cfb(), NULL, c->key, c->iv);
if (!enc_ctx) {
enc_ctx = EVP_CIPHER_CTX_new();
EVP_EncryptInit_ex(enc_ctx, EVP_aes_128_cfb(), NULL, c->key, c->iv);
}
EVP_CIPHER_CTX *ctx = enc_ctx;
if(!EVP_EncryptUpdate(ctx, outbuf, &tmplen, intext, (int)srclen)) {
debug(LOG_ERR, "EVP_EncryptUpdate error!");
@@ -208,12 +248,12 @@ decrypt_data(const uint8_t *enc_data, size_t enclen, struct frp_coder *decoder,
assert(decoder);
int outlen = 0, tmplen = 0;
static EVP_CIPHER_CTX *ctx= NULL;
if (!ctx) {
ctx= EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(ctx, EVP_aes_128_cfb(), NULL, c->key, c->iv);
if (!dec_ctx) {
dec_ctx= EVP_CIPHER_CTX_new();
EVP_DecryptInit_ex(dec_ctx, EVP_aes_128_cfb(), NULL, c->key, c->iv);
}
EVP_CIPHER_CTX *ctx = dec_ctx;
if(!EVP_DecryptUpdate(ctx, outbuf, &tmplen, inbuf, enclen)) {
debug(LOG_ERR, "EVP_DecryptUpdate error!");
goto D_END;

View File

@@ -55,5 +55,6 @@ struct frp_coder *get_main_encoder();
struct frp_coder *get_main_decoder();
size_t get_block_size();
void free_encoder(struct frp_coder *encoder);
void free_evp_cipher_ctx();
#endif // _CRYPTO_H_

3
msg.c
View File

@@ -268,8 +268,7 @@ new_proxy_resp_unmarshal(const char *jres)
if (port) {
port++;
npr->remote_port = atoi(port);
}else
goto END_ERROR;
}
struct json_object *npr_proxy_name = NULL;
if (! json_object_object_get_ex(j_np_res, "proxy_name", &npr_proxy_name))

View File

@@ -1,54 +0,0 @@
#
# Copyright (C) 2022 Dengfeng Liu
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=xfrpc
PKG_VERSION:=master
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/liudf0716/xfrpc.git
PKG_SOURCE_VERSION:=$(PKG_VERSION)
PKG_MIRROR_HASH:=a7141da8a85203d8341fd6d2551f1228396ae54aace6ec0bad2dfeb89e0a377d
PKG_MAINTAINER:=Dengfeng Liu <liudf0716@gmail.com>
PKG_LICENSE:=GPL-3.0-or-later
PKG_LICENSE_FILES:=COPYING
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/xfrpc
SUBMENU:=Web Servers/Proxies
SECTION:=net
CATEGORY:=Network
DEPENDS:=+zlib +libjson-c +libevent2 +libevent2-openssl
TITLE:= C language fast reverse proxy client
URL:=https://github.com/liudf0716/xfrpc
endef
define Package/xfrpc/description
xfrpc is C language fast reverse proxy client
compare with golang version frpc
xfrpc can run in almost all openwrt device
endef
define Package/xfrpc/conffiles
/etc/config/xfrpc
endef
define Package/xfrpc/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/xfrpc $(1)/usr/bin/xfrpc
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/xfrpc.init $(1)/etc/init.d/xfrpc
$(INSTALL_DIR) $(1)/etc/config
$(CP) ./files/xfrpc.conf $(1)/etc/config/xfrpc
endef
$(eval $(call BuildPackage,xfrpc))

View File

@@ -1,26 +0,0 @@
config xfrp 'init'
option disabled 1
option loglevel 7
config xfrpc 'common'
option server_addr 127.0.0.1
option server_port 7000
option token abdesf13d
config xfrpc 'ssh01'
option type tcp
option local_ip 127.0.0.1
option local_port 22
option remote_port 6000
#config xfrpc 'web01'
# option type http
# option local_ip 127.0.0.1
# option local_port 8080
# option custom_domains yourdomain
#config xfrpc 'web02'
# option type https
# option local_ip 127.0.0.1
# option local_port 8443
# option custom_domains yourdomain

View File

@@ -1,93 +0,0 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2022 Dengfeng Liu <liu_df@qq.com>
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
START=99
USE_PROCD=1
NAME=xfrpc
PROG=/usr/bin/$NAME
handle_xfrpc() {
local name="$1"
local config="$2"
echo "[$name]" >> "$config"
handle_type() {
uci_validate_section xfrpc xfrpc "$name" \
'type:or("tcp", "udp", "ftp", "http", "https")' \
'local_ip:ipaddr:127.0.0.1' \
'local_port:uinteger'
echo "type = $type" >> "$config"
echo "local_ip = $local_ip" >> "$config"
echo "local_port = $local_port" >> "$config"
case "$type" in
"tcp"|"udp")
config_get remote_port "$name" remote_port
echo "remote_port = $remote_port" >> "$config"
;;
"ftp")
config_get remote_port "$name" remote_port
config_get remote_data_port "$name" remote_data_port
echo "remote_port = $remote_port" >> "$config"
echo "remote_data_port = $remote_data_port" >> "$config"
;;
esac
}
if [ "$name" = "common" ]; then
uci_validate_section xfrpc xfrpc "$name" \
'server_addr:ipaddr' \
'server_port:uinteger' \
'token:string'
[ -z "$token" ] && {
echo "no token"
exit
}
echo "server_addr = $server_addr" >> "$config"
echo "server_port = $server_port" >> "$config"
echo "token = $token" >> "$config"
else
handle_type
fi
}
service_triggers() {
procd_add_reload_trigger "$NAME"
}
start_service() {
local conf_file="/var/etc/$NAME.ini"
> "$conf_file"
config_load "$NAME"
uci_validate_section xfrpc xfrpc init \
'disabled:bool:1' \
'loglevel:uinteger:0'
if [ $disabled = 1 ]; then
echo "xfrpc service disabled"
return
fi
config_foreach handle_xfrpc xfrpc "$conf_file"
procd_open_instance
procd_set_param command "$PROG" -c "$conf_file" -f -d $loglevel
procd_set_param file "$conf_file"
procd_set_param respawn
procd_close_instance
}
reload_service() {
stop
start
}

View File

@@ -1,8 +1,8 @@
#ifndef _VERSION_H_
#define _VERSION_H_
#define VERSION "1.05.561"
#define PROTOCOL_VERESION "0.42.0"
#define VERSION "1.05.579"
#define PROTOCOL_VERESION "0.43.0"
#define CLIENT_V 1
#endif //_VERSION_H_