-
Notifications
You must be signed in to change notification settings - Fork 2
/
filters.c
124 lines (94 loc) · 2.89 KB
/
filters.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "filters.h"
#include <string.h>
#include <stdlib.h>
#include "util.h"
void filters_init(filters_ctx *ctx, pcap_t* pcap_ctx) {
ctx->filters = list_new();
ctx->pcap_ctx = pcap_ctx;
}
void filters_finish(filters_ctx *ctx) {
// free the filters
list_foreach(ctx->filters, f) {
struct filter *tmp = list_data(f, struct filter);
pcap_freecode(tmp->bpf);
free(tmp->bpf);
free(tmp);
}
list_free(ctx->filters);
}
static void filters_bpfstr_unwind(filters_ctx *ctx, char *bpf_str)
{
char token[1024 + strlen("${}")];
list_foreach(ctx->filters, f) {
struct filter *tmp = list_data(f, struct filter);
snprintf(token, sizeof(token), "${%s}", tmp->id);
strnrepl(token, tmp->bpf_str, bpf_str, 4096);
}
}
static void filters_bpfstr_unwind_finish(filters_ctx *ctx)
{
list_foreach(ctx->filters, f)
free(list_data(f, struct filter)->bpf_str);
}
static void filters_add(filters_ctx *ctx, const char *id, char *bpf_str) {
struct filter *instance = malloc(sizeof(*instance));
// TODO: document maximum len of id
strncpy(instance->id, id, 1023);
instance->id[1023] = '\0';
instance->bpf_str = bpf_str;
instance->bpf = malloc(sizeof(struct bpf_program));
instance->packets_count = 0;
instance->bytes_count = 0;
if (pcap_compile(ctx->pcap_ctx, instance->bpf, bpf_str, 0, PCAP_NETMASK_UNKNOWN) == -1) {
fprintf(stderr, "Error at compiling bpf \"%s\": %s\n", bpf_str, pcap_geterr(ctx->pcap_ctx));
exit(1);
}
list_insert(ctx->filters, instance);
}
void filters_load(filters_ctx *ctx, const char *filterfile_path, const char *mac_addr) {
// TODO: test with /dev/random as input
FILE *fp = fopen(filterfile_path, "r");
char *line = NULL;
size_t read = 0;
int line_no = 0;
if (fp == NULL) {
fprintf(stderr, "Error while opening the filterfile '%s': ", filterfile_path);
perror("");
exit(1);
}
while ((read = getline(&line, &read, fp)) != -1) {
line_no++;
line[read-1] = 0; // remove the \n at the end of the line
// skip the line if it's empty
if (read == 1)
continue;
char *id = strtok(line, ";");
char *bpf_tmp = strtok(NULL, ";");
if (id == NULL || bpf_tmp == NULL) {
fprintf(stderr, "Wrong format in filterfile in line %d.\n", line_no);
exit(1);
}
// create new buffers for id and bpf, since they will get
// free when line will be free
//
// TODO: here is dump!!
char *bpf = malloc(4096);
strncpy(bpf, bpf_tmp, 4095);
strnrepl("$MAC", mac_addr, bpf, 4096);
filters_bpfstr_unwind(ctx, bpf);
fprintf(stderr, "id: %s; bpf: \"%s\";\n", id, bpf);
filters_add(ctx, id, bpf);
}
filters_bpfstr_unwind_finish(ctx);
free(line);
fclose(fp);
}
void filters_process(filters_ctx *ctx, const struct pcap_pkthdr *pkthdr, const u_char *packet) {
list_foreach(ctx->filters, f) {
struct filter *tmp = list_data(f, struct filter);
if (pcap_offline_filter(tmp->bpf, pkthdr, packet)) {
tmp->packets_count += 1;
tmp->bytes_count += pkthdr->len;
}
}
}