6938848f238df9f4d48612961ff3698a4a9090de
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 **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26 #include "configfile.h"
28 #if HAVE_LIBIPTC_LIBIPTC_H
29 # include <libiptc/libiptc.h>
30 #endif
32 #if HAVE_LIBIPTC_LIBIPTC_H
33 # define IPTABLES_HAVE_READ 1
34 #else
35 # define IPTABLES_HAVE_READ 0
36 #endif
38 #define MODULE_NAME "iptables"
39 #define BUFSIZE 512
41 /*
42 * (Module-)Global variables
43 */
45 /*
46 * Files will go into iptables-chain/comment.rrd files
47 */
48 static char *file_template = "iptables-%s.rrd";
50 /*
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
54 */
55 static char *ds_def[] =
56 {
57 /* "DS:packets:COUNTER:"COLLECTD_HEARTBEAT":0:U", */
58 "DS:bytes:DERIVE:"COLLECTD_HEARTBEAT":0:U",
59 NULL
60 };
61 static int ds_num = 1;
63 #if IPTABLES_HAVE_READ
64 /*
65 * Config format should be `Chain table chainname',
66 * e. g. `Chain mangle incoming'
67 */
68 static char *config_keys[] =
69 {
70 "Chain",
71 NULL
72 };
73 static int config_keys_num = 1;
74 /*
75 Each table/chain combo that will be queried goes into this list
76 */
77 typedef struct {
78 char table[16];
79 char name[32];
80 } ip_chain_t;
82 static ip_chain_t **chain_list = NULL;
83 static int chain_num = 0;
85 static int iptables_config (char *key, char *value)
86 {
87 if (strcasecmp (key, "Chain") == 0)
88 {
89 ip_chain_t temp, *final, **list;
90 char *chain;
91 int tLen;
93 memset( &temp, 0, sizeof( temp ));
95 /* simple parsing, only allow a space... */
96 chain = rindex(value, ' ' );
97 if (!chain)
98 {
99 syslog (LOG_EMERG, "missing chain." );
100 return (1);
101 }
102 tLen = (int)(chain - value);
103 if ( tLen > sizeof( temp.table ))
104 {
105 syslog (LOG_EMERG, "table too long." );
106 return (1);
107 }
108 memcpy( temp.table, value, tLen );
109 temp.table[tLen] = 0;
110 chain++;
111 strncpy( temp.name, chain, sizeof( temp.name ));
113 list = (ip_chain_t **) realloc (chain_list, (chain_num + 1) * sizeof (ip_chain_t *));
114 if ( list == NULL )
115 {
116 syslog (LOG_EMERG, "Cannot allocate more memory.");
117 return (1);
118 }
119 chain_list = list;
120 final = (ip_chain_t *) malloc( sizeof(temp) );
121 if (final == NULL)
122 {
123 syslog (LOG_EMERG, "Cannot allocate memory.");
124 return (1);
125 }
126 *final = temp;
127 chain_list[chain_num++] = final;
128 } else
129 {
130 return (-1);
131 }
133 return (0);
134 }
135 #endif /* IPTABLES_HAVE_READ */
137 static void iptables_init (void)
138 {
139 return;
140 }
142 static void iptables_write (char *host, char *inst, char *val)
143 {
144 char file[BUFSIZE];
145 int status;
147 status = snprintf (file, BUFSIZE, file_template, inst);
148 if (status < 1)
149 return;
150 else if (status >= BUFSIZE)
151 return;
153 rrd_update_file (host, file, val, ds_def, ds_num);
154 }
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)
159 {
160 char name[BUFSIZE];
161 char buf[BUFSIZE];
162 int status;
164 /* Only log rules that have a comment, although could probably also do numerical targets sometime */
165 if ( strcmp( match->u.user.name, "comment" ) )
166 return 0;
168 /*
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 );
172 */
173 status = snprintf (name, BUFSIZE, "%s/%s", chain->name, match->data );
175 if ((status >= BUFSIZE) || (status < 1))
176 return 0;
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))
183 return 0;
185 plugin_submit (MODULE_NAME, name, buf);
187 return 0;
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 );
195 while ( entry ) {
196 IPT_MATCH_ITERATE( entry, submit_match, entry, chain );
197 entry = iptc_next_rule( entry, handle );
198 }
199 }
202 static void iptables_read (void) {
203 int i;
205 /* Init the iptc handle structure and query the correct table */
206 for( i = 0; i < chain_num; i++) {
207 iptc_handle_t handle;
208 ip_chain_t *chain;
210 chain = chain_list[i];
211 if (!chain)
212 continue;
213 handle = iptc_init( chain->table );
214 if (!handle)
215 continue;
216 submit_chain( &handle, chain );
217 iptc_free( &handle );
218 }
219 }
220 #else /* !IPTABLES_HAVE_READ */
221 # define iptables_read NULL
222 #endif
224 void module_register (void)
225 {
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);
229 #endif
230 }
232 #undef BUFSIZE
233 #undef MODULE_NAME
235 /*
236 * vim:shiftwidth=4:softtabstop=4:tabstop=8
237 */