Skip to content

Commit

Permalink
plugin: add instaloder plugin to download instagram
Browse files Browse the repository at this point in the history
Signed-off-by: staylightblow8 <liudf0716@gmail.com>
  • Loading branch information
liudf0716 committed Oct 22, 2023
1 parent 86866e7 commit d7e064c
Show file tree
Hide file tree
Showing 7 changed files with 272 additions and 6 deletions.
9 changes: 7 additions & 2 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ set(src_xfrpc
)

set(src_xfrpc_plugins
plugins/telnetd.c)
plugins/telnetd.c
plugins/instaloader.c)

set(libs
ssl
Expand Down
9 changes: 8 additions & 1 deletion config.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,13 +318,20 @@ 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->local_ip == NULL)
ps->local_ip = strdup("127.0.0.1");
} else {
debug(LOG_INFO, "plugin %s is not supportted", ps->plugin);
}
}

Expand Down
3 changes: 3 additions & 0 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +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 FTP_RMT_CTL_PROXY_SUFFIX "_ftp_remote_ctl_proxy"

//client common config
Expand Down
235 changes: 235 additions & 0 deletions plugins/instaloader.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
#include <json-c/json.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <pthread.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[200] = {0};
if (strcmp(p->action, "download") == 0) {
// download profile
snprintf(cmd, 200, "instaloader %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);
} 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) == FALSE) {
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));

// get profile
json_object *jprofile = NULL;
if (json_object_object_get_ex(jobj, "profile", &jprofile) == FALSE) {
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 bufferevent *bev, char *result)
{
char resp[128] = {0};
snprintf(resp, 128, "{\"status\": \"%s\"}", result);
bufferevent_write(bev, resp, strlen(resp));
}

// define instaloader read callback function
static void
instaloader_read_cb(struct bufferevent *bev, void *ctx)
{
#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);
return;
}
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);
if (nret != 0) {
debug(LOG_ERR, "instaloader: parse_command failed\n");
free(param);
instaloader_response(bev, "failed to parse command");
bufferevent_free(bev);
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(bev, "ok");

// close bufferevent
bufferevent_free(bev);
}

// define instaloader event callback function
static void
instaloader_event_cb(struct bufferevent *bev, short events, void *ctx)
{
if (events & BEV_EVENT_ERROR) {
debug(LOG_ERR, "instaloader: Error from bufferevent\n");
}
if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR)) {
bufferevent_free(bev);
}
}

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

// 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)
{
// Initialize libevent
struct event_base *base = event_base_new();
if (!base) {
debug(LOG_ERR, "instaloader: Failed to initialize libevent\n");
return -1;
}

// 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(*local_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);
return -1;
}

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

// Start the event loop
event_base_dispatch(base);

// Clean up
evconnlistener_free(listener);
event_base_free(base);

return 0;
}


int
start_instaloader_service(uint16_t 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, &local_port);
// destroy thread attribute
pthread_attr_destroy(&attr);

return 0;
}
6 changes: 6 additions & 0 deletions plugins/instaloader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef _INSTALOADER_H_
#define _INSTALOADER_H_

int start_instaloader_service(uint16_t local_port);

#endif
13 changes: 11 additions & 2 deletions xfrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "config.h"

#include "plugins/telnetd.h"
#include "plugins/instaloader.h"

static void start_xfrpc_local_service()
{
Expand All @@ -61,8 +62,16 @@ static void start_xfrpc_local_service()
// 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 {
debug(LOG_ERR, "start_xfrpc_local_service: unknown plugin %s\n", ps->plugin);
}
}
}

Expand Down

0 comments on commit d7e064c

Please sign in to comment.