X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fiptables.c;h=286c6e9b6ca4318fa6a1b059e3f1337643434e19;hp=35975e6d8adff4979a18c841fabe57035eec416f;hb=1159cb5d383c55a80a0db100b8f7aadcf44740a5;hpb=10139cda6f68ae1f921d79c930dd85944afb74a3 diff --git a/src/iptables.c b/src/iptables.c index 35975e6d..286c6e9b 100644 --- a/src/iptables.c +++ b/src/iptables.c @@ -29,11 +29,11 @@ #include "common.h" #include "plugin.h" -#include #include +#include #ifdef HAVE_SYS_CAPABILITY_H -# include +#include #endif /* @@ -63,465 +63,385 @@ typedef struct ip6tc_handle ip6tc_handle_t; * Config format should be `Chain table chainname', * e. g. `Chain mangle incoming' */ -static const char *config_keys[] = -{ - "Chain", - "Chain6" -}; -static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); -enum protocol_version_e -{ - IPV4, - IPV6 -}; +static const char *config_keys[] = {"Chain", "Chain6"}; +static int config_keys_num = STATIC_ARRAY_SIZE(config_keys); +enum protocol_version_e { IPV4, IPV6 }; typedef enum protocol_version_e protocol_version_t; /* * Each table/chain combo that will be queried goes into this list */ #ifndef XT_TABLE_MAXNAMELEN -# define XT_TABLE_MAXNAMELEN 32 +#define XT_TABLE_MAXNAMELEN 32 #endif typedef struct { - protocol_version_t ip_version; - char table[XT_TABLE_MAXNAMELEN]; - char chain[XT_TABLE_MAXNAMELEN]; - union - { - int num; - char *comment; - } rule; - enum - { - RTYPE_NUM, - RTYPE_COMMENT, - RTYPE_COMMENT_ALL - } rule_type; - char name[64]; + protocol_version_t ip_version; + char table[XT_TABLE_MAXNAMELEN]; + char chain[XT_TABLE_MAXNAMELEN]; + union { + int num; + char *comment; + } rule; + enum { RTYPE_NUM, RTYPE_COMMENT, RTYPE_COMMENT_ALL } rule_type; + char name[64]; } ip_chain_t; static ip_chain_t **chain_list = NULL; static int chain_num = 0; -static int iptables_config (const char *key, const char *value) -{ - /* int ip_value; */ - protocol_version_t ip_version = 0; - - if (strcasecmp (key, "Chain") == 0) - ip_version = IPV4; - else if (strcasecmp (key, "Chain6") == 0) - ip_version = IPV6; - else - return (1); - - ip_chain_t temp = { 0 }; - ip_chain_t *final, **list; - char *table; - int table_len; - char *chain; - int chain_len; - - char *value_copy; - char *fields[4]; - int fields_num; - - value_copy = strdup (value); - if (value_copy == NULL) - { - char errbuf[1024]; - ERROR ("strdup failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); - return (1); - } - - /* - * Time to fill the temp element - * Examine value string, it should look like: - * Chain[6] [ [name]] - */ - - /* set IPv4 or IPv6 */ - temp.ip_version = ip_version; - - /* Chain
[ [name]] */ - fields_num = strsplit (value_copy, fields, 4); - if (fields_num < 2) - { - free (value_copy); - return (1); +static int iptables_config(const char *key, const char *value) { + /* int ip_value; */ + protocol_version_t ip_version = 0; + + if (strcasecmp(key, "Chain") == 0) + ip_version = IPV4; + else if (strcasecmp(key, "Chain6") == 0) + ip_version = IPV6; + else + return 1; + + ip_chain_t temp = {0}; + ip_chain_t *final, **list; + char *table; + int table_len; + char *chain; + int chain_len; + + char *value_copy; + char *fields[4]; + int fields_num; + + value_copy = strdup(value); + if (value_copy == NULL) { + char errbuf[1024]; + ERROR("strdup failed: %s", sstrerror(errno, errbuf, sizeof(errbuf))); + return 1; + } + + /* + * Time to fill the temp element + * Examine value string, it should look like: + * Chain[6]
[ [name]] + */ + + /* set IPv4 or IPv6 */ + temp.ip_version = ip_version; + + /* Chain
[ [name]] */ + fields_num = strsplit(value_copy, fields, 4); + if (fields_num < 2) { + free(value_copy); + return 1; + } + + table = fields[0]; + chain = fields[1]; + + table_len = strlen(table) + 1; + if ((unsigned int)table_len > sizeof(temp.table)) { + ERROR("Table `%s' too long.", table); + free(value_copy); + return 1; + } + sstrncpy(temp.table, table, table_len); + + chain_len = strlen(chain) + 1; + if ((unsigned int)chain_len > sizeof(temp.chain)) { + ERROR("Chain `%s' too long.", chain); + free(value_copy); + return 1; + } + sstrncpy(temp.chain, chain, chain_len); + + if (fields_num >= 3) { + char *comment = fields[2]; + int rule = atoi(comment); + + if (rule) { + temp.rule.num = rule; + temp.rule_type = RTYPE_NUM; + } else { + temp.rule.comment = strdup(comment); + if (temp.rule.comment == NULL) { + free(value_copy); + return 1; + } + temp.rule_type = RTYPE_COMMENT; } - - table = fields[0]; - chain = fields[1]; - - table_len = strlen (table) + 1; - if ((unsigned int)table_len > sizeof(temp.table)) - { - ERROR ("Table `%s' too long.", table); - free (value_copy); - return (1); - } - sstrncpy (temp.table, table, table_len); - - chain_len = strlen (chain) + 1; - if ((unsigned int)chain_len > sizeof(temp.chain)) - { - ERROR ("Chain `%s' too long.", chain); - free (value_copy); - return (1); - } - sstrncpy (temp.chain, chain, chain_len); - - if (fields_num >= 3) - { - char *comment = fields[2]; - int rule = atoi (comment); - - if (rule) - { - temp.rule.num = rule; - temp.rule_type = RTYPE_NUM; - } - else - { - temp.rule.comment = strdup (comment); - if (temp.rule.comment == NULL) - { - free (value_copy); - return (1); - } - temp.rule_type = RTYPE_COMMENT; - } - } - else - { - temp.rule_type = RTYPE_COMMENT_ALL; - } - - if (fields_num >= 4) - sstrncpy (temp.name, fields[3], sizeof (temp.name)); - - free (value_copy); - value_copy = NULL; - table = NULL; - chain = NULL; - - list = realloc (chain_list, (chain_num + 1) * sizeof (ip_chain_t *)); - if (list == NULL) - { - char errbuf[1024]; - ERROR ("realloc failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); - sfree (temp.rule.comment); - return (1); - } - - chain_list = list; - final = malloc(sizeof (*final)); - if (final == NULL) - { - char errbuf[1024]; - ERROR ("malloc failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); - sfree (temp.rule.comment); - return (1); - } - memcpy (final, &temp, sizeof (temp)); - chain_list[chain_num] = final; - chain_num++; - - DEBUG ("Chain #%i: table = %s; chain = %s;", chain_num, final->table, final->chain); - - return (0); + } else { + temp.rule_type = RTYPE_COMMENT_ALL; + } + + if (fields_num >= 4) + sstrncpy(temp.name, fields[3], sizeof(temp.name)); + + free(value_copy); + value_copy = NULL; + table = NULL; + chain = NULL; + + list = realloc(chain_list, (chain_num + 1) * sizeof(ip_chain_t *)); + if (list == NULL) { + char errbuf[1024]; + ERROR("realloc failed: %s", sstrerror(errno, errbuf, sizeof(errbuf))); + sfree(temp.rule.comment); + return 1; + } + + chain_list = list; + final = malloc(sizeof(*final)); + if (final == NULL) { + char errbuf[1024]; + ERROR("malloc failed: %s", sstrerror(errno, errbuf, sizeof(errbuf))); + sfree(temp.rule.comment); + return 1; + } + memcpy(final, &temp, sizeof(temp)); + chain_list[chain_num] = final; + chain_num++; + + DEBUG("Chain #%i: table = %s; chain = %s;", chain_num, final->table, + final->chain); + + return 0; } /* int iptables_config */ -static int submit6_match (const struct ip6t_entry_match *match, - const struct ip6t_entry *entry, - const ip_chain_t *chain, - int rule_num) -{ - int status; - value_list_t vl = VALUE_LIST_INIT; - - /* Select the rules to collect */ +static int submit6_match(const struct ip6t_entry_match *match, + const struct ip6t_entry *entry, + const ip_chain_t *chain, int rule_num) { + int status; + value_list_t vl = VALUE_LIST_INIT; + + /* Select the rules to collect */ + if (chain->rule_type == RTYPE_NUM) { + if (chain->rule.num != rule_num) + return 0; + } else { + if (strcmp(match->u.user.name, "comment") != 0) + return 0; + if ((chain->rule_type == RTYPE_COMMENT) && + (strcmp(chain->rule.comment, (char *)match->data) != 0)) + return 0; + } + + sstrncpy(vl.plugin, "ip6tables", sizeof(vl.plugin)); + + status = snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s", + chain->table, chain->chain); + if ((status < 1) || ((unsigned int)status >= sizeof(vl.plugin_instance))) + return 0; + + if (chain->name[0] != '\0') { + sstrncpy(vl.type_instance, chain->name, sizeof(vl.type_instance)); + } else { if (chain->rule_type == RTYPE_NUM) - { - if (chain->rule.num != rule_num) - return (0); - } + snprintf(vl.type_instance, sizeof(vl.type_instance), "%i", + chain->rule.num); else - { - if (strcmp (match->u.user.name, "comment") != 0) - return (0); - if ((chain->rule_type == RTYPE_COMMENT) - && (strcmp (chain->rule.comment, (char *) match->data) != 0)) - return (0); - } + sstrncpy(vl.type_instance, (char *)match->data, sizeof(vl.type_instance)); + } - sstrncpy (vl.host, hostname_g, sizeof (vl.host)); - sstrncpy (vl.plugin, "ip6tables", sizeof (vl.plugin)); + sstrncpy(vl.type, "ipt_bytes", sizeof(vl.type)); + vl.values = &(value_t){.derive = (derive_t)entry->counters.bcnt}; + vl.values_len = 1; + plugin_dispatch_values(&vl); - status = ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), - "%s-%s", chain->table, chain->chain); - if ((status < 1) || ((unsigned int)status >= sizeof (vl.plugin_instance))) - return (0); + sstrncpy(vl.type, "ipt_packets", sizeof(vl.type)); + vl.values = &(value_t){.derive = (derive_t)entry->counters.pcnt}; + plugin_dispatch_values(&vl); - if (chain->name[0] != '\0') - { - sstrncpy (vl.type_instance, chain->name, sizeof (vl.type_instance)); - } - else - { - if (chain->rule_type == RTYPE_NUM) - ssnprintf (vl.type_instance, sizeof (vl.type_instance), - "%i", chain->rule.num); - else - sstrncpy (vl.type_instance, (char *) match->data, - sizeof (vl.type_instance)); - } - - sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type)); - vl.values = &(value_t) { .derive = (derive_t) entry->counters.bcnt }; - vl.values_len = 1; - plugin_dispatch_values (&vl); - - sstrncpy (vl.type, "ipt_packets", sizeof (vl.type)); - vl.values = &(value_t) { .derive = (derive_t) entry->counters.pcnt }; - plugin_dispatch_values (&vl); - - return (0); + return 0; } /* int submit6_match */ /* This needs to return `int' for IPT_MATCH_ITERATE to work. */ -static int submit_match (const struct ipt_entry_match *match, - const struct ipt_entry *entry, - const ip_chain_t *chain, - int rule_num) -{ - int status; - value_list_t vl = VALUE_LIST_INIT; - - /* Select the rules to collect */ +static int submit_match(const struct ipt_entry_match *match, + const struct ipt_entry *entry, const ip_chain_t *chain, + int rule_num) { + int status; + value_list_t vl = VALUE_LIST_INIT; + + /* Select the rules to collect */ + if (chain->rule_type == RTYPE_NUM) { + if (chain->rule.num != rule_num) + return 0; + } else { + if (strcmp(match->u.user.name, "comment") != 0) + return 0; + if ((chain->rule_type == RTYPE_COMMENT) && + (strcmp(chain->rule.comment, (char *)match->data) != 0)) + return 0; + } + + sstrncpy(vl.plugin, "iptables", sizeof(vl.plugin)); + + status = snprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%s", + chain->table, chain->chain); + if ((status < 1) || ((unsigned int)status >= sizeof(vl.plugin_instance))) + return 0; + + if (chain->name[0] != '\0') { + sstrncpy(vl.type_instance, chain->name, sizeof(vl.type_instance)); + } else { if (chain->rule_type == RTYPE_NUM) - { - if (chain->rule.num != rule_num) - return (0); - } - else - { - if (strcmp (match->u.user.name, "comment") != 0) - return (0); - if ((chain->rule_type == RTYPE_COMMENT) - && (strcmp (chain->rule.comment, (char *) match->data) != 0)) - return (0); - } - - sstrncpy (vl.host, hostname_g, sizeof (vl.host)); - sstrncpy (vl.plugin, "iptables", sizeof (vl.plugin)); - - status = ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), - "%s-%s", chain->table, chain->chain); - if ((status < 1) || ((unsigned int)status >= sizeof (vl.plugin_instance))) - return (0); - - if (chain->name[0] != '\0') - { - sstrncpy (vl.type_instance, chain->name, sizeof (vl.type_instance)); - } + snprintf(vl.type_instance, sizeof(vl.type_instance), "%i", + chain->rule.num); else - { - if (chain->rule_type == RTYPE_NUM) - ssnprintf (vl.type_instance, sizeof (vl.type_instance), - "%i", chain->rule.num); - else - sstrncpy (vl.type_instance, (char *) match->data, - sizeof (vl.type_instance)); - } + sstrncpy(vl.type_instance, (char *)match->data, sizeof(vl.type_instance)); + } - sstrncpy (vl.type, "ipt_bytes", sizeof (vl.type)); - vl.values = &(value_t) { .derive = (derive_t) entry->counters.bcnt }; - vl.values_len = 1; - plugin_dispatch_values (&vl); + sstrncpy(vl.type, "ipt_bytes", sizeof(vl.type)); + vl.values = &(value_t){.derive = (derive_t)entry->counters.bcnt}; + vl.values_len = 1; + plugin_dispatch_values(&vl); - sstrncpy (vl.type, "ipt_packets", sizeof (vl.type)); - vl.values = &(value_t) { .derive = (derive_t) entry->counters.pcnt }; - plugin_dispatch_values (&vl); + sstrncpy(vl.type, "ipt_packets", sizeof(vl.type)); + vl.values = &(value_t){.derive = (derive_t)entry->counters.pcnt}; + plugin_dispatch_values(&vl); - return (0); + return 0; } /* int submit_match */ - /* ipv6 submit_chain */ -static void submit6_chain (ip6tc_handle_t *handle, ip_chain_t *chain) -{ - const struct ip6t_entry *entry; - int rule_num; - - /* Find first rule for chain and use the iterate macro */ - entry = ip6tc_first_rule( chain->chain, handle ); - if (entry == NULL) - { - DEBUG ("ip6tc_first_rule failed: %s", ip6tc_strerror (errno)); - return; +static void submit6_chain(ip6tc_handle_t *handle, ip_chain_t *chain) { + const struct ip6t_entry *entry; + int rule_num; + + /* Find first rule for chain and use the iterate macro */ + entry = ip6tc_first_rule(chain->chain, handle); + if (entry == NULL) { + DEBUG("ip6tc_first_rule failed: %s", ip6tc_strerror(errno)); + return; + } + + rule_num = 1; + while (entry) { + if (chain->rule_type == RTYPE_NUM) { + submit6_match(NULL, entry, chain, rule_num); + } else { + IP6T_MATCH_ITERATE(entry, submit6_match, entry, chain, rule_num); } - rule_num = 1; - while (entry) - { - if (chain->rule_type == RTYPE_NUM) - { - submit6_match (NULL, entry, chain, rule_num); - } - else - { - IP6T_MATCH_ITERATE( entry, submit6_match, entry, chain, rule_num ); - } - - entry = ip6tc_next_rule( entry, handle ); - rule_num++; - } /* while (entry) */ + entry = ip6tc_next_rule(entry, handle); + rule_num++; + } /* while (entry) */ } - /* ipv4 submit_chain */ -static void submit_chain (iptc_handle_t *handle, ip_chain_t *chain) -{ - const struct ipt_entry *entry; - int rule_num; - - /* Find first rule for chain and use the iterate macro */ - entry = iptc_first_rule( chain->chain, handle ); - if (entry == NULL) - { - DEBUG ("iptc_first_rule failed: %s", iptc_strerror (errno)); - return; +static void submit_chain(iptc_handle_t *handle, ip_chain_t *chain) { + const struct ipt_entry *entry; + int rule_num; + + /* Find first rule for chain and use the iterate macro */ + entry = iptc_first_rule(chain->chain, handle); + if (entry == NULL) { + DEBUG("iptc_first_rule failed: %s", iptc_strerror(errno)); + return; + } + + rule_num = 1; + while (entry) { + if (chain->rule_type == RTYPE_NUM) { + submit_match(NULL, entry, chain, rule_num); + } else { + IPT_MATCH_ITERATE(entry, submit_match, entry, chain, rule_num); } - rule_num = 1; - while (entry) - { - if (chain->rule_type == RTYPE_NUM) - { - submit_match (NULL, entry, chain, rule_num); - } - else - { - IPT_MATCH_ITERATE( entry, submit_match, entry, chain, rule_num ); - } - - entry = iptc_next_rule( entry, handle ); - rule_num++; - } /* while (entry) */ + entry = iptc_next_rule(entry, handle); + rule_num++; + } /* while (entry) */ } +static int iptables_read(void) { + int num_failures = 0; + ip_chain_t *chain; -static int iptables_read (void) -{ - int num_failures = 0; - ip_chain_t *chain; - - /* Init the iptc handle structure and query the correct table */ - for (int i = 0; i < chain_num; i++) - { - chain = chain_list[i]; + /* Init the iptc handle structure and query the correct table */ + for (int i = 0; i < chain_num; i++) { + chain = chain_list[i]; - if (!chain) - { - DEBUG ("iptables plugin: chain == NULL"); - continue; - } + if (!chain) { + DEBUG("iptables plugin: chain == NULL"); + continue; + } - if ( chain->ip_version == IPV4 ) - { + if (chain->ip_version == IPV4) { #ifdef HAVE_IPTC_HANDLE_T - iptc_handle_t _handle; - iptc_handle_t *handle = &_handle; + iptc_handle_t _handle; + iptc_handle_t *handle = &_handle; - *handle = iptc_init (chain->table); + *handle = iptc_init(chain->table); #else - iptc_handle_t *handle; - handle = iptc_init (chain->table); + iptc_handle_t *handle; + handle = iptc_init(chain->table); #endif - if (!handle) - { - ERROR ("iptables plugin: iptc_init (%s) failed: %s", - chain->table, iptc_strerror (errno)); - num_failures++; - continue; - } - - submit_chain (handle, chain); - iptc_free (handle); - } - else if ( chain->ip_version == IPV6 ) - { + if (!handle) { + ERROR("iptables plugin: iptc_init (%s) failed: %s", chain->table, + iptc_strerror(errno)); + num_failures++; + continue; + } + + submit_chain(handle, chain); + iptc_free(handle); + } else if (chain->ip_version == IPV6) { #ifdef HAVE_IP6TC_HANDLE_T - ip6tc_handle_t _handle; - ip6tc_handle_t *handle = &_handle; + ip6tc_handle_t _handle; + ip6tc_handle_t *handle = &_handle; - *handle = ip6tc_init (chain->table); + *handle = ip6tc_init(chain->table); #else - ip6tc_handle_t *handle; - handle = ip6tc_init (chain->table); + ip6tc_handle_t *handle; + handle = ip6tc_init(chain->table); #endif - if (!handle) - { - ERROR ("iptables plugin: ip6tc_init (%s) failed: %s", - chain->table, ip6tc_strerror (errno)); - num_failures++; - continue; - } - - submit6_chain (handle, chain); - ip6tc_free (handle); - } - else - num_failures++; - } /* for (i = 0 .. chain_num) */ - - return ((num_failures < chain_num) ? 0 : -1); + if (!handle) { + ERROR("iptables plugin: ip6tc_init (%s) failed: %s", chain->table, + ip6tc_strerror(errno)); + num_failures++; + continue; + } + + submit6_chain(handle, chain); + ip6tc_free(handle); + } else + num_failures++; + } /* for (i = 0 .. chain_num) */ + + return (num_failures < chain_num) ? 0 : -1; } /* int iptables_read */ -static int iptables_shutdown (void) -{ - for (int i = 0; i < chain_num; i++) - { - if ((chain_list[i] != NULL) && (chain_list[i]->rule_type == RTYPE_COMMENT)) - sfree (chain_list[i]->rule.comment); - sfree (chain_list[i]); - } - sfree (chain_list); +static int iptables_shutdown(void) { + for (int i = 0; i < chain_num; i++) { + if ((chain_list[i] != NULL) && (chain_list[i]->rule_type == RTYPE_COMMENT)) + sfree(chain_list[i]->rule.comment); + sfree(chain_list[i]); + } + sfree(chain_list); - return (0); + return 0; } /* int iptables_shutdown */ -static int iptables_init (void) -{ +static int iptables_init(void) { #if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_NET_ADMIN) - if (check_capability (CAP_NET_ADMIN) != 0) - { - if (getuid () == 0) - WARNING ("iptables plugin: Running collectd as root, but the " - "CAP_NET_ADMIN capability is missing. The plugin's read " - "function will probably fail. Is your init system dropping " - "capabilities?"); - else - WARNING ("iptables plugin: collectd doesn't have the CAP_NET_ADMIN " - "capability. If you don't want to run collectd as root, try " - "running \"setcap cap_net_admin=ep\" on the collectd binary."); - } + if (check_capability(CAP_NET_ADMIN) != 0) { + if (getuid() == 0) + WARNING("iptables plugin: Running collectd as root, but the " + "CAP_NET_ADMIN capability is missing. The plugin's read " + "function will probably fail. Is your init system dropping " + "capabilities?"); + else + WARNING("iptables plugin: collectd doesn't have the CAP_NET_ADMIN " + "capability. If you don't want to run collectd as root, try " + "running \"setcap cap_net_admin=ep\" on the collectd binary."); + } #endif - return (0); + return 0; } /* int iptables_init */ -void module_register (void) -{ - plugin_register_config ("iptables", iptables_config, - config_keys, config_keys_num); - plugin_register_init ("iptables", iptables_init); - plugin_register_read ("iptables", iptables_read); - plugin_register_shutdown ("iptables", iptables_shutdown); +void module_register(void) { + plugin_register_config("iptables", iptables_config, config_keys, + config_keys_num); + plugin_register_init("iptables", iptables_init); + plugin_register_read("iptables", iptables_read); + plugin_register_shutdown("iptables", iptables_shutdown); } /* void module_register */ -