Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acb79bcf1f | ||
|
|
75adc0a669 | ||
|
|
2ef0200276 | ||
|
|
7940a4f949 | ||
|
|
81779637ba | ||
|
|
91d6129426 | ||
|
|
d333533639 |
34
README.md
34
README.md
@@ -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,6 +45,7 @@ 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 :
|
||||
|
||||
@@ -57,6 +59,34 @@ Run in release mode :
|
||||
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
|
||||
|
||||
16
config.c
16
config.c
@@ -63,8 +63,16 @@ 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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -142,11 +150,6 @@ static void dump_proxy_service(const int index, struct proxy_service *ps)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!is_valid_ip_address((const char *)c_conf->server_addr)){
|
||||
debug(LOG_ERR, "now ftp proxy only support ip address in [server_addr]");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
new_ftp_data_proxy_service(ps);
|
||||
}
|
||||
|
||||
@@ -369,6 +372,7 @@ static void init_common_conf(struct common_conf *config)
|
||||
config->heartbeat_timeout = 60;
|
||||
config->tcp_mux = 0;
|
||||
config->user = NULL;
|
||||
config->server_ip = NULL;
|
||||
}
|
||||
|
||||
// it should be free after using
|
||||
|
||||
2
config.h
2
config.h
@@ -46,6 +46,7 @@ struct base_conf{
|
||||
// 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 +72,6 @@ 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_
|
||||
|
||||
164
control.c
164
control.c
@@ -29,10 +29,9 @@
|
||||
#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>
|
||||
|
||||
@@ -60,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);
|
||||
@@ -71,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)
|
||||
@@ -195,21 +186,18 @@ static size_t request(struct bufferevent *bev, struct frame *f)
|
||||
bout = main_ctl->connect_bev;
|
||||
}
|
||||
|
||||
if ( ! bout) {
|
||||
goto REQ_END;
|
||||
}
|
||||
if ( ! bout)
|
||||
return 0;
|
||||
|
||||
struct common_conf *c = get_common_config();
|
||||
if ( ! c)
|
||||
goto REQ_END;
|
||||
return 0;
|
||||
|
||||
write_len = (size_t)f->len;
|
||||
if ( 0 == write_len)
|
||||
goto REQ_END;;
|
||||
return 0;
|
||||
|
||||
bufferevent_write(bout, f->data, write_len);
|
||||
|
||||
REQ_END:
|
||||
return write_len;
|
||||
}
|
||||
|
||||
@@ -255,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;
|
||||
@@ -756,7 +745,9 @@ 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)
|
||||
@@ -764,15 +755,16 @@ 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)) {
|
||||
if (retry_times >= 10) {
|
||||
debug(LOG_INFO,
|
||||
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, "connect server [%s:%d] failed",
|
||||
debug(LOG_ERR, "error: connect server [%s:%d] failed",
|
||||
c_conf->server_addr,
|
||||
c_conf->server_port);
|
||||
free_control();
|
||||
@@ -781,11 +773,14 @@ static void connect_event_cb (struct bufferevent *bev, short what, void *ctx)
|
||||
close_main_control();
|
||||
} else if (what & BEV_EVENT_CONNECTED) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -802,17 +797,40 @@ 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",
|
||||
"error: connect server [%s:%d] failed",
|
||||
c_conf->server_addr,
|
||||
c_conf->server_port);
|
||||
exit(0);
|
||||
@@ -827,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);
|
||||
@@ -846,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);
|
||||
}
|
||||
@@ -880,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;
|
||||
@@ -906,34 +924,12 @@ void send_msg_frp_server(struct bufferevent *bev,
|
||||
unsigned char *pack_buf = NULL;
|
||||
size_t pack_buf_len = pack(&req_msg, &pack_buf);
|
||||
if ( ! pack_buf_len || ! pack_buf) {
|
||||
debug(LOG_ERR, "send buffer pack failed!");
|
||||
debug(LOG_ERR, "error: send buffer pack failed!");
|
||||
goto S_M_F_END;
|
||||
}
|
||||
|
||||
#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(pack_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);
|
||||
}
|
||||
|
||||
#endif //ENCRYPTO
|
||||
if (! f->data) {
|
||||
set_frame_len(f, (ushort) pack_buf_len);
|
||||
f->data = pack_buf;
|
||||
}
|
||||
set_frame_len(f, (ushort) pack_buf_len);
|
||||
f->data = pack_buf;
|
||||
|
||||
if (get_common_config()->tcp_mux) {
|
||||
switch (type)
|
||||
@@ -957,7 +953,8 @@ void send_msg_frp_server(struct bufferevent *bev,
|
||||
|
||||
S_M_F_END:
|
||||
SAFE_FREE(req_msg.data_p);
|
||||
SAFE_FREE(f->data);
|
||||
SAFE_FREE(pack_buf);
|
||||
f->data = NULL;
|
||||
free_frame(f);
|
||||
}
|
||||
|
||||
@@ -1007,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");
|
||||
|
||||
@@ -1034,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()
|
||||
@@ -1064,6 +1091,5 @@ void free_control()
|
||||
if (!main_ctl)
|
||||
return;
|
||||
|
||||
SAFE_FREE(request_buf);
|
||||
SAFE_FREE(main_ctl);
|
||||
}
|
||||
11
proxy_ftp.c
11
proxy_ftp.c
@@ -101,7 +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;
|
||||
|
||||
strncpy(r_fp->ftp_server_ip, c_conf->server_addr, IP_LEN);
|
||||
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) {
|
||||
@@ -117,6 +122,10 @@ void ftp_proxy_c2s_cb(struct bufferevent *bev, void *ctx)
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user