4
* Copyright (c) 2002 Dug Song <dugsong@monkey.org>
5
* Copyright (c) 2001 Jean-Baptiste Marchand, Herv� Schauer Consultants.
7
* $Id: fw-pktfilter.c,v 1.1 2004/01/07 00:02:15 dugsong Exp $
23
#define PKTFILTER_PIPE "\\\\.\\pipe\\PktFltPipe"
24
#define MAX_RULE_LENGTH 256
26
#define FILTER_FAILURE 0 /* filter had a syntax error */
27
#define FILTER_SUCCESS 1 /* filter was correctly added */
28
#define FILTER_MESSAGE 2 /* informative message returned to the client */
30
char *icmp_types[] = {
31
"echorep", /* 0: echo reply */
34
"unreach", /* 3: destination unreachable */
35
"squench", /* 4: source quench */
36
"redir", /* 5: redirect */
39
"echo", /* 8: echo request */
40
"router_adv", /* 9: router advertisement */
41
"router_sol", /* 10: router solicitation */
42
"timex", /* 11: time exceeded */
43
"paramprob", /* 12: parameter problem */
44
"timest", /* 13: timestamp request */
45
"timestrep", /* 14: timestamp reply */
46
"inforeq", /* 15: information request */
47
"inforep", /* 16: information reply */
48
"maskreq", /* 17: address mask request */
49
"maskrep", /* 18: address mask reply */
54
IP_ADAPTER_INFO *ifinfo;
55
/* XXX - rules cache for delete lookup? */
59
parse_addr(char *p, struct addr *a)
61
if (strcmp(p, "any") == 0)
62
return (addr_aton("0.0.0.0/0", a));
63
return (addr_aton(p, a));
67
parse_portspec(char *str, uint16_t *ports)
69
char *p = strsep(&str, " ");
72
ports[0] = ports[1] = atoi(strsep(&str, " "));
73
} else if (p[0] == '<') {
74
ports[1] = atoi(strsep(&str, " "));
75
if (p[1] != '=') ports[1]--;
76
} else if (p[0] == '>') {
77
ports[1] = TCP_PORT_MAX;
78
ports[0] = atoi(strsep(&str, " "));
79
if (p[1] != '=') ports[0]++;
80
} else if (p[0] != '\0') {
81
if (strcmp(strsep(&str, " "), "><") != 0)
83
ports[0] = atoi(p) + 1;
84
ports[1] = atoi(strsep(&str, " ")) - 1;
90
parse_icmpspec(char *str, uint16_t *type, uint16_t *code)
95
p = strsep(&str, " ");
96
for (i = 0; icmp_types[i] && strcmp(p, icmp_types[i]); i++)
98
if (icmp_types[i] == NULL) {
99
i = strtol(p, &e, 10);
106
p = strsep(&str, " ");
107
if (p != NULL && strcmp(p, "code")) {
108
p = strsep(&str, " ");
109
i = strtol(p, &e, 10);
119
<op> <dir> on <device> all
120
<op> <dir> on <device> proto <proto> all
121
<op> <dir> on <device> proto <proto> from <src> [ports] to <dst> [ports]
122
<op> <dir> on <device> proto icmp all [icmp-type <type> [code <code>]]
123
<op> <dir> on <device> proto icmp from <src> to <dst> [icmp-type <type> [code <code>]]
126
parse_rule(char *str, struct fw_rule *rule)
130
memset(rule, 0, sizeof(*rule));
133
p = strsep(&str, " ");
134
if (strcmp(p, "block") == 0)
135
rule->fw_op = FW_OP_BLOCK;
136
else if (strcmp(p, "pass") == 0)
137
rule->fw_op = FW_OP_ALLOW;
141
p = strsep(&str, " ");
142
if (strcmp(p, "in") == 0)
143
rule->fw_dir = FW_DIR_IN;
144
else if (strcmp(p, "out") == 0)
145
rule->fw_dir = FW_DIR_OUT;
149
if (strcmp(strsep(&str, " "), "on") != 0)
151
p = strsep(&str, " ");
152
/* XXX - handle bug in pktfltsrv.c */
153
if ((q = strstr(p, "proto")) != NULL)
155
if (strcmp(p, "all") != 0)
156
strlcpy(rule->fw_device, p, sizeof(rule->fw_device));
159
p = strsep(&str, " ");
160
/* XXX - handle bug in pktfltsrv.c */
161
if (strcmp(p, "proto") == 0)
162
p = strsep(&str, " ");
163
/* XXX - handle default rules */
164
if (strcmp(p, "all") == 0)
166
if (strcmp(p, "icmp") == 0)
167
rule->fw_proto = IP_PROTO_ICMP;
168
else if (strcmp(p, "tcp") == 0)
169
rule->fw_proto = IP_PROTO_TCP;
170
else if (strcmp(p, "udp") == 0)
171
rule->fw_proto = IP_PROTO_UDP;
172
else rule->fw_proto = atoi(p);
175
p = strsep(&str, " ");
176
if (strcmp(p, "all") == 0)
178
if (strcmp(p, "from") != 0)
180
p = strsep(&str, " ");
181
if (parse_addr(p, &rule->fw_src) < 0)
185
p = strsep(&str, " ");
186
if (strcmp(p, "port") == 0) {
187
if ((p = strstr(str, " to ")) == NULL)
190
if (parse_portspec(str, rule->fw_sport) < 0)
193
} else if (strcmp(p, "to") != 0)
197
p = strsep(&str, " ");
198
if (parse_addr(p, &rule->fw_dst) < 0)
201
/* destination port */
202
p = strsep(&str, " ");
203
if (strcmp(p, "port") == 0)
204
return (parse_portspec(str, rule->fw_dport));
207
/* icmp-type, code */
208
if (strcmp(p, "icmp-type") == 0) {
209
if (parse_icmpspec(str, rule->fw_sport, rule->fw_dport) < 0)
216
format_rule(const struct fw_rule *rule, char *buf, int len)
220
strlcpy(buf, (rule->fw_op == FW_OP_ALLOW) ? "pass " : "block ", len);
221
strlcat(buf, (rule->fw_dir == FW_DIR_IN) ? "in " : "out ", len);
222
snprintf(tmp, sizeof(tmp), "on %s ", rule->fw_device);
223
strlcat(buf, tmp, len);
224
if (rule->fw_proto != 0) {
225
snprintf(tmp, sizeof(tmp), "proto %d ", rule->fw_proto);
226
strlcat(buf, tmp, len);
229
if (rule->fw_src.addr_type != ADDR_TYPE_NONE) {
230
snprintf(tmp, sizeof(tmp), "from %s ",
231
addr_ntoa(&rule->fw_src));
232
strlcat(buf, tmp, len);
234
strlcat(buf, "from any ", len);
237
if (rule->fw_proto == IP_PROTO_TCP || rule->fw_proto == IP_PROTO_UDP) {
238
if (rule->fw_sport[0] == rule->fw_sport[1])
239
snprintf(tmp, sizeof(tmp), "port = %d ",
242
snprintf(tmp, sizeof(tmp), "port %d >< %d ",
243
rule->fw_sport[0] - 1, rule->fw_sport[1] + 1);
244
strlcat(buf, tmp, len);
247
if (rule->fw_dst.addr_type != ADDR_TYPE_NONE) {
248
snprintf(tmp, sizeof(tmp), "to %s ",
249
addr_ntoa(&rule->fw_dst));
250
strlcat(buf, tmp, len);
252
strlcat(buf, "to any ", len);
255
if (rule->fw_proto == IP_PROTO_TCP || rule->fw_proto == IP_PROTO_UDP) {
256
if (rule->fw_dport[0] == rule->fw_dport[1])
257
snprintf(tmp, sizeof(tmp), "port = %d",
260
snprintf(tmp, sizeof(tmp), "port %d >< %d",
261
rule->fw_dport[0] - 1, rule->fw_dport[1] + 1);
262
strlcat(buf, tmp, len);
263
} else if (rule->fw_proto == IP_PROTO_ICMP) {
264
if (rule->fw_sport[1]) {
265
snprintf(tmp, sizeof(tmp), "icmp-type %d",
267
strlcat(buf, tmp, len);
268
if (rule->fw_dport[1]) {
269
snprintf(tmp, sizeof(tmp), " code %d",
271
strlcat(buf, tmp, len);
275
return (strlen(buf));
279
call_pipe(const char *msg, int len)
283
char *p, *reply, status;
285
if (!WaitNamedPipe(PKTFILTER_PIPE, NMPWAIT_USE_DEFAULT_WAIT) ||
286
(pipe = CreateFile(PKTFILTER_PIPE, GENERIC_READ | GENERIC_WRITE,
287
0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) {
292
if (WriteFile(pipe, msg, len, &i, NULL)) {
293
if (ReadFile(pipe, &status, sizeof(status), &i, NULL)) {
294
if (status == FILTER_FAILURE) {
295
ReadFile(pipe, &status, sizeof(status),
297
} else if (status == FILTER_MESSAGE) {
299
if (ReadFile(pipe, &len, 4, &i, NULL)) {
301
p = reply = calloc(1, len + 1);
302
if (!ReadFile(pipe, reply, len,
308
} else if (status == FILTER_SUCCESS)
309
reply = strdup(""); /* XXX */
320
IP_ADAPTER_INFO *ifinfo;
323
if ((f = calloc(1, sizeof(*f))) == NULL)
326
size = sizeof(*f->ifinfo);
327
f->ifinfo = malloc(size);
328
if (GetAdaptersInfo(f->ifinfo, &size) != ERROR_SUCCESS) {
330
f->ifinfo = malloc(size);
331
GetAdaptersInfo(f->ifinfo, &size);
333
/* XXX - normalize interface names. */
334
for (ifinfo = f->ifinfo; ifinfo != NULL; ifinfo = ifinfo->Next) {
336
if (ifinfo->Type == MIB_IF_TYPE_ETHERNET)
338
else if (ifinfo->Type == MIB_IF_TYPE_PPP)
340
else if (ifinfo->Type == MIB_IF_TYPE_SLIP)
342
else if (ifinfo->Type == MIB_IF_TYPE_LOOPBACK)
344
else if (ifinfo->Type == MIB_IF_TYPE_TOKENRING)
346
else if (ifinfo->Type == MIB_IF_TYPE_FDDI)
350
sprintf(ifinfo->AdapterName, "%s%lu", fmt, ifinfo->ComboIndex);
356
fw_add(fw_t *f, const struct fw_rule *rule)
358
char *p, buf[MAX_RULE_LENGTH];
361
len = format_rule(rule, buf, sizeof(buf));
363
if ((p = call_pipe(buf, len)) == NULL)
370
fw_delete(fw_t *f, const struct fw_rule *rule)
373
char *p, *line, *msg, cmd[128], buf[MAX_RULE_LENGTH];
376
format_rule(rule, buf, sizeof(buf));
378
len = snprintf(cmd, sizeof(cmd), "List on %s", rule->fw_device);
379
if ((msg = call_pipe(cmd, len)) == NULL)
382
for (ruleno = 0, p = msg; (line = strsep(&p, "\r\n")) != NULL; ) {
383
if (strncmp(line, "rule ", 5) == 0) {
385
n = atoi(strsep(&line, ":"));
386
if (parse_rule(line + 1, &tmp) == 0 &&
387
memcmp(&tmp, rule, sizeof(tmp)) == 0) {
396
SetLastError(ERROR_NO_DATA);
399
len = snprintf(cmd, sizeof(cmd), "delete %d on %s",
400
ruleno, rule->fw_device);
401
if ((p = call_pipe(cmd, len)) == NULL)
409
fw_loop(fw_t *f, fw_handler callback, void *arg)
412
IP_ADAPTER_INFO *ifinfo;
413
char *p, *line, *msg, buf[MAX_RULE_LENGTH];
416
for (ret = 0, ifinfo = f->ifinfo; ret == 0 && ifinfo != NULL;
417
ifinfo = ifinfo->Next) {
418
len = snprintf(buf, sizeof(buf), "list on %s",
419
ifinfo->AdapterName);
420
if ((msg = call_pipe(buf, len)) == NULL)
424
for (p = msg; (line = strsep(&p, "\r\n")) != NULL; ) {
425
if (*line == '\0' || *line == '#' || isspace(*line))
427
if (parse_rule(line, &rule) == 0) {
428
if ((ret = callback(&rule, arg)) != 0)