📄 realms.c
字号:
} } if (pool->server_type != server_type) { cf_log_err(cf_sectiontoitem(cs), "Incompatible home_server_pool \"%s\" (mixed auth_pool / acct_pool)", name); return 0; } *dest = pool; return 1;}static int realm_add(realm_config_t *rc, CONF_SECTION *cs){ const char *name2; REALM *r = NULL; CONF_PAIR *cp; home_pool_t *auth_pool, *acct_pool; const char *auth_pool_name, *acct_pool_name; name2 = cf_section_name1(cs); if (!name2 || (strcasecmp(name2, "realm") != 0)) { cf_log_err(cf_sectiontoitem(cs), "Section is not a realm."); return 0; } name2 = cf_section_name2(cs); if (!name2) { cf_log_err(cf_sectiontoitem(cs), "Realm section is missing the realm name."); return 0; } auth_pool = acct_pool = NULL; auth_pool_name = acct_pool_name = NULL; /* * Prefer new configuration to old one. */ cp = cf_pair_find(cs, "pool"); if (!cp) cp = cf_pair_find(cs, "home_server_pool"); if (cp) auth_pool_name = cf_pair_value(cp); if (cp && auth_pool_name) { acct_pool_name = auth_pool_name; if (!add_pool_to_realm(rc, cs, auth_pool_name, &auth_pool, HOME_TYPE_AUTH, 1)) { return 0; } if (!add_pool_to_realm(rc, cs, auth_pool_name, &acct_pool, HOME_TYPE_ACCT, 0)) { return 0; } } cp = cf_pair_find(cs, "auth_pool"); if (cp) auth_pool_name = cf_pair_value(cp); if (cp && auth_pool_name) { if (auth_pool) { cf_log_err(cf_sectiontoitem(cs), "Cannot use \"pool\" and \"auth_pool\" at the same time."); return 0; } if (!add_pool_to_realm(rc, cs, auth_pool_name, &auth_pool, HOME_TYPE_AUTH, 1)) { return 0; } } cp = cf_pair_find(cs, "acct_pool"); if (cp) acct_pool_name = cf_pair_value(cp); if (cp && acct_pool_name) { int do_print = TRUE; if (acct_pool) { cf_log_err(cf_sectiontoitem(cs), "Cannot use \"pool\" and \"acct_pool\" at the same time."); return 0; } if (!auth_pool || (strcmp(auth_pool_name, acct_pool_name) != 0)) { do_print = TRUE; } if (!add_pool_to_realm(rc, cs, acct_pool_name, &acct_pool, HOME_TYPE_ACCT, do_print)) { return 0; } } cf_log_info(cs, " realm %s {", name2); /* * The realm MAY already exist if it's an old-style realm. * In that case, merge the old-style realm with this one. */ r = realm_find2(name2); if (r && (strcmp(r->name, name2) == 0)) { if (cf_pair_find(cs, "auth_pool") || cf_pair_find(cs, "acct_pool")) { cf_log_err(cf_sectiontoitem(cs), "Duplicate realm \"%s\"", name2); goto error; } if (!old_realm_config(rc, cs, r)) { goto error; } cf_log_info(cs, " } # realm %s", name2); return 1; }#ifdef HAVE_REGEX_H if (name2[0] == '~') { regex_t reg; /* * Include substring matches. */ if (regcomp(®, name2 + 1, REG_EXTENDED | REG_NOSUB | REG_ICASE) != 0) { cf_log_err(cf_sectiontoitem(cs), "Invalid regex in realm \"%s\"", name2); goto error; } regfree(®); }#endif r = rad_malloc(sizeof(*r)); memset(r, 0, sizeof(*r)); r->name = name2; r->auth_pool = auth_pool; r->acct_pool = acct_pool; r->striprealm = 1; if (auth_pool_name && (auth_pool_name == acct_pool_name)) { /* yes, ptr comparison */ cf_log_info(cs, "\tpool = %s", auth_pool_name); } else { if (auth_pool_name) cf_log_info(cs, "\tauth_pool = %s", auth_pool_name); if (acct_pool_name) cf_log_info(cs, "\tacct_pool = %s", acct_pool_name); } cp = cf_pair_find(cs, "nostrip"); if (cp && (cf_pair_value(cp) == NULL)) { r->striprealm = 0; cf_log_info(cs, "\tnostrip"); } /* * We're a new-style realm. Complain if we see the old * directives. */ if (r->auth_pool || r->acct_pool) { if (((cp = cf_pair_find(cs, "authhost")) != NULL) || ((cp = cf_pair_find(cs, "accthost")) != NULL) || ((cp = cf_pair_find(cs, "secret")) != NULL) || ((cp = cf_pair_find(cs, "ldflag")) != NULL)) { DEBUG2("WARNING: Ignoring old-style configuration entry \"%s\" in realm \"%s\"", cf_pair_attr(cp), r->name); } /* * The realm MAY be an old-style realm, as there * was no auth_pool or acct_pool. Double-check * it, just to be safe. */ } else if (!old_realm_config(rc, cs, r)) { goto error; }#ifdef HAVE_REGEX_H /* * It's a regex. Add it to a separate list. */ if (name2[0] == '~') { realm_regex_t *rr, **last; rr = rad_malloc(sizeof(*rr)); last = &realms_regex; while (*last) last = &((*last)->next); /* O(N^2)... sue me. */ r->name = name2; rr->realm = r; rr->next = NULL; *last = rr; cf_log_info(cs, " }"); return 1; }#endif if (!rbtree_insert(realms_byname, r)) { rad_assert("Internal sanity check failed"); goto error; } cf_log_info(cs, " }"); return 1; error: cf_log_info(cs, " } # realm %s", name2); free(r); return 0;}int realms_init(CONF_SECTION *config){ CONF_SECTION *cs; realm_config_t *rc, *old_rc; if (realms_byname) return 1; realms_byname = rbtree_create(realm_name_cmp, free, 0); if (!realms_byname) { realms_free(); return 0; } home_servers_byaddr = rbtree_create(home_server_addr_cmp, free, 0); if (!home_servers_byaddr) { realms_free(); return 0; } home_servers_byname = rbtree_create(home_server_name_cmp, NULL, 0); if (!home_servers_byname) { realms_free(); return 0; } home_pools_byname = rbtree_create(home_pool_name_cmp, free, 0); if (!home_pools_byname) { realms_free(); return 0; } rc = rad_malloc(sizeof(*rc)); memset(rc, 0, sizeof(*rc)); rc->cs = config; cs = cf_subsection_find_next(config, NULL, "proxy"); if (cs) { cf_section_parse(cs, rc, proxy_config); } else { rc->dead_time = DEAD_TIME; rc->retry_count = RETRY_COUNT; rc->retry_delay = RETRY_DELAY; rc->fallback = 0; rc->wake_all_if_all_dead= 0; } for (cs = cf_subsection_find_next(config, NULL, "realm"); cs != NULL; cs = cf_subsection_find_next(config, cs, "realm")) { if (!realm_add(rc, cs)) { free(rc); realms_free(); return 0; } } xlat_register("home_server", xlat_home_server, NULL); xlat_register("home_server_pool", xlat_server_pool, NULL); /* * Swap pointers atomically. */ old_rc = realm_config; realm_config = rc; free(old_rc); return 1;}/* * Find a realm where "name" might be the regex. */REALM *realm_find2(const char *name){ REALM myrealm; REALM *realm; if (!name) name = "NULL"; myrealm.name = name; realm = rbtree_finddata(realms_byname, &myrealm); if (realm) return realm;#ifdef HAVE_REGEX_H if (realms_regex) { realm_regex_t *this; for (this = realms_regex; this != NULL; this = this->next) { if (strcmp(this->realm->name, name) == 0) { return this->realm; } } }#endif /* * Couldn't find a realm. Look for DEFAULT. */ myrealm.name = "DEFAULT"; return rbtree_finddata(realms_byname, &myrealm);}/* * Find a realm in the REALM list. */REALM *realm_find(const char *name){ REALM myrealm; REALM *realm; if (!name) name = "NULL"; myrealm.name = name; realm = rbtree_finddata(realms_byname, &myrealm); if (realm) return realm;#ifdef HAVE_REGEX_H if (realms_regex) { realm_regex_t *this; for (this = realms_regex; this != NULL; this = this->next) { int compare; regex_t reg; /* * Include substring matches. */ if (regcomp(®, this->realm->name + 1, REG_EXTENDED | REG_NOSUB | REG_ICASE) != 0) { continue; } compare = regexec(®, name, 0, NULL, 0); regfree(®); if (compare == 0) return this->realm; } }#endif /* * Couldn't find a realm. Look for DEFAULT. */ myrealm.name = "DEFAULT"; return rbtree_finddata(realms_byname, &myrealm);}home_server *home_server_ldb(const char *realmname, home_pool_t *pool, REQUEST *request){ int start; int count; home_server *found = NULL; VALUE_PAIR *vp; start = 0; /* * Determine how to pick choose the home server. */ switch (pool->type) { uint32_t hash; /* * For load-balancing by client IP address, we * pick a home server by hashing the client IP. * * This isn't as even a load distribution as * tracking the State attribute, but it's better * than nothing. */ case HOME_POOL_CLIENT_BALANCE: switch (request->packet->src_ipaddr.af) { case AF_INET: hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr, sizeof(request->packet->src_ipaddr.ipaddr.ip4addr)); break; case AF_INET6: hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr, sizeof(request->packet->src_ipaddr.ipaddr.ip6addr)); break; default: hash = 0; break; } start = hash % pool->num_home_servers; break; case HOME_POOL_CLIENT_PORT_BALANCE: switch (request->packet->src_ipaddr.af) { case AF_INET: hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip4addr, sizeof(request->packet->src_ipaddr.ipaddr.ip4addr)); break; case AF_INET6: hash = fr_hash(&request->packet->src_ipaddr.ipaddr.ip6addr, sizeof(request->packet->src_ipaddr.ipaddr.ip6addr)); break; default: hash = 0; break; } fr_hash_update(&request->packet->src_port, sizeof(request->packet->src_port), hash); start = hash % pool->num_home_servers; break; case HOME_POOL_KEYED_BALANCE: if ((vp = pairfind(request->config_items, PW_LOAD_BALANCE_KEY)) != NULL) { hash = fr_hash(vp->vp_strvalue, vp->length); start = hash % pool->num_home_servers; break; } /* FALL-THROUGH */ case HOME_POOL_LOAD_BALANCE: found = pool->servers[0]; default: start = 0; break; } /* * Starting with the home server we chose, loop through * all home servers. If the current one is dead, skip * it. If it is too busy, skip it. * * Otherwise, use it. */ for (count = 0; count < pool->num_home_servers; count++) { home_server *home = pool->servers[(start + count) % pool->num_home_servers]; if (home->state == HOME_STATE_IS_DEAD) { continue; } /* * This home server is too busy. Choose another one. */ if (home->currently_outstanding >= home->max_outstanding) { continue; } if (pool->type != HOME_POOL_LOAD_BALANCE) { return home; } DEBUG3("PROXY %s %d\t%s %d", found->name, found->currently_outstanding, home->name, home->currently_outstanding); /* * Prefer this server if it's less busy than the * one we previously found. */ if (home->currently_outstanding < found->currently_outstanding) { DEBUG3("Choosing %s: It's less busy than %s", home->name, found->name); found = home; continue; } /* * Ignore servers which are busier than the one * we found. */ if (home->currently_outstanding > found->currently_outstanding) { DEBUG3("Skipping %s: It's busier than %s", home->name, found->name); continue; } if (home->total_requests_sent < found->total_requests_sent) { DEBUG3("Choosing %s: It's been less busy than %s", home->name, found->name); found = home; continue; } if (home->total_requests_sent > found->total_requests_sent) { DEBUG3("Skipping %s: It's been busier than %s", home->name, found->name); continue; } /* * From the list of servers which have the same * load, choose one at random. */ if (((count + 1) * (fr_rand() & 0xffff)) < (uint32_t) 0x10000) { found = home; } } /* loop over the home servers */ if (found) return found; /* * There's a fallback if they're all dead. */ if (pool->fallback && (pool->fallback->state == HOME_STATE_ALIVE)) { return pool->fallback; } /* * No live match found, and no fallback to the "DEFAULT" * realm. We fix this by blindly marking all servers as * "live". But only do it for ones that don't support * "pings", as they will be marked live when they * actually are live. */ if (!realm_config->fallback && realm_config->wake_all_if_all_dead) { home_server *lb = NULL; for (count = 0; count < pool->num_home_servers; count++) { home_server *home = pool->servers[count]; if ((home->state == HOME_STATE_IS_DEAD) && (home->ping_check == HOME_PING_CHECK_NONE)) { home->state = HOME_STATE_ALIVE; if (!lb) lb = home; } } if (lb) return lb; } /* * Still nothing. Look up the DEFAULT realm, but only * if we weren't looking up the NULL or DEFAULT realms. */ if (realm_config->fallback && realmname && (strcmp(realmname, "NULL") != 0) && (strcmp(realmname, "DEFAULT") != 0)) { REALM *rd = realm_find("DEFAULT"); if (!rd) return NULL; pool = NULL; if (request->packet->code == PW_AUTHENTICATION_REQUEST) { pool = rd->auth_pool; } else if (request->packet->code == PW_ACCOUNTING_REQUEST) { pool = rd->acct_pool; } if (!pool) return NULL; DEBUG2(" Realm %s has no live home servers. Falling back to the DEFAULT realm.", realmname); return home_server_ldb(rd->name, pool, request); } /* * Still haven't found anything. Oh well. */ return NULL;}home_server *home_server_find(fr_ipaddr_t *ipaddr, int port){ home_server myhome; memset(&myhome, 0, sizeof(myhome)); myhome.ipaddr = *ipaddr; myhome.port = port; myhome.server = NULL; /* we're not called for internal proxying */ return rbtree_finddata(home_servers_byaddr, &myhome);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -