Hello! ====================================== Regular expression matching in proxy.conf enables very flexible and intiutive realm proxying. It can reduce number of realm entries:
realm company2.com { regexp = "^.*\.company2\.com$" type = radius authhost = rad.company2.com accthost = rad.company2.com } ====================================== I'm operating a TLD radius server and "delegating" certain RADIUS realms to sub-node RADIUS severs. We have built a sort of RADIUS tree structure. For example (radiator config): <Handler Realm=/^subX\.tld$|^.*\.subX\.tld$/> <AuthBy RADIUS> [...] </AuthBy> </Handler> The subX.org.tld are usualy freeradius servers, that define a subX.tld and a few subsub1.subX.tld, subsub2.subX.tld, subsub3.subX.tld. This can be dangerous, becouse I delegate all *.subX.tld to the organisation and they delegate DEFAULT to me. So for a non-existant subsub4.subX.tld we create a RADIUS loop :)))). I could: - delegate realms strictly (too much administration on my part and too restrictive for subX operators) - implement split horizont in TLD server (I might do this, but I prefer to enhance free software) - imeplement regexp realm matching in freeradius (this is this patch) ====================================== proxy.conf: # Local realms realm subsub1.orgX.tld { } realm subsub2.orgX.tld { } realm subsub3.orgX.tld { } realm NULL { } # this realm is matched by: # *.orgX.tld # blackhole.orgX.tld # blackhole is handled locally (denied) realm blackhole.orgX.tld { regex = "^.*\.orgX\.tld$" } realm DEFAULT { type = radius authhost = radius.tld:1812 accthost = radius.tld:1813 secret = blah nostrip } ====================================== users: DEFAULT Realm == blackhole.orgX.tld, Auth-Type := Reject ====================================== This patch is based on this regex patch: http://projects.nuschkys.net/patches/ I've cleaned it up a bit and did some testing. It seems to work fine and not add overhead if no regex is used. It also makes realm proxying in freeradius very flexible and intiutive. Appreciate any review :). ====================================== diff -ur freeradius-1.0.1/raddb/proxy.conf freeradius-1.0.1-rlm_regexp/raddb/proxy.conf --- freeradius-1.0.1/raddb/proxy.conf 2004-02-26 17:16:32.000000000 +0100 +++ freeradius-1.0.1-rlm_regexp/raddb/proxy.conf 2004-11-17 14:47:41.000000000 +0100 @@ -136,6 +136,22 @@ # secret = testing123 #} +# A realm containing a regular expression, matching anything like +# "[EMAIL PROTECTED]" as well as "[EMAIL PROTECTED]". All +# requests with this realm will be handled locally. +# +# Please note that the regular expressions must be POSIX compatible +# and will be matched case insensitive. +# Additionally, the regexp should be the same on all servers of +# a fail-over and round-robin realm. +# +#realm company2.com { +# regexp = "^.*\.company2\.com$" +# type = radius +# authhost = rad.company2.com +# accthost = rad.company2.com +#} + # A realm entry with an optional fail-over realm. A request from # "[EMAIL PROTECTED]" will be sent to radius.isp2.com as "[EMAIL PROTECTED]", # because the 'nostrip' directive is specified for this realm. diff -ur freeradius-1.0.1/src/include/radiusd.h freeradius-1.0.1-rlm_regexp/src/include/radiusd.h --- freeradius-1.0.1/src/include/radiusd.h 2004-09-09 16:31:06.000000000 +0200 +++ freeradius-1.0.1-rlm_regexp/src/include/radiusd.h 2004-11-17 14:47:41.000000000 +0100 @@ -35,6 +35,10 @@ #include <arpa/inet.h> #endif +#ifdef HAVE_REGEX_H +#include <regex.h> +#endif + #include "missing.h" #define NO_SUCH_CHILD_PID (child_pid_t) (0) @@ -139,6 +143,10 @@ int acct_active; time_t acct_wakeup; int ldflag; +#ifdef HAVE_REGEX_H + regex_t *regex; +#endif + struct _realm *next; } REALM; @@ -328,6 +336,7 @@ void clients_free(RADCLIENT *cl); /* files.c */ +int realm_find_cmp(const REALM *rlm, const char *realm); REALM *realm_find(const char *, int); REALM *realm_findbyaddr(uint32_t ipno, int port); void realm_free(REALM *cl); diff -ur freeradius-1.0.1/src/main/files.c freeradius-1.0.1-rlm_regexp/src/main/files.c --- freeradius-1.0.1/src/main/files.c 2004-04-06 22:43:49.000000000 +0200 +++ freeradius-1.0.1-rlm_regexp/src/main/files.c 2004-11-17 14:47:41.000000000 +0100 @@ -33,6 +33,10 @@ # include <netinet/in.h> #endif +#ifdef HAVE_REGEX_H +# include <regex.h> +#endif + #include <stdlib.h> #include <string.h> #include <netdb.h> @@ -314,6 +318,12 @@ while(cl) { next = cl->next; +#ifdef HAVE_REGEX_H + if (cl->regex != NULL) { + regfree(cl->regex); + free(cl->regex); + } +#endif free(cl); cl = next; } @@ -435,6 +445,14 @@ c->active = TRUE; c->acct_active = TRUE; + /* + * Regular expressions for realms are not supported + * with the old-style realm file + */ +#ifdef HAVE_REGEX_H + c->regex = NULL; +#endif + while (getword(&p, opts, sizeof(opts))) { if (strcmp(opts, "nostrip") == 0) c->striprealm = FALSE; @@ -504,6 +522,21 @@ } /* + * Compare a realm name with entry + * If enabled also compare with regexp + */ +int realm_find_cmp(const REALM *rlm, const char *realm) { +#ifdef HAVE_REGEX_H + if ((rlm->regex != NULL) && + (regexec(rlm->regex, realm, 0, NULL, 0) == 0)) { + return 0; + } +#endif /* HAVE_REGEX_H */ + + return(strcasecmp(rlm->realm, realm)); +} + +/* * Find a realm in the REALM list. */ REALM *realm_find(const char *realm, int accounting) @@ -548,7 +581,7 @@ * dead. */ if ((!mainconfig.proxy_fallback) && - (strcasecmp(cl->realm, realm) == 0)) { + (realm_find_cmp(cl, realm) == 0)) { dead_match = 1; } continue; @@ -562,7 +595,7 @@ * scatter techniques, as that's more properly * the responsibility of the proxying code. */ - if (strcasecmp(cl->realm, realm) == 0) { + if (realm_find_cmp(cl, realm) == 0) { return cl; } @@ -585,7 +618,7 @@ if (mainconfig.wake_all_if_all_dead) { REALM *rcl = NULL; for (cl = mainconfig.realms; cl; cl = cl->next) { - if(strcasecmp(cl->realm,realm) == 0) { + if(realm_find_cmp(cl,realm) == 0) { if (!accounting && !cl->active) { cl->active = TRUE; rcl = cl; diff -ur freeradius-1.0.1/src/main/mainconfig.c freeradius-1.0.1-rlm_regexp/src/main/mainconfig.c --- freeradius-1.0.1/src/main/mainconfig.c 2004-06-08 17:09:40.000000000 +0200 +++ freeradius-1.0.1-rlm_regexp/src/main/mainconfig.c 2004-11-18 08:04:26.000000000 +0100 @@ -35,6 +35,10 @@ #include <arpa/inet.h> #endif +#ifdef HAVE_REGEX_H +#include <regex.h> +#endif + #include "radiusd.h" #include "rad_assert.h" #include "conffile.h" @@ -349,6 +353,9 @@ REALM *c, **tail; char *s, *t, *authhost, *accthost; char *name2; +#ifdef HAVE_REGEX_H + char *regex; +#endif /* HAVE_REGEX_H */ tail = &my_realms; for (cs = cf_subsection_find_next(mainconfig.config, NULL, "realm"); @@ -485,6 +492,30 @@ c->striprealm = 1; +#ifdef HAVE_REGEX_H + /* + * If the realm has a regex configured, try to + * precompile it and store it in the realm struct. + */ + regex = cf_section_value_find(cs, "regex"); + if (regex != NULL && strcmp(c->realm, "NULL") && strcmp(c->realm, "DEFAULT")) { + DEBUG2("read_config_files: found a regular expression \"%s\" for realm %s", + regex, c->realm); + c->regex = rad_malloc(sizeof(regex_t)); + + int res = regcomp(c->regex, regex, REG_NOSUB|REG_ICASE); + if (res != 0) { + char msg[128]; + + regerror(res, c->regex, msg, sizeof(msg)); + radlog(L_ERR, "%s[%d]: Found illegal regular expression %s, disabling regex support for realm %s.", + filename, cf_section_lineno(cs), msg, c->realm); + + return -1; + } + } +#endif + if ((cf_section_value_find(cs, "nostrip")) != NULL) c->striprealm = 0; if ((cf_section_value_find(cs, "noacct")) != NULL) diff -ur freeradius-1.0.1/src/main/proxy.c freeradius-1.0.1-rlm_regexp/src/main/proxy.c --- freeradius-1.0.1/src/main/proxy.c 2004-05-28 23:45:07.000000000 +0200 +++ freeradius-1.0.1-rlm_regexp/src/main/proxy.c 2004-11-17 14:47:42.000000000 +0100 @@ -150,7 +150,7 @@ /* * The realm name doesn't match, skip it. */ - if (strcasecmp(cl->realm, realm_name) != 0) { + if (realm_find_cmp(cl, realm_name) != 0) { continue; } -- lep pozdrav, Rok Papež. - List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html