Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9ff2e1a62 | ||
|
|
3396100bc4 | ||
|
|
c53693be69 | ||
|
|
855f602e2f | ||
|
|
fd9a5ae249 | ||
|
|
61d5243678 | ||
|
|
e75a4dda25 | ||
|
|
65bfe5c03c | ||
|
|
b7c3e1f80b | ||
|
|
3fb01ce735 | ||
|
|
f14562b26b | ||
|
|
d4f35909c5 | ||
|
|
1ee2b1ff56 | ||
|
|
cab6e8a20f | ||
|
|
e53f8e1c94 | ||
|
|
23819fcb44 | ||
|
|
51930c855f | ||
|
|
690a6f4feb | ||
|
|
56e4020969 | ||
|
|
e06a9a40a3 | ||
|
|
767d2859f9 | ||
|
|
fa0a273865 | ||
|
|
030a7b8784 | ||
|
|
d2cd54d831 | ||
|
|
9c90f6b5cd | ||
|
|
d1e2f549a7 | ||
|
|
ffa9e1ad97 | ||
|
|
ca64905266 | ||
|
|
6b1f70407c | ||
|
|
5d298156e4 | ||
|
|
37f124ffe7 | ||
|
|
675e47ef43 | ||
|
|
176e4006f6 | ||
|
|
d91d5d91ef | ||
|
|
36eba09bbe | ||
|
|
4ac16540b7 | ||
|
|
ab4da37e72 | ||
|
|
b49dd4e97c | ||
|
|
6fb2e167d6 | ||
|
|
4b633a7c2a |
@@ -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
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
74
README.md
74
README.md
@@ -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 |
|
||||
@@ -28,9 +30,10 @@ the following table is detail compatible feature:
|
||||
|
||||
## Architecture
|
||||
|
||||

|
||||
|
||||
Architecture quote from [frp](https://github.com/fatedier/frp) project, replace frpc with xfrpc.
|
||||

|
||||
|
||||
|
||||
|
||||
## Sequence Diagram
|
||||
|
||||
@@ -77,7 +80,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 +101,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 +121,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 +144,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 +162,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 +185,12 @@ xfrpc -c frpc_mini.ini -f -d 7
|
||||
xfrpc -c frpc_mini.ini -d 0
|
||||
```
|
||||
|
||||
## Openwrt luci configure ui
|
||||
|
||||
If running xfrpc in openwrt box, [luci-app-xfrpc](https://github.com/liudf0716/luci-app-xfrpc) is a good choice
|
||||
|
||||
luci-app-xfrpc was recruited by [luci project](https://github.com/openwrt/luci)
|
||||
|
||||
## 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 +202,27 @@ QQ群 : [331230369](https://jq.qq.com/?_wv=1027&k=47QGEhL)
|
||||
|
||||
## Please support us and star our project
|
||||
|
||||
[](https://star-history.com/#liudf0716/xfrpc&Date)
|
||||
|
||||
## 打赏
|
||||
|
||||
支付宝打赏
|
||||
|
||||

|
||||
|
||||
|
||||
微信打赏
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
<!--
|
||||
|
||||
## 广告
|
||||
|
||||
想学习OpenWrt开发,但是摸不着门道?自学没毅力?基础太差?怕太难学不会?跟着佐大学OpenWrt开发入门培训班助你能学有所成
|
||||
|
||||
报名地址:https://forgotfun.org/2018/04/openwrt-training-2018.html
|
||||
|
||||
-->
|
||||
|
||||
25
agent.c
25
agent.c
@@ -1,25 +0,0 @@
|
||||
/* 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 agent.c
|
||||
@brief agent for router to communicate with frp server
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
94
client.c
94
client.c
@@ -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,13 @@ 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));
|
||||
tmux_stream_close(client->ctl_bev, &client->stream);
|
||||
} 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 +124,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 +134,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 +174,19 @@ 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);
|
||||
debug(LOG_DEBUG, "free client %d", client->stream_id);
|
||||
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,21 @@ 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)
|
||||
void
|
||||
del_proxy_client_by_stream_id(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;
|
||||
del_stream(sid);
|
||||
|
||||
struct proxy_client *pc = get_proxy_client(sid);
|
||||
del_proxy_client(pc);
|
||||
}
|
||||
|
||||
struct proxy_client *
|
||||
get_proxy_client(uint32_t sid)
|
||||
{
|
||||
struct proxy_client *pc = NULL;
|
||||
HASH_FIND_INT(all_pc, &sid, pc);
|
||||
return pc;
|
||||
}
|
||||
|
||||
struct proxy_client *
|
||||
@@ -213,5 +217,21 @@ new_proxy_client()
|
||||
{
|
||||
struct proxy_client *client = calloc(1, sizeof(struct proxy_client));
|
||||
assert(client);
|
||||
client->stream_id = get_next_session_id();
|
||||
init_tmux_stream(&client->stream, client->stream_id, 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);
|
||||
}
|
||||
}
|
||||
|
||||
21
client.h
21
client.h
@@ -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,18 @@ 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;
|
||||
struct tmux_stream stream;
|
||||
|
||||
//private arguments
|
||||
UT_hash_handle hh;
|
||||
uint32_t stream_id;
|
||||
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 +77,7 @@ struct proxy_service {
|
||||
char *http_user;
|
||||
char *http_pwd;
|
||||
|
||||
//provate arguments
|
||||
// private arguments
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
@@ -88,13 +90,16 @@ void start_xfrp_tunnel(struct proxy_client *client);
|
||||
|
||||
void del_proxy_client(struct proxy_client *client);
|
||||
|
||||
void free_proxy_client(struct proxy_client *client);
|
||||
void del_proxy_client_by_stream_id(uint32_t sid);
|
||||
|
||||
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_
|
||||
|
||||
@@ -282,11 +282,11 @@ function(from_hex HEX DEC)
|
||||
set(${DEC} ${_res} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
if (OPENSSL_INCLUDE_DIR)
|
||||
if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h")
|
||||
file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str
|
||||
REGEX "^# *define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*")
|
||||
if(OPENSSL_INCLUDE_DIR AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h")
|
||||
file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str
|
||||
REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])+.*")
|
||||
|
||||
if(openssl_version_str)
|
||||
# The version number is encoded as 0xMNNFFPPS: major minor fix patch status
|
||||
# The status gives if this is a developer or prerelease and is ignored here.
|
||||
# Major, minor, and fix directly translate into the version numbers shown in
|
||||
@@ -315,6 +315,25 @@ if (OPENSSL_INCLUDE_DIR)
|
||||
endif ()
|
||||
|
||||
set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}")
|
||||
else ()
|
||||
# Since OpenSSL 3.0.0, the new version format is MAJOR.MINOR.PATCH and
|
||||
# a new OPENSSL_VERSION_STR macro contains exactly that
|
||||
file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" OPENSSL_VERSION_STR
|
||||
REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_STR[\t ]+\"([0-9])+\\.([0-9])+\\.([0-9])+\".*")
|
||||
string(REGEX REPLACE "^.*OPENSSL_VERSION_STR[\t ]+\"([0-9]+\\.[0-9]+\\.[0-9]+)\".*$"
|
||||
"\\1" OPENSSL_VERSION_STR "${OPENSSL_VERSION_STR}")
|
||||
|
||||
set(OPENSSL_VERSION "${OPENSSL_VERSION_STR}")
|
||||
|
||||
# Setting OPENSSL_VERSION_MAJOR OPENSSL_VERSION_MINOR and OPENSSL_VERSION_FIX
|
||||
string(REGEX MATCHALL "([0-9])+" OPENSSL_VERSION_NUMBER "${OPENSSL_VERSION}")
|
||||
list(POP_FRONT OPENSSL_VERSION_NUMBER
|
||||
OPENSSL_VERSION_MAJOR
|
||||
OPENSSL_VERSION_MINOR
|
||||
OPENSSL_VERSION_FIX)
|
||||
|
||||
unset(OPENSSL_VERSION_NUMBER)
|
||||
unset(OPENSSL_VERSION_STR)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
26
common.c
26
common.c
@@ -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"
|
||||
|
||||
|
||||
36
common.h
36
common.h
@@ -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
|
||||
|
||||
128
config.c
128
config.c
@@ -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);
|
||||
|
||||
@@ -57,43 +56,9 @@ void free_common_config()
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
|
||||
if (c_conf->server_addr) free(c_conf->server_addr);
|
||||
if (c_conf->http_proxy) free(c_conf->http_proxy);
|
||||
if (c_conf->log_file) free(c_conf->log_file);
|
||||
if (c_conf->log_way) free(c_conf->log_way);
|
||||
if (c_conf->log_level) free(c_conf->log_level);
|
||||
if (c_conf->auth_token) free(c_conf->auth_token);
|
||||
if (c_conf->privilege_token) free(c_conf->privilege_token);
|
||||
SAFE_FREE(c_conf->server_ip);
|
||||
};
|
||||
|
||||
void set_common_server_ip(const char *ip)
|
||||
{
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
c_conf->server_ip = strdup(ip);
|
||||
assert(c_conf->server_ip);
|
||||
|
||||
debug(LOG_DEBUG, "server IP address: [%s]", c_conf->server_ip);
|
||||
}
|
||||
|
||||
void free_base_config(struct base_conf *bconf)
|
||||
{
|
||||
if (bconf->name) free(bconf->name);
|
||||
if (bconf->auth_token) free(bconf->auth_token);
|
||||
if (bconf->privilege_token) free(bconf->privilege_token);
|
||||
if (bconf->host_header_rewrite) free(bconf->host_header_rewrite);
|
||||
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 +75,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;
|
||||
}
|
||||
@@ -127,8 +90,9 @@ static void dump_common_conf()
|
||||
return;
|
||||
}
|
||||
|
||||
debug(LOG_DEBUG, "Section[common]: {server_addr:%s, server_port:%d, auth_token:%s, privilege_token:%s, interval:%d, timeout:%d}",
|
||||
c_conf->server_addr, c_conf->server_port, c_conf->auth_token, c_conf->privilege_token, c_conf->heartbeat_interval, c_conf->heartbeat_timeout);
|
||||
debug(LOG_DEBUG, "Section[common]: {server_addr:%s, server_port:%d, auth_token:%s, interval:%d, timeout:%d}",
|
||||
c_conf->server_addr, c_conf->server_port, c_conf->auth_token,
|
||||
c_conf->heartbeat_interval, c_conf->heartbeat_timeout);
|
||||
}
|
||||
|
||||
static void dump_proxy_service(const int index, struct proxy_service *ps)
|
||||
@@ -161,7 +125,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 +167,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 +184,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 +204,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 +212,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
|
||||
@@ -275,22 +239,17 @@ proxy_service_handler(void *user, const char *sect, const char *nm, const char *
|
||||
ps->remote_data_port = atoi(value);
|
||||
} else if (MATCH_NAME("http_user")) {
|
||||
ps->http_user = strdup(value);
|
||||
assert(ps->http_user);
|
||||
} else if (MATCH_NAME("http_pwd")) {
|
||||
ps->http_pwd = strdup(value);
|
||||
assert(ps->http_pwd);
|
||||
} else if (MATCH_NAME("subdomain")) {
|
||||
ps->subdomain = strdup(value);
|
||||
assert(ps->http_pwd);
|
||||
} else if (MATCH_NAME("custom_domains")) {
|
||||
ps->custom_domains = strdup(value);
|
||||
assert(ps->custom_domains);
|
||||
} else if (MATCH_NAME("locations")) {
|
||||
ps->locations = strdup(value);
|
||||
assert(ps->locations);
|
||||
} else if (MATCH_NAME("host_header_rewrite")) {
|
||||
ps->host_header_rewrite = strdup(value);
|
||||
assert(ps->host_header_rewrite);
|
||||
} else if (MATCH_NAME("use_encryption")) {
|
||||
ps->use_encryption = TO_BOOL(value);
|
||||
} else if (MATCH_NAME("use_compression")) {
|
||||
@@ -308,39 +267,10 @@ static int common_handler(void *user, const char *section, const char *name, con
|
||||
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
||||
if (MATCH("common", "server_addr")) {
|
||||
SAFE_FREE(config->server_addr);
|
||||
int addr_len = strlen(value) + 1;
|
||||
config->server_addr = (char *)calloc(1, addr_len);
|
||||
config->server_addr = strdup(value);
|
||||
assert(config->server_addr);
|
||||
if(dns_unified(value, config->server_addr, addr_len)) {
|
||||
debug(LOG_ERR, "error: server_addr [%s] is invalid!", value);
|
||||
exit(0);
|
||||
}
|
||||
if (is_valid_ip_address(value))
|
||||
set_common_server_ip(value);
|
||||
} else if (MATCH("common", "server_port")) {
|
||||
config->server_port = atoi(value);
|
||||
} else if (MATCH("common", "http_proxy")) {
|
||||
SAFE_FREE(config->http_proxy);
|
||||
config->http_proxy = strdup(value);
|
||||
assert(config->http_proxy);
|
||||
} else if (MATCH("common", "log_file")) {
|
||||
SAFE_FREE(config->log_file);
|
||||
config->log_file = strdup(value);
|
||||
assert(config->log_file);
|
||||
} else if (MATCH("common", "log_way")) {
|
||||
SAFE_FREE(config->log_way);
|
||||
config->log_way = strdup(value);
|
||||
assert(config->log_way);
|
||||
} else if (MATCH("common", "log_level")) {
|
||||
SAFE_FREE(config->log_level);
|
||||
config->log_level = strdup(value);
|
||||
assert(config->log_level);
|
||||
} else if (MATCH("common", "log_max_days")) {
|
||||
config->log_max_days = atoi(value);
|
||||
} else if (MATCH("common", "privilege_token")) {
|
||||
SAFE_FREE(config->privilege_token);
|
||||
config->privilege_token = strdup(value);
|
||||
assert(config->privilege_token);
|
||||
} else if (MATCH("common", "heartbeat_interval")) {
|
||||
config->heartbeat_interval = atoi(value);
|
||||
} else if (MATCH("common", "heartbeat_timeout")) {
|
||||
@@ -349,12 +279,9 @@ static int common_handler(void *user, const char *section, const char *name, con
|
||||
SAFE_FREE(config->auth_token);
|
||||
config->auth_token = strdup(value);
|
||||
assert(config->auth_token);
|
||||
} else if (MATCH("common", "user")) {
|
||||
SAFE_FREE(config->user);
|
||||
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;
|
||||
}
|
||||
@@ -367,18 +294,9 @@ static void init_common_conf(struct common_conf *config)
|
||||
config->server_addr = strdup("0.0.0.0");
|
||||
assert(config->server_addr);
|
||||
config->server_port = 7000;
|
||||
config->log_file = strdup("console");
|
||||
assert(config->log_file);
|
||||
config->log_way = strdup("console");
|
||||
assert(config->log_way);
|
||||
config->log_level = strdup("info");
|
||||
assert(config->log_level);
|
||||
config->log_max_days = 3;
|
||||
config->heartbeat_interval = 30;
|
||||
config->heartbeat_timeout = 60;
|
||||
config->tcp_mux = 0;
|
||||
config->user = NULL;
|
||||
config->server_ip = NULL;
|
||||
config->heartbeat_timeout = 90;
|
||||
config->tcp_mux = 1;
|
||||
config->is_router = 0;
|
||||
}
|
||||
|
||||
@@ -435,3 +353,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;
|
||||
}
|
||||
|
||||
36
config.h
36
config.h
@@ -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_
|
||||
@@ -31,51 +31,31 @@
|
||||
|
||||
#define FTP_RMT_CTL_PROXY_SUFFIX "_ftp_remote_ctl_proxy"
|
||||
|
||||
struct base_conf{
|
||||
char *name;
|
||||
char *auth_token;
|
||||
int use_encryption;
|
||||
int use_gzip;
|
||||
int privilege_mode;
|
||||
char *privilege_token;
|
||||
int pool_count;
|
||||
char *host_header_rewrite;
|
||||
char *subdomain;
|
||||
};
|
||||
|
||||
// common config
|
||||
//client common config
|
||||
struct common_conf {
|
||||
char *server_addr; /* default 0.0.0.0 */
|
||||
char *server_ip;
|
||||
int server_port; /* default 7000 */
|
||||
char *http_proxy;
|
||||
char *log_file; /* default consol */
|
||||
char *log_way; /* default console */
|
||||
char *log_level; /* default info */
|
||||
int log_max_days; /* default 3 */
|
||||
char *privilege_token;
|
||||
char *auth_token;
|
||||
int heartbeat_interval; /* default 10 */
|
||||
int heartbeat_timeout; /* default 30 */
|
||||
int tcp_mux; /* default 0 */
|
||||
char *user;
|
||||
|
||||
/* private fields */
|
||||
int is_router; // to sign router (Openwrt/LEDE) or not
|
||||
};
|
||||
|
||||
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
12
const.h
@@ -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
|
||||
|
||||
455
control.c
455
control.c
@@ -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,39 +47,43 @@
|
||||
#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 client_connected = 0;
|
||||
static int is_login = 0;
|
||||
static time_t pong_time = 0;
|
||||
|
||||
static void sync_new_work_connection(struct bufferevent *bev);
|
||||
static void new_work_connection(struct bufferevent *bev, struct tmux_stream *stream);
|
||||
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()
|
||||
{
|
||||
return clients_conn_signel;
|
||||
return client_connected;
|
||||
}
|
||||
|
||||
static int
|
||||
client_connected(int is_connected)
|
||||
set_client_status(int is_connected)
|
||||
{
|
||||
if (is_connected)
|
||||
clients_conn_signel = 1;
|
||||
client_connected = 1;
|
||||
else
|
||||
clients_conn_signel = 0;
|
||||
client_connected = 0;
|
||||
|
||||
return clients_conn_signel;
|
||||
return client_connected;
|
||||
}
|
||||
|
||||
static int
|
||||
set_client_work_start(struct proxy_client *client, int is_start_work)
|
||||
{
|
||||
assert(client->ps);
|
||||
if (is_start_work) {
|
||||
assert(client->ps);
|
||||
client->work_started = 1;
|
||||
}else
|
||||
client->work_started = 0;
|
||||
@@ -108,12 +106,12 @@ 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);
|
||||
client_connected(1);
|
||||
new_work_connection(bev, &main_ctl->stream);
|
||||
set_client_status(1);
|
||||
debug(LOG_INFO, "proxy service start");
|
||||
}
|
||||
}
|
||||
@@ -125,6 +123,15 @@ 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;
|
||||
send_window_update(client->ctl_bev, &client->stream, 0);
|
||||
new_work_connection(client->ctl_bev, &client->stream);
|
||||
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 +149,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 +168,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);
|
||||
}
|
||||
|
||||
static void
|
||||
sync_new_work_connection(struct bufferevent *bev)
|
||||
new_work_connection(struct bufferevent *bev, struct tmux_stream *stream)
|
||||
{
|
||||
struct bufferevent *bout = bev;
|
||||
assert(bout);
|
||||
assert(bev);
|
||||
|
||||
/* send new work session regist request to frps*/
|
||||
struct work_conn *work_c = new_work_conn();
|
||||
@@ -198,7 +201,7 @@ sync_new_work_connection(struct bufferevent *bev)
|
||||
return;
|
||||
}
|
||||
|
||||
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, stream);
|
||||
|
||||
SAFE_FREE(new_work_conn_request_message);
|
||||
SAFE_FREE(work_c);
|
||||
@@ -232,13 +235,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");
|
||||
//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,34 +298,19 @@ 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();
|
||||
ilen -= get_block_size();
|
||||
debug(LOG_DEBUG, "first recv stream message, init decoder iv succeed! %d", ilen);
|
||||
if (!ilen) {
|
||||
// recv only iv
|
||||
debug(LOG_DEBUG, "recv eas1238 iv data");
|
||||
@@ -324,34 +321,24 @@ 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);
|
||||
|
||||
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,19 +346,19 @@ 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);
|
||||
switch(cmd_type) {
|
||||
case TypeReqWorkConn:
|
||||
debug(LOG_DEBUG, "TypeReqWorkConn cmd");
|
||||
{
|
||||
if (! is_client_connected()) {
|
||||
start_proxy_services();
|
||||
client_connected(1);
|
||||
set_client_status(1);
|
||||
}
|
||||
new_client_connect();
|
||||
break;
|
||||
}
|
||||
case TypeNewProxyResp:
|
||||
debug(LOG_DEBUG, "TypeNewProxyResp cmd");
|
||||
struct new_proxy_response *npr = new_proxy_resp_unmarshal(msg->data);
|
||||
{
|
||||
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;
|
||||
@@ -380,9 +367,10 @@ handle_control_work(const uint8_t *buf, int len, void *ctx)
|
||||
proxy_service_resp_raw(npr);
|
||||
SAFE_FREE(npr);
|
||||
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!");
|
||||
@@ -416,12 +404,12 @@ handle_control_work(const uint8_t *buf, int len, void *ctx)
|
||||
set_client_work_start(client, 1);
|
||||
|
||||
break;
|
||||
}
|
||||
case TypePong:
|
||||
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 +425,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,18 +440,22 @@ 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();
|
||||
client_connected(1);
|
||||
set_client_status(1);
|
||||
debug(LOG_DEBUG, "TypeReqWorkConn cmd, msg :%s", &frps_cmd[8]);
|
||||
assert (frps_cmd[0] == TypeReqWorkConn);
|
||||
new_client_connect();
|
||||
@@ -472,22 +464,18 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
static struct tmux_stream abandon_stream;
|
||||
|
||||
// ctx: if recv_cb was called by common control, ctx == NULL
|
||||
// else ctx == client struct
|
||||
static void
|
||||
@@ -496,17 +484,109 @@ recv_cb(struct bufferevent *bev, void *ctx)
|
||||
struct evbuffer *input = bufferevent_get_input(bev);
|
||||
int len = evbuffer_get_length(input);
|
||||
if (len <= 0) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char *buf = calloc(len+1, 1);
|
||||
assert(buf);
|
||||
evbuffer_remove(input, buf, len);
|
||||
debug(LOG_DEBUG, "recv msg from frps %d ", len);
|
||||
|
||||
handle_frps_msg(buf, len, ctx);
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
if (c_conf->tcp_mux) {
|
||||
static struct tcp_mux_header tmux_hdr;
|
||||
static uint32_t stream_len = 0;
|
||||
while (len > 0) {
|
||||
struct tmux_stream *cur = get_cur_stream();
|
||||
size_t nr = 0;
|
||||
if (!cur) {
|
||||
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
|
||||
uint8_t *data = (uint8_t *)&tmux_hdr;
|
||||
if (len < sizeof(tmux_hdr)) {
|
||||
debug(LOG_INFO, "len [%d] < sizeof tmux_hdr", len);
|
||||
break;
|
||||
}
|
||||
nr = bufferevent_read(bev, data, sizeof(tmux_hdr));
|
||||
assert(nr == sizeof(tmux_hdr));
|
||||
assert(validate_tcp_mux_protocol(&tmux_hdr) > 0);
|
||||
len -= nr;
|
||||
if (tmux_hdr.type == DATA) {
|
||||
uint32_t stream_id = ntohl(tmux_hdr.stream_id);
|
||||
stream_len = ntohl(tmux_hdr.length);
|
||||
cur = get_stream_by_id(stream_id);
|
||||
if (!cur) {
|
||||
debug(LOG_INFO, "cur is NULL stream_id is %d, stream_len is %d len is %d",
|
||||
stream_id, stream_len, len);
|
||||
if (stream_len > 0)
|
||||
cur = &abandon_stream;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
set_cur_stream(cur);
|
||||
break;
|
||||
}
|
||||
if (len >= stream_len) {
|
||||
nr = tmux_stream_read(bev, cur, stream_len);
|
||||
assert(nr == stream_len);
|
||||
len -= stream_len;
|
||||
} else {
|
||||
nr = tmux_stream_read(bev, cur, len);
|
||||
stream_len -= len;
|
||||
assert(nr == len);
|
||||
set_cur_stream(cur);
|
||||
len -= nr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert(tmux_hdr.type == DATA);
|
||||
if (len >= stream_len ) {
|
||||
nr = tmux_stream_read(bev, cur, stream_len);
|
||||
assert(nr == stream_len);
|
||||
len -= stream_len;
|
||||
} else {
|
||||
nr = tmux_stream_read(bev, cur, len);
|
||||
stream_len -= len;
|
||||
assert(nr == len);
|
||||
len -= nr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cur == &abandon_stream) {
|
||||
debug(LOG_INFO, "abandon stream data ...");
|
||||
memset(cur , 0, sizeof(abandon_stream));
|
||||
set_cur_stream(NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(tmux_hdr.type) {
|
||||
case DATA:
|
||||
case WINDOW_UPDATE:
|
||||
{
|
||||
handle_tcp_mux_stream(&tmux_hdr, handle_frps_msg);
|
||||
break;
|
||||
}
|
||||
case PING:
|
||||
handle_tcp_mux_ping(&tmux_hdr);
|
||||
break;
|
||||
case GO_AWAY:
|
||||
handle_tcp_mux_go_away(&tmux_hdr);
|
||||
break;
|
||||
default:
|
||||
debug(LOG_ERR, "impossible here!!!!");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
set_cur_stream(NULL);
|
||||
}
|
||||
} else {
|
||||
uint8_t *buf = calloc(len, 1);
|
||||
assert(buf);
|
||||
evbuffer_remove(input, buf, len);
|
||||
|
||||
handle_frps_msg(buf, len, ctx);
|
||||
SAFE_FREE(buf);
|
||||
}
|
||||
|
||||
|
||||
SAFE_FREE(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -514,76 +594,57 @@ 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));
|
||||
reset_session_id();
|
||||
clear_main_control();
|
||||
run_control();
|
||||
} else if (what & BEV_EVENT_CONNECTED) {
|
||||
retry_times = 0;
|
||||
send_window_update(bev, &main_ctl->stream, 0);
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
server_dns_cb(int event_code, struct evutil_addrinfo *addr, void *ctx)
|
||||
{
|
||||
if (event_code) {
|
||||
set_common_server_ip((const char *)evutil_gai_strerror(event_code));
|
||||
} else {
|
||||
struct evutil_addrinfo *ai;
|
||||
if (addr->ai_canonname)
|
||||
debug(LOG_DEBUG, "addr->ai_canonname [%s]", addr->ai_canonname);
|
||||
for (ai = addr; ai; ai = ai->ai_next) {
|
||||
char buf[128];
|
||||
const char *s = NULL;
|
||||
if (ai->ai_family == AF_INET) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
|
||||
s = evutil_inet_ntop(AF_INET, &sin->sin_addr, buf, 128);
|
||||
} else if (ai->ai_family == AF_INET6) {
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
|
||||
s = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128);
|
||||
}
|
||||
|
||||
if (s) set_common_server_ip(s);
|
||||
}
|
||||
if (addr) evutil_freeaddrinfo(addr);
|
||||
}
|
||||
}
|
||||
|
||||
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 +664,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, &main_ctl->stream);
|
||||
SAFE_FREE(lg_msg);
|
||||
}
|
||||
|
||||
@@ -612,7 +673,7 @@ send_msg_frp_server(struct bufferevent *bev,
|
||||
const enum msg_type type,
|
||||
const char *msg,
|
||||
const size_t msg_len,
|
||||
uint32_t sid)
|
||||
struct tmux_stream *stream)
|
||||
{
|
||||
struct bufferevent *bout = NULL;
|
||||
if (bev) {
|
||||
@@ -622,15 +683,22 @@ 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));
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
if (c_conf->tcp_mux)
|
||||
tmux_stream_write(bout, (uint8_t *)req_msg, len, stream);
|
||||
else
|
||||
bufferevent_write(bout, (uint8_t *)req_msg, len);
|
||||
|
||||
free(req_msg);
|
||||
}
|
||||
@@ -640,7 +708,7 @@ send_enc_msg_frp_server(struct bufferevent *bev,
|
||||
const enum msg_type type,
|
||||
const char *msg,
|
||||
const size_t msg_len,
|
||||
uint32_t sid)
|
||||
struct tmux_stream *stream)
|
||||
{
|
||||
struct bufferevent *bout = NULL;
|
||||
if (bev) {
|
||||
@@ -650,26 +718,28 @@ send_enc_msg_frp_server(struct bufferevent *bev,
|
||||
}
|
||||
assert(bout);
|
||||
|
||||
debug(LOG_DEBUG, "send enc msg ----> [%c: %s]", type, msg);
|
||||
|
||||
struct msg_hdr *req_msg = calloc(msg_len+sizeof(struct msg_hdr), 1);
|
||||
assert(req_msg);
|
||||
req_msg->type = type;
|
||||
req_msg->length = msg_hton((uint64_t)msg_len);
|
||||
memcpy(req_msg->data, msg, msg_len);
|
||||
|
||||
struct common_conf *c_conf = get_common_config();
|
||||
if (get_main_encoder() == NULL) {
|
||||
debug(LOG_DEBUG, "init_main_encoder .......");
|
||||
struct frp_coder *coder = init_main_encoder();
|
||||
bufferevent_write(bout, coder->iv, 16);
|
||||
if (c_conf->tcp_mux)
|
||||
tmux_stream_write(bout, coder->iv, 16, stream);
|
||||
else
|
||||
bufferevent_write(bout, coder->iv, 16);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
bufferevent_write(bout, enc_msg, olen);
|
||||
if (c_conf->tcp_mux)
|
||||
tmux_stream_write(bout, enc_msg, olen, stream);
|
||||
else
|
||||
bufferevent_write(bout, enc_msg, olen);
|
||||
|
||||
free(enc_msg);
|
||||
free(req_msg);
|
||||
@@ -717,7 +787,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);
|
||||
SAFE_FREE(new_proxy_msg);
|
||||
}
|
||||
|
||||
@@ -733,14 +803,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 +811,14 @@ init_main_control()
|
||||
exit(0);
|
||||
}
|
||||
main_ctl->connect_base = base;
|
||||
|
||||
if (c_conf->tcp_mux) {
|
||||
init_tmux_stream(&main_ctl->stream, get_next_session_id(), INIT);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@@ -766,55 +836,44 @@ init_main_control()
|
||||
evdns_base_nameserver_ip_add(dnsbase, "223.5.5.5"); //AliDNS
|
||||
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);
|
||||
static void
|
||||
free_main_control()
|
||||
{
|
||||
SAFE_FREE(main_ctl);
|
||||
main_ctl = NULL;
|
||||
}
|
||||
|
||||
struct evutil_addrinfo hints;
|
||||
struct evdns_getaddrinfo_request *dns_req;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_flags = EVUTIL_AI_CANONNAME;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
dns_req = evdns_getaddrinfo(dnsbase,
|
||||
c_conf->server_addr,
|
||||
NULL /* no service name given */,
|
||||
&hints,
|
||||
server_dns_cb,
|
||||
NULL);
|
||||
if (! dns_req) {
|
||||
debug(LOG_ERR, "error: can not analyse the dns of [%s]", c_conf->server_addr);
|
||||
exit(0);
|
||||
}
|
||||
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();
|
||||
set_client_status(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);
|
||||
}
|
||||
|
||||
23
control.h
23
control.h
@@ -40,38 +40,45 @@ 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;
|
||||
struct tmux_stream stream;
|
||||
};
|
||||
|
||||
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,
|
||||
const char *msg,
|
||||
const size_t msg_len,
|
||||
uint32_t sid);
|
||||
struct tmux_stream *stream);
|
||||
|
||||
void send_enc_msg_frp_server(struct bufferevent *bev,
|
||||
const enum msg_type type,
|
||||
const char *msg,
|
||||
const size_t msg_len,
|
||||
uint32_t sid);
|
||||
struct tmux_stream *stream);
|
||||
|
||||
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_
|
||||
|
||||
109
crypto.c
109
crypto.c
@@ -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->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()
|
||||
@@ -24,14 +91,14 @@ get_block_size()
|
||||
}
|
||||
|
||||
struct frp_coder *
|
||||
new_coder(const char *privilege_token, const char *salt)
|
||||
new_coder(const char *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->token = token ? strdup(token):strdup("\0");
|
||||
enc->salt = strdup(salt);
|
||||
encrypt_key(enc->privilege_token, strlen(enc->privilege_token), enc->salt, enc->key, block_size);
|
||||
encrypt_key(enc->token, strlen(enc->token), enc->salt, enc->key, block_size);
|
||||
encrypt_iv(enc->iv, block_size);
|
||||
return enc;
|
||||
}
|
||||
@@ -42,7 +109,7 @@ clone_coder(const struct frp_coder *coder)
|
||||
assert(coder);
|
||||
struct frp_coder *enc = calloc(sizeof(struct frp_coder), 1);
|
||||
memcpy(enc, coder, sizeof(*coder));
|
||||
enc->privilege_token = strdup(coder->privilege_token);
|
||||
enc->token = strdup(coder->token);
|
||||
enc->salt = strdup(coder->salt);
|
||||
|
||||
return enc;
|
||||
@@ -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;
|
||||
@@ -214,7 +273,7 @@ D_END:
|
||||
void
|
||||
free_encoder(struct frp_coder *encoder) {
|
||||
if (encoder) {
|
||||
SAFE_FREE(encoder->privilege_token);
|
||||
SAFE_FREE(encoder->token);
|
||||
SAFE_FREE(encoder->salt);
|
||||
free(encoder);
|
||||
}
|
||||
|
||||
40
crypto.h
40
crypto.h
@@ -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_
|
||||
|
||||
@@ -11,22 +38,23 @@ struct frp_coder {
|
||||
uint8_t key[16];
|
||||
char *salt;
|
||||
uint8_t iv[16];
|
||||
char *privilege_token;
|
||||
char *token;
|
||||
};
|
||||
|
||||
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 *new_coder(const char *privilege_token, const char *salt);
|
||||
struct frp_coder *init_main_decoder(const uint8_t *iv);
|
||||
struct frp_coder *new_coder(const char *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_
|
||||
|
||||
6
debug.c
6
debug.c
@@ -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);
|
||||
|
||||
1
debug.h
1
debug.h
@@ -28,6 +28,7 @@
|
||||
#define _WIFIDOG_DEBUG_H_
|
||||
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
|
||||
|
||||
27
login.c
27
login.c
@@ -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>
|
||||
@@ -63,7 +89,6 @@ void init_login()
|
||||
c_login->metas = NULL;
|
||||
c_login->pool_count = 1;
|
||||
c_login->privilege_key = NULL;
|
||||
c_login->user = c_conf->user;
|
||||
|
||||
c_login->logged = 0;
|
||||
|
||||
|
||||
26
login.h
26
login.h
@@ -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
17
msg.c
@@ -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
4
msg.h
@@ -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_
|
||||
|
||||
@@ -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))
|
||||
@@ -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
|
||||
@@ -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
30
proxy.c
@@ -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
26
proxy.h
@@ -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_
|
||||
|
||||
|
||||
@@ -101,12 +101,12 @@ void ftp_proxy_c2s_cb(struct bufferevent *bev, void *ctx)
|
||||
struct ftp_pasv *r_fp = new_ftp_pasv();
|
||||
r_fp->code = local_fp->code;
|
||||
|
||||
if (! c_conf->server_ip) {
|
||||
if (! c_conf->server_addr) {
|
||||
debug(LOG_ERR, "error: FTP proxy without server ip!");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
strncpy(r_fp->ftp_server_ip, c_conf->server_ip, IP_LEN);
|
||||
strncpy(r_fp->ftp_server_ip, c_conf->server_addr, IP_LEN);
|
||||
r_fp->ftp_server_port = p->remote_data_port;
|
||||
|
||||
if (r_fp->ftp_server_port <= 0) {
|
||||
@@ -264,4 +264,4 @@ static void free_ftp_pasv(struct ftp_pasv *fp)
|
||||
|
||||
SAFE_FREE(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
60
proxy_tcp.c
60
proxy_tcp.c
@@ -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,42 @@
|
||||
#include "uthash.h"
|
||||
#include "common.h"
|
||||
#include "proxy.h"
|
||||
#include "config.h"
|
||||
#include "tcpmux.h"
|
||||
|
||||
#define BUF_LEN 2*1024
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
uint8_t *buf = (uint8_t *)malloc(len);
|
||||
assert(buf != NULL);
|
||||
memset(buf, 0, len);
|
||||
uint32_t nr = bufferevent_read(bev, buf, len);
|
||||
assert(nr == len);
|
||||
nr = tmux_stream_write(partner, buf, len, &client->stream);
|
||||
if (nr < len) {
|
||||
debug(LOG_DEBUG, "stream_id [%d] len is %d tmux_stream_write %d data, disable read", client->stream.id, len, nr);
|
||||
bufferevent_disable(bev, EV_READ);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 +88,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);
|
||||
}
|
||||
|
||||
54
session.c
54
session.c
@@ -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;
|
||||
}
|
||||
11
session.h
11
session.h
@@ -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
16
systemd/xfrpc.service
Normal 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
|
||||
610
tcpmux.c
Normal file
610
tcpmux.c
Normal file
@@ -0,0 +1,610 @@
|
||||
/* 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 <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 uint8_t remote_go_away;
|
||||
static uint8_t local_go_away;
|
||||
static uint32_t g_session_id = 1;
|
||||
static struct tmux_stream *cur_stream = NULL;
|
||||
static struct tmux_stream *all_stream;
|
||||
|
||||
static uint32_t ring_buffer_read(struct bufferevent *bev, struct ring_buffer *ring, uint32_t len);
|
||||
static uint32_t ring_buffer_write(struct bufferevent *bev, struct ring_buffer *ring, uint32_t len);
|
||||
|
||||
void
|
||||
add_stream(struct tmux_stream *stream)
|
||||
{
|
||||
HASH_ADD_INT(all_stream, id, stream);
|
||||
}
|
||||
|
||||
void
|
||||
del_stream(uint32_t id)
|
||||
{
|
||||
assert(all_stream != NULL);
|
||||
|
||||
struct tmux_stream *stream = get_stream_by_id(id);
|
||||
if (stream)
|
||||
HASH_DEL(all_stream, stream);
|
||||
}
|
||||
|
||||
struct tmux_stream *
|
||||
get_stream_by_id(uint32_t id)
|
||||
{
|
||||
if (!all_stream) return NULL;
|
||||
|
||||
struct tmux_stream *stream = NULL;
|
||||
HASH_FIND_INT(all_stream, &id, stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
struct tmux_stream *
|
||||
get_cur_stream()
|
||||
{
|
||||
return cur_stream;
|
||||
}
|
||||
|
||||
void
|
||||
set_cur_stream(struct tmux_stream *stream)
|
||||
{
|
||||
cur_stream = stream;
|
||||
}
|
||||
|
||||
void
|
||||
init_tmux_stream(struct tmux_stream *stream, uint32_t id, enum tcp_mux_state state)
|
||||
{
|
||||
stream->id = id;
|
||||
stream->state = state;
|
||||
stream->recv_window = MAX_STREAM_WINDOW_SIZE;
|
||||
stream->send_window = MAX_STREAM_WINDOW_SIZE;
|
||||
|
||||
memset(&stream->tx_ring, 0, sizeof(struct ring_buffer));
|
||||
memset(&stream->rx_ring, 0, sizeof(struct ring_buffer));
|
||||
|
||||
add_stream(stream);
|
||||
};
|
||||
|
||||
int
|
||||
validate_tcp_mux_protocol(struct tcp_mux_header *tmux_hdr)
|
||||
{
|
||||
if (tmux_hdr->version != proto_version) return 0;
|
||||
|
||||
if (tmux_hdr->type > GO_AWAY) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
reset_session_id() {
|
||||
g_session_id = 1;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
get_next_session_id() {
|
||||
uint32_t id = g_session_id;
|
||||
g_session_id += 2;
|
||||
return id;
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_mux_send_win_update(struct bufferevent *bout, enum tcp_mux_flag flags, uint32_t stream_id, uint32_t delta)
|
||||
{
|
||||
struct tcp_mux_header tmux_hdr;
|
||||
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
|
||||
tcp_mux_encode(WINDOW_UPDATE, flags, stream_id, delta, &tmux_hdr);
|
||||
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
|
||||
}
|
||||
|
||||
void
|
||||
tcp_mux_send_win_update_syn(struct bufferevent *bout, uint32_t stream_id)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
tcp_mux_send_win_update(bout, SYN, stream_id, 0);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_mux_send_win_update_ack(struct bufferevent *bout, uint32_t stream_id, uint32_t delta)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
tcp_mux_send_win_update(bout, ZERO, stream_id, 0);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_mux_send_win_update_fin(struct bufferevent *bout, uint32_t stream_id)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
tcp_mux_send_win_update(bout, FIN, stream_id, 0);
|
||||
}
|
||||
|
||||
void
|
||||
tcp_mux_send_win_update_rst(struct bufferevent *bout, uint32_t stream_id)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
tcp_mux_send_win_update(bout, RST, stream_id, 0);
|
||||
}
|
||||
void
|
||||
tcp_mux_send_data(struct bufferevent *bout, uint16_t flags, 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, flags, 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));
|
||||
}
|
||||
|
||||
static void
|
||||
tcp_mux_send_go_away(struct bufferevent *bout, uint32_t reason)
|
||||
{
|
||||
if (!tcp_mux_flag()) return;
|
||||
|
||||
struct tcp_mux_header tmux_hdr;
|
||||
memset(&tmux_hdr, 0, sizeof(tmux_hdr));
|
||||
tcp_mux_encode(GO_AWAY, 0, 0, reason, &tmux_hdr);
|
||||
//debug(LOG_DEBUG, "tcp mux send ping ack : %d", ping_id);
|
||||
bufferevent_write(bout, (uint8_t *)&tmux_hdr, sizeof(tmux_hdr));
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
process_flags(uint16_t flags, struct tmux_stream *stream)
|
||||
{
|
||||
uint32_t close_stream = 0;
|
||||
if ( (flags&ACK) == ACK ) {
|
||||
if (stream->state == SYN_SEND)
|
||||
stream->state = ESTABLISHED;
|
||||
} else if ( (flags&FIN) == FIN ) {
|
||||
switch(stream->state) {
|
||||
case SYN_SEND:
|
||||
case SYN_RECEIVED:
|
||||
case ESTABLISHED:
|
||||
stream->state = REMOTE_CLOSE;
|
||||
break;
|
||||
case LOCAL_CLOSE:
|
||||
stream->state = CLOSED;
|
||||
close_stream = 1;
|
||||
break;
|
||||
default:
|
||||
debug(LOG_ERR, "unexpected FIN flag in state %d", stream->state);
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
} else if ( (flags&RST) == RST ) {
|
||||
stream->state = RESET;
|
||||
close_stream = 1;
|
||||
}
|
||||
|
||||
if (close_stream) {
|
||||
debug(LOG_DEBUG, "free stream %d", stream->id);
|
||||
del_proxy_client_by_stream_id(stream->id);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
get_send_flags(struct tmux_stream *stream)
|
||||
{
|
||||
uint16_t flags = 0;
|
||||
|
||||
switch (stream->state) {
|
||||
case INIT:
|
||||
flags |= SYN;
|
||||
stream->state = SYN_SEND;
|
||||
break;
|
||||
case SYN_RECEIVED:
|
||||
flags |= ACK;
|
||||
stream->state = ESTABLISHED;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
void
|
||||
send_window_update(struct bufferevent *bout, struct tmux_stream *stream, uint32_t length)
|
||||
{
|
||||
uint32_t max = MAX_STREAM_WINDOW_SIZE;
|
||||
uint32_t delta = (max - length) - stream->recv_window;
|
||||
|
||||
uint16_t flags = get_send_flags(stream);
|
||||
|
||||
if (delta < max/2 && flags == 0)
|
||||
return;
|
||||
|
||||
stream->recv_window += delta;
|
||||
tcp_mux_send_win_update(bout, flags, stream->id, delta);
|
||||
//debug(LOG_DEBUG, "send window update: flags %d, stream_id %d delta %d, recv_window %u length %u",
|
||||
// flags, stream->id, delta, stream->recv_window, length);
|
||||
}
|
||||
|
||||
static int
|
||||
ring_buffer_pop(struct ring_buffer *ring, uint8_t *data, uint32_t len)
|
||||
{
|
||||
assert(ring->sz >= len);
|
||||
assert(data != NULL);
|
||||
|
||||
uint32_t i = 0;
|
||||
while(i < len) {
|
||||
data[i] = ring->data[ring->cur++];
|
||||
if (ring->cur == RBUF_SIZE)
|
||||
ring->cur = 0;
|
||||
i++;
|
||||
ring->sz--;
|
||||
}
|
||||
|
||||
assert(i == len);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
process_data(struct tmux_stream *stream, uint32_t length, uint16_t flags,
|
||||
void (*fn)(uint8_t *, int, void *), void *param)
|
||||
{
|
||||
if (!process_flags(flags, stream)) return 0;
|
||||
|
||||
|
||||
if (length > stream->recv_window) {
|
||||
debug(LOG_ERR, "receive window exceed (remain %d, recv %d)", stream->recv_window, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream->recv_window -= length;
|
||||
|
||||
struct proxy_client *pc = (struct proxy_client *)param;
|
||||
if (!pc || (pc && !pc->local_proxy_bev)) {
|
||||
uint8_t *data = (uint8_t *)calloc(length, 1);
|
||||
ring_buffer_pop(&stream->rx_ring, data, length);
|
||||
fn(data, length, pc);
|
||||
free(data);
|
||||
} else {
|
||||
ring_buffer_write(pc->local_proxy_bev, &stream->rx_ring, length);
|
||||
}
|
||||
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
send_window_update(bout, stream, length);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int
|
||||
incr_send_window(struct bufferevent *bev, struct tcp_mux_header *tmux_hdr, uint16_t flags, struct tmux_stream *stream)
|
||||
{
|
||||
if (!process_flags(flags, stream))
|
||||
return 0;
|
||||
|
||||
uint32_t length = ntohl(tmux_hdr->length);
|
||||
if (stream->send_window == 0) bufferevent_enable(bev, EV_READ);
|
||||
stream->send_window += length;
|
||||
//debug(LOG_DEBUG, "incr_send_window : stream_id %d length %d send_window %d",
|
||||
// stream->id, length, stream->send_window);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
incoming_stream(uint32_t stream_id)
|
||||
{
|
||||
if (local_go_away) {
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
tcp_mux_send_win_update_rst(bout, stream_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// create new stream
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
handle_tcp_mux_ping(struct tcp_mux_header *tmux_hdr)
|
||||
{
|
||||
uint16_t flags = ntohs(tmux_hdr->flags);
|
||||
uint32_t ping_id = ntohl(tmux_hdr->length);
|
||||
|
||||
if ( (flags&SYN) == SYN) {
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
tcp_mux_handle_ping(bout, ping_id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_tcp_mux_go_away(struct tcp_mux_header *tmux_hdr)
|
||||
{
|
||||
uint32_t code = ntohl(tmux_hdr->length);
|
||||
switch(code) {
|
||||
case NORMAL:
|
||||
remote_go_away = 1;
|
||||
break;
|
||||
case PROTO_ERR:
|
||||
debug(LOG_ERR, "receive protocol error go away");
|
||||
break;
|
||||
case INTERNAL_ERR:
|
||||
debug(LOG_ERR, "receive internal error go away");
|
||||
break;
|
||||
default:
|
||||
debug(LOG_ERR, "receive unexpected go away");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
tmux_stream_read(struct bufferevent *bev, struct tmux_stream *stream, uint32_t len)
|
||||
{
|
||||
assert(stream != NULL);
|
||||
|
||||
return ring_buffer_read(bev, &stream->rx_ring, len);
|
||||
}
|
||||
|
||||
int
|
||||
handle_tcp_mux_stream(struct tcp_mux_header *tmux_hdr, handle_data_fn_t fn)
|
||||
{
|
||||
uint32_t stream_id = ntohl(tmux_hdr->stream_id);
|
||||
uint16_t flags = ntohs(tmux_hdr->flags);
|
||||
|
||||
//debug(LOG_DEBUG, "handle_tcp_mux_stream stream_id %d type %d flags %d", stream_id, tmux_hdr->type, flags);
|
||||
|
||||
if ( (flags&SYN) == SYN) {
|
||||
debug(LOG_INFO, "!!!! as xfrpc, it should not be here %d", stream_id);
|
||||
if (!incoming_stream(stream_id))
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tmux_stream *stream = get_stream_by_id(stream_id);
|
||||
struct proxy_client *pc = get_proxy_client(stream_id);
|
||||
assert(stream != NULL);
|
||||
if (tmux_hdr->type == WINDOW_UPDATE) {
|
||||
struct bufferevent *bev = pc?pc->local_proxy_bev: get_main_control()->connect_bev;
|
||||
if (!incr_send_window(bev, tmux_hdr, flags, stream)) {
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
tcp_mux_send_go_away(bout, PROTO_ERR);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int32_t length = ntohl(tmux_hdr->length);
|
||||
if (!process_data(stream, length, flags, fn, (void *)pc)) {
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
tcp_mux_send_go_away(bout, PROTO_ERR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
static int
|
||||
ring_buffer_append(struct ring_buffer *ring, uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint32_t left = RBUF_SIZE - ring->sz;
|
||||
assert(left >= len);
|
||||
int i = 0;
|
||||
for (; i < len; i++) {
|
||||
ring->data[ring->end++] = data[i];
|
||||
if (ring->end == RBUF_SIZE) ring->end = 0;
|
||||
ring->sz++;
|
||||
if (ring->cur == ring->end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ring_buffer_read(struct bufferevent *bev, struct ring_buffer *ring, uint32_t len)
|
||||
{
|
||||
if (ring->sz == RBUF_SIZE) {
|
||||
debug(LOG_ERR, "ring buffer is full");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t cap = RBUF_SIZE - ring->sz;
|
||||
if (len > cap) {
|
||||
debug(LOG_INFO, "prepare read data [%d] out size ring capacity [%d]", len, cap);
|
||||
len = cap;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
bufferevent_read(bev, &ring->data[ring->end++], 1);
|
||||
if (ring->end == RBUF_SIZE) ring->end = 0;
|
||||
ring->sz++;
|
||||
if (ring->cur == ring->end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
ring_buffer_write(struct bufferevent *bev, struct ring_buffer *ring, uint32_t len)
|
||||
{
|
||||
if (ring->sz == 0) {
|
||||
debug(LOG_ERR, "ring buffer is empty");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len > ring->sz) {
|
||||
debug(LOG_INFO, "prepare write data [%d] out size ring data [%d]", len, ring->sz);
|
||||
len = ring->sz;
|
||||
}
|
||||
|
||||
while(len > 0) {
|
||||
bufferevent_write(bev, &ring->data[ring->cur++], 1);
|
||||
len--;
|
||||
ring->sz--;;
|
||||
if (ring->cur == RBUF_SIZE) ring->cur = 0;
|
||||
if (ring->cur == ring->end) {
|
||||
assert(ring->sz == 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
tmux_stream_write(struct bufferevent *bev, uint8_t *data, uint32_t length, struct tmux_stream *stream)
|
||||
{
|
||||
switch(stream->state) {
|
||||
case LOCAL_CLOSE:
|
||||
case CLOSED:
|
||||
case RESET:
|
||||
debug(LOG_INFO, "stream %d state is closed", stream->id);
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
struct ring_buffer *tx_ring = &stream->tx_ring;
|
||||
uint32_t left = RBUF_SIZE - tx_ring->sz;
|
||||
if (stream->send_window == 0) {
|
||||
debug(LOG_INFO, "stream %d send_window is zero, length %d left %d", stream->id, length, left);
|
||||
ring_buffer_append(tx_ring, data, length);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t flags = get_send_flags(stream);
|
||||
uint32_t max = length;
|
||||
struct bufferevent *bout = get_main_control()->connect_bev;
|
||||
//debug(LOG_DEBUG, "tmux_stream_write stream id %u: send_window %u tx_ring sz %u length %u",
|
||||
// stream->id, stream->send_window, tx_ring->sz, length);
|
||||
if (stream->send_window < tx_ring->sz) {
|
||||
debug(LOG_INFO, " send_window %u less than tx_ring size %u", stream->send_window, tx_ring->sz);
|
||||
max = stream->send_window;
|
||||
tcp_mux_send_data(bout, flags, stream->id, max);
|
||||
ring_buffer_write(bev, tx_ring, max);
|
||||
ring_buffer_append(tx_ring, data, length);
|
||||
} else if (stream->send_window < tx_ring->sz + length) {
|
||||
debug(LOG_INFO, " send_window %u less than %u", stream->send_window, tx_ring->sz+length);
|
||||
max = stream->send_window;
|
||||
tcp_mux_send_data(bout, flags, stream->id, max);
|
||||
if (tx_ring->sz > 0)
|
||||
ring_buffer_write(bev, tx_ring, tx_ring->sz);
|
||||
bufferevent_write(bev, data, max - tx_ring->sz);
|
||||
ring_buffer_append(tx_ring, data + max - tx_ring->sz, length + tx_ring->sz - max);
|
||||
} else {
|
||||
max = tx_ring->sz + length;
|
||||
tcp_mux_send_data(bout, flags, stream->id, max);
|
||||
if (tx_ring->sz > 0)
|
||||
ring_buffer_write(bev, tx_ring, tx_ring->sz);
|
||||
bufferevent_write(bev, data, length);
|
||||
}
|
||||
|
||||
stream->send_window -= max;
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
void
|
||||
tmux_stream_close(struct bufferevent *bout, struct tmux_stream *stream)
|
||||
{
|
||||
int closed = 0;
|
||||
switch(stream->state) {
|
||||
case SYN_SEND:
|
||||
case SYN_RECEIVED:
|
||||
case ESTABLISHED:
|
||||
stream->state = LOCAL_CLOSE;
|
||||
break;
|
||||
case LOCAL_CLOSE:
|
||||
case REMOTE_CLOSE:
|
||||
stream->state = CLOSED;
|
||||
closed = 1;
|
||||
case CLOSED:
|
||||
case RESET:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t flags = get_send_flags(stream);
|
||||
flags |= FIN;
|
||||
tcp_mux_send_win_update(bout, flags, stream->id, 0);
|
||||
if (closed) {
|
||||
debug(LOG_DEBUG, "del proxy client %d", stream->id);
|
||||
del_proxy_client_by_stream_id(stream->id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
153
tcpmux.h
Normal file
153
tcpmux.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/* 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.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"
|
||||
|
||||
#define MAX_STREAM_WINDOW_SIZE 256*1024
|
||||
#define RBUF_SIZE 32*1024
|
||||
|
||||
struct ring_buffer {
|
||||
uint32_t cur;
|
||||
uint32_t end;
|
||||
uint32_t sz;
|
||||
uint8_t data[RBUF_SIZE];
|
||||
};
|
||||
|
||||
enum go_away_type {
|
||||
NORMAL,
|
||||
PROTO_ERR,
|
||||
INTERNAL_ERR,
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
struct tmux_stream {
|
||||
uint32_t id;
|
||||
uint32_t recv_window;
|
||||
uint32_t send_window;
|
||||
enum tcp_mux_state state;
|
||||
struct ring_buffer tx_ring;
|
||||
struct ring_buffer rx_ring;
|
||||
|
||||
// private arguments
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
typedef void (*handle_data_fn_t)(uint8_t *, int, void *);
|
||||
|
||||
void init_tmux_stream(struct tmux_stream *stream, uint32_t id, enum tcp_mux_state state);
|
||||
|
||||
int validate_tcp_mux_protocol(struct tcp_mux_header *tmux_hdr);
|
||||
|
||||
void send_window_update(struct bufferevent *bout, struct tmux_stream *stream, uint32_t length);
|
||||
|
||||
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_win_update_rst(struct bufferevent *bout, uint32_t stream_id);
|
||||
|
||||
void tcp_mux_send_data(struct bufferevent *bout, uint16_t flags, 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);
|
||||
|
||||
int handle_tcp_mux_stream(struct tcp_mux_header *tmux_hdr, handle_data_fn_t fn);
|
||||
|
||||
void handle_tcp_mux_ping(struct tcp_mux_header *tmux_hdr);
|
||||
|
||||
void handle_tcp_mux_go_away(struct tcp_mux_header *tmux_hdr);
|
||||
|
||||
uint32_t tmux_stream_write(struct bufferevent *bev, uint8_t *data, uint32_t length, struct tmux_stream *stream);
|
||||
|
||||
uint32_t tmux_stream_read(struct bufferevent *bev, struct tmux_stream *stream, uint32_t len);
|
||||
|
||||
void reset_session_id();
|
||||
|
||||
struct tmux_stream *get_cur_stream();
|
||||
|
||||
void set_cur_stream(struct tmux_stream *stream);
|
||||
|
||||
void add_stream(struct tmux_stream *stream);
|
||||
|
||||
void del_stream(uint32_t stream_id);
|
||||
|
||||
struct tmux_stream* get_stream_by_id(uint32_t id);
|
||||
|
||||
void tmux_stream_close(struct bufferevent *bout, struct tmux_stream *stream);
|
||||
|
||||
#endif
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef _VERSION_H_
|
||||
#define _VERSION_H_
|
||||
|
||||
#define VERSION "1.41.1"
|
||||
#define PROTOCOL_VERESION "0.41.0"
|
||||
#define VERSION "1.11.587"
|
||||
#define PROTOCOL_VERESION "0.43.0"
|
||||
#define CLIENT_V 1
|
||||
|
||||
#endif //_VERSION_H_
|
||||
|
||||
2
xfrpc.c
2
xfrpc.c
@@ -20,7 +20,7 @@
|
||||
\********************************************************************/
|
||||
|
||||
/** @file xfrpc.c
|
||||
@brief xfrp client
|
||||
@brief xfrpc client
|
||||
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
|
||||
*/
|
||||
|
||||
|
||||
4
xfrpc.h
4
xfrpc.h
@@ -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_
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
[common]
|
||||
server_addr = your_server_ip
|
||||
server_port = 7000
|
||||
token = 12345678
|
||||
|
||||
[ssh]
|
||||
type = tcp
|
||||
|
||||
Reference in New Issue
Block a user