From 14ac6fa5abc63f2ea7dd1190749262db811692c8 Mon Sep 17 00:00:00 2001 From: Kano Date: Thu, 22 Aug 2013 09:27:49 +1000 Subject: [PATCH 1/2] Initial API Multicast response v0.1 to find cgminer APIs --- api.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++- cgminer.c | 34 +++++++++++ miner.h | 7 +++ 3 files changed, 204 insertions(+), 1 deletion(-) diff --git a/api.c b/api.c index 4fcc66f9..b046a980 100644 --- a/api.c +++ b/api.c @@ -126,6 +126,7 @@ char *WSAErrorMsg(void) { #endif static const char *UNAVAILABLE = " - API will not be available"; +static const char *MUNAVAILABLE = " - API multicast listener will not be available"; static const char *BLANK = ""; static const char *COMMA = ","; @@ -134,7 +135,7 @@ static const char SEPARATOR = '|'; #define SEPSTR "|" static const char GPUSEP = ','; -static const char *APIVERSION = "1.28"; +static const char *APIVERSION = "1.29"; static const char *DEAD = "Dead"; #if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) || defined(HAVE_AN_ASIC) static const char *SICK = "Sick"; @@ -4259,6 +4260,164 @@ static void *restart_thread(__maybe_unused void *userdata) return NULL; } +static void mcast() +{ + struct sockaddr_in listen; + struct ip_mreq grp; + struct sockaddr_in came_from; + time_t bindstart; + char *binderror; + SOCKETTYPE mcast_sock; + SOCKETTYPE reply_sock; + socklen_t came_from_siz; + ssize_t rep; + int bound; + int count; + int reply_port; + + char expect[] = "cgminer-"; // first 8 bytes constant + char *expect_code; + size_t expect_code_len; + char buf[1024]; + char reply[] = "cgm-" API_MCAST_CODE "-"; // constant + char replybuf[1024]; + + memset(&grp, 0, sizeof(grp)); + grp.imr_multiaddr.s_addr = inet_addr(opt_api_mcast_addr); + if (grp.imr_multiaddr.s_addr == INADDR_NONE) + quit(1, "Invalid Multicast Address"); + grp.imr_interface.s_addr = inet_addr("192.168.7.70"); + + mcast_sock = socket(AF_INET, SOCK_DGRAM, 0); + + int optval = 1; + if (SOCKETFAIL(setsockopt(mcast_sock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval)))) { + applog(LOG_ERR, "API mcast setsockopt SO_REUSEADDR failed (%s)%s", SOCKERRMSG, MUNAVAILABLE); + goto die; + } + + memset(&listen, 0, sizeof(listen)); + listen.sin_family = AF_INET; + listen.sin_addr.s_addr = INADDR_ANY; + listen.sin_port = htons(opt_api_mcast_port); + + // try for more than 1 minute ... in case the old one hasn't completely gone yet + bound = 0; + bindstart = time(NULL); + while (bound == 0) { + if (SOCKETFAIL(bind(mcast_sock, (struct sockaddr *)(&listen), sizeof(listen)))) { + binderror = SOCKERRMSG; + if ((time(NULL) - bindstart) > 61) + break; + else + cgsleep_ms(30000); + } else + bound = 1; + } + + if (bound == 0) { + applog(LOG_ERR, "API mcast bind to port %d failed (%s)%s", opt_api_port, binderror, MUNAVAILABLE); + goto die; + } + + if (SOCKETFAIL(setsockopt(mcast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)(&grp), sizeof(grp)))) { + applog(LOG_ERR, "API mcast join failed (%s)%s", SOCKERRMSG, MUNAVAILABLE); + goto die; + } + + expect_code_len = sizeof(expect) + strlen(opt_api_mcast_code); + expect_code = malloc(expect_code_len+1); + if (!expect_code) + quit(1, "Failed to malloc mcast expect_code"); + snprintf(expect_code, expect_code_len+1, "%s%s-", expect, opt_api_mcast_code); + + count = 0; + while (80085) { + cgsleep_ms(1000); + + count++; + came_from_siz = sizeof(came_from); + if (SOCKETFAIL(rep = recvfrom(mcast_sock, buf, sizeof(buf), + 0, (struct sockaddr *)(&came_from), &came_from_siz))) { + applog(LOG_DEBUG, "API mcast failed count=%d (%s) (%d)", + count, SOCKERRMSG, (int)mcast_sock); + continue; + } + buf[rep] = '\0'; + if (rep > 0 && buf[rep-1] == '\n') + buf[--rep] = '\0'; + + applog(LOG_DEBUG, "API mcast request rep=%d (%s) from %s:%d", + (int)rep, buf, + inet_ntoa(came_from.sin_addr), + ntohs(came_from.sin_port)); + + if ((size_t)rep > expect_code_len && memcmp(buf, expect_code, expect_code_len) == 0) { + reply_port = atoi(&buf[expect_code_len]); + if (reply_port < 1 || reply_port > 65535) { + applog(LOG_DEBUG, "API mcast request ignored - invalid port (%s)", + &buf[expect_code_len]); + } else { + applog(LOG_DEBUG, "API mcast request OK port %s=%d", + &buf[expect_code_len], reply_port); + + came_from.sin_port = htons(reply_port); + reply_sock = socket(AF_INET, SOCK_DGRAM, 0); + + snprintf(replybuf, sizeof(replybuf), + "cgm-" API_MCAST_CODE "-%d", + opt_api_port); + + rep = sendto(reply_sock, replybuf, strlen(replybuf)+1, + 0, (struct sockaddr *)(&came_from), + sizeof(came_from)); + if (SOCKETFAIL(rep)) { + applog(LOG_DEBUG, "API mcast reply failed (%s) (%d)", + SOCKERRMSG, (int)reply_sock); + } else { + applog(LOG_DEBUG, "API mcast reply (%s) succeeded (%d) (%d)", + reply, (int)rep, (int)reply_sock); + } + + CLOSESOCKET(reply_sock); + } + } else + applog(LOG_DEBUG, "API mcast request was no good"); + } + +die: + + CLOSESOCKET(mcast_sock); +} + +static void *mcast_thread(void *userdata) +{ + struct thr_info *mythr = userdata; + + pthread_detach(pthread_self()); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + RenameThread("api_mcast"); + + mcast(); + + PTH(mythr) = 0L; + + return NULL; +} + +void mcast_init() +{ + struct thr_info *thr; + + thr = calloc(1, sizeof(*thr)); + if (!thr) + quit(1, "Failed to calloc mcast thr"); + + if (thr_info_create(thr, NULL, mcast_thread, thr)) + quit(1, "API mcast thread create failed"); +} + void api(int api_thr_id) { struct io_data *io_data; @@ -4389,6 +4548,9 @@ void api(int api_thr_id) applog(LOG_WARNING, "API running in local read access mode on port %d (%d)", port, (int)*apisock); } + if (opt_api_mcast) + mcast_init(); + while (!bye) { clisiz = sizeof(cli); if (SOCKETFAIL(c = accept(*apisock, (struct sockaddr *)(&cli), &clisiz))) { diff --git a/cgminer.c b/cgminer.c index d997534d..1552d2cd 100644 --- a/cgminer.c +++ b/cgminer.c @@ -145,6 +145,10 @@ char *opt_api_groups; char *opt_api_description = PACKAGE_STRING; int opt_api_port = 4028; bool opt_api_listen; +bool opt_api_mcast; +char *opt_api_mcast_addr = API_MCAST_ADDR; +char *opt_api_mcast_code = API_MCAST_CODE; +int opt_api_mcast_port = 4028; bool opt_api_network; bool opt_delaynet; bool opt_disable_pool; @@ -890,6 +894,20 @@ static char *set_api_description(const char *arg) return NULL; } +static char *set_api_mcast_addr(const char *arg) +{ + opt_set_charp(arg, &opt_api_mcast_addr); + + return NULL; +} + +static char *set_api_mcast_code(const char *arg) +{ + opt_set_charp(arg, &opt_api_mcast_code); + + return NULL; +} + #ifdef USE_ICARUS static char *set_icarus_options(const char *arg) { @@ -943,6 +961,18 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--api-listen", opt_set_bool, &opt_api_listen, "Enable API, default: disabled"), + OPT_WITHOUT_ARG("--api-mcast", + opt_set_bool, &opt_api_mcast, + "Enable API Multicast listener, default: disabled"), + OPT_WITH_ARG("--api-mcast-addr", + set_api_mcast_addr, NULL, NULL, + "API Multicast listen address"), + OPT_WITH_ARG("--api-mcast-code", + set_api_mcast_code, NULL, NULL, + "Code expected in the API Multicast"), + OPT_WITH_ARG("--api-mcast-port", + set_int_1_to_65535, opt_show_intval, &opt_api_mcast_port, + "Port number of miner API Multicast listener"), OPT_WITHOUT_ARG("--api-network", opt_set_bool, &opt_api_network, "Allow API (if enabled) to listen on/for any address, default: only 127.0.0.1"), @@ -4177,6 +4207,10 @@ void write_config(FILE *fcfg) fprintf(fcfg, ",\n\"remove-disabled\" : true"); if (opt_api_allow) fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", json_escape(opt_api_allow)); + if (strcmp(opt_api_mcast_addr, API_MCAST_ADDR) != 0) + fprintf(fcfg, ",\n\"api-mcast-addr\" : \"%s\"", json_escape(opt_api_mcast_addr)); + if (strcmp(opt_api_mcast_code, API_MCAST_CODE) != 0) + fprintf(fcfg, ",\n\"api-mcast-code\" : \"%s\"", json_escape(opt_api_mcast_code)); if (strcmp(opt_api_description, PACKAGE_STRING) != 0) fprintf(fcfg, ",\n\"api-description\" : \"%s\"", json_escape(opt_api_description)); if (opt_api_groups) diff --git a/miner.h b/miner.h index f4eb91a8..ab59cba0 100644 --- a/miner.h +++ b/miner.h @@ -867,6 +867,9 @@ static inline void cg_wunlock(cglock_t *lock) struct pool; +#define API_MCAST_CODE "FTW" +#define API_MCAST_ADDR "224.0.0.75" + extern bool opt_protocol; extern bool have_longpoll; extern char *opt_kernel_path; @@ -877,6 +880,10 @@ extern bool opt_autofan; extern bool opt_autoengine; extern bool use_curses; extern char *opt_api_allow; +extern bool opt_api_mcast; +extern char *opt_api_mcast_addr; +extern char *opt_api_mcast_code; +extern int opt_api_mcast_port; extern char *opt_api_groups; extern char *opt_api_description; extern int opt_api_port; From 55e7f31425f444b3511d71d67f2fbb9e76054ef1 Mon Sep 17 00:00:00 2001 From: Kano Date: Thu, 22 Aug 2013 23:38:57 +1000 Subject: [PATCH 2/2] API mcast only reply to remote IP's that are allowed access --- api.c | 67 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/api.c b/api.c index b046a980..1afbec09 100644 --- a/api.c +++ b/api.c @@ -626,6 +626,8 @@ struct CODES { { SEVERITY_FAIL, 0, 0, NULL } }; +static const char *localaddr = "127.0.0.1"; + static int my_thr_id = 0; static bool bye; @@ -4260,6 +4262,33 @@ static void *restart_thread(__maybe_unused void *userdata) return NULL; } +static bool check_connect(struct sockaddr_in *cli, char **connectaddr, char *group) +{ + bool addrok = false; + int i; + + *connectaddr = inet_ntoa(cli->sin_addr); + + *group = NOPRIVGROUP; + if (opt_api_allow) { + int client_ip = htonl(cli->sin_addr.s_addr); + for (i = 0; i < ips; i++) { + if ((client_ip & ipaccess[i].mask) == ipaccess[i].ip) { + addrok = true; + *group = ipaccess[i].group; + break; + } + } + } else { + if (opt_api_network) + addrok = true; + else + addrok = (strcmp(*connectaddr, localaddr) == 0); + } + + return addrok; +} + static void mcast() { struct sockaddr_in listen; @@ -4270,10 +4299,13 @@ static void mcast() SOCKETTYPE mcast_sock; SOCKETTYPE reply_sock; socklen_t came_from_siz; + char *connectaddr; ssize_t rep; int bound; int count; int reply_port; + bool addrok; + char group; char expect[] = "cgminer-"; // first 8 bytes constant char *expect_code; @@ -4286,7 +4318,7 @@ static void mcast() grp.imr_multiaddr.s_addr = inet_addr(opt_api_mcast_addr); if (grp.imr_multiaddr.s_addr == INADDR_NONE) quit(1, "Invalid Multicast Address"); - grp.imr_interface.s_addr = inet_addr("192.168.7.70"); + grp.imr_interface.s_addr = INADDR_ANY; mcast_sock = socket(AF_INET, SOCK_DGRAM, 0); @@ -4343,6 +4375,13 @@ static void mcast() count, SOCKERRMSG, (int)mcast_sock); continue; } + + addrok = check_connect(&came_from, &connectaddr, &group); + applog(LOG_DEBUG, "API mcast from %s - %s", + connectaddr, addrok ? "Accepted" : "Ignored"); + if (!addrok) + continue; + buf[rep] = '\0'; if (rep > 0 && buf[rep-1] == '\n') buf[--rep] = '\0'; @@ -4424,7 +4463,6 @@ void api(int api_thr_id) struct thr_info bye_thr; char buf[TMPBUFSIZ]; char param_buf[TMPBUFSIZ]; - const char *localaddr = "127.0.0.1"; SOCKETTYPE c; int n, bound; char *connectaddr; @@ -4558,28 +4596,9 @@ void api(int api_thr_id) goto die; } - connectaddr = inet_ntoa(cli.sin_addr); - - addrok = false; - group = NOPRIVGROUP; - if (opt_api_allow) { - int client_ip = htonl(cli.sin_addr.s_addr); - for (i = 0; i < ips; i++) { - if ((client_ip & ipaccess[i].mask) == ipaccess[i].ip) { - addrok = true; - group = ipaccess[i].group; - break; - } - } - } else { - if (opt_api_network) - addrok = true; - else - addrok = (strcmp(connectaddr, localaddr) == 0); - } - - if (opt_debug) - applog(LOG_DEBUG, "API: connection from %s - %s", connectaddr, addrok ? "Accepted" : "Ignored"); + addrok = check_connect(&cli, &connectaddr, &group); + applog(LOG_DEBUG, "API: connection from %s - %s", + connectaddr, addrok ? "Accepted" : "Ignored"); if (addrok) { n = recv(c, &buf[0], TMPBUFSIZ-1, 0);