1
|
diff -rNu ./src/Makefile.am ./src.new/Makefile.am
|
2
|
--- ./src/Makefile.am 2013-09-24 06:28:37.000000000 -0400
|
3
|
+++ ./src.new/Makefile.am 2014-04-18 16:36:04.000000000 -0400
|
4
|
@@ -10,6 +10,7 @@
|
5
|
alert-debuglog.c alert-debuglog.h \
|
6
|
alert-fastlog.c alert-fastlog.h \
|
7
|
alert-pcapinfo.c alert-pcapinfo.h \
|
8
|
+alert-pf.c alert-pf.h \
|
9
|
alert-prelude.c alert-prelude.h \
|
10
|
alert-syslog.c alert-syslog.h \
|
11
|
alert-unified2-alert.c alert-unified2-alert.h \
|
12
|
diff -rNu ./src/Makefile.in ./src.new/Makefile.in
|
13
|
--- ./src/Makefile.in 2013-09-24 06:28:49.000000000 -0400
|
14
|
+++ ./src.new/Makefile.in 2014-04-18 16:38:02.000000000 -0400
|
15
|
@@ -73,7 +73,7 @@
|
16
|
PROGRAMS = $(bin_PROGRAMS)
|
17
|
am__suricata_SOURCES_DIST = alert-debuglog.c alert-debuglog.h \
|
18
|
alert-fastlog.c alert-fastlog.h alert-pcapinfo.c \
|
19
|
- alert-pcapinfo.h alert-prelude.c alert-prelude.h \
|
20
|
+ alert-pcapinfo.h alert-pf.c alert-pf.h alert-prelude.c alert-prelude.h \
|
21
|
alert-syslog.c alert-syslog.h alert-unified2-alert.c \
|
22
|
alert-unified2-alert.h app-layer.c app-layer.h \
|
23
|
app-layer-dcerpc.c app-layer-dcerpc.h app-layer-dcerpc-udp.c \
|
24
|
@@ -274,7 +274,7 @@
|
25
|
cuda-ptxdump.h
|
26
|
am__objects_1 =
|
27
|
am_suricata_OBJECTS = alert-debuglog.$(OBJEXT) alert-fastlog.$(OBJEXT) \
|
28
|
- alert-pcapinfo.$(OBJEXT) alert-prelude.$(OBJEXT) \
|
29
|
+ alert-pcapinfo.$(OBJEXT) alert-pf.$(OBJEXT) alert-prelude.$(OBJEXT) \
|
30
|
alert-syslog.$(OBJEXT) alert-unified2-alert.$(OBJEXT) \
|
31
|
app-layer.$(OBJEXT) app-layer-dcerpc.$(OBJEXT) \
|
32
|
app-layer-dcerpc-udp.$(OBJEXT) \
|
33
|
@@ -621,6 +621,7 @@
|
34
|
|
35
|
suricata_SOURCES = alert-debuglog.c alert-debuglog.h alert-fastlog.c \
|
36
|
alert-fastlog.h alert-pcapinfo.c alert-pcapinfo.h \
|
37
|
+ alert-pf.c alert-pf.h \
|
38
|
alert-prelude.c alert-prelude.h alert-syslog.c alert-syslog.h \
|
39
|
alert-unified2-alert.c alert-unified2-alert.h app-layer.c \
|
40
|
app-layer.h app-layer-dcerpc.c app-layer-dcerpc.h \
|
41
|
@@ -947,6 +948,7 @@
|
42
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-debuglog.Po@am__quote@
|
43
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-fastlog.Po@am__quote@
|
44
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-pcapinfo.Po@am__quote@
|
45
|
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-pf.Po@am__quote@
|
46
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-prelude.Po@am__quote@
|
47
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-syslog.Po@am__quote@
|
48
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert-unified2-alert.Po@am__quote@
|
49
|
diff -rNu ./src/alert-pf.c ./src.new/alert-pf.c
|
50
|
--- ./src/alert-pf.c 1969-12-31 19:00:00.000000000 -0500
|
51
|
+++ ./src.new/alert-pf.c 2014-04-30 20:20:08.000000000 -0400
|
52
|
@@ -0,0 +1,835 @@
|
53
|
+/* Copyright (C) 2007-2014 Open Information Security Foundation
|
54
|
+ *
|
55
|
+ * You can copy, redistribute or modify this Program under the terms of
|
56
|
+ * the GNU General Public License version 2 as published by the Free
|
57
|
+ * Software Foundation.
|
58
|
+ *
|
59
|
+ * This program is distributed in the hope that it will be useful,
|
60
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
61
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
62
|
+ * GNU General Public License for more details.
|
63
|
+ *
|
64
|
+ * You should have received a copy of the GNU General Public License
|
65
|
+ * version 2 along with this program; if not, write to the Free Software
|
66
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
67
|
+ * 02110-1301, USA.
|
68
|
+ *
|
69
|
+ * Portions of this module are based on previous works of the following:
|
70
|
+ *
|
71
|
+ * Copyright (c) 2012 Ermal Lu?i
|
72
|
+ * Copyright (c) 2006 Antonio Benojar <zz.stalker@gmail.com>
|
73
|
+ * Copyright (c) 2005 Antonio Benojar <zz.stalker@gmail.com>
|
74
|
+ *
|
75
|
+ * Copyright (c) 2003, 2004 Armin Wolfermann:
|
76
|
+ *
|
77
|
+ * The AlertPfBlock() function is based
|
78
|
+ * on Armin's Wolfermann pftabled-1.03 functions.
|
79
|
+ *
|
80
|
+ * All rights reserved.
|
81
|
+ *
|
82
|
+ * Redistribution and use in source and binary forms, with or without
|
83
|
+ * modification, are permitted provided that the following conditions
|
84
|
+ * are met:
|
85
|
+ *
|
86
|
+ * 1. Redistributions of source code must retain the above copyright
|
87
|
+ * notice, this list of conditions and the following disclaimer.
|
88
|
+ *
|
89
|
+ * 2. Redistributions in binary form must reproduce the above copyright
|
90
|
+ * notice, this list of conditions and the following disclaimer in the
|
91
|
+ * documentation and/or other materials provided with the distribution.
|
92
|
+ *
|
93
|
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
|
94
|
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
95
|
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
96
|
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
97
|
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
98
|
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
99
|
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
100
|
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
101
|
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
102
|
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
103
|
+ */
|
104
|
+
|
105
|
+/**
|
106
|
+ * \file
|
107
|
+ *
|
108
|
+ * \author Bill Meeks <bill@themeeks.net>
|
109
|
+ *
|
110
|
+ * Inserts blocks for IP alerts into the pf firewall used in NetBSD and FreeBSD,
|
111
|
+ * and logs the event, including the IP address, in "block.log".
|
112
|
+ *
|
113
|
+ * # alert_pf blocking plugin
|
114
|
+ * - alert-pf:
|
115
|
+ * enabled: yes/no # "yes" to enable blocking plugin
|
116
|
+ * kill-state: yes/no # "yes" to kill open state table entries associated with blocked IP addresses (default is YES)
|
117
|
+ * pass-list: <filename> # complete path and filename for txt file of single IP addresses or CIDR networks that should never be blocked
|
118
|
+ * block-ip: src/dst/both # which IP in packet to block (default is BOTH)
|
119
|
+ * pf-table: <pf table name> # name of packet filter firewall table where block IP addresses should be added. This table must exist!
|
120
|
+ *
|
121
|
+ */
|
122
|
+
|
123
|
+#include "suricata-common.h"
|
124
|
+#include "conf.h"
|
125
|
+#include "output.h"
|
126
|
+#include "threads.h"
|
127
|
+#include "tm-threads.h"
|
128
|
+#include "threadvars.h"
|
129
|
+
|
130
|
+#include "alert-pf.h"
|
131
|
+
|
132
|
+#include "util-atomic.h"
|
133
|
+#include "util-debug.h"
|
134
|
+#include "util-logopenfile.h"
|
135
|
+#include "util-print.h"
|
136
|
+#include "util-proto-name.h"
|
137
|
+#include "util-radix-tree.h"
|
138
|
+
|
139
|
+#include <sys/types.h>
|
140
|
+#include <sys/ioctl.h>
|
141
|
+#include <sys/socket.h>
|
142
|
+#include <sys/stat.h>
|
143
|
+#include <ctype.h>
|
144
|
+#include <net/if.h>
|
145
|
+#include <net/pfvar.h>
|
146
|
+#include <err.h>
|
147
|
+#include <unistd.h>
|
148
|
+#include <regex.h>
|
149
|
+
|
150
|
+#define PFDEVICE "/dev/pf"
|
151
|
+#define WLMAX 1024
|
152
|
+#define MODULE_NAME "AlertPf"
|
153
|
+#define DEFAULT_LOG_FILENAME "block.log"
|
154
|
+
|
155
|
+enum spblock { BLOCK_SRC, BLOCK_DST, BLOCK_BOTH };
|
156
|
+
|
157
|
+TmEcode AlertPf (ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
|
158
|
+TmEcode AlertPfIPv4(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
|
159
|
+TmEcode AlertPfIPv6(ThreadVars *, Packet *, void *, PacketQueue *, PacketQueue *);
|
160
|
+TmEcode AlertPfThreadInit(ThreadVars *, void *, void **);
|
161
|
+TmEcode AlertPfThreadDeinit(ThreadVars *, void *);
|
162
|
+void AlertPfExitPrintStats(ThreadVars *, void *);
|
163
|
+static void AlertPfDeInitCtx(OutputCtx *);
|
164
|
+
|
165
|
+void TmModuleAlertPfRegister (void) {
|
166
|
+ tmm_modules[TMM_ALERTPF].name = MODULE_NAME;
|
167
|
+ tmm_modules[TMM_ALERTPF].ThreadInit = AlertPfThreadInit;
|
168
|
+ tmm_modules[TMM_ALERTPF].Func = AlertPf;
|
169
|
+ tmm_modules[TMM_ALERTPF].ThreadExitPrintStats = AlertPfExitPrintStats;
|
170
|
+ tmm_modules[TMM_ALERTPF].ThreadDeinit = AlertPfThreadDeinit;
|
171
|
+ tmm_modules[TMM_ALERTPF].RegisterTests = NULL;
|
172
|
+ tmm_modules[TMM_ALERTPF].cap_flags = 0;
|
173
|
+
|
174
|
+ OutputRegisterModule(MODULE_NAME, "alert-pf", AlertPfInitCtx);
|
175
|
+}
|
176
|
+
|
177
|
+void TmModuleAlertPfIPv4Register (void) {
|
178
|
+ tmm_modules[TMM_ALERTPF4].name = "AlertPfIPv4";
|
179
|
+ tmm_modules[TMM_ALERTPF4].ThreadInit = AlertPfThreadInit;
|
180
|
+ tmm_modules[TMM_ALERTPF4].Func = AlertPfIPv4;
|
181
|
+ tmm_modules[TMM_ALERTPF4].ThreadExitPrintStats = AlertPfExitPrintStats;
|
182
|
+ tmm_modules[TMM_ALERTPF4].ThreadDeinit = AlertPfThreadDeinit;
|
183
|
+ tmm_modules[TMM_ALERTPF4].RegisterTests = NULL;
|
184
|
+}
|
185
|
+
|
186
|
+void TmModuleAlertPfIPv6Register (void) {
|
187
|
+ tmm_modules[TMM_ALERTPF6].name = "AlertPfIPv6";
|
188
|
+ tmm_modules[TMM_ALERTPF6].ThreadInit = AlertPfThreadInit;
|
189
|
+ tmm_modules[TMM_ALERTPF6].Func = AlertPfIPv6;
|
190
|
+ tmm_modules[TMM_ALERTPF6].ThreadExitPrintStats = AlertPfExitPrintStats;
|
191
|
+ tmm_modules[TMM_ALERTPF6].ThreadDeinit = AlertPfThreadDeinit;
|
192
|
+ tmm_modules[TMM_ALERTPF6].RegisterTests = NULL;
|
193
|
+}
|
194
|
+
|
195
|
+/**
|
196
|
+ * This holds global structures and variables.
|
197
|
+ * Each thread gets a pointer to this data.
|
198
|
+ */
|
199
|
+typedef struct _AlertPfCtx_ {
|
200
|
+ char *pftable;
|
201
|
+ int kill_state;
|
202
|
+ enum spblock block_ip;
|
203
|
+ SCRadixTree *tree;
|
204
|
+ LogFileCtx* file_ctx;
|
205
|
+} AlertPfCtx;
|
206
|
+
|
207
|
+/**
|
208
|
+ * This holds per-thread specific structures and variables.
|
209
|
+ */
|
210
|
+typedef struct AlertPfThread_ {
|
211
|
+ AlertPfCtx* ctx; /* Pointer to the global context data */
|
212
|
+ int fd; /* pf device handle */
|
213
|
+} AlertPfThread;
|
214
|
+
|
215
|
+SC_ATOMIC_DECLARE(uint64_t, alert_pf_blocks); /**< Atomic counter, to hold block count */
|
216
|
+
|
217
|
+static int AlertPf_parse_line(char *, FILE *);
|
218
|
+static int AlertPfLoadPassList(char *, AlertPfCtx *);
|
219
|
+static int AlertPfDeviceInit(void);
|
220
|
+static int AlertPfTableExists(char *);
|
221
|
+static int AlertPfBlock(AlertPfThread *, Address *net_addr);
|
222
|
+
|
223
|
+/** \brief Print and format a UNIX timestamp into supplied buffer
|
224
|
+ * \param *ts pointer to a timeval structure
|
225
|
+ * \param *str pointer to a buffer to hold output string
|
226
|
+ * \param size size of output string buffer
|
227
|
+ * \retval None */
|
228
|
+static void CreateTimeString (const struct timeval *ts, char *str, size_t size) {
|
229
|
+ time_t time = ts->tv_sec;
|
230
|
+ struct tm local_tm;
|
231
|
+ struct tm *t = (struct tm *)SCLocalTime(time, &local_tm);
|
232
|
+
|
233
|
+ snprintf(str, size, "%02d/%02d/%02d-%02d:%02d:%02d.%06u",
|
234
|
+ t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour,
|
235
|
+ t->tm_min, t->tm_sec, (uint32_t) ts->tv_usec);
|
236
|
+}
|
237
|
+
|
238
|
+/**
|
239
|
+ * This opens the pf device and returns a file descriptor.
|
240
|
+ */
|
241
|
+static int AlertPfDeviceInit(void)
|
242
|
+{
|
243
|
+ return(open(PFDEVICE, O_RDWR));
|
244
|
+}
|
245
|
+
|
246
|
+/** \brief Verifies the supplied pf table exists
|
247
|
+ * \param *tablename pointer to pf table name string
|
248
|
+ * \retval -1 on error, 1 if table exists or 0 if not */
|
249
|
+static int AlertPfTableExists(char *tablename)
|
250
|
+{
|
251
|
+ int i;
|
252
|
+ int dev;
|
253
|
+ struct pfioc_table io;
|
254
|
+ struct pfr_table *table_aux = NULL;
|
255
|
+
|
256
|
+ memset(&io, 0x00, sizeof(struct pfioc_table));
|
257
|
+
|
258
|
+ io.pfrio_buffer = table_aux;
|
259
|
+ io.pfrio_esize = sizeof(struct pfr_table);
|
260
|
+ io.pfrio_size = 0;
|
261
|
+
|
262
|
+ dev = AlertPfDeviceInit();
|
263
|
+ if (dev == -1) {
|
264
|
+ SCLogError(SC_ERR_SYSCALL, "Failed to open pf device.");
|
265
|
+ return -1;
|
266
|
+ }
|
267
|
+
|
268
|
+ if(ioctl(dev, DIOCRGETTABLES, &io)) {
|
269
|
+ SCLogError(SC_ERR_SYSCALL, "AlertPfTableExists() => ioctl() DIOCRGETTABLES: %s\n", strerror(errno));
|
270
|
+ return -1;
|
271
|
+ }
|
272
|
+
|
273
|
+ table_aux = (struct pfr_table*)malloc(sizeof(struct pfr_table)*io.pfrio_size);
|
274
|
+
|
275
|
+ if (table_aux == NULL) {
|
276
|
+ SCLogError(SC_ERR_SYSCALL, "AlertPfTableExists() => malloc(): %s\n", strerror(errno));
|
277
|
+ return -1;
|
278
|
+ }
|
279
|
+
|
280
|
+ io.pfrio_buffer = table_aux;
|
281
|
+ io.pfrio_esize = sizeof(struct pfr_table);
|
282
|
+
|
283
|
+ if(ioctl(dev, DIOCRGETTABLES, &io)) {
|
284
|
+ SCLogError(SC_ERR_SYSCALL, "AlertPfTableExists() => ioctl() DIOCRGETTABLES: %s\n", strerror(errno));
|
285
|
+ return -1;
|
286
|
+ }
|
287
|
+
|
288
|
+ for(i=0; i < io.pfrio_size; i++) {
|
289
|
+ if (!strcmp(table_aux[i].pfrt_name, tablename))
|
290
|
+ return 1;
|
291
|
+ }
|
292
|
+
|
293
|
+ return 0;
|
294
|
+}
|
295
|
+
|
296
|
+/** \brief Inserts the passed IP address into the pf block table
|
297
|
+ * \param *data pointer to AlertPfThread structure for current thread
|
298
|
+ * \param *net_addr pointer to IP address to block
|
299
|
+ * \retval -1 on error, 1 if IP blocked, 0 if already blocked */
|
300
|
+static int AlertPfBlock(AlertPfThread *data, Address *net_addr)
|
301
|
+{
|
302
|
+ struct pfioc_table io;
|
303
|
+ struct pfr_table table;
|
304
|
+ struct pfr_addr addr;
|
305
|
+
|
306
|
+ if (data->fd < 0)
|
307
|
+ data->fd = AlertPfDeviceInit();
|
308
|
+ if (data->fd == -1) {
|
309
|
+ SCLogError(SC_ERR_SYSCALL, "AlertPfDeviceInit() => no pf device\n");
|
310
|
+ return -1;
|
311
|
+ }
|
312
|
+
|
313
|
+ memset(&io, 0x00, sizeof(struct pfioc_table));
|
314
|
+ memset(&table, 0x00, sizeof(struct pfr_table));
|
315
|
+ memset(&addr, 0x00, sizeof(struct pfr_addr));
|
316
|
+
|
317
|
+ strlcpy(table.pfrt_name, data->ctx->pftable, PF_TABLE_NAME_SIZE);
|
318
|
+
|
319
|
+ net_addr->family == AF_INET ? memcpy(&addr.pfra_ip4addr.s_addr, net_addr->addr_data32, sizeof(in_addr_t)) : memcpy(&addr.pfra_ip6addr, net_addr->addr_data8, sizeof(struct in6_addr));
|
320
|
+
|
321
|
+ addr.pfra_af = net_addr->family;
|
322
|
+ addr.pfra_net = net_addr->family == AF_INET ? 32 : 128;
|
323
|
+
|
324
|
+ io.pfrio_table = table;
|
325
|
+ io.pfrio_buffer = &addr;
|
326
|
+ io.pfrio_esize = sizeof(addr);
|
327
|
+ io.pfrio_size = 1;
|
328
|
+
|
329
|
+ if (ioctl(data->fd, DIOCRADDADDRS, &io)) {
|
330
|
+ SCLogError(SC_ERR_SYSCALL, "AlertPfBlock() => ioctl() DIOCRADDADDRS: %s\n", strerror(errno));
|
331
|
+ return (-1);
|
332
|
+ }
|
333
|
+
|
334
|
+ if (io.pfrio_nadd > 0) {
|
335
|
+ SC_ATOMIC_ADD(alert_pf_blocks, 1);
|
336
|
+ }
|
337
|
+
|
338
|
+ if (data->ctx->kill_state) {
|
339
|
+ struct pfioc_state_kill psk;
|
340
|
+
|
341
|
+ memset(&psk, 0, sizeof(psk));
|
342
|
+ memset(&psk.psk_src.addr.v.a.mask, 0xff, sizeof(psk.psk_src.addr.v.a.mask));
|
343
|
+ psk.psk_af = net_addr->family;
|
344
|
+ if (psk.psk_af == AF_INET)
|
345
|
+ memcpy(&psk.psk_src.addr.v.a.addr.v4.s_addr, net_addr->addr_data32, sizeof(in_addr_t));
|
346
|
+ else if (psk.psk_af == AF_INET6)
|
347
|
+ memcpy(&psk.psk_src.addr.v.a.addr.v6, net_addr->addr_data8, sizeof(struct in6_addr));
|
348
|
+ else {
|
349
|
+ SCLogError(SC_ERR_UNKNOWN_VALUE, "AlertPfBlock() unknown address family type: %d for source IP.", psk.psk_af);
|
350
|
+ return (-1);
|
351
|
+ }
|
352
|
+
|
353
|
+ /* Attempt to clear any open states for source IP */
|
354
|
+ if (ioctl(data->fd, DIOCKILLSTATES, &psk))
|
355
|
+ SCLogError(SC_ERR_SYSCALL, "AlertPfBlock() => ioctl() DIOCKILLSTATES: %s\n", strerror(errno));
|
356
|
+
|
357
|
+ memset(&psk, 0, sizeof(psk));
|
358
|
+ memset(&psk.psk_dst.addr.v.a.mask, 0xff, sizeof(psk.psk_dst.addr.v.a.mask));
|
359
|
+ psk.psk_af = net_addr->family;
|
360
|
+ if (psk.psk_af == AF_INET)
|
361
|
+ memcpy(&psk.psk_dst.addr.v.a.addr.v4.s_addr, net_addr->addr_data32, sizeof(in_addr_t));
|
362
|
+ else if (psk.psk_af == AF_INET6)
|
363
|
+ memcpy(&psk.psk_dst.addr.v.a.addr.v6, net_addr->addr_data8, sizeof(struct in6_addr));
|
364
|
+ else {
|
365
|
+ SCLogError(SC_ERR_UNKNOWN_VALUE, "AlertPfBlock() unknown address family type: %d for destination IP.", psk.psk_af);
|
366
|
+ return (-1);
|
367
|
+ }
|
368
|
+
|
369
|
+ /* Attempt to clear any open states for destination IP */
|
370
|
+ if (ioctl(data->fd, DIOCKILLSTATES, &psk))
|
371
|
+ SCLogError(SC_ERR_SYSCALL, "AlertPfBlock() => ioctl() DIOCKILLSTATES: %s\n", strerror(errno));
|
372
|
+ }
|
373
|
+
|
374
|
+ /* Return the number of effective IP blocks inserted */
|
375
|
+ return (io.pfrio_nadd);
|
376
|
+}
|
377
|
+
|
378
|
+/** \brief Load and parse a single line of text from Pass List file
|
379
|
+ * \param buf buffer of length WLMAX to receive a line of text from Pass List file
|
380
|
+ * \param *wfile FILE pointer to open Pass List text file
|
381
|
+ * \retval buf[] filled with next line of text from Pass List file
|
382
|
+ * \retval 0 on EOF, 1 if success or -1 if line exceed WLMAX length */
|
383
|
+static int AlertPf_parse_line(char buf[WLMAX], FILE* wfile)
|
384
|
+{
|
385
|
+ static char next_ch = '\n';
|
386
|
+ int i = 0;
|
387
|
+
|
388
|
+ if (feof(wfile))
|
389
|
+ return (0);
|
390
|
+
|
391
|
+ do {
|
392
|
+ next_ch = fgetc(wfile);
|
393
|
+ if (i < WLMAX)
|
394
|
+ buf[i++] = next_ch;
|
395
|
+ } while (!feof(wfile) && next_ch != '\n');
|
396
|
+
|
397
|
+ if (i >= WLMAX)
|
398
|
+ return (-1);
|
399
|
+
|
400
|
+ buf[--i] = '\0';
|
401
|
+ return (1);
|
402
|
+}
|
403
|
+
|
404
|
+/** \brief Load and parse a Pass List text file and insert
|
405
|
+ * the IP addresses and networks (in CIDR form) into a
|
406
|
+ * Radix Tree for easy searching.
|
407
|
+ * \param *plfile pointer to Pass List filename string
|
408
|
+ * \param *ctx pointer to AlertPfCtx global data structure
|
409
|
+ * \retval false (0) if error, true (-1) if success */
|
410
|
+static int AlertPfLoadPassList(char *plfile, AlertPfCtx *ctx)
|
411
|
+{
|
412
|
+ FILE *wfile;
|
413
|
+ struct flock lock;
|
414
|
+ char cad[WLMAX];
|
415
|
+ int ret;
|
416
|
+ int count = 0;
|
417
|
+
|
418
|
+ wfile = fopen(plfile, "r");
|
419
|
+ if (wfile == NULL) {
|
420
|
+ SCLogError(SC_ERR_FATAL, "Unable to open Pass List file: %s", strerror(errno));
|
421
|
+ return (0);
|
422
|
+ }
|
423
|
+
|
424
|
+ memset(&lock, 0x00, sizeof(struct flock));
|
425
|
+ lock.l_type = F_RDLCK;
|
426
|
+ fcntl(fileno(wfile), F_SETLKW, &lock);
|
427
|
+
|
428
|
+ ctx->tree = SCRadixCreateRadixTree(free, NULL);
|
429
|
+
|
430
|
+ memset(cad, 0, WLMAX);
|
431
|
+ while((ret = AlertPf_parse_line(cad, wfile)) != 0) {
|
432
|
+ if (ret == 1 && strlen(cad) > 0) {
|
433
|
+ /* is it an IPv6 address? */
|
434
|
+ if (strchr(cad, ':') != NULL) {
|
435
|
+ if (SCRadixAddKeyIPV6String(cad, ctx->tree, NULL) == NULL) {
|
436
|
+ SCLogInfo("Invalid IP(%s) parameter provided in Pass List, skipping...", cad);
|
437
|
+ continue;
|
438
|
+ }
|
439
|
+ count++;
|
440
|
+ }
|
441
|
+ else {
|
442
|
+ if (SCRadixAddKeyIPV4String(cad, ctx->tree, NULL) == NULL) {
|
443
|
+ SCLogInfo("Invalid IP(%s) parameter provided in Pass List, skipping...", cad);
|
444
|
+ continue;
|
445
|
+ }
|
446
|
+ count++;
|
447
|
+ }
|
448
|
+ } else if (ret == -1)
|
449
|
+ SCLogInfo("Error occurred parsing line(%s) in Pass List, skipping...", cad);
|
450
|
+ }
|
451
|
+
|
452
|
+ lock.l_type = F_UNLCK;
|
453
|
+ fcntl(fileno(wfile), F_SETLKW, &lock);
|
454
|
+ fclose(wfile);
|
455
|
+
|
456
|
+ if (count == 1)
|
457
|
+ SCLogInfo("Pass List %s parsed: %d IP address loaded.", plfile, count);
|
458
|
+ else
|
459
|
+ SCLogInfo("Pass List %s parsed: %d IP addresses loaded.", plfile, count);
|
460
|
+
|
461
|
+ return (-1);
|
462
|
+}
|
463
|
+
|
464
|
+/**
|
465
|
+ * This initializes the data for a new thread.
|
466
|
+ */
|
467
|
+TmEcode AlertPfThreadInit(ThreadVars *t, void *initdata, void **data)
|
468
|
+{
|
469
|
+ AlertPfThread *apft;
|
470
|
+
|
471
|
+ if(initdata == NULL)
|
472
|
+ {
|
473
|
+ SCLogDebug("Error getting context for Alert-PF. \"initdata\" argument NULL");
|
474
|
+ return TM_ECODE_FAILED;
|
475
|
+ }
|
476
|
+
|
477
|
+ apft = SCMalloc(sizeof(AlertPfThread));
|
478
|
+
|
479
|
+ if (unlikely(apft == NULL))
|
480
|
+ return TM_ECODE_FAILED;
|
481
|
+ memset(apft, 0, sizeof(AlertPfThread));
|
482
|
+
|
483
|
+ /* Use the Ouput Context */
|
484
|
+ apft->ctx = ((OutputCtx *)initdata)->data;
|
485
|
+
|
486
|
+ /* Open the pf device */
|
487
|
+ apft->fd = AlertPfDeviceInit();
|
488
|
+ if (apft->fd == -1) {
|
489
|
+ SCLogError(SC_ERR_SYSCALL, "Failed to open pf device, alert-pf module thread init failed.");
|
490
|
+ return TM_ECODE_FAILED;
|
491
|
+ }
|
492
|
+
|
493
|
+ *data = (void *)apft;
|
494
|
+ return TM_ECODE_OK;
|
495
|
+}
|
496
|
+
|
497
|
+/**
|
498
|
+ * This clears and releases the data for a thread.
|
499
|
+ */
|
500
|
+TmEcode AlertPfThreadDeinit(ThreadVars *t, void *data)
|
501
|
+{
|
502
|
+ AlertPfThread *apft = (AlertPfThread *)data;
|
503
|
+
|
504
|
+ if (apft == NULL) {
|
505
|
+ SCLogDebug("AlertPfThreadDeinit done (error)");
|
506
|
+ return TM_ECODE_FAILED;
|
507
|
+ }
|
508
|
+
|
509
|
+ /* Close the pf device */
|
510
|
+ close(apft->fd);
|
511
|
+
|
512
|
+ /* clear memory */
|
513
|
+ memset(apft, 0, sizeof(AlertPfThread));
|
514
|
+ SCFree(apft);
|
515
|
+
|
516
|
+ return TM_ECODE_OK;
|
517
|
+}
|
518
|
+
|
519
|
+/** \brief Print the pf alert module blocking stats.
|
520
|
+ * \param *tv pointer to ThreadVars structure
|
521
|
+ * \param *data pointer to AlertPfThread structure
|
522
|
+*/
|
523
|
+void AlertPfExitPrintStats(ThreadVars *tv, void *data)
|
524
|
+{
|
525
|
+ AlertPfThread *apft = (AlertPfThread *)data;
|
526
|
+ if (apft == NULL) {
|
527
|
+ return;
|
528
|
+ }
|
529
|
+
|
530
|
+ uint64_t alerts = SC_ATOMIC_GET(alert_pf_blocks);
|
531
|
+ if (alerts == 1)
|
532
|
+ SCLogInfo("alert-pf output inserted %" PRIu64 " IP address block", alerts);
|
533
|
+ else
|
534
|
+ SCLogInfo("alert-pf output inserted %" PRIu64 " IP address blocks", alerts);
|
535
|
+
|
536
|
+ if (apft->ctx->file_ctx->alerts == 1)
|
537
|
+ SCLogInfo("alert-pf output wrote %" PRIu64 " alerts", apft->ctx->file_ctx->alerts);
|
538
|
+ else
|
539
|
+ SCLogInfo("alert-pf output wrote %" PRIu64 " alerts", apft->ctx->file_ctx->alerts);
|
540
|
+
|
541
|
+ SC_ATOMIC_DESTROY(alert_pf_blocks);
|
542
|
+}
|
543
|
+
|
544
|
+/** \brief Initialize the pf alert blocking module.
|
545
|
+ * \param *conf pointer to module's ConfNode structure
|
546
|
+ * \return A newly allocated AlertPfCtx structure, or NULL
|
547
|
+ */
|
548
|
+OutputCtx *AlertPfInitCtx(ConfNode *conf)
|
549
|
+{
|
550
|
+ AlertPfCtx *ctx;
|
551
|
+ LogFileCtx *logfile_ctx;
|
552
|
+ const char *pass_list_name;
|
553
|
+ const char *kill_state;
|
554
|
+ const char *block_ip;
|
555
|
+ const char *pf_table;
|
556
|
+ OutputCtx *output_ctx;
|
557
|
+
|
558
|
+ pass_list_name = ConfNodeLookupChildValue(conf, "pass-list");
|
559
|
+ if (pass_list_name == NULL) {
|
560
|
+ SCLogWarning(SC_WARN_UNCOMMON, "alert-pf: No Pass List specified, critical interface IPs may become blocked.");
|
561
|
+ }
|
562
|
+
|
563
|
+ kill_state = ConfNodeLookupChildValue(conf, "kill-state");
|
564
|
+ block_ip = ConfNodeLookupChildValue(conf, "block-ip");
|
565
|
+ pf_table = ConfNodeLookupChildValue(conf, "pf-table");
|
566
|
+
|
567
|
+ if (unlikely(pf_table == NULL)) {
|
568
|
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "alert-pf: No PF table name specified, module init failed.");
|
569
|
+ exit(EXIT_FAILURE);
|
570
|
+ }
|
571
|
+
|
572
|
+ ctx = SCMalloc(sizeof(AlertPfCtx));
|
573
|
+ if (unlikely(ctx == NULL)) {
|
574
|
+ SCLogError(SC_ERR_MEM_ALLOC, "alert-pf: Unable to allocate memory for AlertPfCtx, module init failed.");
|
575
|
+ exit(EXIT_FAILURE);
|
576
|
+ }
|
577
|
+
|
578
|
+ /* Create a LogFileCtx for the block.log output */
|
579
|
+ logfile_ctx = LogFileNewCtx();
|
580
|
+ if (logfile_ctx == NULL) {
|
581
|
+ SCLogDebug("AlertPfInitCtx: Could not create new LogFileCtx");
|
582
|
+ SCFree(ctx);
|
583
|
+ return NULL;
|
584
|
+ }
|
585
|
+
|
586
|
+ if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME) < 0) {
|
587
|
+ LogFileFreeCtx(logfile_ctx);
|
588
|
+ SCLogDebug("AlertPfInitCtx: Could not create new LogFileCtx");
|
589
|
+ SCFree(ctx);
|
590
|
+ return NULL;
|
591
|
+ }
|
592
|
+
|
593
|
+ ctx->file_ctx = logfile_ctx;
|
594
|
+
|
595
|
+ ctx->kill_state = 1;
|
596
|
+ if (kill_state == NULL) {
|
597
|
+ SCLogWarning(SC_ERR_INVALID_ARGUMENT, "alert-pf: kill-state parameter not recognized, defaulting to 'yes'.");
|
598
|
+ }
|
599
|
+ if (kill_state && ConfValIsFalse(kill_state))
|
600
|
+ ctx->kill_state = 0;
|
601
|
+
|
602
|
+ if (block_ip == NULL) {
|
603
|
+ SCLogWarning(SC_ERR_INVALID_ARGUMENT, "alert-pf: block-ip parameter not recognized, defaulting to 'both'.");
|
604
|
+ }
|
605
|
+ if (block_ip && !strncasecmp("src", block_ip, strlen("src")))
|
606
|
+ ctx->block_ip = BLOCK_SRC;
|
607
|
+ else if (block_ip && !strncasecmp("dst", block_ip, strlen("dst")))
|
608
|
+ ctx->block_ip = BLOCK_DST;
|
609
|
+ else
|
610
|
+ ctx->block_ip = BLOCK_BOTH;
|
611
|
+
|
612
|
+ if (pass_list_name) {
|
613
|
+ AlertPfLoadPassList(SCStrdup(pass_list_name), ctx);
|
614
|
+ }
|
615
|
+
|
616
|
+ ctx->pftable = SCStrdup(pf_table);
|
617
|
+
|
618
|
+ /* TODO -- add validation of pf table */
|
619
|
+ if (AlertPfTableExists(ctx->pftable) != 1) {
|
620
|
+ LogFileFreeCtx(logfile_ctx);
|
621
|
+ SCFree(ctx);
|
622
|
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "alert-pf: Could not validate pf table: %s, module init failed.", pf_table);
|
623
|
+ exit(EXIT_FAILURE);
|
624
|
+ }
|
625
|
+
|
626
|
+ output_ctx = SCMalloc(sizeof(OutputCtx));
|
627
|
+ if (unlikely(output_ctx == NULL)) {
|
628
|
+ LogFileFreeCtx(logfile_ctx);
|
629
|
+ SCFree(ctx);
|
630
|
+ SCLogError(SC_ERR_MEM_ALLOC, "alert-pf: Unable to allocate memory for OutputCtx, module init failed.");
|
631
|
+ exit(EXIT_FAILURE);
|
632
|
+ }
|
633
|
+ output_ctx->data = ctx;
|
634
|
+ output_ctx->DeInit = AlertPfDeInitCtx;
|
635
|
+ SC_ATOMIC_INIT(alert_pf_blocks);
|
636
|
+
|
637
|
+ const char *block;
|
638
|
+ switch (ctx->block_ip) {
|
639
|
+ case BLOCK_SRC:
|
640
|
+ block = "src";
|
641
|
+ break;
|
642
|
+
|
643
|
+ case BLOCK_DST:
|
644
|
+ block = "dst";
|
645
|
+ break;
|
646
|
+
|
647
|
+ default:
|
648
|
+ block = "both";
|
649
|
+ }
|
650
|
+ const char *state = ctx->kill_state ? "on" : "off";
|
651
|
+ SCLogInfo("alert-pf output initialized, pf-table=%s block-ip=%s kill-state=%s", ctx->pftable, block, state);
|
652
|
+
|
653
|
+ return output_ctx;
|
654
|
+}
|
655
|
+
|
656
|
+/** \brief This releases the memory used by the global
|
657
|
+ * AlertPfCtx data structure.
|
658
|
+ */
|
659
|
+static void AlertPfDeInitCtx(OutputCtx *output_ctx)
|
660
|
+{
|
661
|
+ AlertPfCtx *ctx = (AlertPfCtx *)output_ctx->data;
|
662
|
+ LogFileFreeCtx(ctx->file_ctx);
|
663
|
+ SCRadixReleaseRadixTree(ctx->tree);
|
664
|
+ SCFree(ctx);
|
665
|
+ SCFree(output_ctx);
|
666
|
+}
|
667
|
+
|
668
|
+/** \brief This processes an IPv4 alert and inserts the appropriate
|
669
|
+ * block if the IP address is not on the Pass List.
|
670
|
+ */
|
671
|
+TmEcode AlertPfIPv4(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
|
672
|
+{
|
673
|
+ AlertPfThread *apft = (AlertPfThread *)data;
|
674
|
+ int i;
|
675
|
+ char proto[16] = "";
|
676
|
+ char timebuf[64];
|
677
|
+ char srcip[16], dstip[16];
|
678
|
+
|
679
|
+ if (p->alerts.cnt == 0)
|
680
|
+ return TM_ECODE_OK;
|
681
|
+
|
682
|
+ CreateTimeString(&p->ts, timebuf, sizeof(timebuf));
|
683
|
+ PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), srcip, sizeof(srcip));
|
684
|
+ PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), dstip, sizeof(dstip));
|
685
|
+
|
686
|
+ if (SCProtoNameValid(IPV4_GET_IPPROTO(p)) == TRUE) {
|
687
|
+ strlcpy(proto, known_proto[IPV4_GET_IPPROTO(p)], sizeof(proto));
|
688
|
+ } else {
|
689
|
+ snprintf(proto, sizeof(proto), "PROTO:%03" PRIu32, IPV4_GET_IPPROTO(p));
|
690
|
+ }
|
691
|
+
|
692
|
+ for (i = 0; i < p->alerts.cnt; i++) {
|
693
|
+ PacketAlert *pa = &p->alerts.alerts[i];
|
694
|
+ if (unlikely(pa->s == NULL)) {
|
695
|
+ continue;
|
696
|
+ }
|
697
|
+
|
698
|
+ switch (apft->ctx->block_ip) {
|
699
|
+
|
700
|
+ case BLOCK_BOTH:
|
701
|
+ /* Block only if IP is not in Pass List */
|
702
|
+ if (SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_SRC_ADDR_U32(p), apft->ctx->tree) == NULL) {
|
703
|
+ if (AlertPfBlock(apft, &p->src) > 0) {
|
704
|
+ SCMutexLock(&apft->ctx->file_ctx->fp_mutex);
|
705
|
+ fprintf(apft->ctx->file_ctx->fp, "%s,Block Src,%" PRIu32 ",%" PRIu32 ",%"
|
706
|
+ PRIu32 ",%s,%s,%" PRIu32
|
707
|
+ ",%s,%s,%" PRIu32 "\n", timebuf, pa->s->gid,
|
708
|
+ pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio,
|
709
|
+ proto, srcip, p->sp);
|
710
|
+ fflush(apft->ctx->file_ctx->fp);
|
711
|
+ apft->ctx->file_ctx->alerts++;
|
712
|
+ SCMutexUnlock(&apft->ctx->file_ctx->fp_mutex);
|
713
|
+ }
|
714
|
+ }
|
715
|
+ if (SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_DST_ADDR_U32(p), apft->ctx->tree) == NULL) {
|
716
|
+ if (AlertPfBlock(apft, &p->dst) > 0) {
|
717
|
+ SCMutexLock(&apft->ctx->file_ctx->fp_mutex);
|
718
|
+ fprintf(apft->ctx->file_ctx->fp, "%s,Block Dst,%" PRIu32 ",%" PRIu32 ",%"
|
719
|
+ PRIu32 ",%s,%s,%" PRIu32
|
720
|
+ ",%s,%s,%" PRIu32 "\n", timebuf, pa->s->gid,
|
721
|
+ pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio,
|
722
|
+ proto, dstip, p->dp);
|
723
|
+ fflush(apft->ctx->file_ctx->fp);
|
724
|
+ apft->ctx->file_ctx->alerts++;
|
725
|
+ SCMutexUnlock(&apft->ctx->file_ctx->fp_mutex);
|
726
|
+ }
|
727
|
+ }
|
728
|
+ break;
|
729
|
+
|
730
|
+ case BLOCK_SRC:
|
731
|
+ /* Block SRC only if IP is not in Pass List */
|
732
|
+ if (SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_SRC_ADDR_U32(p), apft->ctx->tree) == NULL) {
|
733
|
+ if (AlertPfBlock(apft, &p->src) > 0) {
|
734
|
+ SCMutexLock(&apft->ctx->file_ctx->fp_mutex);
|
735
|
+ fprintf(apft->ctx->file_ctx->fp, "%s,Block Src,%" PRIu32 ",%" PRIu32 ",%"
|
736
|
+ PRIu32 ",%s,%s,%" PRIu32
|
737
|
+ ",%s,%s,%" PRIu32 "\n", timebuf, pa->s->gid,
|
738
|
+ pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio,
|
739
|
+ proto, srcip, p->sp);
|
740
|
+ fflush(apft->ctx->file_ctx->fp);
|
741
|
+ apft->ctx->file_ctx->alerts++;
|
742
|
+ SCMutexUnlock(&apft->ctx->file_ctx->fp_mutex);
|
743
|
+ }
|
744
|
+ }
|
745
|
+ break;
|
746
|
+
|
747
|
+ case BLOCK_DST:
|
748
|
+ /* Block DST only if IP is not in Pass List */
|
749
|
+ if (SCRadixFindKeyIPV4BestMatch((uint8_t *)&GET_IPV4_DST_ADDR_U32(p), apft->ctx->tree) == NULL) {
|
750
|
+ if (AlertPfBlock(apft, &p->dst) > 0) {
|
751
|
+ SCMutexLock(&apft->ctx->file_ctx->fp_mutex);
|
752
|
+ fprintf(apft->ctx->file_ctx->fp, "%s,Block Dst,%" PRIu32 ",%" PRIu32 ",%"
|
753
|
+ PRIu32 ",%s,%s,%" PRIu32
|
754
|
+ ",%s,%s,%" PRIu32 "\n", timebuf, pa->s->gid,
|
755
|
+ pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio,
|
756
|
+ proto, dstip, p->dp);
|
757
|
+ fflush(apft->ctx->file_ctx->fp);
|
758
|
+ apft->ctx->file_ctx->alerts++;
|
759
|
+ SCMutexUnlock(&apft->ctx->file_ctx->fp_mutex);
|
760
|
+ }
|
761
|
+ }
|
762
|
+ }
|
763
|
+
|
764
|
+ /* Once we find and block the first packet alert for this IP, we're done */
|
765
|
+ break;
|
766
|
+ }
|
767
|
+
|
768
|
+ return TM_ECODE_OK;
|
769
|
+}
|
770
|
+
|
771
|
+/** \brief This processes an IPv6 alert and inserts the appropriate
|
772
|
+ * block if the IP address is not on the Pass List.
|
773
|
+ */
|
774
|
+TmEcode AlertPfIPv6(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
|
775
|
+{
|
776
|
+ AlertPfThread *apft = (AlertPfThread *)data;
|
777
|
+ int i;
|
778
|
+ char proto[16] = "";
|
779
|
+ char timebuf[64];
|
780
|
+ char srcip[46], dstip[46];
|
781
|
+
|
782
|
+ if (p->alerts.cnt == 0)
|
783
|
+ return TM_ECODE_OK;
|
784
|
+
|
785
|
+ CreateTimeString(&p->ts, timebuf, sizeof(timebuf));
|
786
|
+ PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), srcip, sizeof(srcip));
|
787
|
+ PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), dstip, sizeof(dstip));
|
788
|
+
|
789
|
+ if (SCProtoNameValid(IPV6_GET_L4PROTO(p)) == TRUE) {
|
790
|
+ strlcpy(proto, known_proto[IPV6_GET_L4PROTO(p)], sizeof(proto));
|
791
|
+ } else {
|
792
|
+ snprintf(proto, sizeof(proto), "PROTO:%03" PRIu32, IPV6_GET_L4PROTO(p));
|
793
|
+ }
|
794
|
+
|
795
|
+ for (i = 0; i < p->alerts.cnt; i++) {
|
796
|
+ PacketAlert *pa = &p->alerts.alerts[i];
|
797
|
+ if (unlikely(pa->s == NULL)) {
|
798
|
+ continue;
|
799
|
+ }
|
800
|
+
|
801
|
+ switch (apft->ctx->block_ip) {
|
802
|
+
|
803
|
+ case BLOCK_BOTH:
|
804
|
+ /* Block only if IP is not in Pass List */
|
805
|
+ if (SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_SRC_ADDR(p), apft->ctx->tree) == NULL) {
|
806
|
+ if (AlertPfBlock(apft, &p->src) > 0) {
|
807
|
+ SCMutexLock(&apft->ctx->file_ctx->fp_mutex);
|
808
|
+ fprintf(apft->ctx->file_ctx->fp, "%s,Block Src,%" PRIu32 ",%" PRIu32 ",%"
|
809
|
+ PRIu32 ",%s,%s,%" PRIu32
|
810
|
+ ",%s,%s,%" PRIu32 "\n", timebuf, pa->s->gid,
|
811
|
+ pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio,
|
812
|
+ proto, srcip, p->sp);
|
813
|
+ fflush(apft->ctx->file_ctx->fp);
|
814
|
+ apft->ctx->file_ctx->alerts++;
|
815
|
+ SCMutexUnlock(&apft->ctx->file_ctx->fp_mutex);
|
816
|
+ }
|
817
|
+ }
|
818
|
+ if (SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_DST_ADDR(p), apft->ctx->tree) == NULL) {
|
819
|
+ if (AlertPfBlock(apft, &p->dst) > 0) {
|
820
|
+ SCMutexLock(&apft->ctx->file_ctx->fp_mutex);
|
821
|
+ fprintf(apft->ctx->file_ctx->fp, "%s,Block Dst,%" PRIu32 ",%" PRIu32 ",%"
|
822
|
+ PRIu32 ",%s,%s,%" PRIu32
|
823
|
+ ",%s,%s,%" PRIu32 "\n", timebuf, pa->s->gid,
|
824
|
+ pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio,
|
825
|
+ proto, dstip, p->dp);
|
826
|
+ fflush(apft->ctx->file_ctx->fp);
|
827
|
+ apft->ctx->file_ctx->alerts++;
|
828
|
+ SCMutexUnlock(&apft->ctx->file_ctx->fp_mutex);
|
829
|
+ }
|
830
|
+ }
|
831
|
+ break;
|
832
|
+
|
833
|
+ case BLOCK_SRC:
|
834
|
+ /* Block SRC only if IP is not in Pass List */
|
835
|
+ if (SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_SRC_ADDR(p), apft->ctx->tree) == NULL) {
|
836
|
+ if (AlertPfBlock(apft, &p->src) > 0) {
|
837
|
+ SCMutexLock(&apft->ctx->file_ctx->fp_mutex);
|
838
|
+ fprintf(apft->ctx->file_ctx->fp, "%s,Block Src,%" PRIu32 ",%" PRIu32 ",%"
|
839
|
+ PRIu32 ",%s,%s,%" PRIu32
|
840
|
+ ",%s,%s,%" PRIu32 "\n", timebuf, pa->s->gid,
|
841
|
+ pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio,
|
842
|
+ proto, srcip, p->sp);
|
843
|
+ fflush(apft->ctx->file_ctx->fp);
|
844
|
+ apft->ctx->file_ctx->alerts++;
|
845
|
+ SCMutexUnlock(&apft->ctx->file_ctx->fp_mutex);
|
846
|
+ }
|
847
|
+ }
|
848
|
+ break;
|
849
|
+
|
850
|
+ case BLOCK_DST:
|
851
|
+ /* Block DST only if IP is not in Pass List */
|
852
|
+ if (SCRadixFindKeyIPV6BestMatch((uint8_t *)&GET_IPV6_DST_ADDR(p), apft->ctx->tree) == NULL) {
|
853
|
+ if (AlertPfBlock(apft, &p->dst) > 0) {
|
854
|
+ SCMutexLock(&apft->ctx->file_ctx->fp_mutex);
|
855
|
+ fprintf(apft->ctx->file_ctx->fp, "%s,Block Dst,%" PRIu32 ",%" PRIu32 ",%"
|
856
|
+ PRIu32 ",%s,%s,%" PRIu32
|
857
|
+ ",%s,%s,%" PRIu32 "\n", timebuf, pa->s->gid,
|
858
|
+ pa->s->id, pa->s->rev, pa->s->msg, pa->s->class_msg, pa->s->prio,
|
859
|
+ proto, dstip, p->dp);
|
860
|
+ fflush(apft->ctx->file_ctx->fp);
|
861
|
+ apft->ctx->file_ctx->alerts++;
|
862
|
+ SCMutexUnlock(&apft->ctx->file_ctx->fp_mutex);
|
863
|
+ }
|
864
|
+ }
|
865
|
+ }
|
866
|
+
|
867
|
+ /* Once we find and block the first packet alert for this IP, we're done */
|
868
|
+ break;
|
869
|
+ }
|
870
|
+
|
871
|
+ return TM_ECODE_OK;
|
872
|
+}
|
873
|
+
|
874
|
+/** \brief This processes an IP alert and routes it to the
|
875
|
+ * appropriate handler.
|
876
|
+ */
|
877
|
+TmEcode AlertPf (ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQueue *postpq)
|
878
|
+{
|
879
|
+ if (PKT_IS_IPV4(p)) {
|
880
|
+ return AlertPfIPv4(tv, p, data, pq, postpq);
|
881
|
+ } else if (PKT_IS_IPV6(p)) {
|
882
|
+ return AlertPfIPv6(tv, p, data, pq, postpq);
|
883
|
+ }
|
884
|
+
|
885
|
+ return TM_ECODE_OK;
|
886
|
+}
|
887
|
+
|
888
|
diff -rNu ./src/alert-pf.h ./src.new/alert-pf.h
|
889
|
--- ./src/alert-pf.h 1969-12-31 19:00:00.000000000 -0500
|
890
|
+++ ./src.new/alert-pf.h 2014-04-21 20:13:22.000000000 -0400
|
891
|
@@ -0,0 +1,51 @@
|
892
|
+/* Copyright (C) 2007-2010 Open Information Security Foundation
|
893
|
+ *
|
894
|
+ * You can copy, redistribute or modify this Program under the terms of
|
895
|
+ * the GNU General Public License version 2 as published by the Free
|
896
|
+ * Software Foundation.
|
897
|
+ *
|
898
|
+ * This program is distributed in the hope that it will be useful,
|
899
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
900
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
901
|
+ * GNU General Public License for more details.
|
902
|
+ *
|
903
|
+ * You should have received a copy of the GNU General Public License
|
904
|
+ * version 2 along with this program; if not, write to the Free Software
|
905
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
906
|
+ * 02110-1301, USA.
|
907
|
+ */
|
908
|
+
|
909
|
+/**
|
910
|
+ * \file
|
911
|
+ *
|
912
|
+ * \author Bill Meeks <bill@themeeks.net>
|
913
|
+ */
|
914
|
+
|
915
|
+#ifndef __ALERT_PF_H__
|
916
|
+#define __ALERT_PF_H__
|
917
|
+
|
918
|
+/**
|
919
|
+ * define these macros since we need them in <net/pfvar.h>
|
920
|
+ * and Suricata by default uses it's own customized
|
921
|
+ * <queue.h> file that omits these particular macros.
|
922
|
+ */
|
923
|
+#define SLIST_HEAD(name, type) \
|
924
|
+struct name { \
|
925
|
+ struct type *slh_first; /* first element */ \
|
926
|
+}
|
927
|
+
|
928
|
+#define SLIST_HEAD_INITIALIZER(head) \
|
929
|
+ { NULL }
|
930
|
+
|
931
|
+#define SLIST_ENTRY(type) \
|
932
|
+struct { \
|
933
|
+ struct type *sle_next; /* next element */ \
|
934
|
+}
|
935
|
+
|
936
|
+void TmModuleAlertPfRegister (void);
|
937
|
+void TmModuleAlertPfIPv4Register (void);
|
938
|
+void TmModuleAlertPfIPv6Register (void);
|
939
|
+OutputCtx *AlertPfInitCtx(ConfNode *);
|
940
|
+
|
941
|
+#endif /* __ALERT_PF_H__ */
|
942
|
+
|
943
|
diff -rNu ./src/suricata.c ./src.new/suricata.c
|
944
|
--- ./src/suricata.c 2013-09-24 06:28:37.000000000 -0400
|
945
|
+++ ./src.new/suricata.c 2014-04-30 19:20:58.000000000 -0400
|
946
|
@@ -100,6 +100,7 @@
|
947
|
#include "alert-prelude.h"
|
948
|
#include "alert-syslog.h"
|
949
|
#include "alert-pcapinfo.h"
|
950
|
+#include "alert-pf.h"
|
951
|
|
952
|
#include "log-droplog.h"
|
953
|
#include "log-httplog.h"
|
954
|
@@ -1557,6 +1558,10 @@
|
955
|
/* napatech */
|
956
|
TmModuleNapatechStreamRegister();
|
957
|
TmModuleNapatechDecodeRegister();
|
958
|
+ /* alert pf */
|
959
|
+ TmModuleAlertPfRegister();
|
960
|
+ TmModuleAlertPfIPv4Register();
|
961
|
+ TmModuleAlertPfIPv6Register();
|
962
|
|
963
|
/* stream engine */
|
964
|
TmModuleStreamTcpRegister();
|
965
|
@@ -1887,6 +1892,7 @@
|
966
|
if (engine_analysis) {
|
967
|
exit(EXIT_SUCCESS);
|
968
|
}
|
969
|
+ SCThresholdConfInitContext(de_ctx,NULL);
|
970
|
}
|
971
|
|
972
|
/* registering singal handlers we use. We register usr2 here, so that one
|
973
|
@@ -1898,7 +1904,6 @@
|
974
|
SCCudaPBSetUpQueuesAndBuffers();
|
975
|
#endif /* __SC_CUDA_SUPPORT__ */
|
976
|
|
977
|
- SCThresholdConfInitContext(de_ctx,NULL);
|
978
|
SCAsn1LoadConfig();
|
979
|
|
980
|
CoredumpLoadConfig();
|
981
|
@@ -2019,6 +2024,7 @@
|
982
|
if (de_ctx->failure_fatal)
|
983
|
exit(EXIT_FAILURE);
|
984
|
}
|
985
|
+ SCThresholdConfInitContext(de_ctx,NULL);
|
986
|
TmThreadActivateDummySlot();
|
987
|
SCLogInfo("Signature(s) loaded, Detect thread(s) activated.");
|
988
|
}
|
989
|
diff -rNu ./src/tm-modules.c ./src.new/tm-modules.c
|
990
|
--- ./src/tm-modules.c 2013-09-24 06:28:37.000000000 -0400
|
991
|
+++ ./src.new/tm-modules.c 2014-04-18 16:45:17.000000000 -0400
|
992
|
@@ -238,6 +238,9 @@
|
993
|
CASE_CODE (TMM_ALERTPRELUDE);
|
994
|
CASE_CODE (TMM_ALERTDEBUGLOG);
|
995
|
CASE_CODE (TMM_ALERTSYSLOG);
|
996
|
+ CASE_CODE (TMM_ALERTPF);
|
997
|
+ CASE_CODE (TMM_ALERTPF4);
|
998
|
+ CASE_CODE (TMM_ALERTPF6);
|
999
|
CASE_CODE (TMM_LOGDROPLOG);
|
1000
|
CASE_CODE (TMM_ALERTSYSLOG4);
|
1001
|
CASE_CODE (TMM_ALERTSYSLOG6);
|
1002
|
diff -rNu ./src/tm-threads-common.h ./src.new/tm-threads-common.h
|
1003
|
--- ./src/tm-threads-common.h 2013-09-24 06:28:37.000000000 -0400
|
1004
|
+++ ./src.new/tm-threads-common.h 2014-04-18 18:59:26.000000000 -0400
|
1005
|
@@ -78,6 +78,9 @@
|
1006
|
TMM_ALERTPCAPINFO,
|
1007
|
TMM_RECEIVENAPATECH,
|
1008
|
TMM_DECODENAPATECH,
|
1009
|
+ TMM_ALERTPF,
|
1010
|
+ TMM_ALERTPF4,
|
1011
|
+ TMM_ALERTPF6,
|
1012
|
TMM_SIZE,
|
1013
|
} TmmId;
|
1014
|
|