diff --git a/src/connector.c b/src/connector.c index ff9badb7..91b91183 100644 --- a/src/connector.c +++ b/src/connector.c @@ -1204,7 +1204,9 @@ static void *urecv_process(void *arg) goto decref; } if (!safecmp(method, stratum_msgs[SM_TRANSACTIONS])) - parse_remote_txns(ckp, val); + parse_upstream_txns(ckp, val); + else if (!safecmp(method, stratum_msgs[SM_AUTHRESULT])) + parse_upstream_auth(ckp, val); else if (!safecmp(method, "submitblock")) parse_remote_submitblock(ckp, val, cs->buf); else if (!safecmp(method, "pong")) diff --git a/src/stratifier.c b/src/stratifier.c index c3c35656..aeb4314a 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -312,6 +312,7 @@ struct stratum_instance { int subproxyid; /* Which subproxy */ bool trusted; /* Is this a trusted remote server */ + bool remote; /* Is this a remote client on a trusted remote server */ }; struct share { @@ -5218,6 +5219,41 @@ static void check_global_user(ckpool_t *ckp, user_instance_t *user, stratum_inst send_generator(ckp, buf, GEN_LAX); } +/* Manage the response to auth, client must hold ref */ +static void client_auth(ckpool_t *ckp, stratum_instance_t *client, user_instance_t *user, + const bool ret) +{ + if (ret) { + client->authorised = ret; + user->authorised = ret; + if (ckp->proxy) { + LOGNOTICE("Authorised client %s to proxy %d:%d, worker %s as user %s", + client->identity, client->proxyid, client->subproxyid, + client->workername, user->username); + if (ckp->userproxy) + check_global_user(ckp, user, client); + } else { + LOGNOTICE("Authorised client %s worker %s as user %s", + client->identity, client->workername, user->username); + } + user->failed_authtime = 0; + user->auth_backoff = DEFAULT_AUTH_BACKOFF; /* Reset auth backoff time */ + user->throttled = false; + } else { + LOGNOTICE("Client %s %s worker %s failed to authorise as user %s", + client->identity, client->address, client->workername, + user->username); + user->failed_authtime = time(NULL); + user->auth_backoff <<= 1; + /* Cap backoff time to 10 mins */ + if (user->auth_backoff > 600) + user->auth_backoff = 600; + client->reject = 3; + } + /* We can set this outside of lock safely */ + client->authorising = false; +} + /* Needs to be entered with client holding a ref count. */ static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_val, json_t **err_val, int *errnum) @@ -5308,35 +5344,8 @@ static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_ /* We do the preauth etc. in remote mode, and leave final auth to * upstream pool to complete. */ - if (ckp->remote) - goto out; - - if (ret) { - client->authorised = ret; - user->authorised = ret; - if (ckp->proxy) { - LOGNOTICE("Authorised client %s to proxy %d:%d, worker %s as user %s", - client->identity, client->proxyid, client->subproxyid, buf, user->username); - if (ckp->userproxy) - check_global_user(ckp, user, client); - } else { - LOGNOTICE("Authorised client %s worker %s as user %s", - client->identity, buf, user->username); - } - user->failed_authtime = 0; - user->auth_backoff = DEFAULT_AUTH_BACKOFF; /* Reset auth backoff time */ - user->throttled = false; - } else { - LOGNOTICE("Client %s %s worker %s failed to authorise as user %s", - client->identity, client->address, buf,user->username); - user->failed_authtime = time(NULL); - user->auth_backoff <<= 1; - /* Cap backoff time to 10 mins */ - if (user->auth_backoff > 600) - user->auth_backoff = 600; - } - /* We can set this outside of lock safely */ - client->authorising = false; + if (!ckp->remote) + client_auth(ckp, client, user, ret); out: return json_boolean(ret); } @@ -6507,6 +6516,70 @@ void parse_remote_txns(ckpool_t *ckp, const json_t *val) LOGNOTICE("Submitted %d remote transactions", added); } +static void send_auth_response(sdata_t *sdata, const int64_t client_id, const bool ret, + json_t *id_val, json_t *err_val) +{ + json_t *json_msg = json_object(); + + json_object_set_new_nocheck(json_msg, "result", json_boolean(ret)); + json_object_set_new_nocheck(json_msg, "error", err_val ? err_val : json_null()); + json_object_set(json_msg, "id", id_val); + stratum_add_send(sdata, json_msg, client_id, SM_AUTHRESULT); +} + +static void send_auth_success(ckpool_t *ckp, sdata_t *sdata, stratum_instance_t *client) +{ + char *buf; + + ASPRINTF(&buf, "Authorised, welcome to %s %s!", ckp->name, + client->user_instance->username); + stratum_send_message(sdata, client, buf); + free(buf); +} + +static void send_auth_failure(sdata_t *sdata, stratum_instance_t *client) +{ + stratum_send_message(sdata, client, "Failed authorisation :("); +} + +void parse_upstream_auth(ckpool_t *ckp, json_t *val) +{ + json_t *json_msg, *id_val = NULL, *err_val = NULL; + sdata_t *sdata = ckp->sdata; + stratum_instance_t *client; + bool ret, warn = false; + int64_t client_id; + + id_val = json_object_get(val, "id"); + if (unlikely(!id_val)) + goto out; + if (unlikely(!json_get_int64(&client_id, val, "client_id"))) + goto out; + if (unlikely(!json_get_bool(&ret, val, "result"))) + goto out; + err_val = json_object_get(val, "error"); + client = ref_instance_by_id(sdata, client_id); + if (!client) { + LOGINFO("Failed to find client id %"PRId64" in parse_upstream_auth", + client_id); + goto out; + } + if (ret) + send_auth_success(ckp, sdata, client); + else + send_auth_failure(sdata, client); + send_auth_response(sdata, client_id, ret, id_val, err_val); + client_auth(ckp, client, client->user_instance, ret); + dec_instance_ref(sdata, client); +out: + if (unlikely(warn)) { + char *s = json_dumps(val, 0); + + LOGWARNING("Failed to get valid upstream result in parse_upstream_auth %s", s); + free(s); + } +} + #define parse_remote_workinfo(ckp, val) add_node_base(ckp, val) static void parse_remote_auth(ckpool_t *ckp, sdata_t *sdata, json_t *val, stratum_instance_t *remote, @@ -6534,11 +6607,12 @@ static void parse_remote_auth(ckpool_t *ckp, sdata_t *sdata, json_t *val, stratu if (likely(!client)) client = __stratum_add_instance(ckp, client_id, remote->address, remote->server); __inc_instance_ref(client); - ck_wunlock(&sdata->instance_lock); - + client->remote = true; json_strdup(&client->useragent, val, "useragent"); json_strcpy(client->enonce1, val, "enonce1"); json_strcpy(client->address, val, "address"); + ck_wunlock(&sdata->instance_lock); + ckmsgq_add(sdata->sauthq, jp); } @@ -7031,11 +7105,12 @@ static void upstream_auth(ckpool_t *ckp, stratum_instance_t *client, json_params static void sauth_process(ckpool_t *ckp, json_params_t *jp) { - json_t *result_val, *json_msg, *err_val = NULL; + json_t *result_val, *err_val = NULL; sdata_t *sdata = ckp->sdata; stratum_instance_t *client; int64_t mindiff, client_id; int errnum = 0; + bool ret; client_id = jp->client_id; @@ -7046,34 +7121,31 @@ static void sauth_process(ckpool_t *ckp, json_params_t *jp) } result_val = parse_authorise(client, jp->params, &err_val, &errnum); - if (json_is_true(result_val)) { - char *buf; - + ret = json_is_true(result_val); + if (ret) { /* So far okay in remote mode, remainder to be done by upstream * pool */ if (ckp->remote) { upstream_auth(ckp, client, jp); goto out; } - - ASPRINTF(&buf, "Authorised, welcome to %s %s!", ckp->name, - client->user_instance->username); - stratum_send_message(sdata, client, buf); - free(buf); + send_auth_success(ckp, sdata, client); } else { if (errnum < 0) stratum_send_message(sdata, client, "Authorisations temporarily offline :("); else - stratum_send_message(sdata, client, "Failed authorisation :("); + send_auth_failure(sdata, client); } - json_msg = json_object(); - json_object_set_new_nocheck(json_msg, "result", result_val); - json_object_set_new_nocheck(json_msg, "error", err_val ? err_val : json_null()); - steal_json_id(json_msg, jp); - stratum_add_send(sdata, json_msg, client_id, SM_AUTHRESULT); + send_auth_response(sdata, client_id, ret, jp->id_val, err_val); + if (!ret) + goto out; - if (!json_is_true(result_val)) + if (client->remote) { + /* We don't need to keep a record of clients on remote trusted + * servers after auth'ing them. */ + client->dropped = true; goto out; + } /* Update the client now if they have set a valid mindiff different * from the startdiff. suggest_diff overrides worker mindiff */ diff --git a/src/stratifier.h b/src/stratifier.h index dab06747..259c4acc 100644 --- a/src/stratifier.h +++ b/src/stratifier.h @@ -11,6 +11,8 @@ #define STRATIFIER_H void parse_remote_txns(ckpool_t *ckp, const json_t *val); +#define parse_upstream_txns(ckp, val) parse_remote_txns(ckp, val) +void parse_upstream_auth(ckpool_t *ckp, json_t *val); void stratifier_add_recv(ckpool_t *ckp, json_t *val); void *stratifier(void *arg);