~ubuntu-branches/ubuntu/precise/iptables/precise-proposed

« back to all changes in this revision

Viewing changes to extensions/libipt_policy.c

  • Committer: Bazaar Package Importer
  • Author(s): Bhavani Shankar
  • Date: 2009-07-14 15:59:54 UTC
  • mfrom: (5.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20090714155954-9039kro8cnh6lb1q
Tags: 1.4.4-1ubuntu1
* Merge from debian unstable, remaining changes: LP: #399211
  - Don't fail to run iptables-save if iptables module isn't loaded.
  - debian/patches/0901-build-libipq_pic.a.patch - Build libipq_pic.a with
    -fPIC. Upstream changed build system and patch modified accordingly.
  - Revert changes between 1.4.1.1-3 and 1.4.1.1-4, thus bringing back
    the howtos.
  - Added linuxdoc-tools to Build-Depends
  - Modified debian/iptables{,-dev}.install to match DM syntax
    (removed debian/tmp)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Shared library add-on to iptables to add policy support. */
2
 
#include <stdio.h>
3
 
#include <netdb.h>
4
 
#include <string.h>
5
 
#include <stdlib.h>
6
 
#include <syslog.h>
7
 
#include <getopt.h>
8
 
#include <netdb.h>
9
 
#include <errno.h>
10
 
#include <sys/socket.h>
11
 
#include <netinet/in.h>
12
 
#include <arpa/inet.h>
13
 
#include <xtables.h>
14
 
 
15
 
#include <linux/netfilter_ipv4/ipt_policy.h>
16
 
 
17
 
/*
18
 
 * HACK: global pointer to current matchinfo for making
19
 
 * final checks and adjustments in final_check.
20
 
 */
21
 
static struct ipt_policy_info *policy_info;
22
 
 
23
 
static void policy_help(void)
24
 
{
25
 
        printf(
26
 
"policy match options:\n"
27
 
"  --dir in|out                 match policy applied during decapsulation/\n"
28
 
"                               policy to be applied during encapsulation\n"
29
 
"  --pol none|ipsec             match policy\n"
30
 
"  --strict                     match entire policy instead of single element\n"
31
 
"                               at any position\n"
32
 
"[!] --reqid reqid              match reqid\n"
33
 
"[!] --spi spi                  match SPI\n"
34
 
"[!] --proto proto              match protocol (ah/esp/ipcomp)\n"
35
 
"[!] --mode mode                match mode (transport/tunnel)\n"
36
 
"[!] --tunnel-src addr/mask     match tunnel source\n"
37
 
"[!] --tunnel-dst addr/mask     match tunnel destination\n"
38
 
"  --next                       begin next element in policy\n");
39
 
}
40
 
 
41
 
static const struct option policy_opts[] =
42
 
{
43
 
        {
44
 
                .name           = "dir",
45
 
                .has_arg        = 1,
46
 
                .val            = '1',
47
 
        },
48
 
        {
49
 
                .name           = "pol",
50
 
                .has_arg        = 1,
51
 
                .val            = '2',
52
 
        },
53
 
        {
54
 
                .name           = "strict",
55
 
                .val            = '3'
56
 
        },
57
 
        {
58
 
                .name           = "reqid",
59
 
                .has_arg        = 1,
60
 
                .val            = '4',
61
 
        },
62
 
        {
63
 
                .name           = "spi",
64
 
                .has_arg        = 1,
65
 
                .val            = '5'
66
 
        },
67
 
        {
68
 
                .name           = "tunnel-src",
69
 
                .has_arg        = 1,
70
 
                .val            = '6'
71
 
        },
72
 
        {
73
 
                .name           = "tunnel-dst",
74
 
                .has_arg        = 1,
75
 
                .val            = '7'
76
 
        },
77
 
        {
78
 
                .name           = "proto",
79
 
                .has_arg        = 1,
80
 
                .val            = '8'
81
 
        },
82
 
        {
83
 
                .name           = "mode",
84
 
                .has_arg        = 1,
85
 
                .val            = '9'
86
 
        },
87
 
        {
88
 
                .name           = "next",
89
 
                .val            = 'a'
90
 
        },
91
 
        { .name = NULL }
92
 
};
93
 
 
94
 
static int parse_direction(char *s)
95
 
{
96
 
        if (strcmp(s, "in") == 0)
97
 
                return IPT_POLICY_MATCH_IN;
98
 
        if (strcmp(s, "out") == 0)
99
 
                return IPT_POLICY_MATCH_OUT;
100
 
        xtables_error(PARAMETER_PROBLEM, "policy_match: invalid dir \"%s\"", s);
101
 
}
102
 
 
103
 
static int parse_policy(char *s)
104
 
{
105
 
        if (strcmp(s, "none") == 0)
106
 
                return IPT_POLICY_MATCH_NONE;
107
 
        if (strcmp(s, "ipsec") == 0)
108
 
                return 0;
109
 
        xtables_error(PARAMETER_PROBLEM, "policy match: invalid policy \"%s\"", s);
110
 
}
111
 
 
112
 
static int parse_mode(char *s)
113
 
{
114
 
        if (strcmp(s, "transport") == 0)
115
 
                return IPT_POLICY_MODE_TRANSPORT;
116
 
        if (strcmp(s, "tunnel") == 0)
117
 
                return IPT_POLICY_MODE_TUNNEL;
118
 
        xtables_error(PARAMETER_PROBLEM, "policy match: invalid mode \"%s\"", s);
119
 
}
120
 
 
121
 
static int policy_parse(int c, char **argv, int invert, unsigned int *flags,
122
 
                        const void *entry, struct xt_entry_match **match)
123
 
{
124
 
        struct ipt_policy_info *info = (void *)(*match)->data;
125
 
        struct ipt_policy_elem *e = &info->pol[info->len];
126
 
        struct in_addr *addr = NULL, mask;
127
 
        unsigned int naddr = 0, num;
128
 
        int mode;
129
 
 
130
 
        xtables_check_inverse(optarg, &invert, &optind, 0);
131
 
 
132
 
        switch (c) {
133
 
        case '1':
134
 
                if (info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))
135
 
                        xtables_error(PARAMETER_PROBLEM,
136
 
                                   "policy match: double --dir option");
137
 
                if (invert)
138
 
                        xtables_error(PARAMETER_PROBLEM,
139
 
                                   "policy match: can't invert --dir option");
140
 
 
141
 
                info->flags |= parse_direction(argv[optind-1]);
142
 
                break;
143
 
        case '2':
144
 
                if (invert)
145
 
                        xtables_error(PARAMETER_PROBLEM,
146
 
                                   "policy match: can't invert --policy option");
147
 
 
148
 
                info->flags |= parse_policy(argv[optind-1]);
149
 
                break;
150
 
        case '3':
151
 
                if (info->flags & IPT_POLICY_MATCH_STRICT)
152
 
                        xtables_error(PARAMETER_PROBLEM,
153
 
                                   "policy match: double --strict option");
154
 
 
155
 
                if (invert)
156
 
                        xtables_error(PARAMETER_PROBLEM,
157
 
                                   "policy match: can't invert --strict option");
158
 
 
159
 
                info->flags |= IPT_POLICY_MATCH_STRICT;
160
 
                break;
161
 
        case '4':
162
 
                if (e->match.reqid)
163
 
                        xtables_error(PARAMETER_PROBLEM,
164
 
                                   "policy match: double --reqid option");
165
 
 
166
 
                e->match.reqid = 1;
167
 
                e->invert.reqid = invert;
168
 
                if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
169
 
                        xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg);
170
 
                e->reqid = num;
171
 
                break;
172
 
        case '5':
173
 
                if (e->match.spi)
174
 
                        xtables_error(PARAMETER_PROBLEM,
175
 
                                   "policy match: double --spi option");
176
 
 
177
 
                e->match.spi = 1;
178
 
                e->invert.spi = invert;
179
 
                if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
180
 
                        xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg);
181
 
                e->spi = num;
182
 
                break;
183
 
        case '6':
184
 
                if (e->match.saddr)
185
 
                        xtables_error(PARAMETER_PROBLEM,
186
 
                                   "policy match: double --tunnel-src option");
187
 
 
188
 
                xtables_ipparse_any(argv[optind-1], &addr, &mask, &naddr);
189
 
                if (naddr > 1)
190
 
                        xtables_error(PARAMETER_PROBLEM,
191
 
                                   "policy match: name resolves to multiple IPs");
192
 
 
193
 
                e->match.saddr = 1;
194
 
                e->invert.saddr = invert;
195
 
                e->saddr.a4 = addr[0];
196
 
                e->smask.a4 = mask;
197
 
                break;
198
 
        case '7':
199
 
                if (e->match.daddr)
200
 
                        xtables_error(PARAMETER_PROBLEM,
201
 
                                   "policy match: double --tunnel-dst option");
202
 
 
203
 
                xtables_ipparse_any(argv[optind-1], &addr, &mask, &naddr);
204
 
                if (naddr > 1)
205
 
                        xtables_error(PARAMETER_PROBLEM,
206
 
                                   "policy match: name resolves to multiple IPs");
207
 
 
208
 
                e->match.daddr = 1;
209
 
                e->invert.daddr = invert;
210
 
                e->daddr.a4 = addr[0];
211
 
                e->dmask.a4 = mask;
212
 
                break;
213
 
        case '8':
214
 
                if (e->match.proto)
215
 
                        xtables_error(PARAMETER_PROBLEM,
216
 
                                   "policy match: double --proto option");
217
 
 
218
 
                e->proto = xtables_parse_protocol(argv[optind-1]);
219
 
                if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
220
 
                    e->proto != IPPROTO_COMP)
221
 
                        xtables_error(PARAMETER_PROBLEM,
222
 
                                   "policy match: protocol must ah/esp/ipcomp");
223
 
                e->match.proto = 1;
224
 
                e->invert.proto = invert;
225
 
                break;
226
 
        case '9':
227
 
                if (e->match.mode)
228
 
                        xtables_error(PARAMETER_PROBLEM,
229
 
                                   "policy match: double --mode option");
230
 
 
231
 
                mode = parse_mode(argv[optind-1]);
232
 
                e->match.mode = 1;
233
 
                e->invert.mode = invert;
234
 
                e->mode = mode;
235
 
                break;
236
 
        case 'a':
237
 
                if (invert)
238
 
                        xtables_error(PARAMETER_PROBLEM,
239
 
                                   "policy match: can't invert --next option");
240
 
 
241
 
                if (++info->len == IPT_POLICY_MAX_ELEM)
242
 
                        xtables_error(PARAMETER_PROBLEM,
243
 
                                   "policy match: maximum policy depth reached");
244
 
                break;
245
 
        default:
246
 
                return 0;
247
 
        }
248
 
 
249
 
        policy_info = info;
250
 
        return 1;
251
 
}
252
 
 
253
 
static void policy_check(unsigned int flags)
254
 
{
255
 
        struct ipt_policy_info *info = policy_info;
256
 
        struct ipt_policy_elem *e;
257
 
        int i;
258
 
 
259
 
        if (info == NULL)
260
 
                xtables_error(PARAMETER_PROBLEM,
261
 
                           "policy match: no parameters given");
262
 
 
263
 
        if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT)))
264
 
                xtables_error(PARAMETER_PROBLEM,
265
 
                           "policy match: neither --in nor --out specified");
266
 
 
267
 
        if (info->flags & IPT_POLICY_MATCH_NONE) {
268
 
                if (info->flags & IPT_POLICY_MATCH_STRICT)
269
 
                        xtables_error(PARAMETER_PROBLEM,
270
 
                                   "policy match: policy none but --strict given");
271
 
 
272
 
                if (info->len != 0)
273
 
                        xtables_error(PARAMETER_PROBLEM,
274
 
                                   "policy match: policy none but policy given");
275
 
        } else
276
 
                info->len++;    /* increase len by 1, no --next after last element */
277
 
 
278
 
        if (!(info->flags & IPT_POLICY_MATCH_STRICT) && info->len > 1)
279
 
                xtables_error(PARAMETER_PROBLEM,
280
 
                           "policy match: multiple elements but no --strict");
281
 
 
282
 
        for (i = 0; i < info->len; i++) {
283
 
                e = &info->pol[i];
284
 
 
285
 
                if (info->flags & IPT_POLICY_MATCH_STRICT &&
286
 
                    !(e->match.reqid || e->match.spi || e->match.saddr ||
287
 
                      e->match.daddr || e->match.proto || e->match.mode))
288
 
                        xtables_error(PARAMETER_PROBLEM,
289
 
                                   "policy match: empty policy element");
290
 
 
291
 
                if ((e->match.saddr || e->match.daddr)
292
 
                    && ((e->mode == IPT_POLICY_MODE_TUNNEL && e->invert.mode) ||
293
 
                        (e->mode == IPT_POLICY_MODE_TRANSPORT && !e->invert.mode)))
294
 
                        xtables_error(PARAMETER_PROBLEM,
295
 
                                   "policy match: --tunnel-src/--tunnel-dst "
296
 
                                   "is only valid in tunnel mode");
297
 
        }
298
 
}
299
 
 
300
 
static void print_mode(char *prefix, u_int8_t mode, int numeric)
301
 
{
302
 
        printf("%smode ", prefix);
303
 
 
304
 
        switch (mode) {
305
 
        case IPT_POLICY_MODE_TRANSPORT:
306
 
                printf("transport ");
307
 
                break;
308
 
        case IPT_POLICY_MODE_TUNNEL:
309
 
                printf("tunnel ");
310
 
                break;
311
 
        default:
312
 
                printf("??? ");
313
 
                break;
314
 
        }
315
 
}
316
 
 
317
 
static void print_proto(char *prefix, u_int8_t proto, int numeric)
318
 
{
319
 
        struct protoent *p = NULL;
320
 
 
321
 
        printf("%sproto ", prefix);
322
 
        if (!numeric)
323
 
                p = getprotobynumber(proto);
324
 
        if (p != NULL)
325
 
                printf("%s ", p->p_name);
326
 
        else
327
 
                printf("%u ", proto);
328
 
}
329
 
 
330
 
#define PRINT_INVERT(x)         \
331
 
do {                            \
332
 
        if (x)                  \
333
 
                printf("! ");   \
334
 
} while(0)
335
 
 
336
 
static void print_entry(char *prefix, const struct ipt_policy_elem *e,
337
 
                        int numeric)
338
 
{
339
 
        if (e->match.reqid) {
340
 
                PRINT_INVERT(e->invert.reqid);
341
 
                printf("%sreqid %u ", prefix, e->reqid);
342
 
        }
343
 
        if (e->match.spi) {
344
 
                PRINT_INVERT(e->invert.spi);
345
 
                printf("%sspi 0x%x ", prefix, e->spi);
346
 
        }
347
 
        if (e->match.proto) {
348
 
                PRINT_INVERT(e->invert.proto);
349
 
                print_proto(prefix, e->proto, numeric);
350
 
        }
351
 
        if (e->match.mode) {
352
 
                PRINT_INVERT(e->invert.mode);
353
 
                print_mode(prefix, e->mode, numeric);
354
 
        }
355
 
        if (e->match.daddr) {
356
 
                PRINT_INVERT(e->invert.daddr);
357
 
                printf("%stunnel-dst %s%s ", prefix,
358
 
                       xtables_ipaddr_to_numeric((const void *)&e->daddr),
359
 
                       xtables_ipmask_to_numeric((const void *)&e->dmask));
360
 
        }
361
 
        if (e->match.saddr) {
362
 
                PRINT_INVERT(e->invert.saddr);
363
 
                printf("%stunnel-src %s%s ", prefix,
364
 
                       xtables_ipaddr_to_numeric((const void *)&e->saddr),
365
 
                       xtables_ipmask_to_numeric((const void *)&e->smask));
366
 
        }
367
 
}
368
 
 
369
 
static void print_flags(char *prefix, const struct ipt_policy_info *info)
370
 
{
371
 
        if (info->flags & IPT_POLICY_MATCH_IN)
372
 
                printf("%sdir in ", prefix);
373
 
        else
374
 
                printf("%sdir out ", prefix);
375
 
 
376
 
        if (info->flags & IPT_POLICY_MATCH_NONE)
377
 
                printf("%spol none ", prefix);
378
 
        else
379
 
                printf("%spol ipsec ", prefix);
380
 
 
381
 
        if (info->flags & IPT_POLICY_MATCH_STRICT)
382
 
                printf("%sstrict ", prefix);
383
 
}
384
 
 
385
 
static void policy_print(const void *ip, const struct xt_entry_match *match,
386
 
                         int numeric)
387
 
{
388
 
        const struct ipt_policy_info *info = (void *)match->data;
389
 
        unsigned int i;
390
 
 
391
 
        printf("policy match ");
392
 
        print_flags("", info);
393
 
        for (i = 0; i < info->len; i++) {
394
 
                if (info->len > 1)
395
 
                        printf("[%u] ", i);
396
 
                print_entry("", &info->pol[i], numeric);
397
 
        }
398
 
}
399
 
 
400
 
static void policy_save(const void *ip, const struct xt_entry_match *match)
401
 
{
402
 
        const struct ipt_policy_info *info = (void *)match->data;
403
 
        unsigned int i;
404
 
 
405
 
        print_flags("--", info);
406
 
        for (i = 0; i < info->len; i++) {
407
 
                print_entry("--", &info->pol[i], 0);
408
 
                if (i + 1 < info->len)
409
 
                        printf("--next ");
410
 
        }
411
 
}
412
 
 
413
 
static struct xtables_match policy_mt_reg = {
414
 
        .name           = "policy",
415
 
        .version        = XTABLES_VERSION,
416
 
        .family         = NFPROTO_IPV4,
417
 
        .size           = XT_ALIGN(sizeof(struct ipt_policy_info)),
418
 
        .userspacesize  = XT_ALIGN(sizeof(struct ipt_policy_info)),
419
 
        .help           = policy_help,
420
 
        .parse          = policy_parse,
421
 
        .final_check    = policy_check,
422
 
        .print          = policy_print,
423
 
        .save           = policy_save,
424
 
        .extra_opts     = policy_opts,
425
 
};
426
 
 
427
 
void _init(void)
428
 
{
429
 
        xtables_register_match(&policy_mt_reg);
430
 
}