iptables plugin: Adds a plugin to collect iptables'-counters.
[collectd.git] / src / iptables.c
1 /**
2  * collectd - src/iptables.c
3  * Copyright (C) 2007 Sjoerd van der Berg
4  *
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.
9  *
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.
14  *
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
18  *
19  * Authors:
20  *  Sjoerd van der Berg <harekiet at users.sourceforge.net>
21  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26 #include "configfile.h"
27 #include "libiptc/libiptc.h"
28
29 #define MODULE_NAME "iptables"
30 #define BUFSIZE 512
31
32 /*
33  * (Module-)Global variables
34  */
35
36 /*
37     Files will go into iptables-chain/comment.rrd files
38 */
39 static char *file_template   = "iptables-%s.rrd";
40 /*
41     Config format should be Chain table chainname 
42     So "Chain mangle incoming"
43 */
44 static char *config_keys[] =
45 {
46         "Chain",
47         NULL
48 };
49 static int config_keys_num = 1;
50 /*
51     Removed packet count for now, should have config option if you want to save them
52     Although other collectd models don't seem to care much for options eitherway for what to log
53 */
54 static char *ds_def[] =
55 {
56 //      "DS:packets:COUNTER:"COLLECTD_HEARTBEAT":0:U",
57         "DS:bytes:DERIVE:"COLLECTD_HEARTBEAT":0:U",
58         NULL
59 };
60 static int ds_num = 1;
61
62 /*
63     Each table/chain combo that will be queried goes into this list
64 */
65 typedef struct {
66     char table[16];
67     char name[32];
68 } ip_chain_t;
69
70 static ip_chain_t **chain_list = NULL;
71 static int chain_num = 0;
72
73 static int iptables_config (char *key, char *value)
74 {
75         if (strcasecmp (key, "Chain") == 0)
76         {
77                 ip_chain_t temp, *final, **list;
78                 char *chain;
79                 int tLen;
80                 
81                 memset( &temp, 0, sizeof( temp ));
82         
83                 /* simple parsing, only allow a space... */
84                 chain = rindex(value, ' ' );
85                 if (!chain) 
86                 {
87                         syslog (LOG_EMERG, "missing chain." );
88                         return (1);
89                 }
90                 tLen = (int)(chain - value);
91                 if ( tLen > sizeof( temp.table ))
92                 {
93                         syslog (LOG_EMERG, "table too long." );
94                         return (1);
95                 }
96                 memcpy( temp.table, value, tLen );
97                 temp.table[tLen] = 0; 
98                 chain++;
99                 strncpy( temp.name, chain, sizeof( temp.name ));
100                         
101                 list = (ip_chain_t **) realloc (chain_list, (chain_num + 1) * sizeof (ip_chain_t *));
102                 if ( list == NULL )
103                 {
104                         syslog (LOG_EMERG, "Cannot allocate more memory.");
105                         return (1);
106                 }
107                 chain_list = list;
108                 final = (ip_chain_t *) malloc( sizeof(temp) );
109                 if (final == NULL) 
110                 {
111                         syslog (LOG_EMERG, "Cannot allocate memory.");
112                         return (1);
113                 }
114                 *final = temp;
115                 chain_list[chain_num++] = final;
116         } else 
117         {
118                 return (-1);
119         }
120
121         return (0);
122 }
123
124 static void iptables_init (void)
125 {       
126     return;
127 }
128
129 static void iptables_write (char *host, char *inst, char *val) 
130 {
131         char file[BUFSIZE];
132         int status;
133
134         status = snprintf (file, BUFSIZE, file_template, inst);
135         if (status < 1)
136                 return;
137         else if (status >= BUFSIZE)
138                 return;
139
140         rrd_update_file (host, file, val, ds_def, ds_num);
141 }
142
143
144 static int submit_match( const struct ipt_entry_match *match, const struct ipt_entry *entry, const ip_chain_t *chain ) 
145 {
146     char name[BUFSIZE];
147     char buf[BUFSIZE];
148     int status;
149
150     /* Only log rules that have a comment, although could probably also do numerical targets sometime */
151     if ( strcmp( match->u.user.name, "comment" ) )
152         return 0;
153
154 /*
155     This would also add the table name to the name, but seems a bit overkill
156     status = snprintf (name, BUFSIZE, "%s-%s/%s",
157         table->table, table->chain, match->data );
158 */
159     status = snprintf (name, BUFSIZE, "%s/%s", chain->name, match->data );
160
161     if ((status >= BUFSIZE) || (status < 1))
162         return 0;
163
164     status = snprintf (buf, BUFSIZE, "%u:%lld",// ":lld",
165                                 (unsigned int) curtime,
166 //                              entry->counters.pcnt,
167                                  entry->counters.bcnt );
168     if ((status >= BUFSIZE) || (status < 1))
169         return 0;
170
171     plugin_submit (MODULE_NAME, name, buf);
172
173     return 0;
174 }
175
176 static void submit_chain( iptc_handle_t *handle, ip_chain_t *chain ) {
177     const struct ipt_entry *entry;
178
179     /* Find first rule for chain and use the iterate macro */    
180     entry = iptc_first_rule( chain->name, handle );
181     while ( entry ) {
182         IPT_MATCH_ITERATE( entry, submit_match, entry, chain );
183         entry = iptc_next_rule( entry, handle );
184     }
185 }
186
187
188 static void iptables_read (void) {
189     int i;
190
191     /* Init the iptc handle structure and query the correct table */    
192     for( i = 0; i < chain_num; i++) {
193         iptc_handle_t handle;
194         ip_chain_t *chain;
195         
196         chain = chain_list[i];
197         if (!chain)
198             continue;
199         handle = iptc_init( chain->table );
200         if (!handle)
201             continue;
202         submit_chain( &handle, chain );
203         iptc_free( &handle );
204     }
205 }
206
207 void module_register (void)
208 {
209         plugin_register (MODULE_NAME, iptables_init, iptables_read, iptables_write);
210         cf_register (MODULE_NAME, iptables_config, config_keys, config_keys_num);
211 }
212
213 #undef BUFSIZE
214 #undef MODULE_NAME