|
@@ -18,32 +18,92 @@
|
18
|
18
|
#include "data.h"
|
19
|
19
|
#include "filter.h"
|
20
|
20
|
|
|
21
|
+struct filter_actions_map {
|
|
22
|
+ const char *token;
|
|
23
|
+ bool last;
|
|
24
|
+ enum filter_action type;
|
|
25
|
+};
|
|
26
|
+
|
|
27
|
+static struct filter_actions_map action_tokens[] = {
|
|
28
|
+ { "accept_all", true, FILTER_ACCEPT_ALL },
|
|
29
|
+ { "acceptall", true, FILTER_ACCEPT_ALL },
|
|
30
|
+ { "reject_all", true, FILTER_REJECT_ALL },
|
|
31
|
+ { "rejectall", true, FILTER_REJECT_ALL },
|
|
32
|
+ { "accept", false, FILTER_ACCEPT },
|
|
33
|
+ { "reject", false, FILTER_REJECT },
|
|
34
|
+ { NULL, true, FILTER_NO_MATCH },
|
|
35
|
+};
|
|
36
|
+
|
|
37
|
+enum filter_token { T_UNKNOWN, T_NAME, T_OFFSET, T_DATA, T_MATCH, T_MASK };
|
|
38
|
+
|
|
39
|
+struct filter_data_map {
|
|
40
|
+ const char *token;
|
|
41
|
+ enum filter_token type;
|
|
42
|
+};
|
|
43
|
+
|
|
44
|
+static struct filter_data_map data_tokens[] = {
|
|
45
|
+ { "name", T_NAME },
|
|
46
|
+ { "ofs", T_OFFSET },
|
|
47
|
+ { "offset", T_OFFSET },
|
|
48
|
+ { "data", T_DATA },
|
|
49
|
+ { "match", T_MATCH },
|
|
50
|
+ { "mask", T_MASK },
|
|
51
|
+ { NULL, T_UNKNOWN },
|
|
52
|
+};
|
|
53
|
+
|
|
54
|
+int parse_hex(char *data, uint8_t *output, uint8_t *output_len, uint8_t output_size) {
|
|
55
|
+ int i, len = strlen(data), consumed = 0;
|
|
56
|
+ uint8_t local_output_len = 0;
|
|
57
|
+ if (!output_len)
|
|
58
|
+ output_len = &local_output_len;
|
|
59
|
+ for (i = 0; i < len; i++) { // Parse data (01 02 03 04 ...)
|
|
60
|
+ char ch = toupper(data[i]);
|
|
61
|
+ // Skip 0x prefixes
|
|
62
|
+ if (i + 1 < len && ch == '0' && toupper(data[i + 1]) == 'X')
|
|
63
|
+ continue;
|
|
64
|
+ if (!isxdigit(ch))
|
|
65
|
+ continue;
|
|
66
|
+ ch -= ch > 64 ? 55 : 48; // hex2dec
|
|
67
|
+ if (consumed % 2 == 0) {
|
|
68
|
+ output[*output_len] = 0; // Reset
|
|
69
|
+ output[*output_len] += ch << 4;
|
|
70
|
+ } else {
|
|
71
|
+ output[*output_len] += ch;
|
|
72
|
+ (*output_len)++;
|
|
73
|
+ if (*output_len + 1 >= output_size) {
|
|
74
|
+ fprintf(stderr, "WARN : Too much filter data (max %d bytes), ignoring last bytes: %s\n",
|
|
75
|
+ output_size, data + i + 2);
|
|
76
|
+ break;
|
|
77
|
+ }
|
|
78
|
+ }
|
|
79
|
+ consumed++;
|
|
80
|
+ }
|
|
81
|
+ return *output_len;
|
|
82
|
+}
|
|
83
|
+
|
21
|
84
|
int filter_parse(char *filter_def, struct filter *filter) {
|
22
|
|
- int i, j, k, ret = 0;
|
|
85
|
+ int j, k, ret = 0;
|
23
|
86
|
char *str1, *saveptr1;
|
24
|
87
|
char *f = strdup(filter_def);
|
25
|
88
|
memset(filter, 0, sizeof(struct filter));
|
|
89
|
+ memset(filter->mask, 0xff, sizeof(filter->mask));
|
26
|
90
|
snprintf(filter->name, sizeof(filter->name), "NONAME");
|
27
|
91
|
for (j = 1, str1 = f; ; j++, str1 = NULL) {
|
28
|
92
|
char *token = strtok_r(str1, "/", &saveptr1);
|
29
|
93
|
if (token == NULL)
|
30
|
94
|
break;
|
31
|
95
|
if (j == 1) { // First token, the command
|
32
|
|
- if (strstr(token, "accept_all") == token || strstr(token, "acceptall") == token) {
|
33
|
|
- filter->action = FILTER_ACCEPT_ALL;
|
34
|
|
- ret = 1;
|
35
|
|
- goto OUT; // Other tokens are not needed
|
36
|
|
- } else if (strstr(token, "reject_all") == token || strstr(token, "rejectall") == token) {
|
37
|
|
- filter->action = FILTER_REJECT_ALL;
|
38
|
|
- ret = 1;
|
39
|
|
- goto OUT; // Other tokens are not needed
|
40
|
|
- } else if (strstr(token, "accept") == token) {
|
41
|
|
- filter->action = FILTER_ACCEPT;
|
42
|
|
- continue; // Continue looking for other tokes
|
43
|
|
- } else if (strstr(token, "reject") == token) {
|
44
|
|
- filter->action = FILTER_REJECT;
|
45
|
|
- continue; // Continue looking for other tokes
|
46
|
|
- } else {
|
|
96
|
+ struct filter_actions_map *m;
|
|
97
|
+ for (m = action_tokens; m->token; m++) {
|
|
98
|
+ if (strstr(token, m->token) == token) {
|
|
99
|
+ filter->action = m->type;
|
|
100
|
+ ret = 1;
|
|
101
|
+ if (m->last)
|
|
102
|
+ goto OUT; // Other tokens are not needed
|
|
103
|
+ break;
|
|
104
|
+ }
|
|
105
|
+ }
|
|
106
|
+ if (filter->action == FILTER_NO_MATCH) {
|
47
|
107
|
fprintf(stderr, "ERROR: Unknown filter command: %s\n", token);
|
48
|
108
|
ret = 0;
|
49
|
109
|
goto OUT; // Other tokens are not needed
|
|
@@ -55,37 +115,36 @@ int filter_parse(char *filter_def, struct filter *filter) {
|
55
|
115
|
char *token2 = strtok_r(str2, ",", &saveptr2);
|
56
|
116
|
if (token2 == NULL)
|
57
|
117
|
break;
|
58
|
|
- char *eq = strrchr(token2, '=');
|
59
|
|
- if (eq) {
|
60
|
|
- if (strstr(token2, "ofs") == token2 || strstr(token2, "offset") == token2) {
|
61
|
|
- filter->offset = strtoul(eq + 1, NULL, 0);
|
62
|
|
- } else if (strstr(token2, "name") == token2) {
|
63
|
|
- snprintf(filter->name, sizeof(filter->name), "%s", eq + 1);
|
64
|
|
- } else if (strstr(token2, "data") == token2) {
|
65
|
|
- char *data = eq + 1;
|
66
|
|
- int len = strlen(data), consumed = 0;
|
67
|
|
- for (i = 0; i < len; i++) { // Parse data (01 02 03 04 ...)
|
68
|
|
- char ch = toupper(data[i]);
|
69
|
|
- // Skip 0x prefixes
|
70
|
|
- if (i + 1 < len && ch == '0' && toupper(data[i + 1]) == 'X')
|
71
|
|
- continue;
|
72
|
|
- if (!isxdigit(ch))
|
73
|
|
- continue;
|
74
|
|
- ch -= ch > 64 ? 55 : 48; // hex2dec
|
75
|
|
- if (consumed % 2 == 0) {
|
76
|
|
- filter->data[filter->data_len ] += ch << 4;
|
77
|
|
- } else {
|
78
|
|
- filter->data[filter->data_len++] += ch;
|
79
|
|
- if (filter->data_len + 1 >= MAX_FILTER_LEN) {
|
80
|
|
- fprintf(stderr, "WARN : Too much filter data (max %d bytes), ignoring last bytes: %s\n",
|
81
|
|
- MAX_FILTER_LEN, data + i + 2);
|
82
|
|
- break;
|
83
|
|
- }
|
84
|
|
- }
|
85
|
|
- consumed++;
|
|
118
|
+ char *tokdata = strrchr(token2, '=');
|
|
119
|
+ if (tokdata) {
|
|
120
|
+ tokdata++; // Skip =
|
|
121
|
+ struct filter_data_map *m;
|
|
122
|
+ enum filter_token data_type = T_UNKNOWN;
|
|
123
|
+ for (m = data_tokens; m->token; m++) {
|
|
124
|
+ if (strstr(token2, m->token) == token2) {
|
|
125
|
+ data_type = m->type;
|
|
126
|
+ break;
|
86
|
127
|
}
|
87
|
|
- ret = filter->data_len;
|
88
|
|
- } else {
|
|
128
|
+ }
|
|
129
|
+ switch (data_type) {
|
|
130
|
+ case T_NAME:
|
|
131
|
+ snprintf(filter->name, sizeof(filter->name), "%s", tokdata);
|
|
132
|
+ break;
|
|
133
|
+ case T_OFFSET:
|
|
134
|
+ filter->offset = strtoul(tokdata, NULL, 0);
|
|
135
|
+ break;
|
|
136
|
+ case T_DATA:
|
|
137
|
+ ret = parse_hex(tokdata, filter->data, &filter->filter_len, MAX_FILTER_LEN);
|
|
138
|
+ break;
|
|
139
|
+ case T_MATCH:
|
|
140
|
+ filter->type = FILTER_TYPE_MASK;
|
|
141
|
+ ret = parse_hex(tokdata, filter->data, &filter->filter_len, MAX_FILTER_LEN);
|
|
142
|
+ break;
|
|
143
|
+ case T_MASK:
|
|
144
|
+ filter->type = FILTER_TYPE_MASK;
|
|
145
|
+ ret = parse_hex(tokdata, filter->mask, NULL, MAX_FILTER_LEN);
|
|
146
|
+ break;
|
|
147
|
+ default:
|
89
|
148
|
fprintf(stderr, "WARN : Unknown filter setting: %s\n", token2);
|
90
|
149
|
}
|
91
|
150
|
}
|
|
@@ -108,9 +167,17 @@ void filter_dump(struct filter *filter, char *buffer, unsigned int buf_len) {
|
108
|
167
|
if (filter->action == FILTER_ACCEPT || filter->action == FILTER_REJECT)
|
109
|
168
|
pos += snprintf(buffer + pos, buf_len - pos, " Name: %-20s", filter->name);
|
110
|
169
|
if (filter->action == FILTER_ACCEPT || filter->action == FILTER_REJECT) {
|
111
|
|
- char tmp[MAX_FILTER_LEN * 6];
|
112
|
|
- ts_hex_dump_buf(tmp, sizeof(tmp), filter->data, filter->data_len, 0);
|
113
|
|
- pos += snprintf(buffer + pos, buf_len - pos, " Offset: %2d Data: %s", filter->offset, tmp);
|
|
170
|
+ char tmp_data[MAX_FILTER_LEN * 6], tmp_mask[MAX_FILTER_LEN * 6];
|
|
171
|
+ ts_hex_dump_buf(tmp_data, sizeof(tmp_data), filter->data, filter->filter_len, 0);
|
|
172
|
+ switch (filter->type) {
|
|
173
|
+ case FILTER_TYPE_DATA:
|
|
174
|
+ pos += snprintf(buffer + pos, buf_len - pos, " Offset: %2d Data: %s", filter->offset, tmp_data);
|
|
175
|
+ break;
|
|
176
|
+ case FILTER_TYPE_MASK:
|
|
177
|
+ ts_hex_dump_buf(tmp_mask, sizeof(tmp_mask), filter->mask, filter->filter_len, 0);
|
|
178
|
+ pos += snprintf(buffer + pos, buf_len - pos, " Match: %s Mask: %s", tmp_data, tmp_mask);
|
|
179
|
+ break;
|
|
180
|
+ } // switch (filter->type)
|
114
|
181
|
}
|
115
|
182
|
}
|
116
|
183
|
|
|
@@ -118,10 +185,33 @@ static enum filter_action filter_match(uint8_t *data, unsigned int data_len, str
|
118
|
185
|
if (filter->action == FILTER_ACCEPT_ALL || filter->action == FILTER_REJECT_ALL)
|
119
|
186
|
return filter->action;
|
120
|
187
|
if (filter->action == FILTER_ACCEPT || filter->action == FILTER_REJECT) {
|
121
|
|
- if (filter->data_len + filter->offset > data_len)
|
122
|
|
- return FILTER_NO_MATCH;
|
123
|
|
- if (memcmp(data + filter->offset, filter->data, filter->data_len) == 0)
|
124
|
|
- return filter->action;
|
|
188
|
+ switch (filter->type) {
|
|
189
|
+ case FILTER_TYPE_DATA: {
|
|
190
|
+ if (filter->filter_len + filter->offset > data_len)
|
|
191
|
+ return FILTER_NO_MATCH;
|
|
192
|
+ if (memcmp(data + filter->offset, filter->data, filter->filter_len) == 0)
|
|
193
|
+ return filter->action;
|
|
194
|
+ break;
|
|
195
|
+ }
|
|
196
|
+ case FILTER_TYPE_MASK: {
|
|
197
|
+ if ((unsigned int)filter->filter_len + 3 > data_len)
|
|
198
|
+ return FILTER_NO_MATCH;
|
|
199
|
+ int matched = 0;
|
|
200
|
+ // Check data[0] against filter->data[0]
|
|
201
|
+ if ((data[0] & filter->mask[0]) == (filter->data[0] & filter->mask[0])) {
|
|
202
|
+ matched++;
|
|
203
|
+ int i;
|
|
204
|
+ for (i = 1; i < filter->filter_len; i++) {
|
|
205
|
+ // Check data[3...] against filter->data[1...]
|
|
206
|
+ if ((data[i + 2] & filter->mask[i]) == (filter->data[i] & filter->mask[i]))
|
|
207
|
+ matched++;
|
|
208
|
+ }
|
|
209
|
+ }
|
|
210
|
+ if (matched == filter->filter_len)
|
|
211
|
+ return filter->action;
|
|
212
|
+ break;
|
|
213
|
+ }
|
|
214
|
+ } // switch (filter->type)
|
125
|
215
|
}
|
126
|
216
|
return FILTER_NO_MATCH;
|
127
|
217
|
}
|