~ubuntu-branches/ubuntu/jaunty/libdumbnet/jaunty

« back to all changes in this revision

Viewing changes to src/fw-pktfilter.c

  • Committer: Bazaar Package Importer
  • Author(s): Javier Fernandez-Sanguino Pen~a
  • Date: 2005-01-11 16:13:41 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050111161341-0a1we1xe03mnd2a1
Tags: 1.8-1.3
Fixed SONAME problem by fixing the -version-info number in
src/Makefile.am (Closes: #289777)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * fw-pktfilter.c
 
3
 *
 
4
 * Copyright (c) 2002 Dug Song <dugsong@monkey.org>
 
5
 * Copyright (c) 2001 Jean-Baptiste Marchand, Herv� Schauer Consultants.  
 
6
 *
 
7
 * $Id: fw-pktfilter.c,v 1.1 2004/01/07 00:02:15 dugsong Exp $
 
8
 */
 
9
 
 
10
#include "config.h"
 
11
 
 
12
#include <ws2tcpip.h>
 
13
#include <iphlpapi.h>
 
14
 
 
15
#include <ctype.h>
 
16
#include <errno.h>
 
17
#include <stdio.h>
 
18
#include <stdlib.h>
 
19
#include <string.h>
 
20
 
 
21
#include "dnet.h"
 
22
 
 
23
#define PKTFILTER_PIPE "\\\\.\\pipe\\PktFltPipe"        
 
24
#define MAX_RULE_LENGTH 256
 
25
 
 
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 */
 
29
 
 
30
char *icmp_types[] = {
 
31
        "echorep",      /* 0: echo reply */
 
32
        "",             /* 1: unused */
 
33
        "",             /* 2: unused */
 
34
        "unreach",      /* 3: destination unreachable */
 
35
        "squench",      /* 4: source quench */
 
36
        "redir",        /* 5: redirect */
 
37
        "",             /* 6: unused */
 
38
        "",             /* 7: unused */
 
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 */
 
50
        NULL
 
51
};
 
52
 
 
53
struct fw_handle {
 
54
        IP_ADAPTER_INFO *ifinfo;
 
55
        /* XXX - rules cache for delete lookup? */
 
56
};
 
57
 
 
58
static int
 
59
parse_addr(char *p, struct addr *a)
 
60
{
 
61
        if (strcmp(p, "any") == 0)
 
62
                return (addr_aton("0.0.0.0/0", a));
 
63
        return (addr_aton(p, a));
 
64
}
 
65
 
 
66
static int
 
67
parse_portspec(char *str, uint16_t *ports)
 
68
{
 
69
        char *p = strsep(&str, " ");
 
70
        
 
71
        if (p[0] == '=') {
 
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)
 
82
                        return (-1);
 
83
                ports[0] = atoi(p) + 1;
 
84
                ports[1] = atoi(strsep(&str, " ")) - 1;
 
85
        }
 
86
        return (0);
 
87
}
 
88
 
 
89
static int
 
90
parse_icmpspec(char *str, uint16_t *type, uint16_t *code)
 
91
{
 
92
        char *p, *e;
 
93
        int i;
 
94
 
 
95
        p = strsep(&str, " ");
 
96
        for (i = 0; icmp_types[i] && strcmp(p, icmp_types[i]); i++)
 
97
                ;
 
98
        if (icmp_types[i] == NULL) {
 
99
                i = strtol(p, &e, 10);
 
100
                if (*e != '\0')
 
101
                        return (-1);
 
102
        }
 
103
        type[0] = i;
 
104
        type[1] = 0xff;
 
105
        
 
106
        p = strsep(&str, " ");
 
107
        if (p != NULL && strcmp(p, "code")) {
 
108
                p = strsep(&str, " ");
 
109
                i = strtol(p, &e, 10);
 
110
                if (*e != '\0')
 
111
                        return (-1);
 
112
                code[0] = i;
 
113
                code[1] = 0xff;
 
114
        }
 
115
        return (0);
 
116
}
 
117
 
 
118
/*
 
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>]]
 
124
*/
 
125
static int
 
126
parse_rule(char *str, struct fw_rule *rule)
 
127
{
 
128
        char *p, *q;
 
129
        
 
130
        memset(rule, 0, sizeof(*rule));
 
131
        
 
132
        /* action */
 
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;
 
138
        else return (-1);
 
139
        
 
140
        /* direction */
 
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;
 
146
        else return (-1);
 
147
 
 
148
        /* device */
 
149
        if (strcmp(strsep(&str, " "), "on") != 0)
 
150
                return (-1);
 
151
        p = strsep(&str, " ");
 
152
        /* XXX - handle bug in pktfltsrv.c */
 
153
        if ((q = strstr(p, "proto")) != NULL)
 
154
                *q = '\0';
 
155
        if (strcmp(p, "all") != 0)
 
156
                strlcpy(rule->fw_device, p, sizeof(rule->fw_device));
 
157
        
 
158
        /* proto */
 
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)
 
165
                return (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);
 
173
        
 
174
        /* source */
 
175
        p = strsep(&str, " ");
 
176
        if (strcmp(p, "all") == 0)
 
177
                return (0);
 
178
        if (strcmp(p, "from") != 0)
 
179
                goto icmp_type_code;
 
180
        p = strsep(&str, " ");
 
181
        if (parse_addr(p, &rule->fw_src) < 0)
 
182
                return (-1);
 
183
        
 
184
        /* source port */
 
185
        p = strsep(&str, " ");
 
186
        if (strcmp(p, "port") == 0) {
 
187
                if ((p = strstr(str, " to ")) == NULL)
 
188
                        return (-1);
 
189
                *p++ = '\0';
 
190
                if (parse_portspec(str, rule->fw_sport) < 0)
 
191
                        return (-1);
 
192
                str = p + 3;
 
193
        } else if (strcmp(p, "to") != 0)
 
194
                return (-1);
 
195
        
 
196
        /* destination */
 
197
        p = strsep(&str, " ");
 
198
        if (parse_addr(p, &rule->fw_dst) < 0)
 
199
                return (-1);
 
200
 
 
201
        /* destination port */
 
202
        p = strsep(&str, " ");
 
203
        if (strcmp(p, "port") == 0)
 
204
                return (parse_portspec(str, rule->fw_dport));
 
205
 
 
206
 icmp_type_code:
 
207
        /* icmp-type, code */
 
208
        if (strcmp(p, "icmp-type") == 0) {
 
209
                if (parse_icmpspec(str, rule->fw_sport, rule->fw_dport) < 0)
 
210
                        return (-1);
 
211
        }
 
212
        return (0);
 
213
}
 
214
 
 
215
static int
 
216
format_rule(const struct fw_rule *rule, char *buf, int len)
 
217
{
 
218
        char tmp[128];
 
219
        
 
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);
 
227
        }
 
228
        /* source */
 
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);
 
233
        } else
 
234
                strlcat(buf, "from any ", len);
 
235
        
 
236
        /* sport */
 
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 ",
 
240
                            rule->fw_sport[0]);
 
241
                else
 
242
                        snprintf(tmp, sizeof(tmp), "port %d >< %d ",
 
243
                            rule->fw_sport[0] - 1, rule->fw_sport[1] + 1);
 
244
                strlcat(buf, tmp, len);
 
245
        }
 
246
        /* destination */
 
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);
 
251
        } else
 
252
                strlcat(buf, "to any ", len);
 
253
        
 
254
        /* dport */
 
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",
 
258
                            rule->fw_dport[0]);
 
259
                else
 
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",
 
266
                            rule->fw_sport[0]);
 
267
                        strlcat(buf, tmp, len);
 
268
                        if (rule->fw_dport[1]) {
 
269
                                snprintf(tmp, sizeof(tmp), " code %d",
 
270
                                    rule->fw_dport[0]);
 
271
                                strlcat(buf, tmp, len);
 
272
                        }
 
273
                }
 
274
        }
 
275
        return (strlen(buf));
 
276
}
 
277
 
 
278
static char *
 
279
call_pipe(const char *msg, int len)
 
280
{
 
281
        HANDLE *pipe;
 
282
        DWORD i;
 
283
        char *p, *reply, status;
 
284
        
 
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) {
 
288
                return (NULL);
 
289
        }
 
290
        reply = NULL;
 
291
        
 
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),
 
296
                                    &i, NULL);
 
297
                        } else if (status == FILTER_MESSAGE) {
 
298
                                /* get msg length */
 
299
                                if (ReadFile(pipe, &len, 4, &i, NULL)) {
 
300
                                        /* get msg */
 
301
                                        p = reply = calloc(1, len + 1);
 
302
                                        if (!ReadFile(pipe, reply, len,
 
303
                                                &i, NULL)) {
 
304
                                                free(reply);
 
305
                                                reply = NULL;
 
306
                                        }
 
307
                                }
 
308
                        } else if (status == FILTER_SUCCESS)
 
309
                                reply = strdup("");     /* XXX */
 
310
                }
 
311
        }
 
312
        CloseHandle(pipe);
 
313
        return (reply);
 
314
}
 
315
 
 
316
fw_t *
 
317
fw_open(void)
 
318
{
 
319
        fw_t *f;
 
320
        IP_ADAPTER_INFO *ifinfo;
 
321
        ULONG size;
 
322
        
 
323
        if ((f = calloc(1, sizeof(*f))) == NULL)
 
324
                return (NULL);
 
325
        
 
326
        size = sizeof(*f->ifinfo);
 
327
        f->ifinfo = malloc(size);
 
328
        if (GetAdaptersInfo(f->ifinfo, &size) != ERROR_SUCCESS) {
 
329
                free(f->ifinfo);
 
330
                f->ifinfo = malloc(size);
 
331
                GetAdaptersInfo(f->ifinfo, &size);
 
332
        }
 
333
        /* XXX - normalize interface names. */
 
334
        for (ifinfo = f->ifinfo; ifinfo != NULL; ifinfo = ifinfo->Next) {
 
335
                char *fmt;
 
336
                if (ifinfo->Type == MIB_IF_TYPE_ETHERNET)
 
337
                        fmt = "eth";
 
338
                else if (ifinfo->Type == MIB_IF_TYPE_PPP)
 
339
                        fmt = "ppp";
 
340
                else if (ifinfo->Type == MIB_IF_TYPE_SLIP)
 
341
                        fmt = "sl";
 
342
                else if (ifinfo->Type == MIB_IF_TYPE_LOOPBACK)
 
343
                        fmt = "lo";
 
344
                else if (ifinfo->Type == MIB_IF_TYPE_TOKENRING)
 
345
                        fmt = "tr";
 
346
                else if (ifinfo->Type == MIB_IF_TYPE_FDDI)
 
347
                        fmt = "fd";
 
348
                else 
 
349
                        fmt = "if";
 
350
                sprintf(ifinfo->AdapterName, "%s%lu", fmt, ifinfo->ComboIndex);
 
351
        }
 
352
        return (f);
 
353
}
 
354
 
 
355
int
 
356
fw_add(fw_t *f, const struct fw_rule *rule)
 
357
{
 
358
        char *p, buf[MAX_RULE_LENGTH];
 
359
        int len;
 
360
        
 
361
        len = format_rule(rule, buf, sizeof(buf));
 
362
        
 
363
        if ((p = call_pipe(buf, len)) == NULL)
 
364
                return (-1);
 
365
        free(p);
 
366
        return (0);
 
367
}
 
368
 
 
369
int
 
370
fw_delete(fw_t *f, const struct fw_rule *rule)
 
371
{
 
372
        struct fw_rule tmp;
 
373
        char *p, *line, *msg, cmd[128], buf[MAX_RULE_LENGTH];
 
374
        int n, ruleno, len;
 
375
        
 
376
        format_rule(rule, buf, sizeof(buf));
 
377
        
 
378
        len = snprintf(cmd, sizeof(cmd), "List on %s", rule->fw_device);
 
379
        if ((msg = call_pipe(cmd, len)) == NULL)
 
380
                return (-1);
 
381
 
 
382
        for (ruleno = 0, p = msg; (line = strsep(&p, "\r\n")) != NULL; ) {
 
383
                if (strncmp(line, "rule ", 5) == 0) {
 
384
                        line += 5;
 
385
                        n = atoi(strsep(&line, ":"));
 
386
                        if (parse_rule(line + 1, &tmp) == 0 &&
 
387
                            memcmp(&tmp, rule, sizeof(tmp)) == 0) {
 
388
                                ruleno = n;
 
389
                                break;
 
390
                        }
 
391
                }
 
392
        }
 
393
        free(msg);
 
394
        if (ruleno == 0) {
 
395
                errno = ENXIO;
 
396
                SetLastError(ERROR_NO_DATA);
 
397
                return (-1);
 
398
        }
 
399
        len = snprintf(cmd, sizeof(cmd), "delete %d on %s",
 
400
            ruleno, rule->fw_device);
 
401
        if ((p = call_pipe(cmd, len)) == NULL)
 
402
                return (-1);
 
403
        free(p);
 
404
 
 
405
        return (0);
 
406
}
 
407
 
 
408
int
 
409
fw_loop(fw_t *f, fw_handler callback, void *arg)
 
410
{
 
411
        struct fw_rule rule;
 
412
        IP_ADAPTER_INFO *ifinfo;
 
413
        char *p, *line, *msg, buf[MAX_RULE_LENGTH];
 
414
        int len, ret;
 
415
 
 
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)
 
421
                        return (-1);
 
422
                
 
423
                /* parse msg */
 
424
                for (p = msg; (line = strsep(&p, "\r\n")) != NULL; ) {
 
425
                        if (*line == '\0' || *line == '#' || isspace(*line))
 
426
                                continue;
 
427
                        if (parse_rule(line, &rule) == 0) {
 
428
                                if ((ret = callback(&rule, arg)) != 0)
 
429
                                        break;
 
430
                        }
 
431
                }
 
432
                free(msg);
 
433
        }
 
434
        return (ret);
 
435
}
 
436
 
 
437
fw_t *
 
438
fw_close(fw_t *f)
 
439
{
 
440
        if (f != NULL) {
 
441
                free(f->ifinfo);
 
442
                free(f);
 
443
        }
 
444
        return (NULL);
 
445
}