8 Commits

Author SHA1 Message Date
staylightblow8
68ffcb2a8a version: 2.12.656 release
Signed-off-by: staylightblow8 <liudf0716@gmail.com>
2023-12-09 21:19:34 +08:00
staylightblow8
2a4eceeeab plugin: add youtube download plugin
Signed-off-by: staylightblow8 <liudf0716@gmail.com>
2023-12-09 16:07:23 +08:00
staylightblow8
46e3f7df6b plugin: add httpd plugin
Signed-off-by: staylightblow8 <liudf0716@gmail.com>
2023-12-03 13:03:21 +08:00
staylightblow8
969c0a160d fix problem of issue
https://github.com/liudf0716/xfrpc/issues/52

Signed-off-by: staylightblow8 <liudf0716@gmail.com>
2023-11-25 12:25:18 +08:00
staylightblow8
1fd95588ed msg: fix some problem
Type: fix

Signed-off-by: staylightblow8 <liudf0716@gmail.com>
2023-11-04 12:07:44 +08:00
staylightblow8
aaeaa2203a instaloader: change working directory to instaloader
Signed-off-by: staylightblow8 <liudf0716@gmail.com>
2023-10-28 20:11:03 +08:00
staylightblow8
c895f221da plugin: add instaloader local redir service
Signed-off-by: staylightblow8 <liudf0716@gmail.com>
2023-10-28 12:06:34 +08:00
staylightblow8
be51233c04 plugin: add instaloder plugin to download instagram
Signed-off-by: staylightblow8 <liudf0716@gmail.com>
2023-10-22 21:43:52 +08:00
19 changed files with 12825 additions and 130 deletions

View File

@@ -16,10 +16,15 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: prepare build environment
run: |
sudo apt-get update
sudo apt-get install -y libjson-c-dev libevent-dev libssl-dev
- name: compile xfrpc
run: |
mkdir build
cd build
cmake -D THIRDPARTY_STATIC_BUILD=ON ..
cmake ..
make

View File

@@ -80,10 +80,14 @@ set(src_xfrpc
proxy.c
tcpmux.c
tcp_redir.c
mongoose.c
)
set(src_xfrpc_plugins
plugins/telnetd.c)
plugins/telnetd.c
plugins/instaloader.c
plugins/httpd.c
plugins/youtubedl.c)
set(libs
ssl

View File

@@ -106,6 +106,8 @@ struct proxy_service {
char *plugin_user;
char *plugin_pwd;
char *s_root_dir;
// private arguments
UT_hash_handle hh;
};

View File

@@ -48,7 +48,6 @@
static const char *valid_types[] = {
"tcp",
"udp",
"mstsc",
"socks5",
"http",
"https",
@@ -195,6 +194,8 @@ new_proxy_service(const char *name)
ps->plugin_user = NULL;
ps->plugin_pwd = NULL;
ps->s_root_dir = NULL;
return ps;
}
@@ -239,11 +240,6 @@ validate_proxy(struct proxy_service *ps)
debug(LOG_ERR, "Proxy [%s] error: remote_port not found", ps->proxy_name);
return 0;
}
} else if (strcmp(ps->proxy_type, "mstsc") == 0) {
if (ps->remote_port == 0 || ps->local_port == 0) {
debug(LOG_ERR, "Proxy [%s] error: remote_port or local_port not found", ps->proxy_name);
return 0;
}
} else if (strcmp(ps->proxy_type, "tcp") == 0 || strcmp(ps->proxy_type, "udp") == 0) {
if (ps->remote_port == 0 || ps->local_port == 0 || ps->local_ip == NULL) {
debug(LOG_ERR, "Proxy [%s] error: remote_port or local_port or local_ip not found", ps->proxy_name);
@@ -318,13 +314,45 @@ process_plugin_conf(struct proxy_service *ps)
if (strcmp(ps->plugin, "telnetd") == 0) {
if (ps->local_port == 0)
ps->local_port = 23;
ps->local_port = XFRPC_PLUGIN_TELNETD_PORT;
if (ps->local_ip == NULL)
ps->local_ip = strdup("127.0.0.1");
if (ps->plugin_user !=NULL && ps->plugin_pwd != NULL) {
add_user_and_set_password (ps->plugin_user, ps->plugin_pwd);
}
} else if (strcmp(ps->plugin, "instaloader") == 0) {
if (ps->local_port == 0)
ps->local_port = XFRPC_PLUGIN_INSTALOADER_PORT;
if (ps->remote_port == 0)
ps->remote_port = XFRPC_PLUGIN_INSTALOADER_REMOTE_PORT;
if (ps->local_ip == NULL)
ps->local_ip = strdup("127.0.0.1");
} else if (strcmp(ps->plugin, "instaloader_client") == 0) {
if (ps->local_port == 0)
ps->local_port = XFRPC_PLUGIN_INSTALOADER_PORT;
if (ps->remote_port == 0)
ps->remote_port == XFRPC_PLUGIN_INSTALOADER_REMOTE_PORT;
if (ps->local_ip == NULL)
ps->local_ip = strdup("0.0.0.0");
} else if (strcmp(ps->plugin, "youtubedl") == 0) {
if (ps->local_port == 0)
ps->local_port = XFRPC_PLUGIN_YOUTUBEDL_PORT;
if (ps->remote_port == 0)
ps->remote_port = XFRPC_PLUGIN_YOUTUBEDL_REMOTE_PORT;
if (ps->local_ip == NULL)
ps->local_ip = strdup("127.0.0.1");
} else if (strcmp(ps->plugin, "httpd") == 0) {
if (ps->local_port == 0)
ps->local_port = XFRPC_PLUGIN_HTTPD_PORT;
if (ps->local_ip == NULL)
ps->local_ip = strdup("127.0.0.1");
if (ps->remote_port == 0)
ps->remote_port = XFRPC_PLUGIN_HTTPD_REMOTE_PORT;
if (ps->s_root_dir == NULL)
ps->s_root_dir = strdup("/var/www/html");
} else {
debug(LOG_INFO, "plugin %s is not supportted", ps->plugin);
}
}
@@ -402,6 +430,8 @@ proxy_service_handler(void *user, const char *sect, const char *nm, const char *
ps->plugin_user = strdup(value);
} else if (MATCH_NAME("plugin_pwd")) {
ps->plugin_pwd = strdup(value);
} else if (MATCH_NAME("root_dir")) {
ps->s_root_dir = strdup(value);
} else {
debug(LOG_ERR, "unknown option %s in section %s", nm, section);
SAFE_FREE(section);
@@ -414,11 +444,6 @@ proxy_service_handler(void *user, const char *sect, const char *nm, const char *
ps->remote_port = DEFAULT_SOCKS5_PORT;
if (ps->group == NULL)
ps->group = strdup("chatgptd");
} else if (ps->proxy_type && strcmp(ps->proxy_type, "mstsc") == 0) {
// if ps->proxy_type is mstsc, and ps->local_port is not set, set it to 3389
// start a thread to listen on local_port, and forward data to remote_port
if (ps->local_port == 0)
ps->local_port = DEFAULT_MSTSC_PORT;
} else if (ps->proxy_type && strcmp(ps->proxy_type, "tcp") == 0) {
process_plugin_conf(ps);
}

View File

@@ -31,6 +31,14 @@
#define DEFAULT_MSTSC_PORT 3389
#define DEFAULT_SOCKS5_PORT 1980
#define XFRPC_PLUGIN_TELNETD_PORT 23
#define XFRPC_PLUGIN_INSTALOADER_PORT 10000
#define XFRPC_PLUGIN_INSTALOADER_REMOTE_PORT 10001
#define XFRPC_PLUGIN_YOUTUBEDL_PORT 20002
#define XFRPC_PLUGIN_YOUTUBEDL_REMOTE_PORT 20003
#define XFRPC_PLUGIN_HTTPD_PORT 8000
#define XFRPC_PLUGIN_HTTPD_REMOTE_PORT 8001
#define FTP_RMT_CTL_PROXY_SUFFIX "_ftp_remote_ctl_proxy"
//client common config

View File

@@ -72,7 +72,8 @@ void init_login()
struct utsname uname_buf;
if (uname(&uname_buf)) {
return;
debug(LOG_ERR, "error: get system info failed!");
exit(0);
}
c_login->version = strdup(PROTOCOL_VERESION);

View File

@@ -31,6 +31,7 @@
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <time.h>
#include "uthash.h"
@@ -41,7 +42,7 @@ struct login {
char *arch;
char *user;
char *privilege_key;
long int timestamp;
time_t timestamp;
char *run_id;
char *metas;
int pool_count;

10039
mongoose.c Normal file

File diff suppressed because it is too large Load Diff

1915
mongoose.h Normal file

File diff suppressed because it is too large Load Diff

255
msg.c
View File

@@ -20,8 +20,8 @@
\********************************************************************/
/** @file msg.c
@brief xfrpc client msg related
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
@brief xfrpc client msg related
@author Copyright (C) 2016 Dengfeng Liu <liu_df@qq.com>
*/
#include <string.h>
@@ -41,44 +41,45 @@
#include "client.h"
#include "utils.h"
#define JSON_MARSHAL_TYPE(jobj,key,jtype,item) \
json_object_object_add(jobj, key, json_object_new_##jtype((item)));
#define JSON_MARSHAL_TYPE(jobj, key, jtype, item) \
json_object_object_add(jobj, key, json_object_new_##jtype((item)));
#define SAFE_JSON_STRING(str_target) \
str_target?str_target:"\0"
str_target ? str_target : "\0"
const char msg_types[] = {TypeLogin,
TypeLoginResp,
TypeNewProxy,
TypeNewProxyResp,
TypeNewWorkConn,
TypeReqWorkConn,
TypeStartWorkConn,
TypePing,
TypePong,
TypeUDPPacket};
const char msg_types[] = {TypeLogin,
TypeLoginResp,
TypeNewProxy,
TypeNewProxyResp,
TypeNewWorkConn,
TypeReqWorkConn,
TypeStartWorkConn,
TypePing,
TypePong,
TypeUDPPacket};
char *
calc_md5(const char *data, int datalen)
{
unsigned char digest[16] = {0};
char *out = (char*)malloc(33);
char *out = (char *)malloc(33);
assert(out);
MD5_CTX md5;
MD5_Init(&md5);
MD5_Update(&md5, data, datalen);
MD5_Final(digest, &md5);
for (int n = 0; n < 16; ++n) {
snprintf(&(out[n*2]), 3, "%02x", (unsigned int)digest[n]);
}
return out;
for (int n = 0; n < 16; ++n)
{
snprintf(&(out[n * 2]), 3, "%02x", (unsigned int)digest[n]);
}
return out;
}
static void
static void
fill_custom_domains(struct json_object *j_ctl_req, const char *custom_domains)
{
struct json_object *jarray_cdomains = json_object_new_array();
@@ -86,7 +87,8 @@ fill_custom_domains(struct json_object *j_ctl_req, const char *custom_domains)
char *tmp = strdup(custom_domains);
assert(tmp);
char *tok = tmp, *end = tmp;
while (tok != NULL) {
while (tok != NULL)
{
strsep(&end, ",");
int dname_len = strlen(tok) + 1;
@@ -99,15 +101,16 @@ fill_custom_domains(struct json_object *j_ctl_req, const char *custom_domains)
tok = end;
}
SAFE_FREE(tmp);
json_object_object_add(j_ctl_req, "custom_domains", jarray_cdomains);
}
struct work_conn *
new_work_conn() {
new_work_conn()
{
struct work_conn *work_c = calloc(1, sizeof(struct work_conn));
assert(work_c);
if (work_c)
if (work_c)
work_c->run_id = NULL;
return work_c;
@@ -122,28 +125,30 @@ get_auth_key(const char *token, long int *timestamp)
snprintf(seed, 128, "%s%ld", token, *timestamp);
else
snprintf(seed, 128, "%ld", *timestamp);
return calc_md5(seed, strlen(seed));
}
size_t
size_t
login_request_marshal(char **msg)
{
size_t nret = 0;
struct json_object *j_login_req = json_object_new_object();
if (j_login_req == NULL)
return 0;
struct login *lg = get_common_login_config();
if (!lg)
if (!lg) {
json_object_put(j_login_req);
return 0;
}
SAFE_FREE(lg->privilege_key);
struct common_conf *cf = get_common_config();
char *auth_key = get_auth_key(cf->auth_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));
JSON_MARSHAL_TYPE(j_login_req, "os", string, lg->os);
@@ -151,11 +156,15 @@ login_request_marshal(char **msg)
JSON_MARSHAL_TYPE(j_login_req, "user", string, SAFE_JSON_STRING(lg->user));
JSON_MARSHAL_TYPE(j_login_req, "privilege_key", string, SAFE_JSON_STRING(lg->privilege_key));
JSON_MARSHAL_TYPE(j_login_req, "timestamp", int64, lg->timestamp);
if (sizeof(time_t) == 4) {
JSON_MARSHAL_TYPE(j_login_req, "timestamp", int, lg->timestamp);
} else {
JSON_MARSHAL_TYPE(j_login_req, "timestamp", int64, lg->timestamp);
}
JSON_MARSHAL_TYPE(j_login_req, "run_id", string, SAFE_JSON_STRING(lg->run_id));
JSON_MARSHAL_TYPE(j_login_req, "pool_count", int, lg->pool_count);
json_object_object_add(j_login_req, "metas", NULL);
const char *tmp = NULL;
tmp = json_object_to_json_string(j_login_req);
if (tmp && strlen(tmp) > 0) {
@@ -168,18 +177,17 @@ login_request_marshal(char **msg)
return nret;
}
int
new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
int new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
{
const char *tmp = NULL;
int nret = 0;
int nret = 0;
char *path = NULL;
char *delimiter = ",";
char *save = NULL;
struct json_object *j_np_req = json_object_new_object();
if ( ! j_np_req)
if (!j_np_req)
return 0;
JSON_MARSHAL_TYPE(j_np_req, "proxy_name", string, np_req->proxy_name);
// if proxy_type is socks5, set the proxy_type to tcp
if (strcmp(np_req->proxy_type, "socks5") == 0 || strcmp(np_req->proxy_type, "mstsc") == 0) {
@@ -191,14 +199,14 @@ 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);
// if proxy_type is tcp, http, https and socks5, set group and group_key to j_np_req
if (strcmp(np_req->proxy_type, "tcp") == 0 ||
strcmp(np_req->proxy_type, "http") == 0 ||
strcmp(np_req->proxy_type, "https") == 0 ||
if (strcmp(np_req->proxy_type, "tcp") == 0 ||
strcmp(np_req->proxy_type, "http") == 0 ||
strcmp(np_req->proxy_type, "https") == 0 ||
strcmp(np_req->proxy_type, "socks5") == 0) {
if (np_req->group) {
JSON_MARSHAL_TYPE(j_np_req, "group", string, np_req->group);
}
}
if (np_req->group_key) {
JSON_MARSHAL_TYPE(j_np_req, "group_key", string, np_req->group_key);
}
@@ -233,11 +241,11 @@ new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
} else {
json_object_object_add(j_np_req, "locations", NULL);
}
JSON_MARSHAL_TYPE(j_np_req, "host_header_rewrite", string, SAFE_JSON_STRING(np_req->host_header_rewrite));
JSON_MARSHAL_TYPE(j_np_req, "http_user", string, SAFE_JSON_STRING(np_req->http_user));
JSON_MARSHAL_TYPE(j_np_req, "http_pwd", string, SAFE_JSON_STRING(np_req->http_pwd));
tmp = json_object_to_json_string(j_np_req);
if (tmp && strlen(tmp) > 0) {
nret = strlen(tmp);
@@ -249,13 +257,12 @@ new_proxy_service_marshal(const struct proxy_service *np_req, char **msg)
return nret;
}
int
new_work_conn_marshal(const struct work_conn *work_c, char **msg)
int new_work_conn_marshal(const struct work_conn *work_c, char **msg)
{
const char *tmp = NULL;
int nret = 0;
struct json_object *j_new_work_conn = json_object_new_object();
if (! j_new_work_conn)
if (!j_new_work_conn)
return 0;
JSON_MARSHAL_TYPE(j_new_work_conn, "run_id", string, SAFE_JSON_STRING(work_c->run_id));
@@ -278,7 +285,7 @@ new_proxy_resp_unmarshal(const char *jres)
struct json_object *j_np_res = json_tokener_parse(jres);
if (j_np_res == NULL)
return NULL;
struct new_proxy_response *npr = calloc(1, sizeof(struct new_proxy_response));
assert(npr);
@@ -287,8 +294,13 @@ new_proxy_resp_unmarshal(const char *jres)
npr->run_id = strdup(json_object_get_string(npr_run_id));
struct json_object *npr_proxy_remote_addr = NULL;
if (! json_object_object_get_ex(j_np_res, "remote_addr", &npr_proxy_remote_addr))
if (!json_object_object_get_ex(j_np_res, "remote_addr", &npr_proxy_remote_addr)) {
free(npr->run_id);
free(npr);
npr = NULL;
goto END_ERROR;
}
const char *remote_addr = json_object_get_string(npr_proxy_remote_addr);
char *port = strrchr(remote_addr, ':');
if (port) {
@@ -297,14 +309,24 @@ new_proxy_resp_unmarshal(const char *jres)
}
struct json_object *npr_proxy_name = NULL;
if (! json_object_object_get_ex(j_np_res, "proxy_name", &npr_proxy_name))
if (!json_object_object_get_ex(j_np_res, "proxy_name", &npr_proxy_name)) {
free(npr->run_id);
free(npr);
npr = NULL;
goto END_ERROR;
}
npr->proxy_name = strdup(json_object_get_string(npr_proxy_name));
assert(npr->proxy_name);
struct json_object *npr_error = NULL;
if(! json_object_object_get_ex(j_np_res, "error", &npr_error))
if (!json_object_object_get_ex(j_np_res, "error", &npr_error)) {
free(npr->run_id);
free(npr->proxy_name);
free(npr);
npr = NULL;
goto END_ERROR;
}
npr->error = strdup(json_object_get_string(npr_error));
assert(npr->error);
@@ -320,25 +342,40 @@ login_resp_unmarshal(const char *jres)
struct json_object *j_lg_res = json_tokener_parse(jres);
if (j_lg_res == NULL)
return NULL;
struct login_resp *lr = calloc(1, sizeof(struct login_resp));
assert(lr);
struct json_object *l_version = NULL;
if (! json_object_object_get_ex(j_lg_res, "version", &l_version))
if (!json_object_object_get_ex(j_lg_res, "version", &l_version)) {
free(lr);
lr = NULL;
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))
if (!json_object_object_get_ex(j_lg_res, "run_id", &l_run_id)) {
free(lr->version);
free(lr);
lr = NULL;
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))
if (!json_object_object_get_ex(j_lg_res, "error", &l_error)) {
free(lr->version);
free(lr->run_id);
free(lr);
lr = NULL;
goto END_ERROR;
}
lr->error = strdup(json_object_get_string(l_error));
assert(lr->error);
@@ -358,8 +395,11 @@ start_work_conn_resp_unmarshal(const char *resp_msg)
assert(sr);
struct json_object *pn = NULL;
if(! json_object_object_get_ex(j_start_w_res, "proxy_name", &pn))
if (!json_object_object_get_ex(j_start_w_res, "proxy_name", &pn)) {
free(sr);
sr = NULL;
goto START_W_C_R_END;
}
sr->proxy_name = strdup(json_object_get_string(pn));
assert(sr->proxy_name);
@@ -377,22 +417,32 @@ control_response_unmarshal(const char *jres)
return NULL;
struct control_response *ctl_res = calloc(sizeof(struct control_response), 1);
assert(ctl_res);
struct json_object *jtype = NULL;
if(! json_object_object_get_ex(j_ctl_res, "type", &jtype))
if (!json_object_object_get_ex(j_ctl_res, "type", &jtype)) {
free(ctl_res);
ctl_res = NULL;
goto END_ERROR;
ctl_res->type = json_object_get_int(jtype);
struct json_object *jcode = NULL;
if(! json_object_object_get_ex(j_ctl_res, "code", &jcode))
goto END_ERROR;
ctl_res->code = json_object_get_int(jcode);
struct json_object *jmsg = NULL;
if(json_object_object_get_ex(j_ctl_res, "msg", &jmsg)) {
ctl_res->msg = strdup(json_object_get_string(jmsg));
assert(ctl_res->msg);
}
ctl_res->type = json_object_get_int(jtype);
struct json_object *jcode = NULL;
if (!json_object_object_get_ex(j_ctl_res, "code", &jcode)) {
free(ctl_res);
ctl_res = NULL;
goto END_ERROR;
}
ctl_res->code = json_object_get_int(jcode);
struct json_object *jmsg = NULL;
if (!json_object_object_get_ex(j_ctl_res, "msg", &jmsg)) {
free(ctl_res);
ctl_res = NULL;
goto END_ERROR;
}
ctl_res->msg = strdup(json_object_get_string(jmsg));
assert(ctl_res->msg);
END_ERROR:
json_object_put(j_ctl_res);
@@ -404,29 +454,11 @@ control_response_free(struct control_response *res)
{
if (!res)
return;
SAFE_FREE(res->msg);
SAFE_FREE(res);
}
int
msg_type_valid_check(char msg_type)
{
int i = 0;
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;
}
// marshal udp packet msg
int
new_udp_packet_marshal(const struct udp_packet *udp, char **msg)
@@ -478,7 +510,7 @@ new_udp_packet_marshal(const struct udp_packet *udp, char **msg)
// raddr is NULL, add null to j_udp
struct json_object *j_raddr = json_object_new_object();
assert(j_raddr);
json_object_object_add(j_udp, "r", j_raddr);
json_object_object_add(j_udp, "r", j_raddr);
}
// convert json to string msg
@@ -494,7 +526,7 @@ udp_packet_free(struct udp_packet *udp)
{
if (!udp)
return;
SAFE_FREE(udp->content);
SAFE_FREE(udp->laddr->addr);
SAFE_FREE(udp->laddr->zone);
@@ -508,7 +540,7 @@ udp_packet_free(struct udp_packet *udp)
// unmarshal udp packet msg
struct udp_packet *
udp_packet_unmarshal (const char *msg)
udp_packet_unmarshal(const char *msg)
{
struct json_object *j_udp = json_tokener_parse(msg);
if (j_udp == NULL)
@@ -517,23 +549,32 @@ udp_packet_unmarshal (const char *msg)
assert(udp);
struct json_object *j_content = NULL;
if(! json_object_object_get_ex(j_udp, "c", &j_content))
if (!json_object_object_get_ex(j_udp, "c", &j_content)) {
goto END_ERROR;
}
udp->content = strdup(json_object_get_string(j_content));
assert(udp->content);
struct json_object *j_laddr = NULL;
if(! json_object_object_get_ex(j_udp, "l", &j_laddr))
if (!json_object_object_get_ex(j_udp, "l", &j_laddr)) {
goto END_ERROR;
}
struct json_object *j_laddr_ip = NULL;
if(! json_object_object_get_ex(j_laddr, "IP", &j_laddr_ip))
if (!json_object_object_get_ex(j_laddr, "IP", &j_laddr_ip)) {
goto END_ERROR;
}
struct json_object *j_laddr_port = NULL;
if(! json_object_object_get_ex(j_laddr, "Port", &j_laddr_port))
if (!json_object_object_get_ex(j_laddr, "Port", &j_laddr_port)) {
goto END_ERROR;
}
struct json_object *j_laddr_zone = NULL;
if(! json_object_object_get_ex(j_laddr, "Zone", &j_laddr_zone))
if (!json_object_object_get_ex(j_laddr, "Zone", &j_laddr_zone)) {
goto END_ERROR;
}
udp->laddr = calloc(sizeof(struct udp_addr), 1);
assert(udp->laddr);
udp->laddr->addr = strdup(json_object_get_string(j_laddr_ip));
@@ -543,17 +584,25 @@ udp_packet_unmarshal (const char *msg)
assert(udp->laddr->zone);
struct json_object *j_raddr = NULL;
if(! json_object_object_get_ex(j_udp, "r", &j_raddr))
if (!json_object_object_get_ex(j_udp, "r", &j_raddr)) {
goto END_ERROR;
}
struct json_object *j_raddr_ip = NULL;
if(! json_object_object_get_ex(j_raddr, "IP", &j_raddr_ip))
if (!json_object_object_get_ex(j_raddr, "IP", &j_raddr_ip)) {
goto END_ERROR;
}
struct json_object *j_raddr_port = NULL;
if(! json_object_object_get_ex(j_raddr, "Port", &j_raddr_port))
if (!json_object_object_get_ex(j_raddr, "Port", &j_raddr_port)) {
goto END_ERROR;
}
struct json_object *j_raddr_zone = NULL;
if(! json_object_object_get_ex(j_raddr, "Zone", &j_raddr_zone))
if (!json_object_object_get_ex(j_raddr, "Zone", &j_raddr_zone)) {
goto END_ERROR;
}
udp->raddr = calloc(sizeof(struct udp_addr), 1);
assert(udp->raddr);
udp->raddr->addr = strdup(json_object_get_string(j_raddr_ip));

3
msg.h
View File

@@ -110,7 +110,6 @@ struct start_work_conn_resp {
int new_udp_packet_marshal(const struct udp_packet *udp, char **msg);
int new_proxy_service_marshal(const struct proxy_service *np_req, char **msg);
int msg_type_valid_check(char msg_type);
char *calc_md5(const char *data, int datalen);
char *get_auth_key(const char *token, long int *timestamp);
size_t login_request_marshal(char **msg);
@@ -132,6 +131,4 @@ void udp_packet_free(struct udp_packet *udp);
void control_response_free(struct control_response *res);
char *get_msg_type(uint8_t type);
#endif //_MSG_H_

81
plugins/httpd.c Normal file
View File

@@ -0,0 +1,81 @@
#include <pthread.h>
#include "../debug.h"
#include "../mongoose.h"
#include "httpd.h"
static const char *s_root_dir = ".";
static const char *s_listening_address = "http://0.0.0.0:8000";
static void
httpd_handler(struct mg_connection *c, int ev, void *ev_data, void *fn_data)
{
if (ev == MG_EV_HTTP_MSG)
{
struct mg_http_message *hm = ev_data, tmp = {0};
struct mg_str unknown = mg_str_n("?", 1), *cl;
struct mg_http_serve_opts opts = {0};
opts.root_dir = s_root_dir;
mg_http_serve_dir(c, hm, &opts);
mg_http_parse((char *)c->send.buf, c->send.len, &tmp);
cl = mg_http_get_header(&tmp, "Content-Length");
if (cl == NULL)
cl = &unknown;
debug(LOG_INFO, "HTTP: %.*s %.*s %.*s %.*s\n",
(int)hm->method.len, hm->method.ptr,
(int)hm->uri.len, hm->uri.ptr,
(int)tmp.uri.len, tmp.uri.ptr,
(int)cl->len, cl->ptr);
}
(void)fn_data;
}
static void *
httpd_thread(void *arg)
{
char path[MG_PATH_MAX] = ".";
struct mg_mgr mgr;
struct mg_connection *c;
struct proxy_service *ps = (struct proxy_service *)arg;
mg_mgr_init(&mgr);
if ((c = mg_http_listen(&mgr, s_listening_address, httpd_handler, &mgr)) == NULL)
{
debug(LOG_ERR, "Cannot listen on %s. Use http://ADDR:PORT or :PORT",
s_listening_address);
exit(EXIT_FAILURE);
}
// Root directory must not contain double dots. Make it absolute
// Do the conversion only if the root dir spec does not contain overrides
if (strchr(ps->s_root_dir, ',') == NULL)
{
realpath(ps->s_root_dir, path);
s_root_dir = path;
}
debug(LOG_INFO, "Listening on : %s", s_listening_address);
debug(LOG_INFO, "Web root : [%s]", s_root_dir);
while (1)
mg_mgr_poll(&mgr, 1000);
mg_mgr_free(&mgr);
return NULL;
}
void start_httpd_service(struct proxy_service *ps)
{
// start a httpd service in a new thread
pthread_t thread;
if (pthread_create(&thread, NULL, httpd_thread, ps) != 0)
{
debug(LOG_ERR, "Failed to create thread\n");
exit(-1);
}
//detach thread
pthread_detach(thread);
return;
}

8
plugins/httpd.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef _HTTPD_H
#define _HTTPD_H
#include "../client.h"
void start_httpd_service(struct proxy_service *ps);
#endif

247
plugins/instaloader.c Normal file
View File

@@ -0,0 +1,247 @@
#include <json-c/json.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <event2/http.h>
#include "../common.h"
#include "../debug.h"
#include "../config.h"
#include "instaloader.h"
struct instaloader_param {
char action[10];
char profile[100];
};
// define instaloader worker function
static void *
instaloader_worker(void *param)
{
struct instaloader_param *p = (struct instaloader_param *)param;
debug(LOG_DEBUG, "instaloader: action: %s, profile: %s\n", p->action, p->profile);
char cmd[512] = {0};
// create directory instaloader and change current directory to it
snprintf(cmd, sizeof(cmd), "mkdir -p instaloader && cd instaloader");
debug(LOG_DEBUG, "instaloader: cmd: %s\n", cmd);
system(cmd);
if (strcmp(p->action, "download") == 0) {
// download profile
snprintf(cmd, sizeof(cmd), "instaloader --no-captions --no-metadata-json --no-compress-json --no-pictures %s", p->profile);
debug(LOG_DEBUG, "instaloader: cmd: %s\n", cmd);
// use popen to execute cmd and get its output
FILE *fp = popen(cmd, "r");
if (fp == NULL) {
debug(LOG_ERR, "instaloader: popen failed\n");
free(param);
return NULL;
}
char buf[512] = {0};
while (fgets(buf, sizeof(buf), fp) != NULL) {
debug(LOG_DEBUG, "instaloader: %s", buf);
memset(buf, 0, sizeof(buf));
}
pclose(fp);
} else if (strcmp(p->action, "stop") == 0) {
// stop instaloader
debug(LOG_DEBUG, "instaloader: exit the program \n");
exit(0);
} else {
debug(LOG_ERR, "instaloader: unknown action: %s\n", p->action);
}
// free param
free(param);
return 0;
}
static int
parse_instaloader_command(char *json_data, struct instaloader_param *param)
{
// parse json data with json-c to param
json_object *jobj = json_tokener_parse(json_data);
if (jobj == NULL) {
debug(LOG_ERR, "instaloader: json_tokener_parse failed\n");
return -1;
}
// get action
json_object *jaction = NULL;
if (!json_object_object_get_ex(jobj, "action", &jaction)) {
debug(LOG_ERR, "instaloader: json_object_object_get_ex failed\n");
json_object_put(jobj);
return -1;
}
strcpy(param->action, json_object_get_string(jaction));
if (strcmp(param->action, "stop") == 0) {
json_object_put(jobj);
return 0;
}
// get profile
json_object *jprofile = NULL;
if (!json_object_object_get_ex(jobj, "profile", &jprofile)) {
debug(LOG_ERR, "instaloader: json_object_object_get_ex failed\n");
json_object_put(jobj);
return -1;
}
strcpy(param->profile, json_object_get_string(jprofile));
// free json object
json_object_put(jobj);
return 0;
}
static void
instaloader_response(struct evhttp_request *req, char *result)
{
struct evbuffer *resp = evbuffer_new();
evbuffer_add_printf(resp, "{\"status\": \"%s\"}", result);
evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "application/json");
evhttp_send_reply(req, HTTP_OK, "OK", resp);
}
// define instaloader read callback function
static void
instaloader_read_cb(struct evhttp_request *req, void *args)
{
#define BUFF_LEN 4096
// read data from bufferevent
char data[BUFF_LEN] = {0};
struct evbuffer *input = evhttp_request_get_input_buffer(req);
size_t len = evbuffer_get_length(input);
assert(len < BUFF_LEN);
if (len >= BUFF_LEN) {
debug(LOG_ERR, "instaloader: data length is too long\n");
instaloader_response(req, "data length is too long");
return;
}
debug(LOG_DEBUG, "instaloader: data: %s\n", data);
// parse http post and get its json data
evbuffer_copyout(input, data, len);
debug(LOG_DEBUG, "instaloader: data: %s\n", data);
struct instaloader_param *param = (struct instaloader_param *)malloc(sizeof(struct instaloader_param));
assert(param != NULL);
memset(param, 0, sizeof(struct instaloader_param));
int nret = parse_instaloader_command(data, param);
if (nret != 0) {
debug(LOG_ERR, "instaloader: parse_command failed\n");
free(param);
instaloader_response(req, "failed to parse command");
return;
}
// create a thread
pthread_t thread;
// create a thread attribute
pthread_attr_t attr;
// initialize thread attribute
pthread_attr_init(&attr);
// set thread attribute to detach
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// create a thread
pthread_create(&thread, &attr, instaloader_worker, param);
// destroy thread attribute
pthread_attr_destroy(&attr);
instaloader_response(req, "ok");
}
// define instaloader http post callback function
static void
http_post_cb(struct evhttp_request *req, void *arg)
{
// check http request method
if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
debug(LOG_ERR, "instaloader: http request method is not POST\n");
evhttp_send_error(req, HTTP_BADMETHOD, "Method Not Allowed");
return;
}
// Check the HTTP request content type
const char *content_type = evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type");
if (content_type == NULL || strcmp(content_type, "application/json") != 0) {
debug(LOG_ERR, "instaloader: http request content type is not application/json\n");
evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
return;
}
// get json data from http request
instaloader_read_cb(req, arg);
}
// define instaloader service
static void *
instaloader_service(void *local_port)
{
uint16_t port = *(uint16_t *)local_port;
free(local_port);
// Initialize libevent
struct event_base *base = event_base_new();
if (!base) {
debug(LOG_ERR, "instaloader: Failed to initialize libevent\n");
return NULL;
}
// Create a new HTTP server
struct evhttp *http = evhttp_new(base);
if (!http) {
debug(LOG_ERR, "Failed to create HTTP server\n");
return NULL;
}
if (evhttp_bind_socket(http, "0.0.0.0", port) != 0) {
debug(LOG_ERR, "Failed to bind HTTP server to port %d\n", port);
return NULL;
}
debug(LOG_DEBUG, "instaloader: start instaloader service on port %d\n", port);
// Set up a callback function for handling HTTP requests
evhttp_set_cb(http, "/", http_post_cb, NULL);
// Start the event loop
event_base_dispatch(base);
// Clean up
evhttp_free(http);
event_base_free(base);
return NULL;
}
int
start_instaloader_service(uint16_t local_port)
{
uint16_t *p = (uint16_t *)malloc(sizeof(uint16_t));
assert(p != NULL);
*p = local_port;
// create a thread
pthread_t thread;
// create a thread attribute
pthread_attr_t attr;
// initialize thread attribute
pthread_attr_init(&attr);
// set thread attribute to detach
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// create a thread
pthread_create(&thread, &attr, instaloader_service, (void *)p);
// destroy thread attribute
pthread_attr_destroy(&attr);
return 0;
}

6
plugins/instaloader.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _INSTALOADER_H_
#define _INSTALOADER_H_
int start_instaloader_service(uint16_t local_port);
#endif

289
plugins/youtubedl.c Normal file
View File

@@ -0,0 +1,289 @@
#include <json-c/json.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <event2/http.h>
#include "../common.h"
#include "../debug.h"
#include "../config.h"
#include "youtubedl.h"
struct yt_dlp_param {
char action[10];
char profile[100];
};
// define yt-dlp worker function
static void *
yt_dlp_worker(void *param)
{
struct yt_dlp_param *p = (struct yt_dlp_param *)param;
debug(LOG_DEBUG, "yt-dlp: action: %s, url: %s\n", p->action, p->profile);
char cmd[512] = {0};
// create directory yt-dlp and change current directory to it
snprintf(cmd, sizeof(cmd), "mkdir -p yt-dlp && cd yt-dlp");
debug(LOG_DEBUG, "yt-dlp: cmd: %s\n", cmd);
system(cmd);
if (strcmp(p->action, "download") == 0) {
// download profile
snprintf(cmd, sizeof(cmd), "yt-dlp %s", p->profile);
debug(LOG_DEBUG, "yt-dlp: cmd: %s\n", cmd);
// use popen to execute cmd and get its output
FILE *fp = popen(cmd, "r");
if (fp == NULL) {
debug(LOG_ERR, "yt-dlp: popen failed\n");
free(param);
return NULL;
}
char buf[512] = {0};
while (fgets(buf, sizeof(buf), fp) != NULL) {
debug(LOG_DEBUG, "yt-dlp: %s", buf);
memset(buf, 0, sizeof(buf));
}
pclose(fp);
} else {
debug(LOG_ERR, "yt-dlp: unknown action: %s\n", p->action);
}
// free param
free(param);
return 0;
}
static int
parse_yt_dlp_command(char *json_data, struct yt_dlp_param *param)
{
// parse json data with json-c to param
json_object *jobj = json_tokener_parse(json_data);
if (jobj == NULL) {
debug(LOG_ERR, "yt-dlp: json_tokener_parse failed\n");
return -1;
}
// get action
json_object *jaction = NULL;
if (!json_object_object_get_ex(jobj, "action", &jaction)) {
debug(LOG_ERR, "yt-dlp: json_object_object_get_ex failed\n");
json_object_put(jobj);
return -1;
}
strcpy(param->action, json_object_get_string(jaction));
if (strcmp(param->action, "stop") == 0) {
json_object_put(jobj);
return 0;
}
// get profile
json_object *jprofile = NULL;
if (!json_object_object_get_ex(jobj, "profile", &jprofile)) {
debug(LOG_ERR, "yt-dlp: json_object_object_get_ex failed\n");
json_object_put(jobj);
return -1;
}
strcpy(param->profile, json_object_get_string(jprofile));
// free json object
json_object_put(jobj);
return 0;
}
static void
yt_dlp_response(struct evhttp_request *req, char *result)
{
struct evbuffer *resp = evbuffer_new();
evbuffer_add_printf(resp, "{\"status\": \"%s\"}", result);
evhttp_add_header(evhttp_request_get_output_headers(req), "Content-Type", "application/json");
evhttp_send_reply(req, HTTP_OK, "OK", resp);
}
// define yt-dlp read callback function
static void
yt_dlp_read_cb(struct evhttp_request *req, void *args)
{
#define BUFF_LEN 4096
// read data from bufferevent
char data[BUFF_LEN] = {0};
struct evbuffer *input = evhttp_request_get_input_buffer(req);
size_t len = evbuffer_get_length(input);
assert(len < BUFF_LEN);
if (len >= BUFF_LEN) {
debug(LOG_ERR, "yt-dlp: data length is too long\n");
yt_dlp_response(req, "data length is too long");
return;
}
debug(LOG_DEBUG, "yt-dlp: data: %s\n", data);
// parse http post and get its json data
evbuffer_copyout(input, data, len);
debug(LOG_DEBUG, "yt-dlp: data: %s\n", data);
struct yt_dlp_param *param = (struct yt_dlp_param *)malloc(sizeof(struct yt_dlp_param));
assert(param != NULL);
memset(param, 0, sizeof(struct yt_dlp_param));
int nret = parse_yt_dlp_command (data, param);
if (nret != 0) {
debug(LOG_ERR, "yt-dlp: parse_command failed\n");
free(param);
yt_dlp_response(req, "failed to parse command");
return;
}
// create a thread
pthread_t thread;
// create a thread attribute
pthread_attr_t attr;
// initialize thread attribute
pthread_attr_init(&attr);
// set thread attribute to detach
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// create a thread
pthread_create(&thread, &attr, yt_dlp_worker, param);
// destroy thread attribute
pthread_attr_destroy(&attr);
yt_dlp_response(req, "ok");
}
// define yt-dlp http post callback function
static void
http_post_cb(struct evhttp_request *req, void *arg)
{
// check http request method
if (evhttp_request_get_command(req) != EVHTTP_REQ_POST) {
debug(LOG_ERR, "yt-dlp: http request method is not POST\n");
evhttp_send_error(req, HTTP_BADMETHOD, "Method Not Allowed");
return;
}
// Check the HTTP request content type
const char *content_type = evhttp_find_header(evhttp_request_get_input_headers(req), "Content-Type");
if (content_type == NULL || strcmp(content_type, "application/json") != 0) {
debug(LOG_ERR, "yt-dlp: http request content type is not application/json\n");
evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
return;
}
// get json data from http request
yt_dlp_read_cb(req, arg);
}
static int
install_yt_dlp()
{
// if yt-dlp exists, return
if (access("/usr/local/bin/yt-dlp", F_OK) == 0) {
debug(LOG_DEBUG, "yt-dlp: yt-dlp exists\n");
return 0;
}
// install yt-dlp to /usr/local/bin
// download yt-dlp through curl or wget if any of them exists
char cmd[512] = {0};
if (access("/usr/bin/curl", F_OK) == 0) {
snprintf(cmd, sizeof(cmd), "sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp");
} else if (access("/usr/bin/wget", F_OK) == 0) {
snprintf(cmd, sizeof(cmd), "sudo wget https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -O /usr/local/bin/yt-dlp");
} else {
debug(LOG_ERR, "yt-dlp: curl and wget are not installed\n");
return -1;
}
debug(LOG_DEBUG, "yt-dlp: cmd: %s\n", cmd);
int nret = system(cmd);
if (nret != 0) {
debug(LOG_ERR, "yt-dlp: system failed\n");
return -1;
}
// change yt-dlp to executable
snprintf(cmd, sizeof(cmd), "sudo chmod a+rx /usr/local/bin/yt-dlp");
debug(LOG_DEBUG, "yt-dlp: cmd: %s\n", cmd);
nret = system(cmd);
if (nret != 0) {
debug(LOG_ERR, "yt-dlp: system failed\n");
return -1;
}
return 0;
}
// define yt-dlp service
static void *
yt_dlp_service(void *local_port)
{
// install yt-dlp
int nret = install_yt_dlp();
if (nret != 0) {
debug(LOG_ERR, "yt-dlp: install_yt_dlp failed\n");
return NULL;
}
uint16_t port = *(uint16_t *)local_port;
free(local_port);
// Initialize libevent
struct event_base *base = event_base_new();
if (!base) {
debug(LOG_ERR, "yt-dlp: Failed to initialize libevent\n");
return NULL;
}
// Create a new HTTP server
struct evhttp *http = evhttp_new(base);
if (!http) {
debug(LOG_ERR, "yt-dlp: Failed to create HTTP server\n");
return NULL;
}
if (evhttp_bind_socket(http, "0.0.0.0", port) != 0) {
debug(LOG_ERR, "yt-dlp: Failed to bind HTTP server to port %d\n", port);
return NULL;
}
debug(LOG_DEBUG, "yt-dlp: start youtube download service on port %d\n", port);
// Set up a callback function for handling HTTP requests
evhttp_set_cb(http, "/", http_post_cb, NULL);
// Start the event loop
event_base_dispatch(base);
// Clean up
evhttp_free(http);
event_base_free(base);
return NULL;
}
int
start_youtubedl_service(uint16_t local_port)
{
uint16_t *p = (uint16_t *)malloc(sizeof(uint16_t));
assert(p != NULL);
*p = local_port;
// create a thread
pthread_t thread;
// create a thread attribute
pthread_attr_t attr;
// initialize thread attribute
pthread_attr_init(&attr);
// set thread attribute to detach
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// create a thread
pthread_create(&thread, &attr, yt_dlp_service, (void *)p);
// destroy thread attribute
pthread_attr_destroy(&attr);
return 0;
}

6
plugins/youtubedl.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef _YOUTUBE_DL_H_
#define _YOUTUBE_DL_H_
int start_youtubedl_service(uint16_t local_port);
#endif

View File

@@ -1,7 +1,7 @@
#ifndef _VERSION_H_
#define _VERSION_H_
#define VERSION "2.9.644"
#define VERSION "2.12.656"
#define PROTOCOL_VERESION "0.43.0"
#define CLIENT_V 1

24
xfrpc.c
View File

@@ -49,6 +49,8 @@
#include "config.h"
#include "plugins/telnetd.h"
#include "plugins/instaloader.h"
#include "plugins/httpd.h"
static void start_xfrpc_local_service()
{
@@ -57,12 +59,22 @@ static void start_xfrpc_local_service()
struct proxy_service *ps, *ps_tmp;
struct proxy_service *all_ps = get_all_proxy_services();
HASH_ITER(hh, all_ps, ps, ps_tmp) {
if (ps->proxy_type && strcmp(ps->proxy_type, "mstsc") == 0) {
// start tcp_redir for it
start_tcp_redir_service(ps);
}
if (ps->plugin && strcmp(ps->plugin, "telnetd") == 0) {
simple_telnetd_start(ps->local_port);
if (ps->plugin) {
if (strcmp(ps->plugin, "telnetd") == 0) {
simple_telnetd_start(ps->local_port);
} else if (strcmp(ps->plugin, "instaloader") == 0) {
// start instaloader service
start_instaloader_service(ps->local_port);
} else if (strcmp(ps->plugin, "youtubedl") == 0) {
// start youtubedl service
start_youtubedl_service(ps->local_port);
} else if (strcmp(ps->plugin, "instaloader_redir") == 0) {
start_tcp_redir_service(ps);
} else if (strcmp(ps->plugin, "httpd") == 0) {
start_httpd_service(ps);
} else {
debug(LOG_ERR, "start_xfrpc_local_service: unknown plugin %s\n", ps->plugin);
}
}
}