X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Frealms.c;h=7abf7f0242dd5ddb7cff01759b2115e38df538c6;hb=afe7358fdedae3032f0cd2d746981f6c11ba141a;hp=65b8b37fed2c1cf98801f5cd52b565d2b208a199;hpb=604d2f5952b29e8670024ff42edf0a400aa2faea;p=freeradius.git diff --git a/src/main/realms.c b/src/main/realms.c index 65b8b37..7abf7f0 100644 --- a/src/main/realms.c +++ b/src/main/realms.c @@ -142,6 +142,7 @@ static int home_server_addr_cmp(const void *one, const void *two) 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; @@ -239,29 +240,6 @@ static size_t xlat_server_pool(UNUSED void *instance, REQUEST *request, } #endif -#ifdef WITH_PROXY -#ifndef WITH_TCP -#define home_server_free free -#else -static void home_server_free(void *data) -{ - int i; - home_server *home = data; - - if (home->proto == IPPROTO_TCP) { - for (i = 0; i < home->max_connections; i++) { - if (!home->listeners[i]) continue; - - listen_free(&home->listeners[i]); - } - } - - free(home); -} - -#endif /* WITH_TCP */ -#endif /* WITH_PROXY */ - void realms_free(void) { #ifdef WITH_PROXY @@ -302,8 +280,7 @@ void realms_free(void) #ifdef WITH_PROXY -#ifdef WITH_TCP -static CONF_PARSER tcp_config[] = { +static CONF_PARSER limit_config[] = { { "max_connections", PW_TYPE_INTEGER, offsetof(home_server, max_connections), NULL, "16" }, @@ -318,7 +295,6 @@ static CONF_PARSER tcp_config[] = { { NULL, -1, 0, NULL, NULL } /* end the list */ }; -#endif static struct in_addr hs_ip4addr; static struct in6_addr hs_ip6addr; @@ -405,24 +381,22 @@ static CONF_PARSER home_server_config[] = { offsetof(home_server, coa_mrd), 0, Stringify(30) }, #endif -#ifdef WITH_TCP - { "limit", PW_TYPE_SUBSECTION, 0, NULL, (const void *) tcp_config }, -#endif + { "limit", PW_TYPE_SUBSECTION, 0, NULL, (const void *) limit_config }, { NULL, -1, 0, NULL, NULL } /* end the list */ }; +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_server *home; int dual = FALSE; CONF_PAIR *cp; -#ifdef WITH_TCP - CONF_SECTION *limit; - int max_connections; -#endif free(hs_virtual_server); /* used only for printing during parsing */ hs_virtual_server = NULL; @@ -441,45 +415,30 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type) return 0; } -#ifdef WITH_TCP - max_connections = 16; - cp = NULL; - limit = cf_subsection_find_next(cs, NULL, "limit"); - if (limit) cp = cf_pair_find(limit, "max_connections"); - if (cp) { - const char *value = cf_pair_value(cp); - - if (value) max_connections = atoi(value); - - if ((max_connections > 1024) || - (max_connections == 0)) max_connections = 1024; - - /* - * Set max_connections to 1 for non-TCP sockets. - */ - cp = cf_pair_find(cs, "proto"); - if (!cp || - (((value = cf_pair_value(cp)) != NULL) && - (strcmp(value, "tcp") != 0))) { - max_connections = 1; - } - } -#endif - - home = rad_malloc(sizeof(*home) -#ifdef WITH_TCP - + (sizeof(home->listeners[0]) * max_connections) -#endif - ); - memset(home, 0, sizeof(*home) -#ifdef WITH_TCP - + (sizeof(home->listeners[0]) * max_connections) -#endif - ); + home = rad_malloc(sizeof(*home)); + memset(home, 0, sizeof(*home)); 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) { @@ -569,16 +528,18 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type) 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) { @@ -640,8 +601,8 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type) } } -#ifdef WITH_TCP home->proto = IPPROTO_UDP; +#ifdef WITH_TCP if (hs_proto) { if (strcmp(hs_proto, "udp") == 0) { free(hs_proto); @@ -658,42 +619,39 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type) goto error; } } - - home->listeners[0] = NULL; - - /* - * We need SOME value. Set it high enough that no one - * will run into it. - */ - - if (home->proto == IPPROTO_TCP) { - home->max_connections = max_connections; - - /* - * FIXME: Parse "min_connections", too, and set - * those up. - */ - memset(home->listeners, 0, - home->max_connections * sizeof(home->listeners[0])); - } #endif - if ((home->ipaddr.af != AF_UNSPEC) && /* could be virtual server */ + if (!home->server && rbtree_finddata(home_servers_byaddr, home)) { cf_log_err(cf_sectiontoitem(cs), "Duplicate home server"); goto error; } /* - * Look up the name using the *same* address family as - * for the home server. + * If the home is a virtual server, don't look up source IP. */ - if (hs_srcipaddr && (home->ipaddr.af != AF_UNSPEC)) { - if (ip_hton(hs_srcipaddr, home->ipaddr.af, &home->src_ipaddr) < 0) { - cf_log_err(cf_sectiontoitem(cs), "Failed parsing src_ipaddr"); - goto error; + if (!home->server) { + rad_assert(home->ipaddr.af != AF_UNSPEC); + + /* + * Otherwise look up the source IP using the same + * address family as the destination IP. + */ + if (hs_srcipaddr) { + if (ip_hton(hs_srcipaddr, home->ipaddr.af, &home->src_ipaddr) < 0) { + cf_log_err(cf_sectiontoitem(cs), "Failed parsing src_ipaddr"); + goto error; + } + + } else { + /* + * Source isn't specified: Source is + * the correct address family, but all zeros. + */ + home->src_ipaddr.af = home->ipaddr.af; } } + free(hs_srcipaddr); hs_srcipaddr = NULL; @@ -704,7 +662,7 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type) goto error; } - if ((home->ipaddr.af != AF_UNSPEC) && /* could be virtual server */ + if (!home->server && !rbtree_insert(home_servers_byaddr, home)) { rbtree_deletebydata(home_servers_byname, home); cf_log_err(cf_sectiontoitem(cs), @@ -766,14 +724,21 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type) if (home->coa_mrd > 60 ) home->coa_mrd = 60; #endif + if (home->max_connections > 1024) home->max_connections = 1024; + #ifdef WITH_TCP + /* + * UDP sockets can't be connection limited. + */ + if (home->proto != IPPROTO_TCP) home->max_connections = 0; +#endif + if ((home->idle_timeout > 0) && (home->idle_timeout < 5)) home->idle_timeout = 5; if ((home->lifetime > 0) && (home->lifetime < 5)) home->lifetime = 5; if ((home->lifetime > 0) && (home->idle_timeout > home->lifetime)) home->idle_timeout = 0; -#endif if (dual) { home_server *home2 = rad_malloc(sizeof(*home2)); @@ -785,6 +750,9 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type) 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.", @@ -793,7 +761,7 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type) return 0; } - if ((home->ipaddr.af != AF_UNSPEC) && + if (!home->server && !rbtree_insert(home_servers_byaddr, home2)) { rbtree_deletebydata(home_servers_byname, home2); cf_log_err(cf_sectiontoitem(cs), @@ -803,15 +771,11 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type) return 0; } -#ifdef WITH_TCP - home2->proto = home->proto; -#endif - #ifdef WITH_STATS home2->number = home_server_max_number++; if (!rbtree_insert(home_servers_bynumber, home2)) { rbtree_deletebydata(home_servers_byname, home2); - if (home2->ipaddr.af != AF_UNSPEC) { + if (!home2->server) { rbtree_deletebydata(home_servers_byname, home2); } cf_log_err(cf_sectiontoitem(cs), @@ -823,6 +787,11 @@ static int home_server_add(realm_config_t *rc, CONF_SECTION *cs, int pool_type) #endif } + /* + * Mark it as already processed + */ + cf_data_add(cs, "home_server", null_free, null_free); + return 1; } @@ -1189,6 +1158,7 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs, home->type = type; home->secret = secret; home->cs = cs; + home->proto = IPPROTO_UDP; p = strchr(name, ':'); if (!p) { @@ -1233,6 +1203,7 @@ static int old_server_add(realm_config_t *rc, CONF_SECTION *cs, free(q); return 0; } + home->src_ipaddr.af = home->ipaddr.af; } else { home->ipaddr.af = AF_UNSPEC; home->server = server; @@ -1617,15 +1588,22 @@ static int realm_add(realm_config_t *rc, CONF_SECTION *cs) #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(®); @@ -1786,7 +1764,7 @@ int realms_init(CONF_SECTION *config) } #ifdef WITH_PROXY - home_servers_byaddr = rbtree_create(home_server_addr_cmp, home_server_free, 0); + home_servers_byaddr = rbtree_create(home_server_addr_cmp, free, 0); if (!home_servers_byaddr) { realms_free(); return 0; @@ -1861,6 +1839,22 @@ int realms_init(CONF_SECTION *config) 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 @@ -2020,7 +2014,7 @@ home_server *home_server_ldb(const char *realmname, 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; @@ -2090,7 +2084,7 @@ home_server *home_server_ldb(const char *realmname, /* * We've found the first "live" one. Use that. */ - if (pool->type == HOME_POOL_FAIL_OVER) { + if (pool->type != HOME_POOL_LOAD_BALANCE) { found = home; break; } @@ -2192,16 +2186,13 @@ home_server *home_server_ldb(const char *realmname, * the 'hints' file. */ request->proxy->vps = paircopy(request->packet->vps); - - /* - * Set the source IP address for proxying. - */ - request->proxy->src_ipaddr = found->src_ipaddr; } /* * Update the various fields as appropriate. */ + request->proxy->src_ipaddr = found->src_ipaddr; + request->proxy->src_port = 0; request->proxy->dst_ipaddr = found->ipaddr; request->proxy->dst_port = found->port; request->home_server = found; @@ -2212,7 +2203,7 @@ home_server *home_server_ldb(const char *realmname, */ 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); @@ -2277,13 +2268,18 @@ home_server *home_server_ldb(const char *realmname, } -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); @@ -2326,54 +2322,3 @@ home_pool_t *home_pool_byname(const char *name, int type) } #endif - -#ifdef WITH_PROXY -static int home_server_create_callback(void *ctx, void *data) -{ - rad_listen_t *head = ctx; - home_server *home = data; - rad_listen_t *this; - - /* - * If there WAS a src address defined, ensure that a - * proxy listener has been defined. - */ - if (home->src_ipaddr.af != AF_UNSPEC) { - this = proxy_new_listener(&home->src_ipaddr, TRUE); - - /* - * Failed to create it: Die - */ - if (!this) return 1; - - this->next = head->next; - head->next = this; - } - - return 0; -} - -/* - * Taking a void* here solves some header issues. - */ -int home_server_create_listeners(void *ctx) -{ - rad_listen_t *head = ctx; - - if (!home_servers_byaddr) return 0; - - rad_assert(head != NULL); - - /* - * Add the listeners to the TAIL of the list. - */ - while (head->next) head = head->next; - - if (rbtree_walk(home_servers_byaddr, InOrder, - home_server_create_callback, head) != 0) { - return -1; - } - - return 0; -} -#endif