31 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
Dengfeng Liu
ca64905266 fix: process unhandle tcp mux header
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-05-31 17:21:08 +08:00
Dengfeng Liu
6b1f70407c Merge branch 'master' of https://github.com/liudf0716/xfrpc 2022-05-28 11:25:39 +08:00
Dengfeng Liu
5d298156e4 refactor: refactor code
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-05-28 11:09:56 +08:00
Dengfeng Liu
37f124ffe7 Update README.md 2022-05-27 08:55:26 +08:00
Dengfeng Liu
675e47ef43 feat: add reconnect frps
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-05-27 08:37:05 +08:00
Dengfeng Liu
176e4006f6 format: format code and prepare release
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-05-26 21:11:52 +08:00
Dengfeng Liu
d91d5d91ef fix: exceed window size bug
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-05-26 18:23:39 +08:00
Dengfeng Liu
36eba09bbe fix: replace auth_token with token
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-05-23 18:47:20 +08:00
Dengfeng Liu
4ac16540b7 release: v1.05.552 release
support tcp mux

Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-05-23 15:24:33 +08:00
Dengfeng Liu
ab4da37e72 feat: add tcp mux support
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-05-20 11:10:33 +08:00
Dengfeng Liu
b49dd4e97c Update README.md 2022-05-16 13:59:09 +08:00
Dengfeng Liu
6fb2e167d6 fix: clean all warning of code
Signed-off-by: Dengfeng Liu <liudf0716@gmail.com>
2022-05-10 10:12:10 +08:00
Dengfeng Liu
4b633a7c2a Update README.md 2022-05-09 16:27:25 +08:00
36 changed files with 1138 additions and 534 deletions

View File

@@ -31,12 +31,12 @@ set(src_xfrpc
crypto.c
fastpbkdf2.c
utils.c
session.c
common.c
login.c
proxy_tcp.c
proxy_ftp.c
proxy.c
tcpmux.c
)
set(libs

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

@@ -3,22 +3,24 @@
## What is xfrpc
`xfrpc` is [frp](https://github.com/fatedier/frp) client implemented by c language for [OpenWRT](https://github.com/openwrt/openwrt) and [LEDE](https://github.com/lede-project/source) system
The motivation to start xfrpc project is that we are OpenWRTer, and openwrt usually ran in device which has little ROM and RAM space, however golang always need more space and memory; therefore we start xfrpc project to support frp.
`xfrpc` is [frp](https://github.com/fatedier/frp) client implemented by c language for [OpenWRT](https://github.com/openwrt/openwrt)
The motivation to start xfrpc project is that we are OpenWRTer, and openwrt usually run in devices which have limit ROM and RAM space, however frpc always need more space and memory; therefore we launched xfrpc project.
## Development Status
xfrpc partially compitable with latest frp release feature, It target to fully compatible with latest frp release.
xfrpc partially compitable with latest frp release feature, It targets to fully compatible with latest frp release.
the following table is detail compatible feature:
| Feature | xfrpc | frpc |
| ------------- | ------------- | ---------|
| tcp | Yes | Yes |
| tcpmux | No | Yes |
| 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 |
@@ -77,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
@@ -98,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)**
@@ -110,11 +120,8 @@ frps use latest release 0.42.0
# frps.ini
[common]
bind_port = 7000
tcp_mux = false
```
**attention! cause xfrpc does not support tcp_mux yet, please disable tcp_mux otherwise xfrpc can not connect frps**
run frps
```
@@ -136,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
@@ -144,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
@@ -162,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.
@@ -173,8 +199,27 @@ QQ群 [331230369](https://jq.qq.com/?_wv=1027&k=47QGEhL)
## Please support us and star our project
[![Star History Chart](https://api.star-history.com/svg?repos=liudf0716/xfrpc&type=Date)](https://star-history.com/#liudf0716/xfrpc&Date)
## 打赏
支付宝打赏
![支付宝打赏](https://user-images.githubusercontent.com/1182593/169465135-d4522479-4068-4714-ab58-987d7d7eb338.png)
微信打赏
![微信打赏](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

@@ -29,20 +29,12 @@
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <syslog.h>
#include <zlib.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
#include "debug.h"
#include "client.h"
@@ -55,15 +47,16 @@
#include "common.h"
#include "proxy.h"
#include "utils.h"
#include "tcpmux.h"
static struct proxy_client *all_pc = NULL;
static void
xfrp_worker_event_cb(struct bufferevent *bev, short what, void *ctx)
{
struct proxy_client *client = (struct proxy_client *)ctx;
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
debug(LOG_DEBUG, "working connection closed!");
bufferevent_free(bev);
free_proxy_client(client);
}
}
@@ -74,9 +67,14 @@ xfrp_proxy_event_cb(struct bufferevent *bev, short what, void *ctx)
assert(client);
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
debug(LOG_DEBUG, "xfrpc proxy close connect server [%s:%d] : %s", client->ps->local_ip, client->ps->local_port, strerror(errno));
bufferevent_free(bev);
} else if (what & BEV_EVENT_CONNECTED) {
debug(LOG_DEBUG, "xfrpc proxy close connect server [%s:%d] stream_id %d: %s",
client->ps->local_ip, client->ps->local_port,
client->stream_id, strerror(errno));
tcp_mux_send_win_update_fin(client->ctl_bev, client->stream_id);
client->stream_state = LOCAL_CLOSE;
} else if (what & BEV_EVENT_CONNECTED) {
debug(LOG_DEBUG, "client [%d] connected", client->stream_id);
//client->stream_state = ESTABLISHED;
if (client->data_tail_size > 0) {
debug(LOG_DEBUG, "send client data ...");
send_client_data_tail(client);
@@ -127,7 +125,7 @@ start_xfrp_tunnel(struct proxy_client *client)
client->local_proxy_bev = connect_server(base, ps->local_ip, ps->local_port);
if ( !client->local_proxy_bev ) {
debug(LOG_ERR, "frpc tunnel connect local proxy port [%d] failed!", ps->local_port);
bufferevent_free(client->ctl_bev);
del_proxy_client(client);
return;
}
@@ -137,30 +135,30 @@ start_xfrp_tunnel(struct proxy_client *client)
ps->local_ip ? ps->local_ip:"::1",
ps->local_port);
bufferevent_data_cb proxy_s2c_cb, proxy_c2s_cb;
bufferevent_data_cb proxy_s2c_recv, proxy_c2s_recv;
if (is_ftp_proxy(client->ps)) {
proxy_c2s_cb = ftp_proxy_c2s_cb;
proxy_s2c_cb = ftp_proxy_s2c_cb;
//ctl_prox->remote_data_port = client->ps->remote_data_port;
//ctl_prox->proxy_name = strdup(ps->proxy_name);
proxy_c2s_recv = ftp_proxy_c2s_cb;
proxy_s2c_recv = ftp_proxy_s2c_cb;
} else {
proxy_c2s_cb = tcp_proxy_c2s_cb; // local service <---> xfrpc
proxy_s2c_cb = tcp_proxy_s2c_cb; // frps <---> xfrpc
proxy_c2s_recv = tcp_proxy_c2s_cb; // local service ---> xfrpc
proxy_s2c_recv = tcp_proxy_s2c_cb; // frps ---> xfrpc
}
bufferevent_setcb(client->ctl_bev,
proxy_s2c_cb,
if (!c_conf->tcp_mux) {
bufferevent_setcb(client->ctl_bev,
proxy_s2c_recv,
NULL,
xfrp_worker_event_cb,
client);
bufferevent_enable(client->ctl_bev, EV_READ|EV_WRITE);
}
bufferevent_setcb(client->local_proxy_bev,
proxy_c2s_cb,
proxy_c2s_recv,
NULL,
xfrp_proxy_event_cb,
client);
bufferevent_enable(client->ctl_bev, EV_READ|EV_WRITE);
bufferevent_enable(client->local_proxy_bev, EV_READ|EV_WRITE);
}
@@ -177,19 +175,18 @@ send_client_data_tail(struct proxy_client *client)
return send_l;
}
void
static void
free_proxy_client(struct proxy_client *client)
{
if (client->ev_timeout) evtimer_del(client->ev_timeout);
if (client->local_proxy_bev) bufferevent_free(client->local_proxy_bev);
free(client);
}
void
del_proxy_client(struct proxy_client *client)
{
struct proxy_client *all_pc = get_all_pc();
if (!client || !all_pc ) {
debug(LOG_INFO, "Error: all_pc or client is NULL");
debug(LOG_INFO, "all_pc or client is NULL");
return;
}
@@ -198,14 +195,12 @@ del_proxy_client(struct proxy_client *client)
free_proxy_client(client);
}
// Return NULL if proxy service not found with proxy_name
struct proxy_service *
get_proxy_service(const char *proxy_name)
struct proxy_client *
get_proxy_client(uint32_t sid)
{
struct proxy_service *ps = NULL;
struct proxy_service *all_ps = get_all_proxy_services();
HASH_FIND_STR(all_ps, proxy_name, ps);
return ps;
struct proxy_client *pc = NULL;
HASH_FIND_INT(all_pc, &sid, pc);
return pc;
}
struct proxy_client *
@@ -213,5 +208,22 @@ 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 = 200*1024;
client->stream_state = INIT;
HASH_ADD_INT(all_pc, stream_id, client);
return client;
}
void
clear_all_proxy_client()
{
if (!all_pc) return;
struct proxy_client *client, *tmp;
HASH_ITER(hh, all_pc, client, tmp) {
HASH_DEL(all_pc, client);
free_proxy_client(client);
}
}

View File

@@ -20,7 +20,7 @@
\********************************************************************/
/** @file client.h
@brief xfrp client proxy client related
@brief xfrpc proxy client related
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
@@ -31,6 +31,7 @@
#include "uthash.h"
#include "common.h"
#include "tcpmux.h"
struct event_base;
struct base_conf;
@@ -42,17 +43,19 @@ struct proxy_client {
struct event_base *base;
struct bufferevent *ctl_bev; // xfrpc proxy <---> frps
struct bufferevent *local_proxy_bev; // xfrpc proxy <---> local service
struct event *ev_timeout;
struct base_conf *bconf;
//private arguments
UT_hash_handle hh;
uint32_t stream_id;
uint32_t send_window;
enum tcp_mux_state stream_state;
int connected;
int work_started;
struct proxy_service *ps;
unsigned char *data_tail; // storage untreated data
size_t data_tail_size;
// private arguments
UT_hash_handle hh;
};
struct proxy_service {
@@ -75,7 +78,7 @@ struct proxy_service {
char *http_user;
char *http_pwd;
//provate arguments
// private arguments
UT_hash_handle hh;
};
@@ -88,13 +91,14 @@ void start_xfrp_tunnel(struct proxy_client *client);
void del_proxy_client(struct proxy_client *client);
void free_proxy_client(struct proxy_client *client);
struct proxy_service *get_proxy_service(const char *proxy_name);
struct proxy_client *get_proxy_client(uint32_t sid);
int send_client_data_tail(struct proxy_client *client);
int is_ftp_proxy(const struct proxy_service *ps);
struct proxy_client *new_proxy_client();
void clear_all_proxy_client();
#endif //_CLIENT_H_

View File

@@ -110,7 +110,7 @@ get_daemon_status()
/** @internal
* @brief Print usage
*
* Prints usage, called when wifidog is run with -h or with an unknown option
* Prints usage, called when xfrpc is run with -h or with an unknown option
*/
static void
usage(const char *appname)

View File

@@ -1,3 +1,29 @@
/* vim: set et ts=4 sts=4 sw=4 : */
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
\********************************************************************/
/** @file common.c
@brief xfrp common function implemented
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include "uthash.h"
#include "common.h"

View File

@@ -1,3 +1,29 @@
/* vim: set et ts=4 sts=4 sw=4 : */
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
\********************************************************************/
/** @file common.h
@brief xfrp common header
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef _COMMON_H_
#define _COMMON_H_
@@ -6,6 +32,16 @@
#include <string.h>
#include <netinet/in.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
#include <event2/dns.h>
#include <event2/event_struct.h>
#include <assert.h>
#include "uthash.h"
#define BIGENDIAN_64BIT 1

View File

@@ -20,7 +20,7 @@
\********************************************************************/
/** @file config.c
@brief xfrp client config related
@brief xfrpc client config related
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include <stdio.h>
@@ -42,8 +42,7 @@
#include "version.h"
static struct common_conf *c_conf;
static struct proxy_client *p_clients;
static struct proxy_service *p_services;
static struct proxy_service *all_ps;
static void new_ftp_data_proxy_service(struct proxy_service *ftp_ps);
@@ -84,16 +83,6 @@ void free_base_config(struct base_conf *bconf)
if (bconf->subdomain) free(bconf->subdomain);
}
struct proxy_client *get_all_pc()
{
return p_clients;
}
struct proxy_service *get_all_proxy_services()
{
return p_services;
}
static int is_true(const char *val)
{
if (val && (strcmp(val, "true") == 0 || strcmp(val, "1") == 0))
@@ -110,9 +99,7 @@ static const char *get_valid_type(const char *val)
#define MATCH_VALUE(s) strcmp(val, s) == 0
if (MATCH_VALUE("tcp") ||
MATCH_VALUE("http") ||
MATCH_VALUE("https") ||
MATCH_VALUE("udp") ||
MATCH_VALUE("ftp")) {
MATCH_VALUE("https")) {
return val;
}
@@ -161,7 +148,7 @@ static void dump_all_ps()
struct proxy_service *ps = NULL, *tmp = NULL;
int index = 0;
HASH_ITER(hh, p_services, ps, tmp) {
HASH_ITER(hh, all_ps, ps, tmp) {
dump_proxy_service(index++, ps);
}
}
@@ -203,7 +190,7 @@ static void new_ftp_data_proxy_service(struct proxy_service *ftp_ps)
struct proxy_service *ps = NULL;
char *ftp_data_proxy_name = get_ftp_data_proxy_name((const char *)ftp_ps->proxy_name);
HASH_FIND_STR(p_services, ftp_data_proxy_name, ps);
HASH_FIND_STR(all_ps, ftp_data_proxy_name, ps);
if (!ps) {
ps = new_proxy_service(ftp_data_proxy_name);
if (! ps) {
@@ -220,7 +207,7 @@ static void new_ftp_data_proxy_service(struct proxy_service *ftp_ps)
ps->local_ip = ftp_ps->local_ip;
ps->local_port = 0; //will be init in working tunnel connectting
HASH_ADD_KEYPTR(hh, p_services, ps->proxy_name, strlen(ps->proxy_name), ps);
HASH_ADD_KEYPTR(hh, all_ps, ps->proxy_name, strlen(ps->proxy_name), ps);
}
free(ftp_data_proxy_name);
@@ -240,7 +227,7 @@ proxy_service_handler(void *user, const char *sect, const char *nm, const char *
return 0;
}
HASH_FIND_STR(p_services, section, ps);
HASH_FIND_STR(all_ps, section, ps);
if (!ps) {
ps = new_proxy_service(section);
if (! ps) {
@@ -248,7 +235,7 @@ proxy_service_handler(void *user, const char *sect, const char *nm, const char *
exit(0);
}
HASH_ADD_KEYPTR(hh, p_services, ps->proxy_name, strlen(ps->proxy_name), ps);
HASH_ADD_KEYPTR(hh, all_ps, ps->proxy_name, strlen(ps->proxy_name), ps);
}
#define MATCH_NAME(s) strcmp(nm, s) == 0
@@ -354,7 +341,8 @@ static int common_handler(void *user, const char *section, const char *name, con
config->user = strdup(value);
assert(config->user);
} else if (MATCH("common", "tcp_mux")) {
config->tcp_mux = 0; // set tcp_mux to default: false
config->tcp_mux = atoi(value);
config->tcp_mux = !!config->tcp_mux;
}
return 1;
}
@@ -375,8 +363,8 @@ 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->tcp_mux = 0;
config->heartbeat_timeout = 90;
config->tcp_mux = 1;
config->user = NULL;
config->server_ip = NULL;
config->is_router = 0;
@@ -435,3 +423,17 @@ int is_running_in_router()
{
return c_conf->is_router;
}
struct proxy_service *
get_proxy_service(const char *proxy_name)
{
struct proxy_service *ps = NULL;
HASH_FIND_STR(all_ps, proxy_name, ps);
return ps;
}
struct proxy_service *
get_all_proxy_services()
{
return all_ps;
}

View File

@@ -20,7 +20,7 @@
\********************************************************************/
/** @file config.h
@brief xfrp client config related
@brief xfrpc client config related
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef _CONFIG_H_
@@ -34,11 +34,11 @@
struct base_conf{
char *name;
char *auth_token;
int use_encryption;
int use_gzip;
int privilege_mode;
int use_encryption;
int use_gzip;
int privilege_mode;
char *privilege_token;
int pool_count;
int pool_count;
char *host_header_rewrite;
char *subdomain;
};
@@ -65,17 +65,21 @@ struct common_conf {
};
struct common_conf *get_common_config();
struct proxy_service *get_all_proxy_services();
void free_common_config();
void free_base_config(struct base_conf *bconf);
struct proxy_client *get_all_pc();
void load_config(const char *confile);
char *get_ftp_data_proxy_name(const char *ftp_proxy_name);
void set_common_server_ip(const char *ip);
int is_running_in_router();
struct proxy_service *get_proxy_service(const char *proxy_name);
struct proxy_service *get_all_proxy_services();
#endif //_CONFIG_H_

12
const.h
View File

@@ -20,7 +20,7 @@
\********************************************************************/
/** @file const.h
@brief xfrp constant parameter define
@brief xfrpc constant parameter define
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
@@ -34,15 +34,5 @@ enum server_status {
Closed
};
// msg type
// enum msg_type {
// NewCtlConn = 0,
// NewWorkConn,
// NoticeUserConn,
// NewCtlConnRes,
// HeartbeatReq,
// HeartbeatRes,
// NewWorkConnUdp
// };
#endif

276
control.c
View File

@@ -34,14 +34,8 @@
#include <netinet/in.h>
#include <json-c/json.h>
#include <syslog.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
#include <event2/dns.h>
#include <event2/event_struct.h>
#include <unistd.h>
#include <time.h>
#include "debug.h"
#include "client.h"
@@ -53,16 +47,20 @@
#include "uthash.h"
#include "crypto.h"
#include "utils.h"
#include "session.h"
#include "common.h"
#include "login.h"
#include "tcpmux.h"
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);
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()
@@ -108,11 +106,11 @@ client_start_event_cb(struct bufferevent *bev, short what, void *ctx)
}
debug(LOG_ERR, "Proxy connect server [%s:%d] error: %s", c_conf->server_addr, c_conf->server_port, strerror(errno));
bufferevent_free(bev);
free_proxy_client(client);
del_proxy_client(client);
} else if (what & BEV_EVENT_CONNECTED) {
bufferevent_setcb(bev, recv_cb, NULL, client_start_event_cb, client);
bufferevent_enable(bev, EV_READ|EV_WRITE);
sync_new_work_connection(bev);
sync_new_work_connection(bev, 0);
client_connected(1);
debug(LOG_INFO, "proxy service start");
}
@@ -125,6 +123,14 @@ new_client_connect()
struct common_conf *c_conf = get_common_config();
assert(c_conf);
client->base = main_ctl->connect_base;
if (c_conf->tcp_mux) {
debug(LOG_DEBUG, "new client through tcp mux: %d", client->stream_id);
client->ctl_bev = main_ctl->connect_bev;
sync_new_work_connection(client->ctl_bev, client->stream_id);
return;
}
struct bufferevent *bev = connect_server(client->base, c_conf->server_addr, c_conf->server_port);
if (!bev) {
debug(LOG_DEBUG, "Connect server [%s:%d] failed", c_conf->server_addr, c_conf->server_port);
@@ -142,10 +148,13 @@ static void
start_proxy_services()
{
struct proxy_service *all_ps = get_all_proxy_services();
assert(all_ps);
struct proxy_service *ps = NULL, *tmp = NULL;
if (!all_ps) {
debug(LOG_INFO, "no proxy service configure by user");
return;
}
debug(LOG_INFO, "Start xfrp proxy services ...");
HASH_ITER(hh, all_ps, ps, tmp) {
@@ -158,30 +167,23 @@ start_proxy_services()
}
static void
ping(struct bufferevent *bev)
ping()
{
struct bufferevent *bout = NULL;
if (bev) {
bout = bev;
} else {
bout = main_ctl->connect_bev;
}
struct bufferevent *bout = main_ctl->connect_bev;
if ( ! bout) {
debug(LOG_ERR, "bufferevent is not legal!");
return;
}
uint32_t sid = get_main_control()->session_id;
char *ping_msg = "{}";
send_enc_msg_frp_server(bev, TypePing, ping_msg, strlen(ping_msg), sid);
send_enc_msg_frp_server(bout, TypePing, ping_msg, strlen(ping_msg), main_ctl->stream_id);
}
static void
sync_new_work_connection(struct bufferevent *bev)
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();
@@ -197,8 +199,10 @@ sync_new_work_connection(struct bufferevent *bev)
debug(LOG_ERR, "new work connection request run_id marshal failed!");
return;
}
tcp_mux_send_win_update_syn(bev, sid);
send_msg_frp_server(bev, TypeNewWorkConn, new_work_conn_request_message, nret, 0);
send_msg_frp_server(bev, TypeNewWorkConn, new_work_conn_request_message, nret, sid);
SAFE_FREE(new_work_conn_request_message);
SAFE_FREE(work_c);
@@ -232,13 +236,22 @@ set_ticker_ping_timer(struct event *timeout)
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);
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
@@ -286,29 +299,15 @@ proxy_service_resp_raw(struct new_proxy_response *npr)
return 0;
}
static void
dump_all_unknown_encypt(uint8_t *enc_msg, int ilen)
{
uint8_t *iv = get_main_decoder()->iv;
uint8_t *key = get_main_decoder()->key;
FILE *fout = fopen("unkown.encrypt", "w");
assert(fout);
fwrite(iv, 16, 1, fout);
fwrite(key, 16, 1, fout);
fwrite((uint8_t *)&ilen, sizeof(int), 1, fout);
fwrite(enc_msg, ilen, 1, fout);
fclose(fout);
}
static int
handle_enc_msg(uint8_t *enc_msg, int ilen, uint8_t **out)
handle_enc_msg(const uint8_t *enc_msg, int ilen, uint8_t **out)
{
if (ilen <= 0) {
debug(LOG_INFO, "enc_msg length should not be %d", ilen);
return -1;
}
uint8_t *buf = enc_msg;
const uint8_t *buf = enc_msg;
if ( !is_decoder_inited() && get_block_size() <= ilen) {
init_main_decoder(buf);
buf += get_block_size();
@@ -324,34 +323,25 @@ handle_enc_msg(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;
}
static void
print_enc_msg(uint8_t *enc_msg, int len)
{
printf("enc_msg is [%d]:\n", len);
for (int i = 0; i < len; i++) {
if (i%16 == 0)
printf("\n");
printf("%1x ", enc_msg[i]);
}
printf("\n");
}
static void
handle_control_work(const uint8_t *buf, int len, void *ctx)
{
uint8_t *frps_cmd = NULL;
uint8_t cmd_type;
uint8_t *enc_msg = buf;
const uint8_t *enc_msg = buf;
if (!ctx)
if (!ctx) {
debug(LOG_DEBUG, "main control message");
handle_enc_msg(enc_msg, len, &frps_cmd);
else
frps_cmd = buf;
} else {
debug(LOG_DEBUG, "worker message");
frps_cmd = (uint8_t *)buf;
}
if (!frps_cmd)
return; // only recv iv
@@ -359,10 +349,10 @@ handle_control_work(const uint8_t *buf, int len, void *ctx)
struct msg_hdr *msg = (struct msg_hdr *)frps_cmd;
cmd_type = msg->type;
debug(LOG_DEBUG, "cmd_type is %d data is %s", cmd_type, msg->data);
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);
@@ -370,8 +360,8 @@ handle_control_work(const uint8_t *buf, int len, void *ctx)
new_client_connect();
break;
case TypeNewProxyResp:
debug(LOG_DEBUG, "TypeNewProxyResp cmd");
struct new_proxy_response *npr = new_proxy_resp_unmarshal(msg->data);
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!");
return;
@@ -382,7 +372,7 @@ handle_control_work(const uint8_t *buf, int len, void *ctx)
break;
case TypeStartWorkConn:
debug(LOG_DEBUG, "TypeStartWorkConn cmd");
struct start_work_conn_resp *sr = start_work_conn_resp_unmarshal(msg->data);
struct start_work_conn_resp *sr = start_work_conn_resp_unmarshal((const char *)msg->data);
if (! sr) {
debug(LOG_ERR,
"TypeStartWorkConn unmarshal failed, it should never be happend!");
@@ -417,11 +407,11 @@ 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);
print_enc_msg(enc_msg, len);
dump_all_unknown_encypt(enc_msg, len);
}
if (!ctx)
@@ -437,7 +427,7 @@ handle_login_response(const uint8_t *buf, int len)
return 0;
}
struct login_resp *lres = login_resp_unmarshal(mhdr->data);
struct login_resp *lres = login_resp_unmarshal((const char *)mhdr->data);
if (!lres) {
return 0;
}
@@ -452,14 +442,18 @@ handle_login_response(const uint8_t *buf, int len)
is_login = 1;
int login_len = msg_hton(mhdr->length);
debug(LOG_ERR, "login success! %d len %d", login_len, len);
if (len-login_len-sizeof(struct msg_hdr) == 0)
int ilen = len - login_len - sizeof(struct msg_hdr);
debug(LOG_ERR, "login success! login_len %d len %d ilen %d", login_len, len, ilen);
assert(ilen >= 0);
if (ilen <= 0)
return 1;
// in case, system get 3 packet together
uint8_t *enc_msg = mhdr->data+login_len;
// in case, libevent reveive continue packet together
struct common_conf *c_conf = get_common_config();
assert(c_conf->tcp_mux == 0);
uint8_t *enc_msg = mhdr->data + login_len;
uint8_t *frps_cmd = NULL;
int nret = handle_enc_msg(enc_msg, len-login_len-sizeof(struct msg_hdr), &frps_cmd);
int nret = handle_enc_msg(enc_msg, ilen, &frps_cmd);
assert(nret > 0);
// start proxy services must first send
start_proxy_services();
@@ -472,18 +466,12 @@ handle_login_response(const uint8_t *buf, int len)
}
static void
handle_frps_msg(unsigned char *buf, int len, void *ctx)
handle_frps_msg(uint8_t *buf, int len, void *ctx)
{
if (!is_login) {
// login response
handle_login_response(buf, len);
}else if (!ctx) {
// control msg
debug(LOG_DEBUG, "main control message");
handle_control_work(buf, len, NULL);
}else {
// client msg
debug(LOG_DEBUG, "client message");
handle_control_work(buf, len, ctx);
}
}
@@ -499,12 +487,17 @@ recv_cb(struct bufferevent *bev, void *ctx)
return;
}
unsigned char *buf = calloc(len+1, 1);
uint8_t *buf = calloc(len+1, 1);
assert(buf);
evbuffer_remove(input, buf, len);
debug(LOG_DEBUG, "recv msg from frps %d ", len);
struct common_conf *c_conf = get_common_config();
handle_frps_msg(buf, len, ctx);
if (c_conf->tcp_mux) {
handle_tcp_mux_frps_msg(buf, len, handle_frps_msg);
} else {
handle_frps_msg(buf, len, ctx);
}
SAFE_FREE(buf);
return;
@@ -514,38 +507,40 @@ static void
connect_event_cb (struct bufferevent *bev, short what, void *ctx)
{
struct common_conf *c_conf = get_common_config();
static int retry_times = 0;
static int retry_times = 1;
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
if (retry_times >= 10) { // only try 10 times consecutively
debug(LOG_ERR,
"have retry connect to xfrp server for %d times, exit!",
if (retry_times >= 100) {
debug(LOG_INFO,
"have retry connect to xfrp server for %d times, exit?",
retry_times);
exit(0);
}
sleep(2);
retry_times++;
debug(LOG_ERR, "error: connect server [%s:%d] failed",
debug(LOG_ERR, "error: connect server [%s:%d] failed %s",
c_conf->server_addr,
c_conf->server_port);
free_control();
init_main_control();
start_base_connect();
close_main_control();
c_conf->server_port,
strerror(errno));
clear_main_control();
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) {
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);
}
@@ -575,15 +570,19 @@ 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();
if (main_ctl->connect_bev)
bufferevent_free(main_ctl->connect_bev);
main_ctl->connect_bev = connect_server(main_ctl->connect_base,
c_conf->server_addr,
c_conf->server_port);
if ( ! main_ctl->connect_bev) {
debug(LOG_ERR, "error: connect server [%s:%d] failed", c_conf->server_addr, c_conf->server_port);
debug(LOG_ERR, "error: connect server [%s:%d] failed: [%d: %s]",
c_conf->server_addr, c_conf->server_port, errno, strerror(errno));
exit(0);
}
@@ -603,7 +602,7 @@ login()
exit(0);
}
send_msg_frp_server(NULL, TypeLogin, lg_msg, len, main_ctl->session_id);
send_msg_frp_server(NULL, TypeLogin, lg_msg, len, 1);
SAFE_FREE(lg_msg);
}
@@ -622,15 +621,20 @@ send_msg_frp_server(struct bufferevent *bev,
}
assert(bout);
debug(LOG_DEBUG, "send plain msg ----> [%c: %s]", type, msg);
struct msg_hdr *req_msg = calloc(msg_len+sizeof(struct msg_hdr), 1);
size_t len = msg_len + sizeof(struct msg_hdr);
struct msg_hdr *req_msg = calloc(len, 1);
assert(req_msg);
req_msg->type = type;
req_msg->length = msg_hton((uint64_t)msg_len);
memcpy(req_msg->data, msg, msg_len);
bufferevent_write(bout, (uint8_t *)req_msg, msg_len+sizeof(struct msg_hdr));
tcp_mux_send_data(bout, sid, len);
bufferevent_write(bout, (uint8_t *)req_msg, len);
free(req_msg);
}
@@ -660,6 +664,9 @@ send_enc_msg_frp_server(struct bufferevent *bev,
if (get_main_encoder() == NULL) {
debug(LOG_DEBUG, "init_main_encoder .......");
tcp_mux_send_data(bout, sid, 16);
struct frp_coder *coder = init_main_encoder();
bufferevent_write(bout, coder->iv, 16);
}
@@ -667,7 +674,9 @@ 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);
bufferevent_write(bout, enc_msg, olen);
@@ -717,7 +726,7 @@ send_new_proxy(struct proxy_service *ps)
debug(LOG_DEBUG, "control proxy client: [Type %d : proxy_name %s : msg_len %d]", TypeNewProxy, ps->proxy_name, len);
send_enc_msg_frp_server(NULL, TypeNewProxy, new_proxy_msg, len, main_ctl->session_id);
send_enc_msg_frp_server(NULL, TypeNewProxy, new_proxy_msg, len, main_ctl->stream_id);
SAFE_FREE(new_proxy_msg);
}
@@ -733,14 +742,6 @@ init_main_control()
assert(main_ctl);
struct common_conf *c_conf = get_common_config();
if (c_conf->tcp_mux) {
uint32_t *sid = init_sid_index();
assert(sid);
main_ctl->session_id = *sid;
debug(LOG_DEBUG, "Connect Frps with control session ID: %d", main_ctl->session_id);
}
struct event_base *base = NULL;
struct evdns_base *dnsbase = NULL;
base = event_base_new();
@@ -749,6 +750,13 @@ init_main_control()
exit(0);
}
main_ctl->connect_base = base;
if (c_conf->tcp_mux)
main_ctl->stream_id = get_next_session_id();
// if server_addr is ip, done control init.
if (is_valid_ip_address((const char *)c_conf->server_addr))
return;
dnsbase = evdns_base_new(base, 1);
if (! dnsbase) {
@@ -767,10 +775,7 @@ init_main_control()
evdns_base_nameserver_ip_add(dnsbase, "223.6.6.6"); //AliDNS
evdns_base_nameserver_ip_add(dnsbase, "114.114.114.114"); //114DNS
// if server_addr is ip, done control init.
if (is_valid_ip_address((const char *)c_conf->server_addr))
return;
// if server_addr is domain, analyze it to ip for server_ip
debug(LOG_DEBUG, "Get ip address of [%s] from DNServer", c_conf->server_addr);
@@ -788,33 +793,48 @@ init_main_control()
&hints,
server_dns_cb,
NULL);
if (! dns_req) {
if (!dns_req) {
debug(LOG_ERR, "error: can not analyse the dns of [%s]", c_conf->server_addr);
exit(0);
}
}
static void
free_main_control()
{
SAFE_FREE(main_ctl);
main_ctl = NULL;
}
static void
clear_main_control()
{
assert(main_ctl);
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
close_main_control()
{
assert(main_ctl);
clear_main_control();
event_base_dispatch(main_ctl->connect_base);
event_base_free(main_ctl->connect_base);
evdns_base_free(main_ctl->dnsbase, 0);
event_base_free(main_ctl->connect_base);
free_main_control();
}
void
run_control()
{
start_base_connect();
keep_control_alive();
}
void
free_control()
{
if (!main_ctl)
return;
SAFE_FREE(main_ctl);
}

View File

@@ -40,21 +40,28 @@ struct control {
struct event_base *connect_base; //main netevent
struct evdns_base *dnsbase;
struct bufferevent *connect_bev; //main io evet buf
char session_id;
struct event *ticker_ping; //heartbeat timer
struct event *tcp_mux_ping_event;
uint32_t tcp_mux_ping_id;
uint32_t stream_id;
};
void connect_eventcb(struct bufferevent *bev, short events, void *ptr);
void start_base_connect();
void init_main_control();
void run_control();
struct control *get_main_control();
void close_main_control();
void start_login_frp_server(struct event_base *base);
void send_login_frp_server(struct bufferevent *bev);
void login();
void free_control();
void sync_session_id(uint32_t sid);
void send_msg_frp_server(struct bufferevent *bev,
const enum msg_type type,
@@ -69,9 +76,9 @@ void send_enc_msg_frp_server(struct bufferevent *bev,
uint32_t sid);
void control_process(struct proxy_client *client);
void send_new_proxy(struct proxy_service *ps);
struct bufferevent
*connect_server(struct event_base *base, const char *name, const int port);
struct bufferevent *connect_server(struct event_base *base, const char *name, const int port);
#endif //_CONTROL_H_

101
crypto.c
View File

@@ -1,3 +1,30 @@
/* vim: set et ts=4 sts=4 sw=4 : */
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
\********************************************************************/
/** @file crypto.c
@brief xfrpc crypto implement
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@@ -16,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()
@@ -29,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);
@@ -67,7 +134,7 @@ init_main_encoder()
}
struct frp_coder *
init_main_decoder(unsigned char *iv)
init_main_decoder(const uint8_t *iv)
{
struct common_conf *c_conf = get_common_config();
main_decoder = new_coder(c_conf->auth_token, default_salt);
@@ -132,19 +199,11 @@ encrypt_iv(unsigned char *iv_buf, size_t iv_len)
return iv_buf;
}
static void
print_hex(uint8_t *val, size_t len)
{
for(int i = 0; i < len; i++)
printf("%1x", val[i]);
printf("\n");
}
// using aes-128-cfb and nopadding
size_t
encrypt_data(const unsigned char *src_data, size_t srclen, struct frp_coder *encoder, unsigned char **ret)
encrypt_data(const uint8_t *src_data, size_t srclen, struct frp_coder *encoder, unsigned char **ret)
{
uint8_t *intext = src_data;
uint8_t *intext = (uint8_t *)src_data;
assert(intext);
assert(encoder);
struct frp_coder *c = encoder;
@@ -156,11 +215,11 @@ encrypt_data(const unsigned char *src_data, size_t srclen, struct frp_coder *enc
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!");
@@ -180,7 +239,7 @@ E_END:
size_t
decrypt_data(const uint8_t *enc_data, size_t enclen, struct frp_coder *decoder, uint8_t **ret)
{
uint8_t *inbuf = enc_data;
uint8_t *inbuf = (uint8_t *)enc_data;
uint8_t *outbuf = calloc(enclen+1, 1);
struct frp_coder *c = decoder;
assert(inbuf);
@@ -189,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

@@ -1,3 +1,30 @@
/* vim: set et ts=4 sts=4 sw=4 : */
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
\********************************************************************/
/** @file crypto.h
@brief xfrpc crypto header
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef _CRYPTO_H_
#define _CRYPTO_H_
@@ -15,18 +42,19 @@ struct frp_coder {
};
size_t get_encrypt_block_size();
size_t decrypt_data(const unsigned char *enc_data, size_t enc_len, struct frp_coder *decoder, unsigned char **ret);
size_t decrypt_data(const uint8_t *enc_data, size_t enc_len, struct frp_coder *decoder, uint8_t **ret);
int is_encoder_inited();
int is_decoder_inited();
struct frp_coder *init_main_encoder();
struct frp_coder *init_main_decoder(unsigned char *iv);
struct frp_coder *init_main_decoder(const uint8_t *iv);
struct frp_coder *new_coder(const char *privilege_token, const char *salt);
uint8_t *encrypt_key(const char *token, size_t token_len, const char *salt, uint8_t *key, size_t key_len);
uint8_t *encrypt_iv(unsigned char *iv_buf, size_t iv_len);
size_t encrypt_data(const unsigned char *src_data, size_t srclen, struct frp_coder *encoder, unsigned char **ret);
uint8_t *encrypt_iv(uint8_t *iv_buf, size_t iv_len);
size_t encrypt_data(const uint8_t *src_data, size_t srclen, struct frp_coder *encoder, uint8_t **ret);
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_

View File

@@ -34,6 +34,8 @@
#include "debug.h"
#define PROGNAME "xfrpc"
debugconf_t debugconf = {
.debuglevel = LOG_INFO,
.log_stderr = 1,
@@ -46,7 +48,7 @@ Do not use directly, use the debug macro */
void
_debug(const char *filename, int line, int level, const char *format, ...)
{
char buf[28];
char buf[32] = {0};
va_list vlist;
time_t ts;
sigset_t block_chld;
@@ -75,7 +77,7 @@ _debug(const char *filename, int line, int level, const char *format, ...)
}
if (debugconf.log_syslog) {
openlog("wifidog", LOG_PID, debugconf.syslog_facility);
openlog(PROGNAME, LOG_PID, debugconf.syslog_facility);
va_start(vlist, format);
vsyslog(level, format, vlist);
va_end(vlist);

View File

@@ -28,6 +28,7 @@
#define _WIFIDOG_DEBUG_H_
#include <string.h>
#include <syslog.h>
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

26
login.c
View File

@@ -1,3 +1,29 @@
/* vim: set et ts=4 sts=4 sw=4 : */
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
\********************************************************************/
/** @file login.c
@brief xfrpc login protocol implemented
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

26
login.h
View File

@@ -1,3 +1,29 @@
/* vim: set et ts=4 sts=4 sw=4 : */
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
\********************************************************************/
/** @file login.h
@brief xfrp login header
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef _LOGIN_H_
#define _LOGIN_H_

17
msg.c
View File

@@ -20,7 +20,7 @@
\********************************************************************/
/** @file msg.c
@brief xfrp client msg related
@brief xfrpc client msg related
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
@@ -48,7 +48,7 @@ json_object_object_add(jobj, key, json_object_new_##jtype((item)));
#define SAFE_JSON_STRING(str_target) \
str_target?str_target:"\0"
const char msg_typs[] = {TypeLogin,
const char msg_types[] = {TypeLogin,
TypeLoginResp,
TypeNewProxy,
TypeNewProxyResp,
@@ -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))
@@ -388,11 +387,17 @@ int
msg_type_valid_check(char msg_type)
{
int i = 0;
for(i = 0; i<(sizeof(msg_typs) / sizeof(*msg_typs)); i++) {
if (msg_typs[i] == msg_type)
for(i = 0; i<(sizeof(msg_types) / sizeof(*msg_types)); i++) {
if (msg_types[i] == msg_type)
return 1;
}
return 0;
}
char *
get_msg_type(uint8_t type)
{
return NULL;
}

4
msg.h
View File

@@ -20,7 +20,7 @@
\********************************************************************/
/** @file msg.h
@brief xfrp msg struct
@brief xfrpc msg struct
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
@@ -114,4 +114,6 @@ int new_work_conn_marshal(const struct work_conn *work_c, char **msg);
void control_response_free(struct control_response *res);
char *get_msg_type(uint8_t type);
#endif //_MSG_H_

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,31 +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 auth_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 'ftp01'
# option type ftp
# option local_ip 127.0.01
# option local_port 21
# option remote_port 8021
# option remote_data_port 8022
#config xfrpc 'web01'
# option type http
# option local_ip 127.0.0.1
# option local_port 8080
#config xfrpc 'web02'
# option type https
# option local_ip 127.0.0.1
# option local_port 8443

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' \
'auth_token:string'
[ -z "$auth_token" ] && {
echo "no auth_token"
exit
}
echo "server_addr = $server_addr" >> "$config"
echo "server_port = $server_port" >> "$config"
echo "auth_token = $auth_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
}

30
proxy.c
View File

@@ -1,3 +1,29 @@
/* vim: set et ts=4 sts=4 sw=4 : */
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
\********************************************************************/
/** @file proxy.c
@brief xfrp proxy implemented
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
@@ -8,10 +34,6 @@
#include <errno.h>
#include <syslog.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/event.h>
#include "debug.h"
#include "uthash.h"

26
proxy.h
View File

@@ -1,3 +1,29 @@
/* vim: set et ts=4 sts=4 sw=4 : */
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
\********************************************************************/
/** @file proxy.h
@brief xfrp proxy header file
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef _PROXY_H_
#define _PROXY_H_

View File

@@ -1,3 +1,29 @@
/* vim: set et ts=4 sts=4 sw=4 : */
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
\********************************************************************/
/** @file proxy_tcp.c
@brief xfrp proxy tcp implemented
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
@@ -7,6 +33,7 @@
#include <netinet/in.h>
#include <errno.h>
#include <syslog.h>
#include <unistd.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
@@ -17,25 +44,50 @@
#include "uthash.h"
#include "common.h"
#include "proxy.h"
#include "config.h"
#include "tcpmux.h"
#define BUF_LEN 4096
// read data from local service
void tcp_proxy_c2s_cb(struct bufferevent *bev, void *ctx)
{
struct common_conf *c_conf = get_common_config();
struct proxy_client *client = (struct proxy_client *)ctx;
assert(client);
struct bufferevent *partner = client->ctl_bev;
assert(partner);
struct evbuffer *src, *dst;
size_t len;
src = bufferevent_get_input(bev);
len = evbuffer_get_length(src);
if (len > 0) {
dst = bufferevent_get_output(partner);
evbuffer_add_buffer(dst, src);
struct evbuffer *src = bufferevent_get_input(bev);
size_t len = evbuffer_get_length(src);
assert(len > 0);
if (!c_conf->tcp_mux) {
struct evbuffer *dst = bufferevent_get_output(partner);
evbuffer_add_buffer(dst, src);
return;
}
if (client->send_window == 0) {
debug(LOG_DEBUG, "client %d recv len %d exceed send windows: %d", client->stream_id, len, client->send_window);
bufferevent_disable(bev, EV_READ);
return;
} else {
len = client->send_window>=len?len:client->send_window;
client->send_window -= len;
}
tcp_mux_send_data(partner, client->stream_id, len);
uint8_t buf[BUF_LEN];
while(len > 0) {
memset(buf, 0, BUF_LEN);
int nread = bufferevent_read(bev, buf, len>BUF_LEN?BUF_LEN:len);
assert(nread >= 0);
bufferevent_write(partner, buf, nread);
len -= nread;
}
}
// read data from frps
// when tcp mux enable this function will not be used
void tcp_proxy_s2c_cb(struct bufferevent *bev, void *ctx)
{
struct proxy_client *client = (struct proxy_client *)ctx;
@@ -44,6 +96,8 @@ void tcp_proxy_s2c_cb(struct bufferevent *bev, void *ctx)
assert(partner);
struct evbuffer *src, *dst;
src = bufferevent_get_input(bev);
size_t len = evbuffer_get_length(src);
assert(len > 0);
dst = bufferevent_get_output(partner);
evbuffer_add_buffer(dst, src);
}

View File

@@ -1,54 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <syslog.h>
#include "uthash.h"
#include "session.h"
#include "version.h"
#include "debug.h"
uint32_t *sid_index = NULL;
// need free
uint32_t *
init_sid_index()
{
if (NULL == sid_index) {
sid_index = (uint32_t *)calloc(1, sizeof(uint32_t));
if (NULL == sid_index)
return sid_index;
#ifdef CLIENT_V
*sid_index = 1;
#elif SERVER
*sid_index = 0;
#endif
}
*sid_index += 2; //xfrp client session id start from 3
return sid_index;
}
uint32_t
get_current_sid_index()
{
if (NULL == sid_index) {
return *init_sid_index();
}
return *sid_index;
}
uint32_t
new_sid()
{
if (NULL == sid_index) {
init_sid_index();
return get_current_sid_index();
}
*sid_index += 2;
return *sid_index;
}

View File

@@ -1,11 +0,0 @@
#ifndef _SESSION_H_
#define _SESSION_H_
#include "uthash.h"
#include "common.h"
uint32_t *init_sid_index();
uint32_t get_current_sid_index();
uint32_t new_sid();
#endif //_SESSION_H_

16
systemd/xfrpc.service Normal file
View File

@@ -0,0 +1,16 @@
# 1. put xfrpc and xfrpc.ini under /usr/local/xfrpc/
# 2. put this file (xfrpc.service) at /etc/systemd/system
# 3. run `sudo systemctl daemon-reload && sudo systemctl enable xfrpc && sudo systemctl start xfrpc`
# Then we can manage xfrpc with `sudo service xfrpc {start|stop|restart|status}`
[Unit]
Description=frp c language client
Wants=network-online.target
After=network.target network-online.target
[Service]
ExecStart=/usr/local/xfrpc/xfrpc -c /usr/local/xfrpc/xfrpc.ini -f -d 0
[Install]
WantedBy=multi-user.target

368
tcpmux.c Normal file
View File

@@ -0,0 +1,368 @@
/* vim: set et ts=4 sts=4 sw=4 : */
/********************************************************************\
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 59 Temple Place - Suite 330 Fax: +1-617-542-2652 *
* Boston, MA 02111-1307, USA gnu@gnu.org *
* *
\********************************************************************/
/** @file tcpmux.c
@brief xfrp tcp mux implemented
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include "common.h"
#include "tcpmux.h"
#include "client.h"
#include "config.h"
#include "debug.h"
#include "control.h"
static uint8_t proto_version = 0;
static struct tcp_mux_type_desc type_desc[] = {
{DATA, "data"},
{WINDOW_UPDATE, "window update"},
{PING, "ping"},
{GO_AWAY, "go away"},
};
static struct tcp_mux_flag_desc flag_desc[] = {
{ZERO, "zero"},
{SYN, "syn"},
{ACK, "ack"},
{FIN, "fin"},
{RST, "rst"},
};
static const char *
type_2_desc(enum tcp_mux_type type)
{
for(int i = 0; i < sizeof(type_desc)/sizeof(struct tcp_mux_type_desc); i++){
if (type == type_desc[i].type)
return type_desc[i].desc;
}
return "unkown_type";
}
static const char *
flag_2_desc(enum tcp_mux_flag flag)
{
for(int i = 0; i < sizeof(flag_desc)/sizeof(struct tcp_mux_flag_desc); i++){
if (flag == flag_desc[i].flag)
return flag_desc[i].desc;
}
return "unkown_flag";
}
static int
valid_tcp_mux_type(uint8_t type)
{
if (type >= DATA && type <= GO_AWAY)
return 1;
return 0;
}
static int
valid_tcp_mux_sid(uint32_t sid)
{
if (sid == 1)
return 1;
return get_proxy_client(sid)?1:0;
}
void
tcp_mux_encode(enum tcp_mux_type type, enum tcp_mux_flag flags, uint32_t stream_id, uint32_t length, struct tcp_mux_header *tmux_hdr)
{
assert(tmux_hdr);
tmux_hdr->version = proto_version;
tmux_hdr->type = type;
tmux_hdr->flags = htons(flags);
tmux_hdr->stream_id = htonl(stream_id);
tmux_hdr->length = length?htonl(length):0;
}
static uint32_t
tcp_mux_flag()
{
struct common_conf *c_conf = get_common_config();
return c_conf->tcp_mux;
}
static void
dump_tcp_mux_header(uint8_t *data, int len)
{
if (len != 12)
return;
printf("tcp mux header is : \n");
for (int i = 0; i < len; i++)
printf("%2x", data[i]);
printf("\n");
}
static uint32_t
parse_tcp_mux_proto(uint8_t *data, int len, uint32_t *flag, uint32_t *type, uint32_t *stream_id, uint32_t *dlen)
{
struct common_conf *c_conf = get_common_config();
if (!c_conf->tcp_mux)
return 0;
if (len < sizeof(struct tcp_mux_header))
return 0;
struct tcp_mux_header *hdr = (struct tcp_mux_header *)data;
if(hdr->version == proto_version &&
valid_tcp_mux_type(hdr->type)) {
if (hdr->type == DATA && !valid_tcp_mux_sid(htonl(hdr->stream_id))) {
debug(LOG_INFO, "!!!!!type is DATA but cant find stream_id : type [%s] flag [%s] stream_id[%d]",
type_2_desc(hdr->type), flag_2_desc(htons(hdr->flags)), htonl(hdr->stream_id));
dump_tcp_mux_header(data, len);
exit(-1);
}
*type = hdr->type;
*flag = htons(hdr->flags);
*stream_id = htonl(hdr->stream_id);
*dlen = htonl(hdr->length);
return 1;
}
return 0;
}
uint32_t
get_next_session_id() {
static uint32_t next_session_id = 1;
uint32_t id = next_session_id;
next_session_id += 2;
return id;
}
void
tcp_mux_send_win_update_syn(struct bufferevent *bout, uint32_t stream_id)
{
if (!tcp_mux_flag()) return;
struct tcp_mux_header tmux_hdr;
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
tcp_mux_encode(WINDOW_UPDATE, SYN, stream_id, 0, &tmux_hdr);
debug(LOG_DEBUG, "tcp mux [%d] send wind update syn", stream_id);
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
}
void
tcp_mux_send_win_update_ack(struct bufferevent *bout, uint32_t stream_id, uint32_t delta)
{
if (!tcp_mux_flag()) return;
struct tcp_mux_header tmux_hdr;
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
tcp_mux_encode(WINDOW_UPDATE, ZERO, stream_id, delta, &tmux_hdr);
debug(LOG_DEBUG, "tcp mux [%d] send wind update ZERO [%d]", stream_id, delta);
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
}
void
tcp_mux_send_win_update_fin(struct bufferevent *bout, uint32_t stream_id)
{
if (!tcp_mux_flag()) return;
struct tcp_mux_header tmux_hdr;
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
tcp_mux_encode(WINDOW_UPDATE, FIN, stream_id, 0, &tmux_hdr);
debug(LOG_DEBUG, "tcp mux [%d] send wind update FIN", stream_id);
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
}
void
tcp_mux_send_data(struct bufferevent *bout, uint32_t stream_id, uint32_t length)
{
if (!tcp_mux_flag()) return;
struct tcp_mux_header tmux_hdr;
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
tcp_mux_encode(DATA, ZERO, stream_id, length, &tmux_hdr);
//debug(LOG_DEBUG, "tcp mux [%d] send data len : %d", stream_id, length);
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
}
void
tcp_mux_send_ping(struct bufferevent *bout, uint32_t ping_id)
{
if (!tcp_mux_flag()) return;
struct tcp_mux_header tmux_hdr;
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
tcp_mux_encode(PING, SYN, 0, ping_id, &tmux_hdr);
//debug(LOG_DEBUG, "tcp mux send ping syn : %d", ping_id);
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
}
static void
tcp_mux_handle_ping(struct bufferevent *bout, uint32_t ping_id)
{
if (!tcp_mux_flag()) return;
struct tcp_mux_header tmux_hdr;
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
tcp_mux_encode(PING, ACK, 0, ping_id, &tmux_hdr);
//debug(LOG_DEBUG, "tcp mux send ping ack : %d", ping_id);
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
}
void
handle_tcp_mux_frps_msg(uint8_t *buf, int ilen, void (*fn)(uint8_t *, int, void *))
{
static uint32_t l_stream_id = 0;
static uint32_t l_dlen = 0;
static uint32_t l_type = 0;
static uint32_t l_flag = 0;
uint8_t *data = buf;
while (ilen > 0) {
uint32_t type = 0, stream_id = 0, dlen = 0, flag = 0;
uint32_t is_tmux = parse_tcp_mux_proto(data, ilen, &flag, &type, &stream_id, &dlen);
if (!is_tmux) {
struct proxy_client *pc = get_proxy_client(l_stream_id);
debug(LOG_DEBUG, "receive only %s data : l_stream_id %d l_type %s l_flag %s l_dlen %d ilen %d",
!pc?"main control ":"worker ",
l_stream_id, type_2_desc(l_type),
flag_2_desc(l_flag), l_dlen, ilen);
assert(ilen);
if (ilen == 12)
dump_tcp_mux_header(data, ilen);
if (!pc || (pc && !pc->local_proxy_bev)) {
assert(ilen >= l_dlen);
assert(l_dlen > 0);
fn(data, l_dlen, pc);
data += l_dlen;
ilen -= l_dlen;
l_dlen = 0;
continue;
}
if (pc->stream_state != ESTABLISHED) {
debug(LOG_INFO, "client [%d] state is [%d]", pc->stream_id, pc->stream_state);
break;
}
if ( ilen >= l_dlen) {
assert(pc->local_proxy_bev);
bufferevent_write(pc->local_proxy_bev, data, l_dlen);
data += l_dlen;
ilen -= l_dlen;
l_dlen = 0;
} else {
assert(pc->local_proxy_bev);
bufferevent_write(pc->local_proxy_bev, data, ilen);
l_dlen -= ilen;
ilen = 0;
}
continue;
}
struct proxy_client *pc = get_proxy_client(stream_id);
debug(LOG_DEBUG, "[%s] receive tcp mux type [%s] flag [%s] stream_id [%d] dlen [%d] ilen [%d]",
pc?"worker":"main control",
type_2_desc(type), flag_2_desc(flag), stream_id, dlen, ilen);
data += sizeof(struct tcp_mux_header);
ilen -= sizeof(struct tcp_mux_header);
l_stream_id = stream_id;
l_type = type;
l_flag = flag;
l_dlen = type==PING?0:dlen;
assert(ilen >= 0);
switch(type) {
case DATA:
{
if (ilen == 0)
break;
if (!pc || (pc && !pc->local_proxy_bev)) {
assert(ilen >= dlen);
fn(data, dlen, pc);
data += dlen;
ilen -= dlen;
l_dlen = 0;
continue;
}
if (pc->stream_state != ESTABLISHED) {
debug(LOG_INFO, "client [%d] state is [%d]", pc->stream_id, pc->stream_state);
break;
}
if (ilen >= dlen){
assert(pc->local_proxy_bev);
bufferevent_write(pc->local_proxy_bev, data, dlen);
data += dlen;
ilen -= dlen;
l_dlen = 0;
} else {
assert(pc->local_proxy_bev);
bufferevent_write(pc->local_proxy_bev, data, ilen);
l_dlen -= ilen;
ilen = 0;
}
break;
}
case PING:
{
struct bufferevent *bout = get_main_control()->connect_bev;
uint32_t seq = dlen;
assert(bout);
if (flag == SYN)
tcp_mux_handle_ping(bout, seq);
break;
}
case WINDOW_UPDATE:
{
switch(flag) {
case RST:
case FIN:
del_proxy_client(pc);
break;
case ZERO:
case ACK:
if (!pc)
break;
if (dlen > 0) {
pc->send_window += dlen;
bufferevent_enable(pc->local_proxy_bev, EV_READ|EV_WRITE);
}
pc->stream_state = ESTABLISHED;
break;
default:
debug(LOG_INFO, "window update no need process : flag %2x %s dlen %d stream_id %d",
flag, flag_2_desc(flag), dlen, stream_id);
}
break;
}
default:
debug(LOG_INFO, "no need unhandle tcp mux msg : type %s flag %s stream_id %d dlen %d ilen %d",
type_2_desc(type), flag_2_desc(flag), stream_id, dlen, ilen);
}
}
}

View File

@@ -19,7 +19,74 @@
* *
\********************************************************************/
/** @file agent.c
@brief agent for router to communicate with frp server
/** @file tcpmux.h
@brief xfrp tcp mux header file
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#ifndef __TCP_MUX__
#define __TCP_MUX__
#include "uthash.h"
enum tcp_mux_type {
DATA,
WINDOW_UPDATE,
PING,
GO_AWAY,
};
struct tcp_mux_type_desc {
enum tcp_mux_type type;
char *desc;
};
enum tcp_mux_flag {
ZERO,
SYN,
ACK = 1<<1,
FIN = 1<<2,
RST = 1<<3,
};
struct __attribute__((__packed__)) tcp_mux_header {
uint8_t version;
uint8_t type;
uint16_t flags;
uint32_t stream_id;
uint32_t length;
};
struct tcp_mux_flag_desc {
enum tcp_mux_flag flag;
char *desc;
};
enum tcp_mux_state {
INIT = 0,
SYN_SEND,
SYN_RECEIVED,
ESTABLISHED,
LOCAL_CLOSE,
REMOTE_CLOSE,
CLOSED,
RESET
};
void tcp_mux_send_win_update_syn(struct bufferevent *bout, uint32_t stream_id);
void tcp_mux_send_win_update_ack(struct bufferevent *bout, uint32_t stream_id, uint32_t delta);
void tcp_mux_send_win_update_fin(struct bufferevent *bout, uint32_t stream_id);
void tcp_mux_send_data(struct bufferevent *bout, uint32_t stream_id, uint32_t length);
void tcp_mux_send_ping(struct bufferevent *bout, uint32_t ping_id);
uint32_t get_next_session_id();
void tcp_mux_encode(enum tcp_mux_type type, enum tcp_mux_flag flags, uint32_t stream_id, uint32_t length, struct tcp_mux_header *tmux_hdr);
void handle_tcp_mux_frps_msg(uint8_t *data, int len, void (*fn)(uint8_t *, int, void *));
#endif

View File

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

View File

@@ -20,7 +20,7 @@
\********************************************************************/
/** @file xfrpc.c
@brief xfrp client
@brief xfrpc client
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/

View File

@@ -20,7 +20,7 @@
\********************************************************************/
/** @file xfrpc.h
@brief xfrp client header file
@brief xfrpc client header file
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
@@ -29,4 +29,4 @@
void xfrpc_loop();
#endif //_XFRPC_H_
#endif //_XFRPC_H_

View File

@@ -1,7 +1,6 @@
[common]
server_addr = your_server_ip
server_port = 7000
token = 12345678
[ssh]
type = tcp