diff --git a/config.c b/config.c index bf35430..837430d 100644 --- a/config.c +++ b/config.c @@ -48,7 +48,6 @@ static const char *valid_types[] = { "tcp", "udp", - "mstsc", "socks5", "http", "https", @@ -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); @@ -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); } @@ -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); } diff --git a/config.h b/config.h index d26c46f..f1ba578 100644 --- a/config.h +++ b/config.h @@ -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" diff --git a/plugins/instaloader.c b/plugins/instaloader.c index ca2997d..a5409b2 100644 --- a/plugins/instaloader.c +++ b/plugins/instaloader.c @@ -6,6 +6,7 @@ #include #include +#include #include "../common.h" #include "../debug.h" @@ -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); } @@ -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; @@ -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; } @@ -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) @@ -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; } diff --git a/xfrpc.c b/xfrpc.c index 6187869..cb87efb 100644 --- a/xfrpc.c +++ b/xfrpc.c @@ -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); }