added support for network masks to clients. We can now do:
authoraland <aland>
Thu, 9 Nov 2000 17:15:24 +0000 (17:15 +0000)
committeraland <aland>
Thu, 9 Nov 2000 17:15:24 +0000 (17:15 +0000)
192.168.0.0/16 secret1
192.168.0.0/24 secret2
192.168.0.0/32 secret3

and the client will match the most restrictive one.

src/main/client.c
src/main/conffile.c

index 8a82d94..292aafa 100644 (file)
@@ -56,6 +56,7 @@ int read_clients_file(const char *file)
        char    hostnm[256];
        char    secret[256];
        char    shortnm[256];
+       uint32_t mask;
        int     lineno = 0;
        char    *p;
 
@@ -66,16 +67,26 @@ int read_clients_file(const char *file)
                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))) {
@@ -87,6 +98,31 @@ int read_clients_file(const char *file)
                (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)) {
@@ -118,11 +154,14 @@ int read_clients_file(const char *file)
                }
 
                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);
@@ -142,12 +181,18 @@ int read_clients_file(const char *file)
 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;
 }
 
 /*
index f557f01..f62d42a 100644 (file)
@@ -785,12 +785,11 @@ static int generate_realms(const char *filename)
  * 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 ;
@@ -805,6 +804,7 @@ static int generate_clients(const char *filename)
                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.",
@@ -813,7 +813,7 @@ static int generate_clients(const char *filename)
                        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;
@@ -826,11 +826,50 @@ static int generate_clients(const char *filename)
                        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;