1
|
|
2
|
#include <sys/types.h>
|
3
|
#include <sys/socket.h>
|
4
|
#include <sys/sbuf.h>
|
5
|
#include <sys/file.h>
|
6
|
|
7
|
#include <net/if.h>
|
8
|
#include <pcap/pcap.h>
|
9
|
|
10
|
#include <net/pfvar.h>
|
11
|
#include <net/if_pflog.h>
|
12
|
|
13
|
#include <netinet/ip.h>
|
14
|
|
15
|
#include <stdlib.h>
|
16
|
#include <syslog.h>
|
17
|
#include <stdarg.h>
|
18
|
#include <time.h>
|
19
|
#include <string.h>
|
20
|
#include <unistd.h>
|
21
|
|
22
|
#include "common.h"
|
23
|
|
24
|
static pcap_t *tap = NULL;
|
25
|
static char *filterlog_pcap_file = NULL;
|
26
|
static char errbuf[PCAP_ERRBUF_SIZE];
|
27
|
static struct sbuf sbuf;
|
28
|
static u_char *sbuf_buf;
|
29
|
static char *pidfile;
|
30
|
|
31
|
static const struct tok pf_reasons[] = {
|
32
|
{ 0, "match" },
|
33
|
{ 1, "bad-offset" },
|
34
|
{ 2, "fragment" },
|
35
|
{ 3, "short" },
|
36
|
{ 4, "normalize" },
|
37
|
{ 5, "memory" },
|
38
|
{ 6, "bad-timestamp" },
|
39
|
{ 7, "congestion" },
|
40
|
{ 8, "ip-option" },
|
41
|
{ 9, "proto-cksum" },
|
42
|
{ 10, "state-mismatch" },
|
43
|
{ 11, "state-insert" },
|
44
|
{ 12, "state-limit" },
|
45
|
{ 13, "src-limit" },
|
46
|
{ 14, "synproxy" },
|
47
|
{ 0, NULL }
|
48
|
};
|
49
|
|
50
|
static const struct tok pf_actions[] = {
|
51
|
{ PF_PASS, "pass" },
|
52
|
{ PF_DROP, "block" },
|
53
|
{ PF_SCRUB, "scrub" },
|
54
|
{ PF_NAT, "nat" },
|
55
|
{ PF_NONAT, "nat" },
|
56
|
{ PF_BINAT, "binat" },
|
57
|
{ PF_NOBINAT, "binat" },
|
58
|
{ PF_RDR, "rdr" },
|
59
|
{ PF_NORDR, "rdr" },
|
60
|
{ PF_SYNPROXY_DROP, "synproxy-drop" },
|
61
|
{ 0, NULL }
|
62
|
};
|
63
|
|
64
|
static const struct tok pf_directions[] = {
|
65
|
{ PF_INOUT, "in/out" },
|
66
|
{ PF_IN, "in" },
|
67
|
{ PF_OUT, "out" },
|
68
|
{ 0, NULL }
|
69
|
};
|
70
|
|
71
|
const char *
|
72
|
code2str(const struct tok *trans, const char *unknown, int action)
|
73
|
{
|
74
|
int i = 0;
|
75
|
|
76
|
for (;;) {
|
77
|
if (trans[i].descr == NULL)
|
78
|
return unknown;
|
79
|
|
80
|
if (action == trans[i].action)
|
81
|
return (trans[i].descr);
|
82
|
|
83
|
i++;
|
84
|
}
|
85
|
|
86
|
return (unknown);
|
87
|
}
|
88
|
|
89
|
static void
|
90
|
decode_packet(u_char *user __unused, const struct pcap_pkthdr *pkthdr, const u_char *packet)
|
91
|
{
|
92
|
const struct pfloghdr *hdr;
|
93
|
const struct ip *ip;
|
94
|
u_int length = pkthdr->len;
|
95
|
u_int hdrlen;
|
96
|
u_int caplen = pkthdr->caplen;
|
97
|
u_int32_t subrulenr;
|
98
|
|
99
|
/* check length */
|
100
|
if (caplen < sizeof(u_int8_t)) {
|
101
|
sbuf_printf(&sbuf, "[|pflog]");
|
102
|
goto printsbuf;
|
103
|
}
|
104
|
|
105
|
#define MIN_PFLOG_HDRLEN 45
|
106
|
hdr = (const struct pfloghdr *)packet;
|
107
|
if (hdr->length < MIN_PFLOG_HDRLEN) {
|
108
|
sbuf_printf(&sbuf, "[pflog: invalid header length!]");
|
109
|
goto printsbuf;
|
110
|
}
|
111
|
hdrlen = PFLOG_HDRLEN;
|
112
|
|
113
|
if (caplen < hdrlen) {
|
114
|
sbuf_printf(&sbuf, "[|pflog]");
|
115
|
goto printsbuf;
|
116
|
}
|
117
|
|
118
|
/* print what we know */
|
119
|
sbuf_printf(&sbuf, "%u,", EXTRACT_32BITS(&hdr->rulenr));
|
120
|
subrulenr = EXTRACT_32BITS(&hdr->subrulenr);
|
121
|
if (subrulenr == (u_int32_t)-1)
|
122
|
sbuf_printf(&sbuf, ",,");
|
123
|
else
|
124
|
sbuf_printf(&sbuf, "%u,%s,", subrulenr, hdr->ruleset);
|
125
|
sbuf_printf(&sbuf, "%u,%s,", hdr->ridentifier, hdr->ifname);
|
126
|
sbuf_printf(&sbuf, "%s,", code2str(pf_reasons, "unkn(%u)", hdr->reason));
|
127
|
sbuf_printf(&sbuf, "%s,", code2str(pf_actions, "unkn(%u)", hdr->action));
|
128
|
sbuf_printf(&sbuf, "%s,", code2str(pf_directions, "unkn(%u)", hdr->dir));
|
129
|
|
130
|
/* skip to the real packet */
|
131
|
length -= hdrlen;
|
132
|
packet += hdrlen;
|
133
|
ip = (const const struct ip *)packet;
|
134
|
|
135
|
if (length < 4) {
|
136
|
sbuf_printf(&sbuf, "%d, IP(truncated-ip %d) ", IP_V(ip), length);
|
137
|
goto printsbuf;
|
138
|
}
|
139
|
switch (IP_V(ip)) {
|
140
|
case 4:
|
141
|
ip_print(&sbuf, packet, length);
|
142
|
break;
|
143
|
case 6:
|
144
|
ip6_print(&sbuf, packet, length);
|
145
|
break;
|
146
|
default:
|
147
|
ip_print(&sbuf, packet, length);
|
148
|
sbuf_printf(&sbuf, "%d", IP_V(ip));
|
149
|
break;
|
150
|
}
|
151
|
|
152
|
printsbuf:
|
153
|
sbuf_finish(&sbuf);
|
154
|
if (filterlog_pcap_file != NULL)
|
155
|
printf("%s\n", sbuf_data(&sbuf));
|
156
|
else
|
157
|
syslog(LOG_INFO, "%s", sbuf_data(&sbuf));
|
158
|
memset(sbuf_data(&sbuf), 0, sbuf_len(&sbuf));
|
159
|
sbuf_clear(&sbuf);
|
160
|
return;
|
161
|
}
|
162
|
|
163
|
int
|
164
|
main(int argc, char **argv)
|
165
|
{
|
166
|
int perr, ch;
|
167
|
char *interface;
|
168
|
|
169
|
pidfile = NULL;
|
170
|
interface = filterlog_pcap_file = NULL;
|
171
|
tzset();
|
172
|
|
173
|
while ((ch = getopt(argc, argv, "i:p:P:")) != -1) {
|
174
|
switch (ch) {
|
175
|
case 'i':
|
176
|
interface = optarg;
|
177
|
break;
|
178
|
case 'p':
|
179
|
pidfile = optarg;
|
180
|
break;
|
181
|
case 'P':
|
182
|
filterlog_pcap_file = optarg;
|
183
|
break;
|
184
|
default:
|
185
|
printf("Unknown option specified\n");
|
186
|
return (-1);
|
187
|
}
|
188
|
}
|
189
|
|
190
|
if (interface == NULL && filterlog_pcap_file == NULL) {
|
191
|
printf("Should specify an interface or a pcap file\n");
|
192
|
exit(-1);
|
193
|
}
|
194
|
|
195
|
if (filterlog_pcap_file == NULL)
|
196
|
daemon(0, 0);
|
197
|
|
198
|
if (pidfile) {
|
199
|
FILE *pidfd;
|
200
|
|
201
|
/* write PID to file */
|
202
|
pidfd = fopen(pidfile, "w");
|
203
|
if (pidfd) {
|
204
|
while (flock(fileno(pidfd), LOCK_EX) != 0)
|
205
|
;
|
206
|
fprintf(pidfd, "%d\n", getpid());
|
207
|
flock(fileno(pidfd), LOCK_UN);
|
208
|
fclose(pidfd);
|
209
|
} else
|
210
|
syslog(LOG_WARNING, "could not open pid file");
|
211
|
}
|
212
|
|
213
|
do {
|
214
|
sbuf_buf = calloc(1, 2048);
|
215
|
} while (sbuf_buf == NULL);
|
216
|
|
217
|
sbuf_new(&sbuf, sbuf_buf, 2048, SBUF_AUTOEXTEND);
|
218
|
|
219
|
openlog("filterlog", LOG_NDELAY, LOG_LOCAL0);
|
220
|
|
221
|
while (1) {
|
222
|
if (tap != NULL)
|
223
|
pcap_close(tap);
|
224
|
|
225
|
if (filterlog_pcap_file != NULL)
|
226
|
tap = pcap_open_offline(filterlog_pcap_file, errbuf);
|
227
|
else
|
228
|
tap = pcap_open_live(interface, MAXIMUM_SNAPLEN, 1, 1000, errbuf);
|
229
|
if (tap == NULL) {
|
230
|
syslog(LOG_ERR, "Failed to initialize: %s(%m)", errbuf);
|
231
|
return (-1);
|
232
|
}
|
233
|
|
234
|
if (pcap_datalink(tap) != DLT_PFLOG) {
|
235
|
syslog(LOG_ERR, "Invalid datalink type");
|
236
|
pcap_close(tap);
|
237
|
tap = NULL;
|
238
|
return (-1);
|
239
|
}
|
240
|
|
241
|
perr = pcap_loop(tap, -1, decode_packet, NULL);
|
242
|
if (perr == -1) {
|
243
|
syslog(LOG_ERR, "An error occured while reading device %s: %m", interface);
|
244
|
} else if (perr == -2) {
|
245
|
pcap_close(tap);
|
246
|
break;
|
247
|
} else if (perr == 0) {
|
248
|
pcap_close(tap);
|
249
|
tap = NULL;
|
250
|
}
|
251
|
|
252
|
if (filterlog_pcap_file != NULL)
|
253
|
break;
|
254
|
}
|
255
|
|
256
|
closelog();
|
257
|
|
258
|
return (0);
|
259
|
}
|