a8cdb3a404ad5155dca1a5e8fd6f333b9379afa0
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"
27 #include "libiptc/libiptc.h"
29 #define MODULE_NAME "iptables"
30 #define BUFSIZE 512
32 /*
33 * (Module-)Global variables
34 */
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;
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;
70 static ip_chain_t **chain_list = NULL;
71 static int chain_num = 0;
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;
81 memset( &temp, 0, sizeof( temp ));
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 ));
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 }
121 return (0);
122 }
124 static void iptables_init (void)
125 {
126 return;
127 }
129 static void iptables_write (char *host, char *inst, char *val)
130 {
131 char file[BUFSIZE];
132 int status;
134 status = snprintf (file, BUFSIZE, file_template, inst);
135 if (status < 1)
136 return;
137 else if (status >= BUFSIZE)
138 return;
140 rrd_update_file (host, file, val, ds_def, ds_num);
141 }
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;
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;
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 );
161 if ((status >= BUFSIZE) || (status < 1))
162 return 0;
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;
171 plugin_submit (MODULE_NAME, name, buf);
173 return 0;
174 }
176 static void submit_chain( iptc_handle_t *handle, ip_chain_t *chain ) {
177 const struct ipt_entry *entry;
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 }
188 static void iptables_read (void) {
189 int i;
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;
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 }
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 }
213 #undef BUFSIZE
214 #undef MODULE_NAME