char hostnm[256];
char secret[256];
char shortnm[256];
+ uint32_t mask;
int lineno = 0;
char *p;
radlog(L_CONS|L_ERR, "cannot open %s", file);
return -1;
}
+
while(fgets(buffer, 256, fp) != NULL) {
lineno++;
if (strchr(buffer, '\n') == NULL) {
radlog(L_ERR, "%s[%d]: line too long", file, lineno);
return -1;
}
- if (buffer[0] == '#' || buffer[0] == '\n')
- continue;
+ /*
+ * Skip whitespace.
+ */
p = buffer;
+ while (*p &&
+ ((*p == ' ') || (*p == '\t'))) p++;
+
+ /*
+ * Skip comments and blank lines.
+ */
+ if ((*p == '#') || (*p == '\n') || (*p == '\r'))
+ continue;
if (!getword(&p, hostnm, sizeof(hostnm)) ||
!getword(&p, secret, sizeof(secret))) {
(void)getword(&p, shortnm, sizeof(shortnm));
/*
+ * Look for a mask in the hostname
+ */
+ p = strchr(hostnm, '/');
+ mask = ~0;
+
+ if (p) {
+ int i, mask_length;
+
+ *p = '\0';
+ p++;
+
+ mask_length = atoi(p);
+ if ((mask_length <= 0) || (mask_length > 32)) {
+ radlog(L_ERR, "%s[%d]: Invalid value '%s' for IP network mask.",
+ file, lineno, p);
+ return -1;
+ }
+
+ mask = (1 << 31);
+ for (i = 1; i < mask_length; i++) {
+ mask |= (mask >> 1);
+ }
+ }
+
+ /*
* Double-check lengths to be sure they're sane
*/
if (strlen(hostnm) >= sizeof(c->longname)) {
}
c->ipaddr = ip_getaddr(hostnm);
- if (c->ipaddr == 0) {
+ if (c->ipaddr == INADDR_NONE) {
radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
file, lineno, hostnm);
return -1;
}
+ c->netmask = htonl(mask);
+ c->ipaddr &= mask;
+
strcpy((char *)c->secret, secret);
strcpy(c->shortname, shortnm);
ip_hostname(c->longname, sizeof(c->longname), c->ipaddr);
RADCLIENT *client_find(uint32_t ipaddr)
{
RADCLIENT *cl;
+ RADCLIENT *match = NULL;
+
+ for(cl = clients; cl; cl = cl->next) {
+ if ((ipaddr & cl->netmask) == cl->ipaddr) {
+ if ((!match) ||
+ (ntohl(cl->netmask) > ntohl(match->netmask))) {
+ match = cl;
+ }
+ }
+ }
- for(cl = clients; cl; cl = cl->next)
- if (ipaddr == cl->ipaddr)
- break;
-
- return cl;
+ return match;
}
/*
* Create the linked list of realms from the new configuration type
* This way we don't have to change to much in the other source-files
*/
-
static int generate_clients(const char *filename)
{
CONF_SECTION *cs;
RADCLIENT *c;
- char *hostnm, *secret, *shortnm;
+ char *hostnm, *secret, *shortnm, *netmask;
for (cs = cf_subsection_find_next(config, NULL, "client")
; cs ;
hostnm = cs->name2;
secret = cf_section_value_find(cs, "secret");
shortnm = cf_section_value_find(cs, "shortname");
+ netmask = strchr(hostnm, '/');
if (strlen(secret) >= sizeof(c->secret)) {
radlog(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
return -1;
}
if (strlen(shortnm) > sizeof(c->shortname)) {
- radlog(L_ERR, "%s[%d]: NAS short name of length %d is greater than the allowed maximum of %d.",
+ radlog(L_ERR, "%s[%d]: Client short name of length %d is greater than the allowed maximum of %d.",
filename, cs->item.lineno,
strlen(shortnm), sizeof(c->shortname) - 1);
return -1;
return -1;
}
+ /*
+ * Look for netmasks.
+ */
+ c->netmask = ~0;
+ if (netmask) {
+ int i, mask_length;
+
+ mask_length = atoi(netmask + 1);
+ if ((mask_length <= 0) || (mask_length > 32)) {
+ radlog(L_ERR, "%s[%d]: Invalid value '%s' for IP network mask.",
+ filename, cs->item.lineno, netmask + 1);
+ return -1;
+ }
+
+ c->netmask = (1 << 31);
+ for (i = 1; i < mask_length; i++) {
+ c->netmask |= (c->netmask >> 1);
+ }
+
+ *netmask = '\0';
+ c->netmask = htonl(c->netmask);
+ }
+
c->ipaddr = ip_getaddr(hostnm);
+ if (c->ipaddr == INADDR_NONE) {
+ radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
+ filename, cs->item.lineno, hostnm);
+ return -1;
+ }
+
+ /*
+ * Update the client name again...
+ */
+ if (netmask) {
+ *netmask = '/';
+ c->ipaddr &= c->netmask;
+ strcpy(c->longname, hostnm);
+ } else {
+ ip_hostname(c->longname, sizeof(c->longname),
+ c->ipaddr);
+ }
+
strcpy((char *)c->secret, secret);
strcpy(c->shortname, shortnm);
- ip_hostname(c->longname, sizeof(c->longname),
- c->ipaddr);
c->next = clients;
clients = c;