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"
28 #if HAVE_LIBIPTC_LIBIPTC_H
29 # include <libiptc/libiptc.h>
32 #if HAVE_LIBIPTC_LIBIPTC_H
33 # define IPTABLES_HAVE_READ 1
35 # define IPTABLES_HAVE_READ 0
38 #define MODULE_NAME "iptables"
42 * (Module-)Global variables
46 * Files will go into iptables-chain/comment.rrd files
48 static char *file_template = "iptables-%s.rrd";
51 * Removed packet count for now, should have config option if you want to save
52 * them Although other collectd models don't seem to care much for options
53 * eitherway for what to log
55 static char *ds_def[] =
57 /* "DS:packets:COUNTER:"COLLECTD_HEARTBEAT":0:U", */
58 "DS:bytes:DERIVE:"COLLECTD_HEARTBEAT":0:U",
61 static int ds_num = 1;
63 #if IPTABLES_HAVE_READ
65 * Config format should be `Chain table chainname',
66 * e. g. `Chain mangle incoming'
68 static char *config_keys[] =
73 static int config_keys_num = 1;
75 Each table/chain combo that will be queried goes into this list
82 static ip_chain_t **chain_list = NULL;
83 static int chain_num = 0;
85 static int iptables_config (char *key, char *value)
87 if (strcasecmp (key, "Chain") == 0)
89 ip_chain_t temp, *final, **list;
93 memset( &temp, 0, sizeof( temp ));
95 /* simple parsing, only allow a space... */
96 chain = rindex(value, ' ' );
99 syslog (LOG_EMERG, "missing chain." );
102 tLen = (int)(chain - value);
103 if ( tLen > sizeof( temp.table ))
105 syslog (LOG_EMERG, "table too long." );
108 memcpy( temp.table, value, tLen );
109 temp.table[tLen] = 0;
111 strncpy( temp.name, chain, sizeof( temp.name ));
113 list = (ip_chain_t **) realloc (chain_list, (chain_num + 1) * sizeof (ip_chain_t *));
116 syslog (LOG_EMERG, "Cannot allocate more memory.");
120 final = (ip_chain_t *) malloc( sizeof(temp) );
123 syslog (LOG_EMERG, "Cannot allocate memory.");
127 chain_list[chain_num++] = final;
135 #endif /* IPTABLES_HAVE_READ */
137 static void iptables_init (void)
142 static void iptables_write (char *host, char *inst, char *val)
147 status = snprintf (file, BUFSIZE, file_template, inst);
150 else if (status >= BUFSIZE)
153 rrd_update_file (host, file, val, ds_def, ds_num);
156 #if IPTABLES_HAVE_READ
157 static int submit_match (const struct ipt_entry_match *match,
158 const struct ipt_entry *entry, const ip_chain_t *chain)
164 /* Only log rules that have a comment, although could probably also do numerical targets sometime */
165 if ( strcmp( match->u.user.name, "comment" ) )
169 This would also add the table name to the name, but seems a bit overkill
170 status = snprintf (name, BUFSIZE, "%s-%s/%s",
171 table->table, table->chain, match->data );
173 status = snprintf (name, BUFSIZE, "%s/%s", chain->name, match->data );
175 if ((status >= BUFSIZE) || (status < 1))
178 status = snprintf (buf, BUFSIZE, "%u:%lld", /* ":lld", */
179 (unsigned int) curtime,
180 /* entry->counters.pcnt, */
181 entry->counters.bcnt );
182 if ((status >= BUFSIZE) || (status < 1))
185 plugin_submit (MODULE_NAME, name, buf);
188 } /* int submit_match */
190 static void submit_chain( iptc_handle_t *handle, ip_chain_t *chain ) {
191 const struct ipt_entry *entry;
193 /* Find first rule for chain and use the iterate macro */
194 entry = iptc_first_rule( chain->name, handle );
196 IPT_MATCH_ITERATE( entry, submit_match, entry, chain );
197 entry = iptc_next_rule( entry, handle );
202 static void iptables_read (void) {
205 /* Init the iptc handle structure and query the correct table */
206 for( i = 0; i < chain_num; i++) {
207 iptc_handle_t handle;
210 chain = chain_list[i];
213 handle = iptc_init( chain->table );
216 submit_chain( &handle, chain );
217 iptc_free( &handle );
220 #else /* !IPTABLES_HAVE_READ */
221 # define iptables_read NULL
224 void module_register (void)
226 plugin_register (MODULE_NAME, iptables_init, iptables_read, iptables_write);
227 #if IPTABLES_HAVE_READ
228 cf_register (MODULE_NAME, iptables_config, config_keys, config_keys_num);
236 * vim:shiftwidth=4:softtabstop=4:tabstop=8