From: Alan T. DeKok Date: Wed, 25 May 2011 08:21:41 +0000 (+0200) Subject: Initial version of rlm_replicate X-Git-Tag: release_2_1_11~29 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e08c398d1682f492e40d79579a156bdbc69a4761;p=thirdparty%2Ffreeradius-server.git Initial version of rlm_replicate Allows replication of packets (send without response), to multiple destinations. --- diff --git a/raddb/modules/replicate b/raddb/modules/replicate new file mode 100644 index 00000000000..6df4523cc18 --- /dev/null +++ b/raddb/modules/replicate @@ -0,0 +1,40 @@ +# Replicate packet(s) to a home server. +# +# This module will open a new socket for each packet, and "clone" +# the incoming packet to the destination realm (i.e. home server). +# +# Use it by setting "Replicate-To-Realm = name" in the control list, +# just like Proxy-To-Realm. The configurations for the two attributes +# are identical. The realm must exist, the home_server_pool must exist, +# and the home_server must exist. +# +# The only difference is that the "replicate" module sends requests +# and does not expect a reply. Any reply is ignored. +# +# Both Replicate-To-Realm and Proxy-To-Realm can be used at the same time. +# +# To use this module, list "replicate" in the "authorize" or +# "accounting" section. Then, ensure that Replicate-To-Realm is set. +# The contents of the "packet" attribute list will be sent to the +# home server. The usual load-balancing, etc. features of the home +# server will be used. +# +# "radmin" can be used to mark home servers alive/dead, in order to +# enable/disable replication to specific servers. +# +# Packets can be replicated to multiple destinations. Just set +# Replicate-To-Realm multiple times. One packet will be sent for +# each of the Replicate-To-Realm attribute in the "control" list. +# +# If no packets are sent, the module returns "noop". If at least one +# packet is sent, the module returns "ok". If an error occurs, the +# module returns "fail" +# +# Note that replication does NOT change any of the packet statistics. +# If you use "radmin" to look at the statistics for a home server, +# the replicated packets will cause NO counters to increment. This +# is not a bug, this is how replication works. +# +replicate { + +} diff --git a/src/modules/rlm_replicate/Makefile b/src/modules/rlm_replicate/Makefile new file mode 100644 index 00000000000..52b1f321d18 --- /dev/null +++ b/src/modules/rlm_replicate/Makefile @@ -0,0 +1,11 @@ +TARGET = rlm_replicate +SRCS = rlm_replicate.c +HEADERS = +RLM_CFLAGS = +RLM_LIBS = + +include ../rules.mak + +$(STATIC_OBJS): $(HEADERS) + +$(DYNAMIC_OBJS): $(HEADERS) diff --git a/src/modules/rlm_replicate/rlm_replicate.c b/src/modules/rlm_replicate/rlm_replicate.c new file mode 100644 index 00000000000..1a219cf8593 --- /dev/null +++ b/src/modules/rlm_replicate/rlm_replicate.c @@ -0,0 +1,191 @@ +/* + * rlm_replicate.c + * + * Version: $Id$ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Copyright 2000,2006 The FreeRADIUS server project + * Copyright 2000 your name + */ + +#include +RCSID("$Id$") + +#include +#include + + +static void cleanup(RADIUS_PACKET *packet) +{ + if (!packet) return; + if (packet->sockfd >= 0) close(packet->sockfd); + rad_free(&packet); +} + +/* + * Write accounting information to this modules database. + */ +static int replicate_packet(void *instance, REQUEST *request) +{ + int rcode = RLM_MODULE_NOOP; + VALUE_PAIR *vp; + home_server *home; + REALM *realm; + home_pool_t *pool; + RADIUS_PACKET *packet; + + instance = instance; /* -Wunused */ + + /* + * Send as many packets as necessary to different + * destinations. + */ + while (1) { + vp = pairfind(request->config_items, PW_REPLICATE_TO_REALM); + if (!vp) break; + + realm = realm_find2(vp->vp_strvalue); + if (!realm) { + RDEBUG2("ERROR: Cannot Replicate to unknown realm %s", realm); + continue; + } + + /* + * We shouldn't really do this on every loop. + */ + switch (request->packet->code) { + default: + RDEBUG2("ERROR: Cannot replicate unknown packet code %d", + request->packet->code); + cleanup(packet); + return RLM_MODULE_FAIL; + + case PW_AUTHENTICATION_REQUEST: + pool = realm->auth_pool; + break; + +#ifdef WITH_ACCOUNTING + + case PW_ACCOUNTING_REQUEST: + pool = realm->acct_pool; + break; +#endif + +#ifdef WITH_COA + case PW_COA_REQUEST: + case PW_DISCONNECT_REQUEST: + pool = realm->acct_pool; + break; +#endif + } + + if (!pool) { + RDEBUG2(" WARNING: Cancelling replication to Realm %s, as the realm is local.", realm->name); + continue; + } + + home = home_server_ldb(realm->name, pool, request); + if (!home) { + RDEBUG2("ERROR: Failed to find live home server for realm %s", + realm->name); + continue; + } + + if (!packet) { + packet = rad_alloc(1); + if (!packet) return RLM_MODULE_FAIL; + packet->sockfd = -1; + packet->code = request->packet->code; + packet->id = fr_rand() & 0xff; + packet->vps = paircopy(request->packet->vps); + + packet->sockfd = fr_socket(&home->src_ipaddr, 0); + if (packet->sockfd < 0) { + RDEBUG("ERROR: Failed opening socket: %s", fr_strerror()); + cleanup(packet); + return RLM_MODULE_FAIL; + } + } else { + int i; + + for (i = 0; i < sizeof(packet->vector)) { + packet->vector[i] = fr_rand() & 0xff; + } + + packet->id++; + free(packet->data); + packet->data = NULL; + packet->data_len = 0; + } + + /* + * (Re)-Write these. + */ + packet->dst_ipaddr = home->ipaddr; + packet->dst_port = home->port; + memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr)); + packet->src_port = 0; + + /* + * Encode, sign and then send the packet. + */ + if (rad_send(packet, NULL, home->secret) < 0) { + RDEBUG("ERROR: Failed replicating packet: %s", + fr_strerror()); + cleanup(packet); + return RLM_MODULE_FAIL; + } + + /* + * We've sent it to at least one destination. + */ + rcode = RLM_MODULE_OK; + } + + cleanup(packet); + return rcode; +} + +/* + * The module name should be the only globally exported symbol. + * That is, everything else should be 'static'. + * + * If the module needs to temporarily modify it's instantiation + * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE. + * The server will then take care of ensuring that the module + * is single-threaded. + */ +module_t rlm_replicate = { + RLM_MODULE_INIT, + "replicate", + RLM_TYPE_THREAD_SAFE, /* type */ + NULL, /* instantiation */ + NULL, /* detach */ + { + NULL, /* authentication */ + replicate_packet, /* authorization */ + NULL, /* preaccounting */ + replicate_packet, /* accounting */ + NULL, /* checksimul */ + NULL, /* pre-proxy */ + NULL, /* post-proxy */ + NULL /* post-auth */ +#ifdef WITH_COA + , replicate_packet, + NULL +#endif + }, +};