if (a->server && !b->server) return -1;
if (!a->server && b->server) return +1;
+
if (a->server && b->server) {
int rcode = a->type - b->type;
if (rcode != 0) return rcode;
};
+static void null_free(UNUSED void *data)
+{
+}
+
static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type)
{
const char *name2;
home->name = name2;
home->cs = cs;
+ /*
+ * For zombie period calculations. We want to count
+ * zombies from the time when the server starts, instead
+ * of from 1970.
+ */
+ home->last_packet = time(NULL);
+
+ /*
+ * Authentication servers have a default "no_response_fail = 0".
+ * Accounting servers have a default "no_response_fail = 1".
+ *
+ * This is because authentication packets are retried, so
+ * they can fail over to another home server. Accounting
+ * packets are not retried, so they cannot fail over, and
+ * instead should be rejected immediately.
+ */
+ home->no_response_fail = 2;
+
memset(&hs_ip4addr, 0, sizeof(hs_ip4addr));
memset(&hs_ip6addr, 0, sizeof(hs_ip6addr));
if (cf_section_parse(cs, home, home_server_config) < 0) {
if (strcasecmp(hs_type, "auth") == 0) {
home->type = HOME_TYPE_AUTH;
+ if (home->no_response_fail == 2) home->no_response_fail = 0;
if (pool_type != home->type) {
mismatch:
cf_log_err(cf_sectiontoitem(cs),
- "Server pool cannot include home server %s of type \"%s\"",
+ "Home server %s of unexpected type \"%s\"",
name2, hs_type);
goto error;
}
} else if (strcasecmp(hs_type, "acct") == 0) {
home->type = HOME_TYPE_ACCT;
+ if (home->no_response_fail == 2) home->no_response_fail = 1;
if (pool_type != home->type) goto mismatch;
} else if (strcasecmp(hs_type, "auth+acct") == 0) {
home2->ping_user_password = NULL;
home2->cs = cs;
+ if (home->no_response_fail == 2) home->no_response_fail = 0;
+ if (home2->no_response_fail == 2) home2->no_response_fail = 1;
+
if (!rbtree_insert(home_servers_byname, home2)) {
cf_log_err(cf_sectiontoitem(cs),
"Internal error %d adding home server %s.",
#endif
}
+ /*
+ * Mark it as already processed
+ */
+ cf_data_add(cs, "home_server", null_free, null_free);
+
return 1;
}
home->type = type;
home->secret = secret;
home->cs = cs;
+ home->proto = IPPROTO_UDP;
p = strchr(name, ':');
if (!p) {
#ifdef HAVE_REGEX_H
if (name2[0] == '~') {
+ int rcode;
regex_t reg;
/*
* Include substring matches.
*/
- if (regcomp(®, name2 + 1,
- REG_EXTENDED | REG_NOSUB | REG_ICASE) != 0) {
+ rcode = regcomp(®, name2 + 1,
+ REG_EXTENDED | REG_NOSUB | REG_ICASE);
+ if (rcode != 0) {
+ char buffer[256];
+
+ regerror(rcode, ®, buffer, sizeof(buffer));
+
cf_log_err(cf_sectiontoitem(cs),
- "Invalid regex in realm \"%s\"", name2);
+ "Invalid regex \"%s\": %s",
+ name2 + 1, buffer);
goto error;
}
regfree(®);
return 0;
}
}
+
+ /*
+ * CoA home servers aren't tied to realms.
+ */
+ for (cs = cf_subsection_find_next(config, NULL, "home_server");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "home_server")) {
+ /*
+ * Server was already loaded.
+ */
+ if (cf_data_find(cs, "home_server")) continue;
+
+ if (!home_server_add(rc, cs, HOME_TYPE_COA)) {
+ return 0;
+ }
+ }
#endif
break;
case HOME_POOL_KEYED_BALANCE:
- if ((vp = pairfind(request->config_items, PW_LOAD_BALANCE_KEY)) != NULL) {
+ if ((vp = pairfind(request->config_items, PW_LOAD_BALANCE_KEY, 0)) != NULL) {
hash = fr_hash(vp->vp_strvalue, vp->length);
start = hash % pool->num_home_servers;
break;
* the 'hints' file.
*/
request->proxy->vps = paircopy(request->packet->vps);
-
- /*
- * Set the source IP address for proxying.
- */
- request->proxy->src_ipaddr = found->src_ipaddr;
}
/*
*/
if (found->message_authenticator &&
(request->packet->code == PW_AUTHENTICATION_REQUEST) &&
- !pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR)) {
+ !pairfind(request->proxy->vps, PW_MESSAGE_AUTHENTICATOR, 0)) {
radius_pairmake(request, &request->proxy->vps,
"Message-Authenticator", "0x00",
T_OP_SET);
}
-home_server *home_server_find(fr_ipaddr_t *ipaddr, int port)
+home_server *home_server_find(fr_ipaddr_t *ipaddr, int port, int proto)
{
home_server myhome;
memset(&myhome, 0, sizeof(myhome));
myhome.ipaddr = *ipaddr;
myhome.port = port;
+#ifdef WITH_TCP
+ myhome.proto = proto;
+#else
+ myhome.proto = IPPROTO_UDP;
+#endif
myhome.server = NULL; /* we're not called for internal proxying */
return rbtree_finddata(home_servers_byaddr, &myhome);