47 Commits

Author SHA1 Message Date
KerwinKoo
acb79bcf1f don't using encrypt 2017-07-11 18:13:16 +08:00
KerwinKoo
75adc0a669 adjust source code 2017-07-11 18:08:31 +08:00
KerwinKoo
2ef0200276 adjust control.c 2017-07-11 17:27:32 +08:00
KerwinKoo
7940a4f949 update README 2017-07-11 11:04:28 +08:00
KerwinKoo
81779637ba update README for FTP proxy descript 2017-07-11 11:01:11 +08:00
KerwinKoo
91d6129426 add domain support for ftp
close #4
close #5
2017-07-10 19:32:21 +08:00
KerwinKoo
d333533639 do never use request buffer 2017-07-10 18:28:25 +08:00
KerwinKoo
2429f79721 add free_ftp_pasv after ftp change buffer 2017-07-10 14:01:18 +08:00
KerwinKoo
044626152c rewrite debug info 2017-07-10 09:50:38 +08:00
KerwinKoo
0d7643ceb1 finish ftp proxy support!! 2017-07-07 19:22:57 +08:00
KerwinKoo
0e581ebf6f do ftp proxy 2017-07-07 17:49:15 +08:00
KerwinKoo
2fcfa6a001 add get_ftp_data_proxy_name func 2017-07-07 15:42:14 +08:00
KerwinKoo
546dfb74d3 add commit 2017-07-07 15:13:23 +08:00
KerwinKoo
a02a5a19c7 add new_ftp_data_proxy_service func 2017-07-07 14:56:28 +08:00
KerwinKoo
09b67f7dc6 set code style 2017-07-07 13:45:21 +08:00
KerwinKoo
731584cbd3 fix debug 2017-07-07 13:41:35 +08:00
KerwinKoo
25a994213f do not support domain name for ftp proxy 2017-07-07 11:52:43 +08:00
KerwinKoo
c4a9f4c97e add is_valid_ip_address func in utils 2017-07-07 11:33:13 +08:00
KerwinKoo
a56d0d4d58 add try times when xfrps do connecting 2017-07-07 11:29:18 +08:00
KerwinKoo
9f01265981 finish ftp proxy 2017-07-07 11:22:30 +08:00
KerwinKoo
1e96d85f88 add remote_data_port in proxy check 2017-07-07 10:35:22 +08:00
KerwinKoo
a668a6deff using proxy instead of bufferevent 2017-07-07 10:31:20 +08:00
KerwinKoo
9ae47ffaa4 add new_proxy_buf define 2017-07-07 10:08:10 +08:00
KerwinKoo
8d1c6f69ca add ftp proxy but have not insert remote ip and port
need a method to insert port
2017-07-06 18:47:41 +08:00
KerwinKoo
4bcc36489b debug 2017-07-06 16:43:39 +08:00
KerwinKoo
e9e2bf759a debug 2017-07-06 16:30:12 +08:00
KerwinKoo
c6e3af8ac8 add pasv_pack func 2017-07-06 16:28:49 +08:00
KerwinKoo
5ab2ac455d remove msg field in pasv ftp 2017-07-06 16:00:44 +08:00
KerwinKoo
ddc3aff29b add ftp pasv_unpack func 2017-07-06 15:33:16 +08:00
KerwinKoo
8f75d7c40c modify argu name 2017-07-06 14:21:39 +08:00
KerwinKoo
3c02e4fbc4 add ftp support in proxy 2017-07-06 14:20:49 +08:00
KerwinKoo
5b2b3a63ab remove unused field in proxy_client struct 2017-07-05 20:33:42 +08:00
KerwinKoo
b96e3d9364 remove control_request struct
it's unused
2017-07-05 20:30:16 +08:00
KerwinKoo
f9636ce89c remove name field in proxy_client 2017-07-05 20:20:05 +08:00
KerwinKoo
c1b7585cd5 add is_ftp_proxy check 2017-07-05 18:41:49 +08:00
KerwinKoo
6f350a33d5 change binary name from xfrp_client to xfrpc 2017-07-05 15:24:45 +08:00
KerwinKoo
b3efc1087a remove unused filed in proxy_client struct 2017-07-05 10:00:23 +08:00
KerwinKoo
e57a99cf6a remove unused field in base_conf struct 2017-07-05 09:44:16 +08:00
KerwinKoo
571de7556d add assert after strdup 2017-07-04 17:08:33 +08:00
KerwinKoo
2ffa39e7cb reset heartbeat interval to 30s 2017-07-04 16:37:11 +08:00
KerwinKoo
1aba513a05 update config.c 2017-07-04 16:32:54 +08:00
KerwinKoo
5d0d1f105e update code 2017-07-04 16:29:21 +08:00
KerwinKoo
cb95f86b08 update code 2017-07-04 16:27:42 +08:00
KerwinKoo
7028aa3baa fix bug 9+16*x bits bug 2017-07-04 16:18:12 +08:00
KerwinKoo
94314af51a add declearation warnming in cmake 2017-07-04 10:56:24 +08:00
KerwinKoo
b587a2d30f add tcp_mux in send_msg_frp_server func 2017-07-04 10:53:39 +08:00
KerwinKoo
f2e482aa2e add ftp support check 2017-07-04 10:50:27 +08:00
25 changed files with 829 additions and 328 deletions

2
.gitignore vendored
View File

@@ -39,7 +39,7 @@ Makefile
cmake_install.cmake
# bin generated
xfrp_client
xfrpc
xfrp_test_server
bin
.vscode

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.6)
project(xfrp C)
set(src_xfrp_client
set(src_xfrpc
main.c
client.c
config.c
@@ -10,7 +10,7 @@ set(src_xfrp_client
frame.c
ini.c
msg.c
xfrp_client.c
xfrpc.c
debug.c
zip.c
commandline.c
@@ -20,6 +20,9 @@ set(src_xfrp_client
session.c
common.c
login.c
proxy_tcp.c
proxy_ftp.c
proxy.c
)
set(libs
@@ -34,11 +37,11 @@ set(test_libs
event
)
ADD_DEFINITIONS(-Wall -g --std=gnu99 -Wmissing-declarations)
ADD_DEFINITIONS(-Wall -g --std=gnu99)
add_executable(xfrp_client ${src_xfrp_client})
target_link_libraries(xfrp_client ${libs})
add_executable(xfrpc ${src_xfrpc})
target_link_libraries(xfrpc ${libs})
install(TARGETS xfrp_client
install(TARGETS xfrpc
RUNTIME DESTINATION bin
)

View File

@@ -25,9 +25,10 @@
## What is xfrp and why start xfrp
xfrp was [xfrps](https://github.com/KunTengRom/xfrp) client implemented by c for OpenWRT system
`xfrp` is [xfrps](https://github.com/KunTengRom/xfrp) client implemented by c for [OpenWRT](https://github.com/openwrt/openwrt) and [LEDE](https://github.com/lede-project/source) system
The motivation to start xfrp 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 xfrp project.
The motivation to start xfrp 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 xfrp project
## Compile
@@ -44,19 +45,48 @@ make
## Quick start
**before using xfrp, you should have built the proxy server: [xfrps](https://github.com/KunTengRom/xfrp), It's no difference with frp at usage, but support `FTP` and more embedded-client-friendly for linux.**
Run in debug mode :
```shell
xfrp_client -c frpc_mini.ini -f -d 7
xfrpc -c frpc_mini.ini -f -d 7
```
Run in release mode :
```shell
xfrp_client -c frpc_mini.ini -d 0
xfrpc -c frpc_mini.ini -d 0
```
## FTP support
xfrp support ftp proxy after version [0.07.451](https://github.com/KunTengRom/xfrp/tree/0.07.451). **Hypothesize you have built [xfrps](https://github.com/KunTengRom/xfrp) succeed!**
Configure ftp in frpc.ini
```
[common]
server_addr = 111.112.113.114
server_port = 7001
[router_ftp_example]
type = ftp
local_port = 21
remote_port = 30621
remote_data_port = 30622
```
`remote_port` is the reporxy port of FTP command tunnel, and `remote_data_port` is FTP-DATA port reporxy.
Use `-p` (PASV Mode) of `ftp` command to connect to proxy ftp server:
```
ftp -p 111.112.113.114 30621
```
In [Master](https://github.com/KunTengRom/xfrp) version `server_addr` can use domain name intead of IP address in FTP proxy. [Issue #4](https://github.com/KunTengRom/xfrp/issues/4) and [Issue #5](https://github.com/KunTengRom/xfrp/issues/5).
----
## Todo list

View File

@@ -52,8 +52,8 @@
#include "const.h"
#include "uthash.h"
#include "zip.h"
#include "msg.h"
#include "common.h"
#include "proxy.h"
#define MAX_OUTPUT (512*1024)
@@ -63,7 +63,8 @@ static void xfrp_event_cb(struct bufferevent *bev, short what, void *ctx);
static void
xfrp_read_cb(struct bufferevent *bev, void *ctx)
{
struct bufferevent *partner = ctx;
struct proxy *p = (struct proxy *)ctx;
struct bufferevent *partner = p?p->bev:NULL;
struct evbuffer *src, *dst;
size_t len;
src = bufferevent_get_input(bev);
@@ -74,13 +75,14 @@ xfrp_read_cb(struct bufferevent *bev, void *ctx)
}
dst = bufferevent_get_output(partner);
evbuffer_add_buffer(dst, src);
struct proxy *p_l = new_proxy_buf(bev);
if (evbuffer_get_length(dst) >= MAX_OUTPUT) {
/* We're giving the other side data faster than it can
* pass it on. Stop reading here until we have drained the
* other side to MAX_OUTPUT/2 bytes. */
bufferevent_setcb(partner, xfrp_read_cb, drained_writecb,
xfrp_event_cb, bev);
xfrp_event_cb, p_l);
bufferevent_setwatermark(partner, EV_WRITE, MAX_OUTPUT/2,
MAX_OUTPUT);
bufferevent_disable(bev, EV_READ);
@@ -90,11 +92,12 @@ xfrp_read_cb(struct bufferevent *bev, void *ctx)
static void
drained_writecb(struct bufferevent *bev, void *ctx)
{
struct bufferevent *partner = ctx;
struct proxy *p = (struct proxy *)ctx;
struct bufferevent *partner = p?p->bev:NULL;
/* We were choking the other side until we drained our outbuf a bit.
* Now it seems drained. */
bufferevent_setcb(bev, xfrp_read_cb, NULL, xfrp_event_cb, partner);
bufferevent_setcb(bev, xfrp_read_cb, NULL, xfrp_event_cb, p);
bufferevent_setwatermark(bev, EV_WRITE, 0, 0);
if (partner)
bufferevent_enable(partner, EV_READ);
@@ -113,13 +116,14 @@ close_on_finished_writecb(struct bufferevent *bev, void *ctx)
static void
xfrp_event_cb(struct bufferevent *bev, short what, void *ctx)
{
struct bufferevent *partner = ctx;
struct proxy *p = (struct proxy *)ctx;
struct bufferevent *partner = p?p->bev:NULL;
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
debug(LOG_DEBUG, "working connection closed");
debug(LOG_DEBUG, "working connection closed!");
if (partner) {
/* Flush all pending data */
xfrp_read_cb(bev, ctx);
xfrp_read_cb(bev, p);
if (evbuffer_get_length(bufferevent_get_output(partner))) {
/* We still have to flush data from the other
@@ -134,42 +138,41 @@ xfrp_event_cb(struct bufferevent *bev, short what, void *ctx)
/* We have nothing left to say to the other
* side; close it. */
bufferevent_free(partner);
free_proxy(p);
}
}
bufferevent_free(bev);
}
}
static void
xfrp_decrypt_cb(struct bufferevent *bev, void *ctx)
int is_ftp_proxy(const struct proxy_service *ps)
{
struct bufferevent *partner = ctx;
struct evbuffer *src, *dst;
src = bufferevent_get_input(bev);
dst = bufferevent_get_output(partner);
evbuffer_add_buffer(dst, src);
}
if (! ps || ! ps->proxy_type)
return 0;
static void
xfrp_encrypt_cb(struct bufferevent *bev, void *ctx)
{
struct bufferevent *partner = ctx;
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);
}
if (0 == strcmp(ps->proxy_type, "ftp") && ps->remote_data_port > 0)
return 1;
return 0;
}
// create frp tunnel for service
void start_frp_tunnel(struct proxy_client *client)
void start_xfrp_tunnel(struct proxy_client *client)
{
if (! client->ctl_bev) {
debug(LOG_ERR, "proxy client control bev is invalid!");
return;
}
struct event_base *base = client->base;
struct common_conf *c_conf = get_common_config();
struct proxy_service *ps = client->ps;
if (! base) {
debug(LOG_ERR, "service event base get failed");
return;
}
if (! ps) {
debug(LOG_ERR, "service tunnel started failed, no proxy service resource.");
return;
@@ -189,21 +192,34 @@ void start_frp_tunnel(struct proxy_client *client)
debug(LOG_DEBUG, "proxy server [%s:%d] <---> client [%s:%d]",
c_conf->server_addr,
c_conf->server_port,
ps->remote_port,
ps->local_ip ? ps->local_ip:"::1",
ps->local_port);
struct proxy *ctl_prox = new_proxy_buf(client->ctl_bev);
struct proxy *local_prox = new_proxy_buf(client->local_proxy_bev);
bufferevent_data_cb proxy_s2c_cb, proxy_c2s_cb;
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);
} else {
proxy_c2s_cb = tcp_proxy_c2s_cb;
proxy_s2c_cb = tcp_proxy_s2c_cb;
}
bufferevent_setcb(client->ctl_bev,
xfrp_decrypt_cb,
proxy_s2c_cb,
NULL,
xfrp_event_cb,
client->local_proxy_bev);
local_prox);
bufferevent_setcb(client->local_proxy_bev,
xfrp_encrypt_cb,
proxy_c2s_cb,
NULL,
xfrp_event_cb,
client->ctl_bev);
ctl_prox);
bufferevent_enable(client->ctl_bev, EV_READ|EV_WRITE);
bufferevent_enable(client->local_proxy_bev, EV_READ|EV_WRITE);
@@ -221,10 +237,7 @@ int send_client_data_tail(struct proxy_client *client)
void free_proxy_client(struct proxy_client *client)
{
if (client->name) free(client->name);
if (client->local_ip) free(client->local_ip);
if (client->custom_domains) free(client->custom_domains);
if (client->locations) free(client->locations);
free_base_config(client->bconf);
@@ -251,4 +264,11 @@ struct proxy_service *get_proxy_service(const char *proxy_name)
struct proxy_service *all_ps = get_all_proxy_services();
HASH_FIND_STR(all_ps, proxy_name, ps);
return ps;
}
struct proxy_client *new_proxy_client()
{
struct proxy_client *client = calloc(1, sizeof(struct proxy_client));
assert(client);
return client;
}

View File

@@ -43,22 +43,13 @@ struct proxy_client {
struct bufferevent *ctl_bev;
struct bufferevent *local_proxy_bev;
struct event *ev_timeout;
struct base_conf *bconf;
char *name; // pointer to bconf->name
char *local_ip;
char *type;
int local_port;
int remote_port;
int use_encryption;
int use_compression;
char *custom_domains;
char *subdomain;
char *locations;
char *host_header_rewrite;
char *http_user;
char *http_pwd;
//provate arguments
UT_hash_handle hh;
@@ -77,6 +68,7 @@ struct proxy_service {
char *local_ip;
int remote_port;
int remote_data_port;
int local_port;
// http and https only
@@ -96,7 +88,7 @@ struct proxy_service {
// when xfrp client receive that request, it will start
// frp tunnel
// if client has data-tail(not NULL), client value will be changed
void start_frp_tunnel(struct proxy_client *client);
void start_xfrp_tunnel(struct proxy_client *client);
void del_proxy_client(struct proxy_client *client);
@@ -106,4 +98,7 @@ struct proxy_service *get_proxy_service(const char *proxy_name);
int send_client_data_tail(struct proxy_client *client);
int is_ftp_proxy(const struct proxy_service *ps);
struct proxy_client *new_proxy_client();
#endif //_CLIENT_H_

View File

@@ -30,6 +30,7 @@
#include <string.h>
#include <signal.h>
#include <syslog.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -146,8 +147,7 @@ parse_commandline(int argc, char **argv)
case 'c':
if (optarg) {
confile = strdup(optarg); //never free it
if (! confile)
exit(0);
assert(confile);
flag = 1;
}

137
config.c
View File

@@ -38,12 +38,14 @@
#include "client.h"
#include "debug.h"
#include "msg.h"
#include "utils.h"
#include "version.h"
static struct common_conf *c_conf;
static struct proxy_client *p_clients;
static struct proxy_service *p_services;
static void new_ftp_data_proxy_service(struct proxy_service *ftp_ps);
struct common_conf *get_common_config()
{
@@ -61,17 +63,22 @@ void free_common_config()
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);
}
void free_base_config(struct base_conf *bconf)
{
if (bconf->name) free(bconf->name);
if (bconf->auth_token) free(bconf->auth_token);
if (bconf->type) free(bconf->type);
if (bconf->privilege_token) free(bconf->privilege_token);
if (bconf->host_header_rewrite) free(bconf->host_header_rewrite);
if (bconf->http_username) free(bconf->http_username);
if (bconf->http_password) free(bconf->http_password);
if (bconf->subdomain) free(bconf->subdomain);
}
@@ -102,7 +109,8 @@ static const char *get_valid_type(const char *val)
if (MATCH_VALUE("tcp") ||
MATCH_VALUE("http") ||
MATCH_VALUE("https") ||
MATCH_VALUE("udp")) { // will add ftp support in here
MATCH_VALUE("udp") ||
MATCH_VALUE("ftp")) {
return val;
}
@@ -112,7 +120,7 @@ static const char *get_valid_type(const char *val)
static void dump_common_conf()
{
if(!c_conf) {
if(! c_conf) {
debug(LOG_ERR, "Error: c_conf is NULL");
return;
}
@@ -133,6 +141,16 @@ static void dump_proxy_service(const int index, struct proxy_service *ps)
if (NULL == ps->proxy_type) {
ps->proxy_type = strdup("tcp");
assert(ps->proxy_type);
} else if (strcmp(ps->proxy_type, "ftp") == 0) {
if (ps->remote_data_port <= 0) {
debug(LOG_ERR,
"Proxy [%s] error: remote_data_port must be exist when type is ftp",
ps->proxy_name);
exit(0);
}
new_ftp_data_proxy_service(ps);
}
debug(LOG_DEBUG,
@@ -157,7 +175,8 @@ static struct proxy_service *new_proxy_service(const char *name)
{
if (! name)
return NULL;
struct proxy_service *ps = calloc(sizeof(struct proxy_service), 1);
struct proxy_service *ps = (struct proxy_service *)calloc(sizeof(struct proxy_service), 1);
assert(ps);
assert(c_conf);
@@ -168,6 +187,7 @@ static struct proxy_service *new_proxy_service(const char *name)
ps->use_encryption = 0;
ps->local_port = -1;
ps->remote_port = -1;
ps->remote_data_port = -1;
ps->use_compression = 0;
ps->use_encryption = 0;
@@ -181,28 +201,53 @@ static struct proxy_service *new_proxy_service(const char *name)
return ps;
}
// create a new proxy service with suffix "_ftp_data_proxy"
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);
if (!ps) {
ps = new_proxy_service(ftp_data_proxy_name);
if (! ps) {
debug(LOG_ERR,
"cannot create ftp data proxy service, it should not happenned!");
exit(0);
}
ps->proxy_type = strdup("tcp");
ps->remote_port = ftp_ps->remote_data_port;
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);
}
free(ftp_data_proxy_name);
}
static int
proxy_service_handler(void *user, const char *sect, const char *nm, const char *value)
{
struct proxy_service *ps = NULL;
char *section = NULL;
section = strdup(sect);
assert(section);
if (strlen(sect) == 25) {//fix proxy name length = 25 bug, not find the reason
section = calloc(1, 26);
memset(section, '_', 26);
memcpy(section, sect, 25);
} else {
section = strdup(sect);
}
if (strcmp(section, "common") == 0)
if (strcmp(section, "common") == 0) {
SAFE_FREE(section);
return 0;
}
HASH_FIND_STR(p_services, section, ps);
if (!ps) {
ps = new_proxy_service(section);
assert(ps);
if (! ps) {
debug(LOG_ERR, "cannot create proxy service, it should not happenned!");
exit(0);
}
HASH_ADD_KEYPTR(hh, p_services, ps->proxy_name, strlen(ps->proxy_name), ps);
}
@@ -213,36 +258,47 @@ proxy_service_handler(void *user, const char *sect, const char *nm, const char *
if (MATCH_NAME("type")) {
if (! get_valid_type(value)) {
debug(LOG_ERR, "proxy service type %s is not supportted", value);
SAFE_FREE(section);
exit(0);
}
ps->proxy_type = strdup(value);
assert(ps->proxy_type);
} else if (MATCH_NAME("local_ip")) {
ps->local_ip = strdup(value);
assert(ps->local_ip);
} else if (MATCH_NAME("local_port")) {
ps->local_port = atoi(value);
} else if (MATCH_NAME("use_encryption")) {
ps->use_encryption = is_true(value);
} else if (MATCH_NAME("remote_port")) {
ps->remote_port = atoi(value);
} else if (MATCH_NAME("remote_data_port")) {
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);
ps->subdomain = strdup(value);
assert(ps->http_pwd);
} else if (MATCH_NAME("custom_domains")) {
ps->custom_domains= strdup(value);
ps->custom_domains = strdup(value);
assert(ps->custom_domains);
} else if (MATCH_NAME("locations")) {
ps->locations= strdup(value);
ps->locations = strdup(value);
assert(ps->locations);
} else if (MATCH_NAME("host_header_rewrite")) {
ps->host_header_rewrite= strdup(value);
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")) {
ps->use_compression = TO_BOOL(value);
}
free(section);
SAFE_FREE(section);
return 1;
}
@@ -254,25 +310,31 @@ static int common_handler(void *user, const char *section, const char *name, con
if (MATCH("common", "server_addr")) {
SAFE_FREE(config->server_addr);
config->server_addr = strdup(value);
assert(config->server_addr);
} 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")) {
@@ -280,9 +342,11 @@ static int common_handler(void *user, const char *section, const char *name, con
} else if (MATCH("common", "auth_token")) {
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
}
@@ -295,20 +359,43 @@ static void init_common_conf(struct common_conf *config)
return;
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 = 10;
config->heartbeat_timeout = 30;
config->heartbeat_interval = 30;
config->heartbeat_timeout = 60;
config->tcp_mux = 0;
config->user = NULL;
config->server_ip = NULL;
}
// it should be free after using
// because of assert it will never return NULL
char *get_ftp_data_proxy_name(const char *ftp_proxy_name)
{
char *ftp_tail_data_name = FTP_DATA_PROXY_SUFFIX;
char *ftp_data_proxy_name = (char *)calloc(1,
strlen(ftp_proxy_name)+strlen(ftp_tail_data_name)+1);
assert(ftp_data_proxy_name);
snprintf(ftp_data_proxy_name,
strlen(ftp_proxy_name) + strlen(ftp_tail_data_name) + 1,
"%s%s",
ftp_proxy_name,
ftp_tail_data_name);
return ftp_data_proxy_name;
}
void load_config(const char *confile)
{
c_conf = calloc(sizeof(struct common_conf), 1);
c_conf = (struct common_conf *)calloc(sizeof(struct common_conf), 1);
assert(c_conf);
init_common_conf(c_conf);

View File

@@ -29,24 +29,24 @@
#include "client.h"
#include "common.h"
#define FTP_DATA_PROXY_SUFFIX "_ftp_data_proxy"
struct base_conf{
char *name;
char *auth_token;
char *type;
int use_encryption;
int use_gzip;
int privilege_mode;
char *privilege_token;
int pool_count;
char *host_header_rewrite;
char *http_username;
char *http_password;
char *subdomain;
};
// 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 */
@@ -71,5 +71,7 @@ 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);
#endif //_CONFIG_H_

331
control.c
View File

@@ -29,13 +29,11 @@
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <json-c/json.h>
#include <syslog.h>
#include <pthread.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
@@ -61,7 +59,6 @@
#include "login.h"
static struct control *main_ctl;
static char *request_buf;
static int clients_conn_signel = 0;
static void sync_new_work_connection(struct bufferevent *bev);
@@ -72,13 +69,6 @@ static int is_client_connected()
return clients_conn_signel;
}
static void init_request_buffer()
{
size_t len = (1<<16) + get_header_size();
request_buf = calloc(1, len);
assert(request_buf);
}
static int client_connected(int is_connected)
{
if (is_connected)
@@ -91,16 +81,17 @@ static int client_connected(int is_connected)
static int set_client_work_start(struct proxy_client *client, int is_start_work)
{
if (is_start_work)
if (is_start_work) {
assert(client->ps);
client->work_started = 1;
else
}else
client->work_started = 0;
return client->work_started;
}
static int is_client_work_started(struct proxy_client *client) {
return client->work_started;
return client->work_started && client->ps;
}
static void client_start_event_cb(struct bufferevent *bev, short what, void *ctx)
@@ -122,14 +113,13 @@ static void client_start_event_cb(struct bufferevent *bev, short what, void *ctx
bufferevent_setcb(bev, recv_cb, NULL, client_start_event_cb, client);
bufferevent_enable(bev, EV_READ|EV_WRITE);
sync_new_work_connection(bev);
debug(LOG_INFO, "proxy service connected");
debug(LOG_INFO, "proxy service start");
}
}
static void new_client_connect()
{
struct proxy_client *client = calloc(1, sizeof(struct proxy_client)); //NEED FREE
assert(client);
struct proxy_client *client = new_proxy_client();
struct common_conf *c_conf = get_common_config();
assert(c_conf);
client->base = main_ctl->connect_base;;
@@ -196,78 +186,21 @@ static size_t request(struct bufferevent *bev, struct frame *f)
bout = main_ctl->connect_bev;
}
if ( ! bout) {
goto REQ_END;
}
// #define DEV_DEBUG 1
#ifdef DEV_DEBUG
/* debug showing */
debug(LOG_DEBUG, "send request byte:");
unsigned int i = 0;
if (f->len) {
printf("[");
for(i = 0; i<f->len; i++) {
printf("%u ", f->data[i]);
}
printf("]\n");
}
#endif // DEV_DEBUG
if ( ! bout)
return 0;
struct common_conf *c = get_common_config();
if ( ! c)
goto REQ_END;
int headersize = get_header_size();
size_t len = (1<<16) + headersize;
memset(request_buf, 0, len);
if (c->tcp_mux) {
request_buf[VERI] = f->ver;
request_buf[CMDI] = f->cmd;
*((ushort *)(request_buf + 2)) = f->len;
*((uint32_t *)(request_buf + 4)) = f->sid;
// insert data to request buffer
if (f->data != NULL && f->len > 0) { //TODO: ENCODE when control
memcpy(request_buf + DATAI, f->data, f->len);
}
write_len = (size_t) (headersize + f->len);
} else {
memcpy(request_buf, f->data, f->len);
write_len = (size_t)f->len;
}
return 0;
write_len = (size_t)f->len;
if ( 0 == write_len)
goto REQ_END;;
return 0;
bufferevent_write(bout, request_buf, write_len);
memset(request_buf, 0, len);
REQ_END:
bufferevent_write(bout, f->data, write_len);
return write_len;
}
void control_request_free(struct control_request *req)
{
if (!req)
return;
if (req->proxy_name) free(req->proxy_name);
if (req->auth_key) free(req->auth_key);
if (req->privilege_key) free(req->privilege_key);
if (req->proxy_type) free(req->proxy_type);
if (req->custom_domains) free(req->custom_domains);
if (req->locations) free(req->locations);
if (req->host_header_rewrite) free(req->host_header_rewrite);
if (req->http_username) free(req->http_username);
if (req->http_password) free(req->http_password);
if (req->subdomain) free(req->subdomain);
free(req);
}
static void base_control_ping(struct bufferevent *bev) {
if ( ! is_client_connected())
return;
@@ -310,6 +243,7 @@ static void ping(struct bufferevent *bev)
struct frame *f = new_frame(cmdNOP, 0); //ping sid is 0
assert(f);
request(bout, f);
free_frame(f);
}
uint32_t sid = get_main_control()->session_id;
@@ -424,7 +358,7 @@ raw_message(struct message *msg, struct bufferevent *bev, struct proxy_client *c
{
if (client) {
if (client->work_started) {
debug(LOG_DEBUG, "raw client [%s] control message.", client->name);
debug(LOG_DEBUG, "raw client [%s] control message.", client->ps->proxy_name);
}
}
@@ -490,14 +424,13 @@ raw_message(struct message *msg, struct bufferevent *bev, struct proxy_client *c
}
client->ps = ps;
client->name = ps->proxy_name;
debug(LOG_INFO,
"proxy service [%s] [%s:%d] start work connection.",
sr->proxy_name,
ps->local_ip,
ps->local_port);
start_frp_tunnel(client);
start_xfrp_tunnel(client);
set_client_work_start(client, 1);
break;
case TypePong:
@@ -513,7 +446,8 @@ static size_t data_handler(unsigned char *buf, ushort len, struct proxy_client *
{
struct bufferevent *bev = NULL;
if (client) {
debug(LOG_DEBUG, "client [name:%s] recved control data", client->name);
debug(LOG_DEBUG, "client(%s): recved control data",
is_client_work_started(client)?"work":"free");
bev = client->ctl_bev;
}
unsigned char *ret_buf = NULL;
@@ -671,7 +605,7 @@ static unsigned char
if (is_client_work_started(client)) {
debug(LOG_DEBUG,
"client [%s] send all work data to proxy tunnel.",
client->name);
client->ps->proxy_name);
return NULL;
}
}
@@ -680,8 +614,6 @@ static unsigned char
if (buf_len > split_lv) {
if (! is_logged()) {
if (buf[0] == 49) {
debug(LOG_DEBUG, "mulity raw login-response...");
msg_size_t data_len_bigend;
data_len_bigend = *(msg_size_t *)(buf + MSG_LEN_I);
msg_size_t data_len = msg_ntoh(data_len_bigend);
@@ -769,7 +701,6 @@ static void recv_cb(struct bufferevent *bev, void *ctx)
if (read_n) {
unsigned char *raw_buf_p = buf;
for( ; raw_buf_p && read_n ; ) {
// #define CONN_DEBUG 1
#ifdef CONN_DEBUG
unsigned int i = 0;
@@ -778,7 +709,7 @@ static void recv_cb(struct bufferevent *bev, void *ctx)
for(i = 0; i<read_n && ((2 * i) < (read_n * 2 + 1)); i++) {
snprintf(dbg_buf + 4*i, 5, "%3u ", (unsigned char)raw_buf_p[i]);
}
debug(LOG_DEBUG, "[%s]: RECV ctl byte:%s", client ? "client":"control", dbg_buf);
debug(LOG_DEBUG, "[%s]: RECV ctl byte:%s", client?"client":"control", dbg_buf);
SAFE_FREE(dbg_buf);
#endif //CONN_DEBUG
@@ -814,14 +745,26 @@ static void open_connection_session(struct bufferevent *bev)
{
struct frame *f = new_frame(cmdSYN, main_ctl->session_id);
assert(f);
request(bev, f);
free_frame(f);
}
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;
if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
debug(LOG_ERR, "connect server [%s:%d] failed",
if (retry_times >= 10) { // only try 10 times consecutively
debug(LOG_ERR,
"have retry connect to xfrp server for %d times, exit!",
retry_times);
exit(0);
}
retry_times++;
debug(LOG_ERR, "error: connect server [%s:%d] failed",
c_conf->server_addr,
c_conf->server_port);
free_control();
@@ -829,11 +772,15 @@ static void connect_event_cb (struct bufferevent *bev, short what, void *ctx)
start_base_connect();
close_main_control();
} else if (what & BEV_EVENT_CONNECTED) {
// recv frpc login-response message before recv othfer fprs messages,
retry_times = 0;
// recv login-response message before recving othfer fprs messages,
bufferevent_setcb(bev, recv_cb, NULL, connect_event_cb, NULL);
bufferevent_enable(bev, EV_READ|EV_WRITE|EV_PERSIST);
open_connection_session(bev);
if (get_common_config()->tcp_mux)
open_connection_session(bev);
login();
}
}
@@ -850,16 +797,42 @@ static void keep_control_alive()
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(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);
}
evutil_freeaddrinfo(addr);
}
}
void start_base_connect()
{
struct common_conf *c_conf = get_common_config();
assert(c_conf);
main_ctl->connect_bev = connect_server(main_ctl->connect_base,
c_conf->server_addr,
c_conf->server_port);
c_conf->server_addr,
c_conf->server_port);
if ( ! main_ctl->connect_bev) {
debug(LOG_ERR, "Connect server [%s:%d] failed", c_conf->server_addr, c_conf->server_port);
debug(LOG_ERR,
"error: connect server [%s:%d] failed",
c_conf->server_addr,
c_conf->server_port);
exit(0);
}
@@ -872,6 +845,7 @@ void sync_iv(unsigned char *iv)
{
struct frame *f = new_frame(cmdPSH, main_ctl->session_id);
assert(f);
f->len = (ushort) get_encrypt_block_size();
f->data = calloc(f->len, 1);
memcpy(f->data, iv, f->len);
@@ -891,14 +865,15 @@ void login()
char *lg_msg = NULL;
int len = login_request_marshal(&lg_msg); //marshal login request
if ( ! lg_msg || ! len) {
debug(LOG_ERR, "login_request_marshal failed");
assert(lg_msg);
debug(LOG_ERR,
"error: login_request_marshal failed, it should never be happenned");
exit(0);
}
if (get_common_config()->tcp_mux) {
// using sid = 3 is only for matching fprs, it will change after using tcp-mux
// using sid = 3 is only for matching fprs, it will change after using tcp-mux
if (get_common_config()->tcp_mux)
sync_session_id(3);
}
send_msg_frp_server(NULL, TypeLogin, lg_msg, len, main_ctl->session_id);
SAFE_FREE(lg_msg);
}
@@ -925,10 +900,8 @@ void send_msg_frp_server(struct bufferevent *bev,
} else {
bout = main_ctl->connect_bev;
}
assert(bout);
if ( ! bout) {
return;
}
debug(LOG_DEBUG, "send ----> [%c: %s]", type, msg);
struct message req_msg;
@@ -936,75 +909,51 @@ void send_msg_frp_server(struct bufferevent *bev,
req_msg.type = type;
req_msg.data_len = msg_len;
if (msg) {
req_msg.data_p = strdup(msg);
}
unsigned char *puck_buf = NULL;
size_t pack_buf_len = pack(&req_msg, &puck_buf);
if ( ! pack_buf_len || ! puck_buf) {
debug(LOG_ERR, "login buffer pack failed!");
return;
}
// #define SEND_MSG_DEBUG 1
#ifdef SEND_MSG_DEBUG
debug(LOG_DEBUG, "puck result:");
size_t j = 0;
for(j=0; j<pack_buf_len; j++) {
printf("%d ", (unsigned char)puck_buf[j]);
}
printf("\n\n");
#endif // SEND_MSG_DEBUG
char frame_type = 0;
struct frame *f = NULL;
f = new_frame(frame_type, sid); // frame_type not truely matter, it will reset by set_frame_cmd
// frame_type not truely matter, it will reset by set_frame_cmd
f = new_frame(frame_type, sid);
assert(f);
#ifdef ENCRYPTO
debug(LOG_DEBUG, "start encode message ...");
unsigned char *encode_ret;
unsigned char *encode_ret_test;
unsigned char *decode_ret_test;
struct frp_coder *encoder = get_main_encoder();
if (encoder) {
size_t encode_ret_len = encrypt_data(puck_buf, pack_buf_len, encoder, &encode_ret);
debug(LOG_DEBUG, "encode len:[%lu]", encode_ret_len);
if (encode_ret_len > 0) {
f->data = encode_ret;
set_frame_len(f, (ushort) encode_ret_len);
}
set_frame_len(f, (ushort) pack_buf_len);
if (msg) {
req_msg.data_p = strdup(msg);
assert(req_msg.data_p);
}
#endif //ENCRYPTO
if (! f->data) {
set_frame_len(f, (ushort) pack_buf_len);
f->data = puck_buf;
unsigned char *pack_buf = NULL;
size_t pack_buf_len = pack(&req_msg, &pack_buf);
if ( ! pack_buf_len || ! pack_buf) {
debug(LOG_ERR, "error: send buffer pack failed!");
goto S_M_F_END;
}
set_frame_len(f, (ushort) pack_buf_len);
f->data = pack_buf;
if (get_common_config()->tcp_mux) {
switch (type)
{
case TypeLogin:
case TypePong:
case TypePing:
case TypeNewProxy:
frame_type = cmdPSH;
break;
default:
break;
}
} else {
frame_type = cmdPSH;
}
switch (type)
{
case TypeLogin:
case TypePong:
case TypePing:
case TypeNewProxy:
frame_type = cmdPSH;
break;
default:
break;
}
set_frame_cmd(f, frame_type);
request(bout, f);
S_M_F_END:
SAFE_FREE(req_msg.data_p);
SAFE_FREE(puck_buf);
SAFE_FREE(pack_buf);
f->data = NULL;
free_frame(f);
}
@@ -1017,13 +966,18 @@ struct control *get_main_control()
void start_login_frp_server(struct event_base *base)
{
struct common_conf *c_conf = get_common_config();
struct bufferevent *bev = connect_server(base, c_conf->server_addr, c_conf->server_port);
struct bufferevent *bev = connect_server(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);
debug(LOG_DEBUG,
"Connect server [%s:%d] failed",
c_conf->server_addr,
c_conf->server_port);
return;
}
debug(LOG_INFO, "Xfrpc login: connect server [%s:%d] ......", c_conf->server_addr, c_conf->server_port);
debug(LOG_INFO, "Xfrpc login: connect server [%s:%d] ...", c_conf->server_addr, c_conf->server_port);
bufferevent_enable(bev, EV_WRITE|EV_READ);
bufferevent_setcb(bev, NULL, NULL, connect_event_cb, NULL);
@@ -1050,20 +1004,26 @@ void send_new_proxy(struct proxy_service *ps)
void init_main_control()
{
if (main_ctl && main_ctl->connect_base)
if (main_ctl && main_ctl->connect_base) {
event_base_loopbreak(main_ctl->connect_base);
free(main_ctl);
}
main_ctl = calloc(sizeof(struct control), 1);
assert(main_ctl);
struct event_base *base = NULL;
struct evdns_base *dnsbase = NULL;
base = event_base_new();
if (!base)
return;
if (! base) {
debug(LOG_ERR, "error: event base init failed!");
exit(0);
}
dnsbase = evdns_base_new(base, 1);
if (!dnsbase)
return;
if (! dnsbase) {
debug(LOG_ERR, "error: evdns base init failed!");
exit(0);
}
evdns_base_set_option(dnsbase, "timeout", "1.0");
@@ -1077,15 +1037,39 @@ void init_main_control()
main_ctl->connect_base = base;
main_ctl->dnsbase = dnsbase;
init_request_buffer();
if (get_common_config()->tcp_mux) {
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);
}
// 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
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);
}
}
void close_main_control()
@@ -1107,6 +1091,5 @@ void free_control()
if (!main_ctl)
return;
SAFE_FREE(request_buf);
SAFE_FREE(main_ctl);
}

View File

@@ -70,6 +70,4 @@ void send_new_proxy(struct proxy_service *ps);
struct bufferevent
*connect_server(struct event_base *base, const char *name, const int port);
void control_request_free(struct control_request *req);
#endif //_CONTROL_H_

View File

@@ -31,8 +31,10 @@ struct frp_coder *new_coder(const char *privilege_token, const char *salt)
assert(enc);
enc->privilege_token = privilege_token ? strdup(privilege_token):"\0";
assert(enc->privilege_token);
enc->key_len = block_size;
enc->salt = strdup(salt);
assert(enc->salt);
enc->key = encrypt_key(enc->privilege_token, strlen(enc->privilege_token), enc->salt);
enc->iv = calloc(block_size, 1);
encrypt_iv(enc->iv, block_size);

View File

@@ -20,6 +20,7 @@ struct frame *new_frame(char cmd, uint32_t sid) {
f->cmd = cmd;
f->sid = sid;
f->len = 0;
f->data = NULL;
}
return f;
@@ -34,7 +35,7 @@ struct frame *raw_frame(unsigned char *buf, const size_t buf_len)
}
char ver = buf[VERI];
char cmd = buf[CMDI];
uint32_t sid = *(uint32_t *)(buf + SIDI);
uint32_t sid = htonl(*(uint32_t *)(buf + SIDI));
struct frame *f = new_frame(cmd, sid);
f->ver = ver;

View File

@@ -1,2 +1,2 @@
/usr/bin/xfrp_client
/usr/bin/xfrpc
/usr/bin/xfrp_test_server

15
login.c
View File

@@ -37,6 +37,7 @@ void init_login()
{
if (! c_login)
c_login = calloc(sizeof(struct login), 1);
assert(c_login);
struct common_conf *c_conf = get_common_config();
@@ -48,9 +49,12 @@ void init_login()
}
c_login->version = strdup(PROTOCOL_VERESION);
assert(c_login->version);
c_login->hostname = NULL;
c_login->os = strdup(uname_buf.sysname);
c_login->os = strdup(uname_buf.sysname);
assert(c_login->os);
c_login->arch = strdup(uname_buf.machine);
assert(c_login->arch);
c_login->user = NULL;
c_login->timestamp = 0;
@@ -64,11 +68,6 @@ void init_login()
int login_resp_check(struct login_resp *lr)
{
debug(LOG_DEBUG, "xfrp login response: run_id: [%s], version: [%s], error: [%s]",
lr->run_id,
lr->version,
lr->error);
if (lr->run_id == NULL || strlen(lr->run_id) <= 1) {
if (lr->error && strlen(lr->error) > 0) {
debug(LOG_ERR, "login response error: %s", lr->error);
@@ -77,9 +76,13 @@ int login_resp_check(struct login_resp *lr)
c_login->logged = 0;
} else {
c_login->logged = 1;
debug(LOG_DEBUG, "xfrp login response: run_id: [%s], version: [%s]",
lr->run_id,
lr->version);
SAFE_FREE(c_login->run_id);
c_login->run_id = strdup(lr->run_id);
assert(c_login->run_id);
}
return c_login->logged;

4
main.c
View File

@@ -24,7 +24,7 @@
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
*/
#include "xfrp_client.h"
#include "xfrpc.h"
#include "commandline.h"
#include "login.h"
@@ -32,5 +32,5 @@ int main(int argc, char **argv)
{
parse_commandline(argc, argv);
init_login();
xfrp_client_loop();
xfrpc_loop();
}

46
msg.c
View File

@@ -41,6 +41,7 @@
#include "debug.h"
#include "common.h"
#include "login.h"
#include "client.h"
#define JSON_MARSHAL_TYPE(jobj,key,jtype,item) \
json_object_object_add(jobj, key, json_object_new_##jtype((item)));
@@ -75,6 +76,7 @@ static void fill_custom_domains(struct json_object *j_ctl_req, const char *custo
struct json_object *jarray_cdomains = json_object_new_array();
assert(jarray_cdomains);
char *tmp = strdup(custom_domains);
assert(tmp);
char *tok = tmp, *end = tmp;
while (tok != NULL) {
strsep(&end, ",");
@@ -133,6 +135,7 @@ size_t login_request_marshal(char **msg)
struct common_conf *cf = get_common_config();
char *auth_key = get_auth_key(cf->privilege_token, &lg->timestamp);
lg->privilege_key = strdup(auth_key);
assert(lg->privilege_key);
JSON_MARSHAL_TYPE(j_login_req, "version", string, lg->version);
JSON_MARSHAL_TYPE(j_login_req, "hostname", string, SAFE_JSON_STRING(lg->hostname));
@@ -150,6 +153,7 @@ size_t login_request_marshal(char **msg)
if (tmp && strlen(tmp) > 0) {
nret = strlen(tmp);
*msg = strdup(tmp);
assert(*msg);
}
json_object_put(j_login_req);
SAFE_FREE(auth_key);
@@ -170,6 +174,10 @@ int new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
JSON_MARSHAL_TYPE(j_np_req, "use_compression", boolean, np_req->use_compression);
JSON_MARSHAL_TYPE(j_np_req, "remote_port", int, np_req->remote_port);
if (is_ftp_proxy(np_req)) {
JSON_MARSHAL_TYPE(j_np_req, "remote_data_port", int, np_req->remote_data_port);
}
if (np_req->custom_domains) {
fill_custom_domains(j_np_req, np_req->custom_domains);
} else {
@@ -193,6 +201,7 @@ int new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
if (tmp && strlen(tmp) > 0) {
nret = strlen(tmp);
*msg = strdup(tmp);
assert(*msg);
}
json_object_put(j_np_req);
@@ -212,6 +221,7 @@ int new_work_conn_marshal(const struct work_conn *work_c, char **msg)
if (tmp && strlen(tmp) > 0) {
nret = strlen(tmp);
*msg = strdup(tmp);
assert(*msg);
}
json_object_put(j_new_work_conn);
@@ -227,25 +237,25 @@ struct login_resp *login_resp_unmarshal(const char *jres)
return NULL;
struct login_resp *lr = calloc(1, sizeof(struct login_resp));
if (lr == NULL) {
goto END_ERROR;
}
assert(lr);
struct json_object *l_version = NULL;
if (! json_object_object_get_ex(j_lg_res, "version", &l_version))
goto END_ERROR;
lr->version = strdup(json_object_get_string(l_version));
assert(lr->version);
struct json_object *l_run_id = NULL;
if (! json_object_object_get_ex(j_lg_res, "run_id", &l_run_id))
goto END_ERROR;
lr->run_id = strdup(json_object_get_string(l_run_id));
assert(lr->run_id);
struct json_object *l_error = NULL;
if(! json_object_object_get_ex(j_lg_res, "error", &l_error))
goto END_ERROR;
lr->error = strdup(json_object_get_string(l_error));
assert(lr->error);
END_ERROR:
json_object_put(j_lg_res);
@@ -259,13 +269,14 @@ struct start_work_conn_resp *start_work_conn_resp_unmarshal(const char *resp_msg
return NULL;
struct start_work_conn_resp *sr = calloc(1, sizeof(struct start_work_conn_resp));
if (! sr)
goto START_W_C_R_END;
assert(sr);
struct json_object *pn = NULL;
if(! json_object_object_get_ex(j_start_w_res, "proxy_name", &pn))
goto START_W_C_R_END;
sr->proxy_name = strdup(json_object_get_string(pn));
assert(sr->proxy_name);
START_W_C_R_END:
json_object_put(j_start_w_res);
@@ -278,9 +289,7 @@ struct control_response *control_response_unmarshal(const char *jres)
if (is_error(j_ctl_res))
return NULL;
struct control_response *ctl_res = calloc(sizeof(struct control_response), 1);
if (ctl_res == NULL) {
goto END_ERROR;
}
assert(ctl_res);
struct json_object *jtype = NULL;
if(! json_object_object_get_ex(j_ctl_res, "type", &jtype))
@@ -293,9 +302,11 @@ struct control_response *control_response_unmarshal(const char *jres)
ctl_res->code = json_object_get_int(jcode);
struct json_object *jmsg = NULL;
if(json_object_object_get_ex(j_ctl_res, "msg", &jmsg))
if(json_object_object_get_ex(j_ctl_res, "msg", &jmsg)) {
ctl_res->msg = strdup(json_object_get_string(jmsg));
assert(ctl_res->msg);
}
END_ERROR:
json_object_put(j_ctl_res);
return ctl_res;
@@ -357,20 +368,13 @@ size_t pack(struct message *req_msg, unsigned char **ret_buf)
else
data_len_bigend = req_msg->data_len;
size_t buf_len = TYPE_LEN + sizeof(data_len_bigend) + req_msg->data_len;
*ret_buf = calloc(buf_len, 1);
if (*ret_buf == NULL) {
return 0;
}
*ret_buf = calloc(1, buf_len);
assert(*ret_buf);
*(*ret_buf + MSG_TYPE_I) = req_msg->type;
*(msg_size_t *)(*ret_buf + MSG_LEN_I) = data_len_bigend;
snprintf((char *)*ret_buf + TYPE_LEN + sizeof(data_len_bigend),
req_msg->data_len + 1,
"%s",
req_msg->data_p);
memcpy((char *)*ret_buf+TYPE_LEN+sizeof(data_len_bigend), req_msg->data_p, req_msg->data_len);
return buf_len;
}

24
msg.h
View File

@@ -61,29 +61,6 @@ struct general_response {
char *msg;
};
// messages between control connections of frpc and frps
struct control_request {
int type;
char *proxy_name;
char *auth_key;
int use_encryption;
int use_gzip;
int pool_count;
int privilege_mode;
char *privilege_key;
char *proxy_type;
int remote_port;
char *custom_domains;
char *locations;
char *host_header_rewrite;
char *http_username;
char *http_password;
char *subdomain;
long timestamp;
};
struct control_response {
int type;
int code;
@@ -114,7 +91,6 @@ size_t pack(struct message *req_msg, unsigned char **ret_buf);
struct message *unpack(unsigned char *recv_msg, const ushort len);
// tranlate control request to json string
int control_request_marshal(const struct control_request *req, char **msg);
struct login_resp *login_resp_unmarshal(const char *jres);
struct start_work_conn_resp *start_work_conn_resp_unmarshal(const char *resp_msg);

36
proxy.c Normal file
View File

@@ -0,0 +1,36 @@
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#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"
#include "common.h"
#include "proxy.h"
#include "config.h"
struct proxy *new_proxy_buf(struct bufferevent *bev)
{
struct proxy *p = (struct proxy *)calloc(1, sizeof(struct proxy));
assert(p);
p->bev = bev;
p->remote_data_port = -1;
p->proxy_name = NULL;
return p;
}
void free_proxy(struct proxy *p)
{
SAFE_FREE(p->proxy_name);
SAFE_FREE(p);
}

37
proxy.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef _PROXY_H_
#define _PROXY_H_
#include <stdint.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include <event2/util.h>
#include <event2/event.h>
#include "client.h"
#include "common.h"
#define IP_LEN 16
struct ftp_pasv {
int code;
char ftp_server_ip[IP_LEN];
int ftp_server_port;
};
struct proxy {
struct bufferevent *bev;
char *proxy_name;
int remote_data_port; //used in ftp proxy
};
void tcp_proxy_c2s_cb(struct bufferevent *bev, void *ctx);
void tcp_proxy_s2c_cb(struct bufferevent *bev, void *ctx);
void ftp_proxy_c2s_cb(struct bufferevent *bev, void *ctx);
void ftp_proxy_s2c_cb(struct bufferevent *bev, void *ctx);
struct proxy *new_proxy_buf(struct bufferevent *bev);
void free_proxy(struct proxy *p);
void set_ftp_data_proxy_tunnel(const char *ftp_proxy_name,
struct ftp_pasv *local_fp,
struct ftp_pasv *remote_fp);
#endif //_PROXY_H_

267
proxy_ftp.c Normal file
View File

@@ -0,0 +1,267 @@
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#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"
#include "common.h"
#include "proxy.h"
#include "config.h"
#include "client.h"
#define FTP_PRO_BUF 256
#define FTP_PASV_PORT_BLOCK 256
static struct ftp_pasv *new_ftp_pasv();
static void free_ftp_pasv(struct ftp_pasv *fp);
static struct ftp_pasv * pasv_unpack(char *data);
static size_t pasv_pack(struct ftp_pasv *fp, char **pack_p);
void set_ftp_data_proxy_tunnel(const char *ftp_proxy_name,
struct ftp_pasv *local_fp,
struct ftp_pasv *remote_fp)
{
struct proxy_service *ps = NULL;
char *ftp_data_proxy_name = get_ftp_data_proxy_name(ftp_proxy_name);
struct proxy_service *p_services = get_all_proxy_services();
HASH_FIND_STR(p_services, ftp_data_proxy_name, ps);
if (!ps) {
debug(LOG_ERR,
"error: ftp data proxy not inserted in proxy-service queue, it should not happend!");
goto FTP_DATA_PROXY_TUNNEL_END;
}
ps->local_port = local_fp->ftp_server_port;
ps->local_ip = strdup(local_fp->ftp_server_ip);
assert(ps->local_ip);
ps->remote_port = remote_fp->ftp_server_port;
debug(LOG_DEBUG,
"set ftp proxy DATA port [local:remote] = [%d:%d]",
ps->local_port, ps->remote_port);
FTP_DATA_PROXY_TUNNEL_END:
free(ftp_data_proxy_name);
}
// read from client-working host port
void ftp_proxy_c2s_cb(struct bufferevent *bev, void *ctx)
{
struct proxy *p = (struct proxy *)ctx;
assert(p);
struct bufferevent *partner = p->bev;
struct evbuffer *src, *dst;
size_t len;
src = bufferevent_get_input(bev);
len = evbuffer_get_length(src);
if (len < 0)
return;
dst = bufferevent_get_output(partner);
assert(dst);
unsigned char *buf = calloc(1, len);
assert(buf);
size_t read_n = 0;
read_n = evbuffer_remove(src, buf, len);
// #define FTP_P_DEBUG 1
#ifdef FTP_P_DEBUG
char *dbg_buf = calloc(1, read_n * 7 + 1);
assert(dbg_buf);
unsigned int i = 0;
for(i = 0; i<read_n && ((2 * i) < (read_n * 2 + 1)); i++) {
snprintf(dbg_buf + 7*i, 8, "%3u[%c] ",
(unsigned char)buf[i],
(unsigned char)buf[i]);
}
debug(LOG_DEBUG, "FTP Client RECV ctl byte:%s", dbg_buf);
debug(LOG_DEBUG, "FTP Client RECV ctl stri:%s", buf);
SAFE_FREE(dbg_buf);
#endif //FTP_P_DEBUG
struct ftp_pasv *local_fp = pasv_unpack((char *)buf);
if (local_fp) {
struct common_conf *c_conf = get_common_config();
struct ftp_pasv *r_fp = new_ftp_pasv();
r_fp->code = local_fp->code;
if (! c_conf->server_ip) {
debug(LOG_ERR, "error: FTP proxy without server ip!");
exit(0);
}
strncpy(r_fp->ftp_server_ip, c_conf->server_ip, IP_LEN);
r_fp->ftp_server_port = p->remote_data_port;
if (r_fp->ftp_server_port <= 0) {
debug(LOG_ERR, "error: remote ftp data port is not init!");
goto FTP_C2S_CB_END;
}
char *pasv_msg = NULL;
size_t pack_len = pasv_pack(r_fp, &pasv_msg);
if ( ! pack_len){
debug(LOG_ERR, "error: ftp proxy replace failed!");
SAFE_FREE(pasv_msg);
goto FTP_C2S_CB_END;
}
#ifdef FTP_P_DEBUG
debug(LOG_DEBUG, "ftp pack result:%s", pasv_msg);
#endif //FTP_P_DEBUG
set_ftp_data_proxy_tunnel(p->proxy_name, local_fp, r_fp);
evbuffer_add(dst, pasv_msg, pack_len);
SAFE_FREE(pasv_msg);
} else {
evbuffer_add(dst, buf, read_n);
}
FTP_C2S_CB_END:
SAFE_FREE(buf);
free_ftp_pasv(local_fp);
return;
}
void ftp_proxy_s2c_cb(struct bufferevent *bev, void *ctx)
{
tcp_proxy_s2c_cb(bev, ctx);
}
static struct ftp_pasv *pasv_unpack(char *data)
{
char cd_buf[4] = {0};
snprintf(cd_buf, 4, "%s", data);
int code = atoi(cd_buf);
if (code != 227 && code != 211 && code != 229)
return NULL;
struct ftp_pasv *fp = new_ftp_pasv();
assert(fp);
fp->code = code;
switch(fp->code) {
case 227:
{
int i = 0, ip_i = 0, port_i = 0, ip_start = 0, comma_n = 0;
char port[2][4] = { {0}, {0} };
for (i=0; i<strlen(data) && ip_i<IP_LEN; i++) {
if (data[i] == '(') {
ip_start = 1;
continue;
}
if (! ip_start)
continue;
if (data[i] == ')')
break;
if (data[i] == ','){
comma_n++;
port_i = 0;
if (comma_n < 4){
fp->ftp_server_ip[ip_i] = '.';
ip_i++;
}
continue;
}
if (comma_n >= 4 && port_i < 4) {
port[comma_n - 4][port_i] = data[i];
port_i++;
continue;
}
fp->ftp_server_ip[ip_i] = data[i];
ip_i++;
}
fp->ftp_server_port = atoi(port[0]) * FTP_PASV_PORT_BLOCK + atoi(port[1]);
debug(LOG_DEBUG, "ftp pasv unpack:[%s:%d]", fp->ftp_server_ip, fp->ftp_server_port);
break;
}
default:
free_ftp_pasv(fp);
break;
}
return fp;
}
// the value returned need FREE after using
static size_t pasv_pack(struct ftp_pasv *fp, char **pack_p)
{
*pack_p = (char *)calloc(1, FTP_PRO_BUF);
assert(*pack_p);
size_t pack_len = 0;
switch (fp->code){
case 227:
{
char ftp_ip[IP_LEN] = {0};
int i =0;
for (i=0; i<strlen(fp->ftp_server_ip) && i < IP_LEN; i++) {
if (fp->ftp_server_ip[i] == '.') {
ftp_ip[i] = ',';
continue;
}
ftp_ip[i] = fp->ftp_server_ip[i];
}
snprintf(*pack_p,
FTP_PRO_BUF,
"227 Entering Passive Mode (%s,%d,%d).\n",
ftp_ip,
fp->ftp_server_port / FTP_PASV_PORT_BLOCK,
fp->ftp_server_port % FTP_PASV_PORT_BLOCK);
pack_len = strlen(*pack_p);
break;
}
default:
debug(LOG_DEBUG, "ftp pasv protocol data not supportted in pasv_pack");
free(*pack_p);
break;
}
return pack_len;
}
// need be free after using
static struct ftp_pasv *new_ftp_pasv()
{
struct ftp_pasv *fp = (struct ftp_pasv *)calloc(1, sizeof(struct ftp_pasv));
if (! fp)
return NULL;
memset(fp->ftp_server_ip, 0, IP_LEN);
fp->ftp_server_port = -1;
fp->code = -1;
return fp;
}
// can be used to free NULL pointer also
static void free_ftp_pasv(struct ftp_pasv *fp)
{
if (!fp)
return;
SAFE_FREE(fp);
fp = NULL;
}

44
proxy_tcp.c Normal file
View File

@@ -0,0 +1,44 @@
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#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"
#include "common.h"
#include "proxy.h"
// read from client-working host port
void tcp_proxy_c2s_cb(struct bufferevent *bev, void *ctx)
{
struct proxy *p = (struct proxy *)ctx;
struct bufferevent *partner = p?p->bev:NULL;
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);
}
}
void tcp_proxy_s2c_cb(struct bufferevent *bev, void *ctx)
{
struct proxy *p = (struct proxy *)ctx;
struct bufferevent *partner = p?p->bev:NULL;
struct evbuffer *src, *dst;
src = bufferevent_get_input(bev);
dst = bufferevent_get_output(partner);
evbuffer_add_buffer(dst, src);
}

View File

@@ -20,3 +20,12 @@ void s_sleep(unsigned int s, unsigned int u)
timeout.tv_usec = u;
select(0, NULL, NULL, NULL, &timeout);
}
// is_valid_ip_address:
// return 0:ipaddress unlegal
int is_valid_ip_address(const char *ip_address)
{
struct sockaddr_in sa;
int result = inet_pton(AF_INET, ip_address, &(sa.sin_addr));
return result;
}

View File

@@ -3,4 +3,8 @@
void s_sleep(unsigned int s, unsigned int u);
// is_valid_ip_address:
// return 0:ipaddress unlegal
int is_valid_ip_address(const char *ip_address);
#endif //_UTILS_H_

View File

@@ -19,7 +19,7 @@
* *
\********************************************************************/
/** @file xfrp_client.c
/** @file xfrpc.c
@brief xfrp client
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
*/
@@ -41,12 +41,12 @@
#include "uthash.h"
#include "control.h"
#include "debug.h"
#include "xfrp_client.h"
#include "xfrpc.h"
#include "crypto.h"
#include "msg.h"
#include "utils.h"
void xfrp_client_loop()
void xfrpc_loop()
{
init_main_control();
run_control();

View File

@@ -19,14 +19,14 @@
* *
\********************************************************************/
/** @file xfrp_client.h
/** @file xfrpc.h
@brief xfrp client header file
@author Copyright (C) 2016 Dengfeng Liu <liudengfeng@kunteng.org>
*/
#ifndef _XFRP_CLIENT_H_
#define _XFRP_CLIENT_H_
#ifndef _XFRPC_H_
#define _XFRPC_H_
void xfrp_client_loop();
void xfrpc_loop();
#endif //_XFRP_CLIENT_H_
#endif //_XFRPC_H_