2 * collectd - src/iptables.c
3 * Copyright (C) 2007 Sjoerd van der Berg
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * Sjoerd van der Berg <harekiet at users.sourceforge.net>
26 #include "configfile.h"
27 #include "utils_debug.h"
29 #if HAVE_LIBIPTC_LIBIPTC_H
30 # include <libiptc/libiptc.h>
33 #if HAVE_LIBIPTC_LIBIPTC_H
34 # define IPTABLES_HAVE_READ 1
36 # define IPTABLES_HAVE_READ 0
39 #define MODULE_NAME "iptables"
43 * (Module-)Global variables
47 * Removed packet count for now, should have config option if you want to save
48 * them Although other collectd models don't seem to care much for options
49 * eitherway for what to log
51 /* Limit to ~125MByte/s (~1GBit/s) */
52 static char *ds_def[] =
54 "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:134217728",
57 static int ds_num = 1;
59 #if IPTABLES_HAVE_READ
61 * Config format should be `Chain table chainname',
62 * e. g. `Chain mangle incoming'
64 static char *config_keys[] =
69 static int config_keys_num = 1;
71 Each table/chain combo that will be queried goes into this list
73 #ifndef XT_TABLE_MAXNAMELEN
74 # define XT_TABLE_MAXNAMELEN 32
77 char table[XT_TABLE_MAXNAMELEN];
78 char chain[XT_TABLE_MAXNAMELEN];
93 static ip_chain_t **chain_list = NULL;
94 static int chain_num = 0;
96 static int iptables_config (char *key, char *value)
98 if (strcasecmp (key, "Chain") == 0)
100 ip_chain_t temp, *final, **list;
110 memset (&temp, 0, sizeof (temp));
112 value_copy = strdup (value);
113 if (value_copy == NULL)
115 syslog (LOG_ERR, "strdup failed: %s", strerror (errno));
119 /* Chain <table> <chain> [<comment|num> [name]] */
120 fields_num = strsplit (value_copy, fields, 4);
130 table_len = strlen (table);
131 if (table_len >= sizeof(temp.table))
133 syslog (LOG_ERR, "Table `%s' too long.", table);
137 strncpy (temp.table, table, table_len);
138 temp.table[table_len] = '\0';
140 chain_len = strlen (chain);
141 if (chain_len >= sizeof(temp.chain))
143 syslog (LOG_ERR, "Chain `%s' too long.", chain);
147 strncpy (temp.chain, chain, chain_len);
148 temp.chain[chain_len] = '\0';
152 char *comment = fields[2];
153 int rule = atoi (comment);
157 temp.rule.num = rule;
158 temp.rule_type = RTYPE_NUM;
162 strncpy (temp.rule.comment, comment,
163 sizeof (temp.rule.comment) - 1);
164 temp.rule_type = RTYPE_COMMENT;
169 temp.rule_type = RTYPE_COMMENT_ALL;
173 strncpy (temp.name, fields[3], sizeof (temp.name) - 1);
180 list = (ip_chain_t **) realloc (chain_list, (chain_num + 1) * sizeof (ip_chain_t *));
183 syslog (LOG_ERR, "realloc failed: %s", strerror (errno));
188 final = (ip_chain_t *) malloc( sizeof(temp) );
191 syslog (LOG_ERR, "malloc failed: %s", strerror (errno));
194 memcpy (final, &temp, sizeof (temp));
195 chain_list[chain_num] = final;
198 DBG ("Chain #%i: table = %s; chain = %s;", chain_num, final->table, final->chain);
207 #endif /* IPTABLES_HAVE_READ */
209 static void iptables_write (char *host, char *orig_inst, char *val, char *type)
216 table = strdup (orig_inst);
219 inst = strchr (table, ',');
234 status = snprintf (file, sizeof (file), "iptables-%s/%s-%s.rrd",
237 if ((status >= sizeof (file)) || (status < 1))
240 rrd_update_file (host, file, val, ds_def, ds_num);
241 } /* void iptables_write */
243 static void iptables_write_bytes (char *host, char *inst, char *val)
245 iptables_write (host, inst, val, "ipt_bytes");
248 static void iptables_write_packets (char *host, char *inst, char *val)
250 iptables_write (host, inst, val, "ipt_packets");
253 #if IPTABLES_HAVE_READ
254 static int submit_match (const struct ipt_entry_match *match,
255 const struct ipt_entry *entry,
256 const ip_chain_t *chain,
263 /* Only log rules that have a comment, although could probably also do
264 * numerical targets sometime */
265 if (chain->rule_type == RTYPE_NUM)
267 if (chain->rule.num != rule_num)
272 if (strcmp (match->u.user.name, "comment") != 0)
274 if ((chain->rule_type == RTYPE_COMMENT)
275 && (strcmp (chain->rule.comment, (char *) match->data) != 0))
279 if (chain->name[0] != '\0')
281 status = snprintf (inst, sizeof (inst), "%s-%s,%s",
282 chain->table, chain->chain, chain->name);
286 if (chain->rule_type == RTYPE_NUM)
287 status = snprintf (inst, sizeof (inst), "%s-%s,%i",
288 chain->table, chain->chain, chain->rule.num);
290 status = snprintf (inst, sizeof (inst), "%s-%s,%s",
291 chain->table, chain->chain, match->data);
293 if ((status >= sizeof (inst)) || (status < 1))
297 status = snprintf (value, sizeof (value), "%u:%lld",
298 (unsigned int) curtime,
299 entry->counters.bcnt);
300 if ((status >= sizeof (value)) || (status < 1))
302 plugin_submit ("ipt_bytes", inst, value);
304 status = snprintf (value, sizeof (value), "%u:%lld",
305 (unsigned int) curtime,
306 entry->counters.pcnt);
307 if ((status >= sizeof (value)) || (status < 1))
309 plugin_submit ("ipt_packets", inst, value);
312 } /* int submit_match */
314 static void submit_chain( iptc_handle_t *handle, ip_chain_t *chain ) {
315 const struct ipt_entry *entry;
318 /* Find first rule for chain and use the iterate macro */
319 entry = iptc_first_rule( chain->chain, handle );
322 DBG ("iptc_first_rule failed: %s", iptc_strerror (errno));
329 if (chain->rule_type == RTYPE_NUM)
331 submit_match (NULL, entry, chain, rule_num);
335 IPT_MATCH_ITERATE( entry, submit_match, entry, chain, rule_num );
338 entry = iptc_next_rule( entry, handle );
340 } /* while (entry) */
344 static void iptables_read (void)
347 static complain_t complaint;
349 /* Init the iptc handle structure and query the correct table */
350 for (i = 0; i < chain_num; i++)
352 iptc_handle_t handle;
355 chain = chain_list[i];
358 DBG ("chain == NULL");
362 handle = iptc_init( chain->table );
365 DBG ("iptc_init (%s) failed: %s", chain->table, iptc_strerror (errno));
366 plugin_complain (LOG_ERR, &complaint, "iptc_init (%s) failed: %s",
367 chain->table, iptc_strerror (errno));
370 plugin_relief (LOG_INFO, &complaint, "iptc_init (%s) succeeded",
373 submit_chain (&handle, chain);
377 #else /* !IPTABLES_HAVE_READ */
378 # define iptables_read NULL
381 void module_register (void)
383 plugin_register ("ipt_bytes", NULL, NULL, iptables_write_bytes);
384 plugin_register ("ipt_packets", NULL, NULL, iptables_write_packets);
385 #if IPTABLES_HAVE_READ
386 plugin_register (MODULE_NAME, NULL, iptables_read, NULL);
387 cf_register (MODULE_NAME, iptables_config, config_keys, config_keys_num);
395 * vim:shiftwidth=4:softtabstop=4:tabstop=8