static xlat_action_t redis_remap_xlat(TALLOC_CTX *ctx, fr_cursor_t *out, REQUEST *request, void const *xlat_inst, UNUSED void *xlat_thread_inst, fr_value_box_t **in) { rlm_redis_t const *inst = talloc_get_type_abort_const(*((void const * const *)xlat_inst), rlm_redis_t); fr_socket_addr_t node_addr; fr_pool_t *pool; fr_redis_conn_t *conn; fr_redis_cluster_rcode_t rcode; fr_value_box_t *vb; if (!in) { REDEBUG("Missing key"); return XLAT_ACTION_FAIL; } if (fr_value_box_list_concat(ctx, *in, in, FR_TYPE_STRING, true) < 0) { RPEDEBUG("Failed concatenating input"); return XLAT_ACTION_FAIL; } if (fr_inet_pton_port(&node_addr.ipaddr, &node_addr.port, (*in)->vb_strvalue, (*in)->vb_length, AF_UNSPEC, true, true) < 0) { RPEDEBUG("Failed parsing node address"); return XLAT_ACTION_FAIL; } if (fr_redis_cluster_pool_by_node_addr(&pool, inst->cluster, &node_addr, true) < 0) { RPEDEBUG("Failed locating cluster node"); return XLAT_ACTION_FAIL; } conn = fr_pool_connection_get(pool, request); if (!conn) { REDEBUG("No connections available for cluster node"); return XLAT_ACTION_FAIL; } rcode = fr_redis_cluster_remap(request, inst->cluster, conn); fr_pool_connection_release(pool, request, conn); MEM(vb = fr_value_box_alloc_null(ctx)); fr_value_box_strdup(vb, vb, NULL, fr_int2str(fr_redis_cluster_rcodes_table, rcode, "<INVALID>"), false); fr_cursor_append(out, vb); return XLAT_ACTION_DONE; }
/** Perform a search and map the result of the search to server attributes * * @param[in] mod_inst #rlm_csv_t. * @param[in] proc_inst mapping map entries to field numbers. * @param[in,out] request The current request. * @param[in] key key to look for * @param[in] maps Head of the map list. * @return * - #RLM_MODULE_NOOP no rows were returned. * - #RLM_MODULE_UPDATED if one or more #VALUE_PAIR were added to the #REQUEST. * - #RLM_MODULE_FAIL if an error occurred. */ static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, REQUEST *request, fr_value_box_t **key, vp_map_t const *maps) { rlm_rcode_t rcode = RLM_MODULE_UPDATED; rlm_csv_t *inst = talloc_get_type_abort(mod_inst, rlm_csv_t); rlm_csv_entry_t *e; vp_map_t const *map; if (!*key) { REDEBUG("CSV key cannot be (null)"); return RLM_MODULE_FAIL; } if (fr_value_box_list_concat(request, *key, key, FR_TYPE_STRING, true) < 0) { REDEBUG("Failed concatenating key elements"); return RLM_MODULE_FAIL; } e = rbtree_finddata(inst->tree, &(rlm_csv_entry_t){ .key = (*key)->vb_strvalue });
/** Return the node that is currently servicing a particular key * * */ static xlat_action_t redis_node_xlat(TALLOC_CTX *ctx, fr_cursor_t *out, REQUEST *request, void const *xlat_inst, UNUSED void *xlat_thread_inst, fr_value_box_t **in) { rlm_redis_t const *inst = talloc_get_type_abort_const(*((void const * const *)xlat_inst), rlm_redis_t); fr_redis_cluster_key_slot_t const *key_slot; fr_redis_cluster_node_t const *node; fr_ipaddr_t ipaddr; uint16_t port; char const *p; char *q; char const *key; size_t key_len; unsigned long idx = 0; fr_value_box_t *vb; if (!in) { REDEBUG("Missing key"); return XLAT_ACTION_FAIL; } if (fr_value_box_list_concat(ctx, *in, in, FR_TYPE_STRING, true) < 0) { RPEDEBUG("Failed concatenating input"); return XLAT_ACTION_FAIL; } key = p = (*in)->vb_strvalue; p = strchr(p, ' '); /* Look for index */ if (p) { key_len = p - key; idx = strtoul(p, &q, 10); if (q == p) { REDEBUG("Tailing garbage after node index"); return XLAT_ACTION_FAIL; } } else { key_len = (*in)->vb_length; } key_slot = fr_redis_cluster_slot_by_key(inst->cluster, request, (uint8_t const *)key, key_len); if (idx == 0) { node = fr_redis_cluster_master(inst->cluster, key_slot); } else { node = fr_redis_cluster_slave(inst->cluster, key_slot, idx - 1); } if (!node) { RDEBUG2("No node available for this key slot"); return XLAT_ACTION_DONE; } if ((fr_redis_cluster_ipaddr(&ipaddr, node) < 0) || (fr_redis_cluster_port(&port, node) < 0)) { REDEBUG("Failed retrieving node information"); return XLAT_ACTION_FAIL; } MEM(vb = fr_value_box_alloc_null(ctx)); fr_value_box_asprintf(vb, vb, NULL, false, "%pV:%u", fr_box_ipaddr(ipaddr), port); fr_cursor_append(out, vb); return XLAT_ACTION_DONE; }
static xlat_action_t xlat_delay(TALLOC_CTX *ctx, UNUSED fr_cursor_t *out, REQUEST *request, void const *xlat_inst, UNUSED void *xlat_thread_inst, fr_value_box_t **in) { rlm_delay_t const *inst; void *instance; struct timeval resume_at, delay, *yielded_at; memcpy(&instance, xlat_inst, sizeof(instance)); /* Stupid const issues */ inst = talloc_get_type_abort(instance, rlm_delay_t); /* * Record the time that we yielded the request */ MEM(yielded_at = talloc(request, struct timeval)); if (gettimeofday(yielded_at, NULL) < 0) { REDEBUG("Failed getting current time: %s", fr_syserror(errno)); return XLAT_ACTION_FAIL; } /* * If there's no input delay, just yield and * immediately re-enqueue the request. * This is very useful for testing. */ if (!*in) { memset(&delay, 0, sizeof(delay)); if (!fr_cond_assert(delay_add(request, &resume_at, yielded_at, &delay, true, true) == 0)) { return XLAT_ACTION_FAIL; } goto yield; } if (fr_value_box_list_concat(ctx, *in, in, FR_TYPE_STRING, true) < 0) { RPEDEBUG("Failed concatenating input"); talloc_free(yielded_at); return XLAT_ACTION_FAIL; } if (fr_timeval_from_str(&delay, (*in)->vb_strvalue) < 0) { RPEDEBUG("Failed parsing delay time"); talloc_free(yielded_at); return XLAT_ACTION_FAIL; } if (delay_add(request, &resume_at, yielded_at, &delay, inst->force_reschedule, inst->relative) != 0) { RDEBUG2("Not adding delay"); talloc_free(yielded_at); return XLAT_ACTION_DONE; } yield: RDEBUG3("Current time %pV, resume time %pV", fr_box_timeval(*yielded_at), fr_box_timeval(resume_at)); if (unlang_xlat_event_timeout_add(request, _delay_done, yielded_at, &resume_at) < 0) { RPEDEBUG("Adding event failed"); return XLAT_ACTION_FAIL; } return unlang_xlat_yield(request, xlat_delay_resume, xlat_delay_cancel, yielded_at); }
/** Map multiple attributes from a client into the request * * @param[in] mod_inst NULL. * @param[in] proc_inst NULL. * @param[in] request The current request. * @param[in] client_override If NULL, use the current client, else use the client matching * the ip given. * @param[in] maps Head of the map list. * @return * - #RLM_MODULE_NOOP no rows were returned. * - #RLM_MODULE_UPDATED if one or more #VALUE_PAIR were added to the #REQUEST. * - #RLM_MODULE_FAIL if an error occurred. */ static rlm_rcode_t map_proc_client(UNUSED void *mod_inst, UNUSED void *proc_inst, REQUEST *request, fr_value_box_t **client_override, vp_map_t const *maps) { rlm_rcode_t rcode = RLM_MODULE_OK; vp_map_t const *map; RADCLIENT *client; client_get_vp_ctx_t uctx; if (*client_override) { fr_ipaddr_t ip; char const *client_str; /* * Concat don't asprint, as this becomes a noop * in the vast majority of cases. */ if (fr_value_box_list_concat(request, *client_override, client_override, FR_TYPE_STRING, true) < 0) { REDEBUG("Failed concatenating input data"); return RLM_MODULE_FAIL; } client_str = (*client_override)->vb_strvalue; if (fr_inet_pton(&ip, client_str, -1, AF_UNSPEC, false, true) < 0) { REDEBUG("\"%s\" is not a valid IPv4 or IPv6 address", client_str); rcode = RLM_MODULE_FAIL; goto finish; } client = client_find(NULL, &ip, IPPROTO_IP); if (!client) { RDEBUG("No client found with IP \"%s\"", client_str); rcode = RLM_MODULE_NOTFOUND; goto finish; } if (client->cs) { char const *filename; int line; filename = cf_filename(client->cs); line = cf_lineno(client->cs); if (filename) { RDEBUG2("Found client matching \"%s\". Defined in \"%s\" line %i", client_str, filename, line); } else { RDEBUG2("Found client matching \"%s\"", client_str); } } } else { client = request->client; } uctx.cs = client->cs; RINDENT(); for (map = maps; map != NULL; map = map->next) { char *field = NULL; if (tmpl_aexpand(request, &field, request, map->rhs, NULL, NULL) < 0) { REDEBUG("Failed expanding RHS at %s", map->lhs->name); rcode = RLM_MODULE_FAIL; talloc_free(field); break; } uctx.cp = cf_pair_find(client->cs, field); if (!uctx.cp) { RDEBUG3("No matching client property \"%s\", skipping...", field); goto next; /* No matching CONF_PAIR found */ } uctx.field = field; /* * Pass the raw data to the callback, which will * create the VP and add it to the map. */ if (map_to_request(request, map, _map_proc_client_get_vp, &uctx) < 0) { rcode = RLM_MODULE_FAIL; talloc_free(field); break; } rcode = RLM_MODULE_UPDATED; next: talloc_free(field); } REXDENT(); finish: return rcode; }