Skip to content

Commit

Permalink
plugin: add instaloader local redir service
Browse files Browse the repository at this point in the history
Signed-off-by: staylightblow8 <liudf0716@gmail.com>
  • Loading branch information
liudf0716 committed Oct 28, 2023
1 parent be51233 commit c895f22
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 93 deletions.
20 changes: 9 additions & 11 deletions config.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
static const char *valid_types[] = {
"tcp",
"udp",
"mstsc",
"socks5",
"http",
"https",
Expand Down Expand Up @@ -239,11 +238,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);
Expand Down Expand Up @@ -328,8 +322,17 @@ process_plugin_conf(struct proxy_service *ps)
} 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_ROMOTE_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_ROMOTE_PORT;
if (ps->local_ip == NULL)
ps->local_ip = strdup("0.0.0.0");
} else {
debug(LOG_INFO, "plugin %s is not supportted", ps->plugin);
}
Expand Down Expand Up @@ -421,11 +424,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);
}
Expand Down
5 changes: 3 additions & 2 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@

#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_TELNETD_PORT 23
#define XFRPC_PLUGIN_INSTALOADER_PORT 10000
#define XFRPC_PLUGIN_INSTALOADER_ROMOTE_PORT 10001

#define FTP_RMT_CTL_PROXY_SUFFIX "_ftp_remote_ctl_proxy"

Expand Down
150 changes: 75 additions & 75 deletions plugins/instaloader.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <errno.h>
#include <pthread.h>

#include <event2/http.h>

#include "../common.h"
#include "../debug.h"
Expand All @@ -23,22 +24,28 @@ 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[200] = {0};
char cmd[512] = {0};
if (strcmp(p->action, "download") == 0) {
// download profile
snprintf(cmd, 200, "instaloader %s", p->profile);
snprintf(cmd, 200, "instaloader --no-captions --no-metadata-json --no-compress-json --no-pictures %s", p->profile);
debug(LOG_DEBUG, "instaloader: cmd: %s\n", cmd);
system(cmd);
} else if (strcmp(p->action, "download_videos") == 0) {
// download videos
snprintf(cmd, 200, "instaloader --no-pictures %s", p->profile);
debug(LOG_DEBUG, "instaloader: cmd: %s\n", cmd);
system(cmd);
} else if (strcmp(p->action, "download_pictures") == 0) {
// download pictures
snprintf(cmd, 200, "instaloader --no-videos %s", p->profile);
debug(LOG_DEBUG, "instaloader: cmd: %s\n", cmd);
system(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);
}
Expand All @@ -62,16 +69,20 @@ parse_instaloader_command(char *json_data, struct instaloader_param *param)

// get action
json_object *jaction = NULL;
if (json_object_object_get_ex(jobj, "action", &jaction) == FALSE) {
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) == FALSE) {
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;
Expand All @@ -85,39 +96,44 @@ parse_instaloader_command(char *json_data, struct instaloader_param *param)
}

static void
instaloader_response(struct bufferevent *bev, char *result)
instaloader_response(struct evhttp_request *req, char *result)
{
char resp[128] = {0};
snprintf(resp, 128, "{\"status\": \"%s\"}", result);
bufferevent_write(bev, resp, strlen(resp));
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 bufferevent *bev, void *ctx)
instaloader_read_cb(struct evhttp_request *req, void *args)
{
#define BUFF_LEN 4096
// read data from bufferevent
char data[BUFF_LEN] = {0};
int nret = bufferevent_read(bev, data, sizeof(data));
if (nret <= 0) {
debug(LOG_ERR, "instaloader: bufferevent_read failed\n");
instaloader_response(bev, "failed to read data");
bufferevent_free(bev);
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));

nret = parse_instaloader_command(data, param);
int nret = parse_instaloader_command(data, param);
if (nret != 0) {
debug(LOG_ERR, "instaloader: parse_command failed\n");
free(param);
instaloader_response(bev, "failed to parse command");
bufferevent_free(bev);
instaloader_response(req, "failed to parse command");
return;
}

Expand All @@ -134,48 +150,34 @@ instaloader_read_cb(struct bufferevent *bev, void *ctx)
// destroy thread attribute
pthread_attr_destroy(&attr);

instaloader_response(bev, "ok");

// close bufferevent
bufferevent_free(bev);
instaloader_response(req, "ok");
}

// define instaloader event callback function
// define instaloader http post callback function
static void
instaloader_event_cb(struct bufferevent *bev, short events, void *ctx)
http_post_cb(struct evhttp_request *req, void *arg)
{
if (events & BEV_EVENT_ERROR) {
debug(LOG_ERR, "instaloader: Error from bufferevent\n");
// 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;
}
if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
bufferevent_free(bev);

// 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;
}
}

// Callback function for handling new connections
static void
accept_conn_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *address, int socklen, void *ctx)
{
debug(LOG_DEBUG, "instaloader: accept_conn_cb\n");
// Create a new bufferevent for the connection
struct event_base *base = evconnlistener_get_base(listener);
struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

// Set up callbacks for the bufferevent
bufferevent_setcb(bev, instaloader_read_cb, NULL, instaloader_event_cb, NULL);
bufferevent_enable(bev, EV_READ | EV_WRITE);
}
// get json data from http request
instaloader_read_cb(req, arg);

// Callback function for handling errors on the listener
static void
accept_error_cb(struct evconnlistener *listener, void *ctx)
{
struct event_base *base = evconnlistener_get_base(listener);
int err = EVUTIL_SOCKET_ERROR();
debug(LOG_ERR, "instaloader: Got an error %d (%s) on the listener. Shutting down.\n", err, evutil_socket_error_to_string(err));
event_base_loopexit(base, NULL);
}


// define instaloader service
static void *
instaloader_service(void *local_port)
Expand All @@ -189,30 +191,28 @@ instaloader_service(void *local_port)
return NULL;
}

// Create a new listener for incoming connections
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(port);

struct evconnlistener *listener = evconnlistener_new_bind(base, accept_conn_cb, NULL, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (struct sockaddr *)&sin, sizeof(sin));
if (!listener) {
debug(LOG_ERR, "instaloader: Failed to create listener\n");
event_base_free(base);
// Create a new HTTP server
struct evhttp *http = evhttp_new(base);
if (!http) {
debug(LOG_ERR, "Failed to create HTTP server\n");
return NULL;
}

// Set up error handling for the listener
evconnlistener_set_error_cb(listener, accept_error_cb);

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;
}

// 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
evconnlistener_free(listener);
evhttp_free(http);
event_base_free(base);

return NULL;
}

Expand Down
7 changes: 2 additions & 5 deletions xfrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,14 @@ 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) {
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, "instaloader_redir") == 0) {
start_tcp_redir_service(ps);
} else {
debug(LOG_ERR, "start_xfrpc_local_service: unknown plugin %s\n", ps->plugin);
}
Expand Down

0 comments on commit c895f22

Please sign in to comment.