예제 #1
0
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;
}
예제 #2
0
/** 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 });
예제 #3
0
/** 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;
}
예제 #4
0
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);
}
예제 #5
0
/** 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;
}