diff --git a/src/defaults.h b/src/defaults.h index a865cf0..3b4f882 100644 --- a/src/defaults.h +++ b/src/defaults.h @@ -52,32 +52,4 @@ static const size_t MAXLEN = 1024; * \brief Maximum number of different shared networks in dhcpd.conf file. */ static const unsigned int SHARED_NETWORKS = 8192; -/*! \var prefixes[2][NUM_OF_PREFIX] - * \brief ISC lease file formats for IPv4 and IPv6. - * - * The .indent.pro in use will mess formatting of array below. - * Please do not commit less readable indentation. */ -static const char *prefixes[2][NUM_OF_PREFIX] = { - [VERSION_4] = { - [PREFIX_LEASE] = "lease ", - [PREFIX_BINDING_STATE_FREE] = " binding state free", - [PREFIX_BINDING_STATE_ABANDONED] = " binding state abandoned", - [PREFIX_BINDING_STATE_EXPIRED] = " binding state expired", - [PREFIX_BINDING_STATE_RELEASED] = " binding state released", - [PREFIX_BINDING_STATE_ACTIVE] = " binding state active", - [PREFIX_BINDING_STATE_BACKUP] = " binding state backup", - [PREFIX_HARDWARE_ETHERNET] = " hardware ethernet" - }, - [VERSION_6] = { - [PREFIX_LEASE] = " iaaddr ", - [PREFIX_BINDING_STATE_FREE] = " binding state free", - [PREFIX_BINDING_STATE_ABANDONED] = " binding state abandoned", - [PREFIX_BINDING_STATE_EXPIRED] = " binding state expired", - [PREFIX_BINDING_STATE_RELEASED] = " binding state released", - [PREFIX_BINDING_STATE_ACTIVE] = " binding state active", - [PREFIX_BINDING_STATE_BACKUP] = " binding state backup", - [PREFIX_HARDWARE_ETHERNET] = " hardware ethernet" - } -}; - #endif /* DEFAULTS_H */ diff --git a/src/dhcpd-pools.c b/src/dhcpd-pools.c index 06641d6..d37d0d0 100644 --- a/src/dhcpd-pools.c +++ b/src/dhcpd-pools.c @@ -272,13 +272,6 @@ int main(int argc, char **argv) * FIXME: This function should return void. */ int prepare_memory(void) { - /* Fill in prefix length cache */ - int i, j; - for (i = 0; i < 2; i++) { - for (j = 0; j < NUM_OF_PREFIX; j++) { - prefix_length[i][j] = strlen(prefixes[i][j]); - } - } config.dhcp_version = VERSION_UNKNOWN; RANGES = 64; num_ranges = num_shared_networks = 0; diff --git a/src/dhcpd-pools.h b/src/dhcpd-pools.h index 3578319..7157a4f 100644 --- a/src/dhcpd-pools.h +++ b/src/dhcpd-pools.h @@ -210,8 +210,7 @@ void copy_ipaddr(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src); const char *ntop_ipaddr(const union ipaddr_t *ip); double get_range_size(const struct range_t *r); -int xstrstr(const char *__restrict a, const char *__restrict b, int len) - __attribute__ ((nonnull(1, 2))) +int xstrstr(const char *__restrict str) # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) __attribute__ ((__hot__)) # endif diff --git a/src/getdata.c b/src/getdata.c index 38d9e74..8b411f4 100644 --- a/src/getdata.c +++ b/src/getdata.c @@ -101,62 +101,52 @@ int parse_leases(void) ethernets = true; } - const char **p = prefixes[config.dhcp_version]; - int *l = prefix_length[config.dhcp_version]; - -/*! \def HAS_PREFIX(line, type) - * \brief A macro to match IPv4 and IPv6 lease lines. - * - * FIXME: This macro should have better name. The HAS_PREFIX sounds like - * some sort of prefix length test. */ -#define HAS_PREFIX(line, type) xstrstr((line), p[type], l[type]) - while (!feof(dhcpd_leases)) { if (!fgets(line, MAXLEN, dhcpd_leases) && ferror(dhcpd_leases)) { err(EXIT_FAILURE, "parse_leases: %s", config.dhcpdlease_file); } + switch(xstrstr(line)) { /* It's a lease, save IP */ - if (HAS_PREFIX(line, PREFIX_LEASE)) { - nth_field(ipstring, line + l[PREFIX_LEASE]); + case PREFIX_LEASE: + nth_field(ipstring, line + (config.dhcp_version == VERSION_4 ? 6 : 9)); parse_ipaddr(ipstring, &addr); - continue; - } - if (HAS_PREFIX(line, PREFIX_BINDING_STATE_FREE) || - HAS_PREFIX(line, PREFIX_BINDING_STATE_ABANDONED) || - HAS_PREFIX(line, PREFIX_BINDING_STATE_EXPIRED) || - HAS_PREFIX(line, PREFIX_BINDING_STATE_RELEASED)) { - /* remove old entry, if exists */ + break; + case PREFIX_BINDING_STATE_FREE: + case PREFIX_BINDING_STATE_ABANDONED: + case PREFIX_BINDING_STATE_EXPIRED: + case PREFIX_BINDING_STATE_RELEASED: if ((lease = find_lease(&addr)) != NULL) { delete_lease(lease); } add_lease(&addr, FREE); - continue; - } - /* Copy IP to correct array */ - if (HAS_PREFIX(line, PREFIX_BINDING_STATE_ACTIVE)) { + break; + case PREFIX_BINDING_STATE_ACTIVE: /* remove old entry, if exists */ if ((lease = find_lease(&addr)) != NULL) { delete_lease(lease); } add_lease(&addr, ACTIVE); - continue; - } - if (HAS_PREFIX(line, PREFIX_BINDING_STATE_BACKUP)) { + break; + case PREFIX_BINDING_STATE_BACKUP: /* remove old entry, if exists */ if ((lease = find_lease(&addr)) != NULL) { delete_lease(lease); } add_lease(&addr, BACKUP); config.backups_found = true; - continue; - } - if (ethernets && (xstrstr(line, " hardware ethernet", 19))) { + break; + case PREFIX_HARDWARE_ETHERNET: + if (ethernets == false) + break; nth_field(macstring, line + 20); macstring[17] = '\0'; if ((lease = find_lease(&addr)) != NULL) { lease->ethernet = xstrdup(macstring); } + break; + default: + /* do nothing */; } } #undef HAS_PREFIX diff --git a/src/other.c b/src/other.c index e31b3bb..a45352c 100644 --- a/src/other.c +++ b/src/other.c @@ -148,53 +148,103 @@ double get_range_size(const struct range_t *r) } } -/*! \fn xstrstr(const char *restrict a, const char *restrict b, const int len) - * \brief Compare two strings. Similar to strcmp, but tuned to be - * quicker which is possible because input data is known to have certain - * structure. +/*! \fn xstrstr(const char *restrict str) + * \brief Categorize dhcpd.leases line. * - * \param a String which is been compared, e.g., a haystack. - * \param b Constant string which is hoped to found, e.g., a needle. - * \param len Stop point in characters when comparison must be ended. - * \return Zero if strings differ, one if they are the same. */ + * \param str A line from dhcpd.conf + * \return prefix_t enum value + */ int #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) __attribute__ ((hot)) #endif - xstrstr(const char *restrict a, const char *restrict b, const int len) + xstrstr(const char *restrict str) { - int i; - + size_t len; /* Needed when dhcpd.conf has zero range definitions. */ if (config.dhcp_version == VERSION_UNKNOWN) { - if (!strcmp(prefixes[VERSION_4][PREFIX_LEASE], a)) { + if (strncmp("lease ", str, 6)) { config.dhcp_version = VERSION_4; - return true; - } - if (!strcmp(prefixes[VERSION_6][PREFIX_LEASE], a)) { + return PREFIX_LEASE; + } else if (strncmp(" iaaddr ", str, 9)) { config.dhcp_version = VERSION_6; - return true; + return PREFIX_LEASE; } - return false; + return NUM_OF_PREFIX; } - - /* two spaces are very common in lease file, after them - * nearly everything differs */ - if (likely(a[2] != b[2])) { - return false; + if ((config.dhcp_version == VERSION_4 && str[2] == 'b') + || (config.dhcp_version == VERSION_6 && str[4] == 'b') + || str[2] == 'h') { + len = strlen(str); + } else { + len = 0; } - /* " binding state " == 16 chars, this will skip right - * to first differing line. */ - if (17 < len && a[17] != b[17]) { - return false; - } - /* looking good, double check the whole thing... */ - for (i = 0; a[i] != '\0' && b[i] != '\0'; i++) { - if (a[i] != b[i]) { - return false; + if (15 < len && config.dhcp_version == VERSION_4) { + switch (str[16]) { + case 'f': + if (!strncmp(" binding state free;", str, 21)) + return PREFIX_BINDING_STATE_FREE; + break; + case 'a': + if (!strncmp(" binding state active;", str, 23)) + return PREFIX_BINDING_STATE_ACTIVE; + if (!strncmp(" binding state abandoned;", str, 25)) + return PREFIX_BINDING_STATE_ABANDONED; + break; + case 'e': + if (!strncmp(" binding state expired;", str, 24)) + return PREFIX_BINDING_STATE_EXPIRED; + break; + case 'r': + if (!strncmp(" binding state released;", str, 25)) + return PREFIX_BINDING_STATE_RELEASED; + break; + case 'b': + if (!strncmp(" binding state backup;", str, 23)) + return PREFIX_BINDING_STATE_BACKUP; + break; + case 'n': + if (!strncmp(" hardware ethernet", str, 19)) + return PREFIX_HARDWARE_ETHERNET; + break; + } + } else if (17 < len /* && config.dhcp_version == VERSION_6 */ ) { + switch (str[18]) { + case 'f': + if (!strncmp(" binding state free;", str, 23)) + return PREFIX_BINDING_STATE_FREE; + break; + case 'a': + if (!strncmp(" binding state active;", str, 25)) + return PREFIX_BINDING_STATE_ACTIVE; + if (!strncmp(" binding state abandoned;", str, 27)) + return PREFIX_BINDING_STATE_ABANDONED; + break; + case 'e': + if (!strncmp(" binding state expired;", str, 26)) + return PREFIX_BINDING_STATE_EXPIRED; + break; + case 'r': + if (!strncmp(" binding state released;", str, 27)) + return PREFIX_BINDING_STATE_RELEASED; + break; + case 'b': + if (!strncmp(" binding state backup;", str, 25)) + return PREFIX_BINDING_STATE_BACKUP; + break; + case 'n': + if (!strncmp(" hardware ethernet", str, 19)) + return PREFIX_HARDWARE_ETHERNET; + break; } } - return true; + if (config.dhcp_version == VERSION_4 && !strncmp("lease ", str, 6)) { + return PREFIX_LEASE; + } else if (config.dhcp_version == VERSION_6 + && !strncmp(" iaaddr ", str, 9)) { + return PREFIX_LEASE; + } + return NUM_OF_PREFIX; } /*! \brief Return a double floating point value.