Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68ffcb2a8a | ||
|
|
2a4eceeeab | ||
|
|
46e3f7df6b | ||
|
|
969c0a160d | ||
|
|
1fd95588ed | ||
|
|
aaeaa2203a | ||
|
|
c895f221da | ||
|
|
be51233c04 |
9
.github/workflows/linux.yml
vendored
9
.github/workflows/linux.yml
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
2
client.h
2
client.h
@@ -106,6 +106,8 @@ struct proxy_service {
|
||||
char *plugin_user;
|
||||
char *plugin_pwd;
|
||||
|
||||
char *s_root_dir;
|
||||
|
||||
// private arguments
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
49
config.c
49
config.c
@@ -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);
|
||||
}
|
||||
|
||||
8
config.h
8
config.h
@@ -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
|
||||
|
||||
3
login.c
3
login.c
@@ -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);
|
||||
|
||||
3
login.h
3
login.h
@@ -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
10039
mongoose.c
Normal file
File diff suppressed because it is too large
Load Diff
1915
mongoose.h
Normal file
1915
mongoose.h
Normal file
File diff suppressed because it is too large
Load Diff
255
msg.c
255
msg.c
@@ -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
3
msg.h
@@ -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
81
plugins/httpd.c
Normal 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
8
plugins/httpd.h
Normal 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
247
plugins/instaloader.c
Normal 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
6
plugins/instaloader.h
Normal 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
289
plugins/youtubedl.c
Normal 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
6
plugins/youtubedl.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef _YOUTUBE_DL_H_
|
||||
#define _YOUTUBE_DL_H_
|
||||
|
||||
int start_youtubedl_service(uint16_t local_port);
|
||||
|
||||
#endif
|
||||
@@ -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
24
xfrpc.c
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user