~ubuntu-branches/ubuntu/oneiric/collectd/oneiric

« back to all changes in this revision

Viewing changes to src/libiptc/libiptc.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Harl
  • Date: 2008-06-17 10:35:51 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080617103551-9d0ym3zejc7agtt3
Tags: 4.4.1-1
* New upstream release.
  - Fixed another issue of the sensors plugin affecting some chip types
    (Closes: #468143).
  - Fixed creation of "vserver" graphs in collection.cgi (Closes: #475120).
  - Fixed a segfault when using libperl 5.10.
  - collectd now ships libiptc itself.
  New plugins:
  - Ascent server statistics: ascent
  - IPMI sensors information: ipmi
  - PowerDNS name server statistics: powerdns
  - incremental parsing of logfiles: tail
  - TeamSpeak2 server statistics: teamspeak2
  - detailed virtual memory statistics: vmem
* Disable "tcpconns" plugin by default (Closes: #478759).
* Reenabled iptables plugin on all architectures (Closes: #473435).
  - Added the plugin to collectd.conf.
  - Added /usr/share/doc/collectd/examples/iptables/.
  - Added build dependency on linux-libc-dev (>= 2.6.25-4) - that version is
    required because of #479899.
* New debconf template translations:
  - gl.po, thanks to Jacobo Tarrio (Closes: #482667).
* Added a work around for #474087 (broken openipmi .pc files) by forcing the
  inclusion of the ipmi plugin and manually specifying the dependencies.
* Updated standards-version to 3.8.0 (no changes).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * This file was imported from the iptables sources.
 
3
 * Copyright (C) 1999-2008 Netfilter Core Team
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify it
 
6
 * under the terms of the GNU General Public License as published by the
 
7
 * Free Software Foundation; only version 2 of the License is applicable.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful, but
 
10
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License along
 
15
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
16
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
17
 */
 
18
 
 
19
/* Library which manipulates firewall rules.  Version $Revision: 7138 $ */
 
20
 
 
21
/* Architecture of firewall rules is as follows:
 
22
 *
 
23
 * Chains go INPUT, FORWARD, OUTPUT then user chains.
 
24
 * Each user chain starts with an ERROR node.
 
25
 * Every chain ends with an unconditional jump: a RETURN for user chains,
 
26
 * and a POLICY for built-ins.
 
27
 */
 
28
 
 
29
/* (C) 1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
 
30
 * COPYING for details). 
 
31
 * (C) 2000-2004 by the Netfilter Core Team <coreteam@netfilter.org>
 
32
 *
 
33
 * 2003-Jun-20: Harald Welte <laforge@netfilter.org>:
 
34
 *      - Reimplementation of chain cache to use offsets instead of entries
 
35
 * 2003-Jun-23: Harald Welte <laforge@netfilter.org>:
 
36
 *      - performance optimization, sponsored by Astaro AG (http://www.astaro.com/)
 
37
 *        don't rebuild the chain cache after every operation, instead fix it
 
38
 *        up after a ruleset change.  
 
39
 * 2004-Aug-18: Harald Welte <laforge@netfilter.org>:
 
40
 *      - futher performance work: total reimplementation of libiptc.
 
41
 *      - libiptc now has a real internal (linked-list) represntation of the
 
42
 *        ruleset and a parser/compiler from/to this internal representation
 
43
 *      - again sponsored by Astaro AG (http://www.astaro.com/)
 
44
 */
 
45
#include <sys/types.h>
 
46
#include <sys/socket.h>
 
47
 
 
48
#include "linux_list.h"
 
49
 
 
50
//#define IPTC_DEBUG2 1
 
51
 
 
52
#ifdef IPTC_DEBUG2
 
53
#include <fcntl.h>
 
54
#define DEBUGP(x, args...)      fprintf(stderr, "%s: " x, __FUNCTION__, ## args)
 
55
#define DEBUGP_C(x, args...)    fprintf(stderr, x, ## args)
 
56
#else
 
57
#define DEBUGP(x, args...)
 
58
#define DEBUGP_C(x, args...)
 
59
#endif
 
60
 
 
61
#ifndef IPT_LIB_DIR
 
62
#define IPT_LIB_DIR "/usr/local/lib/iptables"
 
63
#endif
 
64
 
 
65
static int sockfd = -1;
 
66
static int sockfd_use = 0;
 
67
static void *iptc_fn = NULL;
 
68
 
 
69
static const char *hooknames[] = {
 
70
        [HOOK_PRE_ROUTING]      = "PREROUTING",
 
71
        [HOOK_LOCAL_IN]         = "INPUT",
 
72
        [HOOK_FORWARD]          = "FORWARD",
 
73
        [HOOK_LOCAL_OUT]        = "OUTPUT",
 
74
        [HOOK_POST_ROUTING]     = "POSTROUTING",
 
75
#ifdef HOOK_DROPPING
 
76
        [HOOK_DROPPING]         = "DROPPING"
 
77
#endif
 
78
};
 
79
 
 
80
/* Convenience structures */
 
81
struct ipt_error_target
 
82
{
 
83
        STRUCT_ENTRY_TARGET t;
 
84
        char error[TABLE_MAXNAMELEN];
 
85
};
 
86
 
 
87
struct chain_head;
 
88
struct rule_head;
 
89
 
 
90
struct counter_map
 
91
{
 
92
        enum {
 
93
                COUNTER_MAP_NOMAP,
 
94
                COUNTER_MAP_NORMAL_MAP,
 
95
                COUNTER_MAP_ZEROED,
 
96
                COUNTER_MAP_SET
 
97
        } maptype;
 
98
        unsigned int mappos;
 
99
};
 
100
 
 
101
enum iptcc_rule_type {
 
102
        IPTCC_R_STANDARD,               /* standard target (ACCEPT, ...) */
 
103
        IPTCC_R_MODULE,                 /* extension module (SNAT, ...) */
 
104
        IPTCC_R_FALLTHROUGH,            /* fallthrough rule */
 
105
        IPTCC_R_JUMP,                   /* jump to other chain */
 
106
};
 
107
 
 
108
struct rule_head
 
109
{
 
110
        struct list_head list;
 
111
        struct chain_head *chain;
 
112
        struct counter_map counter_map;
 
113
 
 
114
        unsigned int index;             /* index (needed for counter_map) */
 
115
        unsigned int offset;            /* offset in rule blob */
 
116
 
 
117
        enum iptcc_rule_type type;
 
118
        struct chain_head *jump;        /* jump target, if IPTCC_R_JUMP */
 
119
 
 
120
        unsigned int size;              /* size of entry data */
 
121
        STRUCT_ENTRY entry[0];
 
122
};
 
123
 
 
124
struct chain_head
 
125
{
 
126
        struct list_head list;
 
127
        char name[TABLE_MAXNAMELEN];
 
128
        unsigned int hooknum;           /* hook number+1 if builtin */
 
129
        unsigned int references;        /* how many jumps reference us */
 
130
        int verdict;                    /* verdict if builtin */
 
131
 
 
132
        STRUCT_COUNTERS counters;       /* per-chain counters */
 
133
        struct counter_map counter_map;
 
134
 
 
135
        unsigned int num_rules;         /* number of rules in list */
 
136
        struct list_head rules;         /* list of rules */
 
137
 
 
138
        unsigned int index;             /* index (needed for jump resolval) */
 
139
        unsigned int head_offset;       /* offset in rule blob */
 
140
        unsigned int foot_index;        /* index (needed for counter_map) */
 
141
        unsigned int foot_offset;       /* offset in rule blob */
 
142
};
 
143
 
 
144
STRUCT_TC_HANDLE
 
145
{
 
146
        int changed;                     /* Have changes been made? */
 
147
 
 
148
        struct list_head chains;
 
149
        
 
150
        struct chain_head *chain_iterator_cur;
 
151
        struct rule_head *rule_iterator_cur;
 
152
 
 
153
        STRUCT_GETINFO info;
 
154
        STRUCT_GET_ENTRIES *entries;
 
155
};
 
156
 
 
157
/* allocate a new chain head for the cache */
 
158
static struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
 
159
{
 
160
        struct chain_head *c = malloc(sizeof(*c));
 
161
        if (!c)
 
162
                return NULL;
 
163
        memset(c, 0, sizeof(*c));
 
164
 
 
165
        strncpy(c->name, name, TABLE_MAXNAMELEN);
 
166
        c->hooknum = hooknum;
 
167
        INIT_LIST_HEAD(&c->rules);
 
168
 
 
169
        return c;
 
170
}
 
171
 
 
172
/* allocate and initialize a new rule for the cache */
 
173
static struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int size)
 
174
{
 
175
        struct rule_head *r = malloc(sizeof(*r)+size);
 
176
        if (!r)
 
177
                return NULL;
 
178
        memset(r, 0, sizeof(*r));
 
179
 
 
180
        r->chain = c;
 
181
        r->size = size;
 
182
 
 
183
        return r;
 
184
}
 
185
 
 
186
/* notify us that the ruleset has been modified by the user */
 
187
static void
 
188
set_changed(TC_HANDLE_T h)
 
189
{
 
190
        h->changed = 1;
 
191
}
 
192
 
 
193
#ifdef IPTC_DEBUG
 
194
static void do_check(TC_HANDLE_T h, unsigned int line);
 
195
#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
 
196
#else
 
197
#define CHECK(h)
 
198
#endif
 
199
 
 
200
 
 
201
/**********************************************************************
 
202
 * iptc blob utility functions (iptcb_*)
 
203
 **********************************************************************/
 
204
 
 
205
static inline int
 
206
iptcb_get_number(const STRUCT_ENTRY *i,
 
207
           const STRUCT_ENTRY *seek,
 
208
           unsigned int *pos)
 
209
{
 
210
        if (i == seek)
 
211
                return 1;
 
212
        (*pos)++;
 
213
        return 0;
 
214
}
 
215
 
 
216
static inline int
 
217
iptcb_get_entry_n(STRUCT_ENTRY *i,
 
218
            unsigned int number,
 
219
            unsigned int *pos,
 
220
            STRUCT_ENTRY **pe)
 
221
{
 
222
        if (*pos == number) {
 
223
                *pe = i;
 
224
                return 1;
 
225
        }
 
226
        (*pos)++;
 
227
        return 0;
 
228
}
 
229
 
 
230
static inline STRUCT_ENTRY *
 
231
iptcb_get_entry(TC_HANDLE_T h, unsigned int offset)
 
232
{
 
233
        return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset);
 
234
}
 
235
 
 
236
static unsigned int
 
237
iptcb_entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
 
238
{
 
239
        unsigned int pos = 0;
 
240
 
 
241
        if (ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
 
242
                          iptcb_get_number, seek, &pos) == 0) {
 
243
                fprintf(stderr, "ERROR: offset %u not an entry!\n",
 
244
                        (unsigned int)((char *)seek - (char *)h->entries->entrytable));
 
245
                abort();
 
246
        }
 
247
        return pos;
 
248
}
 
249
 
 
250
static inline STRUCT_ENTRY *
 
251
iptcb_offset2entry(TC_HANDLE_T h, unsigned int offset)
 
252
{
 
253
        return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset);
 
254
}
 
255
 
 
256
 
 
257
static inline unsigned long
 
258
iptcb_entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
 
259
{
 
260
        return (void *)e - (void *)h->entries->entrytable;
 
261
}
 
262
 
 
263
static inline unsigned int
 
264
iptcb_offset2index(const TC_HANDLE_T h, unsigned int offset)
 
265
{
 
266
        return iptcb_entry2index(h, iptcb_offset2entry(h, offset));
 
267
}
 
268
 
 
269
/* Returns 0 if not hook entry, else hooknumber + 1 */
 
270
static inline unsigned int
 
271
iptcb_ent_is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
 
272
{
 
273
        unsigned int i;
 
274
 
 
275
        for (i = 0; i < NUMHOOKS; i++) {
 
276
                if ((h->info.valid_hooks & (1 << i))
 
277
                    && iptcb_get_entry(h, h->info.hook_entry[i]) == e)
 
278
                        return i+1;
 
279
        }
 
280
        return 0;
 
281
}
 
282
 
 
283
 
 
284
/**********************************************************************
 
285
 * iptc cache utility functions (iptcc_*)
 
286
 **********************************************************************/
 
287
 
 
288
/* Is the given chain builtin (1) or user-defined (0) */
 
289
static unsigned int iptcc_is_builtin(struct chain_head *c)
 
290
{
 
291
        return (c->hooknum ? 1 : 0);
 
292
}
 
293
 
 
294
/* Get a specific rule within a chain */
 
295
static struct rule_head *iptcc_get_rule_num(struct chain_head *c,
 
296
                                            unsigned int rulenum)
 
297
{
 
298
        struct rule_head *r;
 
299
        unsigned int num = 0;
 
300
 
 
301
        list_for_each_entry(r, &c->rules, list) {
 
302
                num++;
 
303
                if (num == rulenum)
 
304
                        return r;
 
305
        }
 
306
        return NULL;
 
307
}
 
308
 
 
309
/* Get a specific rule within a chain backwards */
 
310
static struct rule_head *iptcc_get_rule_num_reverse(struct chain_head *c,
 
311
                                            unsigned int rulenum)
 
312
{
 
313
        struct rule_head *r;
 
314
        unsigned int num = 0;
 
315
 
 
316
        list_for_each_entry_reverse(r, &c->rules, list) {
 
317
                num++;
 
318
                if (num == rulenum)
 
319
                        return r;
 
320
        }
 
321
        return NULL;
 
322
}
 
323
 
 
324
/* Returns chain head if found, otherwise NULL. */
 
325
static struct chain_head *
 
326
iptcc_find_chain_by_offset(TC_HANDLE_T handle, unsigned int offset)
 
327
{
 
328
        struct list_head *pos;
 
329
 
 
330
        if (list_empty(&handle->chains))
 
331
                return NULL;
 
332
 
 
333
        list_for_each(pos, &handle->chains) {
 
334
                struct chain_head *c = list_entry(pos, struct chain_head, list);
 
335
                if (offset >= c->head_offset && offset <= c->foot_offset)
 
336
                        return c;
 
337
        }
 
338
 
 
339
        return NULL;
 
340
}
 
341
/* Returns chain head if found, otherwise NULL. */
 
342
static struct chain_head *
 
343
iptcc_find_label(const char *name, TC_HANDLE_T handle)
 
344
{
 
345
        struct list_head *pos;
 
346
 
 
347
        if (list_empty(&handle->chains))
 
348
                return NULL;
 
349
 
 
350
        list_for_each(pos, &handle->chains) {
 
351
                struct chain_head *c = list_entry(pos, struct chain_head, list);
 
352
                if (!strcmp(c->name, name))
 
353
                        return c;
 
354
        }
 
355
 
 
356
        return NULL;
 
357
}
 
358
 
 
359
/* called when rule is to be removed from cache */
 
360
static void iptcc_delete_rule(struct rule_head *r)
 
361
{
 
362
        DEBUGP("deleting rule %p (offset %u)\n", r, r->offset);
 
363
        /* clean up reference count of called chain */
 
364
        if (r->type == IPTCC_R_JUMP
 
365
            && r->jump)
 
366
                r->jump->references--;
 
367
 
 
368
        list_del(&r->list);
 
369
        free(r);
 
370
}
 
371
 
 
372
 
 
373
/**********************************************************************
 
374
 * RULESET PARSER (blob -> cache)
 
375
 **********************************************************************/
 
376
 
 
377
/* Delete policy rule of previous chain, since cache doesn't contain
 
378
 * chain policy rules.
 
379
 * WARNING: This function has ugly design and relies on a lot of context, only
 
380
 * to be called from specific places within the parser */
 
381
static int __iptcc_p_del_policy(TC_HANDLE_T h, unsigned int num)
 
382
{
 
383
        if (h->chain_iterator_cur) {
 
384
                /* policy rule is last rule */
 
385
                struct rule_head *pr = (struct rule_head *)
 
386
                        h->chain_iterator_cur->rules.prev;
 
387
 
 
388
                /* save verdict */
 
389
                h->chain_iterator_cur->verdict = 
 
390
                        *(int *)GET_TARGET(pr->entry)->data;
 
391
 
 
392
                /* save counter and counter_map information */
 
393
                h->chain_iterator_cur->counter_map.maptype = 
 
394
                                                COUNTER_MAP_NORMAL_MAP;
 
395
                h->chain_iterator_cur->counter_map.mappos = num-1;
 
396
                memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters, 
 
397
                        sizeof(h->chain_iterator_cur->counters));
 
398
 
 
399
                /* foot_offset points to verdict rule */
 
400
                h->chain_iterator_cur->foot_index = num;
 
401
                h->chain_iterator_cur->foot_offset = pr->offset;
 
402
 
 
403
                /* delete rule from cache */
 
404
                iptcc_delete_rule(pr);
 
405
                h->chain_iterator_cur->num_rules--;
 
406
 
 
407
                return 1;
 
408
        }
 
409
        return 0;
 
410
}
 
411
 
 
412
/* alphabetically insert a chain into the list */
 
413
static inline void iptc_insert_chain(TC_HANDLE_T h, struct chain_head *c)
 
414
{
 
415
        struct chain_head *tmp;
 
416
 
 
417
        /* sort only user defined chains */
 
418
        if (!c->hooknum) {
 
419
                list_for_each_entry(tmp, &h->chains, list) {
 
420
                        if (!tmp->hooknum && strcmp(c->name, tmp->name) <= 0) {
 
421
                                list_add(&c->list, tmp->list.prev);
 
422
                                return;
 
423
                        }
 
424
                }
 
425
        }
 
426
 
 
427
        /* survived till end of list: add at tail */
 
428
        list_add_tail(&c->list, &h->chains);
 
429
}
 
430
 
 
431
/* Another ugly helper function split out of cache_add_entry to make it less
 
432
 * spaghetti code */
 
433
static void __iptcc_p_add_chain(TC_HANDLE_T h, struct chain_head *c,
 
434
                                unsigned int offset, unsigned int *num)
 
435
{
 
436
        struct list_head  *tail = h->chains.prev;
 
437
        struct chain_head *ctail;
 
438
 
 
439
        __iptcc_p_del_policy(h, *num);
 
440
 
 
441
        c->head_offset = offset;
 
442
        c->index = *num;
 
443
 
 
444
        /* Chains from kernel are already sorted, as they are inserted
 
445
         * sorted. But there exists an issue when shifting to 1.4.0
 
446
         * from an older version, as old versions allow last created
 
447
         * chain to be unsorted.
 
448
         */
 
449
        if (iptcc_is_builtin(c)) /* Only user defined chains are sorted*/
 
450
                list_add_tail(&c->list, &h->chains);
 
451
        else {
 
452
                ctail = list_entry(tail, struct chain_head, list);
 
453
                if (strcmp(c->name, ctail->name) > 0)
 
454
                        list_add_tail(&c->list, &h->chains);/* Already sorted*/
 
455
                else
 
456
                        iptc_insert_chain(h, c);/* Was not sorted */
 
457
        }
 
458
 
 
459
        h->chain_iterator_cur = c;
 
460
}
 
461
 
 
462
/* main parser function: add an entry from the blob to the cache */
 
463
static int cache_add_entry(STRUCT_ENTRY *e, 
 
464
                           TC_HANDLE_T h, 
 
465
                           STRUCT_ENTRY **prev,
 
466
                           unsigned int *num)
 
467
{
 
468
        unsigned int builtin;
 
469
        unsigned int offset = (char *)e - (char *)h->entries->entrytable;
 
470
 
 
471
        DEBUGP("entering...");
 
472
 
 
473
        /* Last entry ("policy rule"). End it.*/
 
474
        if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) {
 
475
                /* This is the ERROR node at the end of the chain */
 
476
                DEBUGP_C("%u:%u: end of table:\n", *num, offset);
 
477
 
 
478
                __iptcc_p_del_policy(h, *num);
 
479
 
 
480
                h->chain_iterator_cur = NULL;
 
481
                goto out_inc;
 
482
        }
 
483
 
 
484
        /* We know this is the start of a new chain if it's an ERROR
 
485
         * target, or a hook entry point */
 
486
 
 
487
        if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
 
488
                struct chain_head *c = 
 
489
                        iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0);
 
490
                DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset, 
 
491
                        (char *)c->name, c);
 
492
                if (!c) {
 
493
                        errno = -ENOMEM;
 
494
                        return -1;
 
495
                }
 
496
 
 
497
                __iptcc_p_add_chain(h, c, offset, num);
 
498
 
 
499
        } else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) {
 
500
                struct chain_head *c =
 
501
                        iptcc_alloc_chain_head((char *)hooknames[builtin-1], 
 
502
                                                builtin);
 
503
                DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n", 
 
504
                        *num, offset, c, &c->rules);
 
505
                if (!c) {
 
506
                        errno = -ENOMEM;
 
507
                        return -1;
 
508
                }
 
509
 
 
510
                c->hooknum = builtin;
 
511
 
 
512
                __iptcc_p_add_chain(h, c, offset, num);
 
513
 
 
514
                /* FIXME: this is ugly. */
 
515
                goto new_rule;
 
516
        } else {
 
517
                /* has to be normal rule */
 
518
                struct rule_head *r;
 
519
new_rule:
 
520
 
 
521
                if (!(r = iptcc_alloc_rule(h->chain_iterator_cur, 
 
522
                                           e->next_offset))) {
 
523
                        errno = ENOMEM;
 
524
                        return -1;
 
525
                }
 
526
                DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
 
527
 
 
528
                r->index = *num;
 
529
                r->offset = offset;
 
530
                memcpy(r->entry, e, e->next_offset);
 
531
                r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP;
 
532
                r->counter_map.mappos = r->index;
 
533
 
 
534
                /* handling of jumps, etc. */
 
535
                if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) {
 
536
                        STRUCT_STANDARD_TARGET *t;
 
537
 
 
538
                        t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
 
539
                        if (t->target.u.target_size
 
540
                            != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
 
541
                                errno = EINVAL;
 
542
                                return -1;
 
543
                        }
 
544
 
 
545
                        if (t->verdict < 0) {
 
546
                                DEBUGP_C("standard, verdict=%d\n", t->verdict);
 
547
                                r->type = IPTCC_R_STANDARD;
 
548
                        } else if (t->verdict == r->offset+e->next_offset) {
 
549
                                DEBUGP_C("fallthrough\n");
 
550
                                r->type = IPTCC_R_FALLTHROUGH;
 
551
                        } else {
 
552
                                DEBUGP_C("jump, target=%u\n", t->verdict);
 
553
                                r->type = IPTCC_R_JUMP;
 
554
                                /* Jump target fixup has to be deferred
 
555
                                 * until second pass, since we migh not
 
556
                                 * yet have parsed the target */
 
557
                        }
 
558
                } else {
 
559
                        DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name);
 
560
                        r->type = IPTCC_R_MODULE;
 
561
                }
 
562
 
 
563
                list_add_tail(&r->list, &h->chain_iterator_cur->rules);
 
564
                h->chain_iterator_cur->num_rules++;
 
565
        }
 
566
out_inc:
 
567
        (*num)++;
 
568
        return 0;
 
569
}
 
570
 
 
571
 
 
572
/* parse an iptables blob into it's pieces */
 
573
static int parse_table(TC_HANDLE_T h)
 
574
{
 
575
        STRUCT_ENTRY *prev;
 
576
        unsigned int num = 0;
 
577
        struct chain_head *c;
 
578
 
 
579
        /* First pass: over ruleset blob */
 
580
        ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
 
581
                        cache_add_entry, h, &prev, &num);
 
582
 
 
583
        /* Second pass: fixup parsed data from first pass */
 
584
        list_for_each_entry(c, &h->chains, list) {
 
585
                struct rule_head *r;
 
586
                list_for_each_entry(r, &c->rules, list) {
 
587
                        struct chain_head *c;
 
588
                        STRUCT_STANDARD_TARGET *t;
 
589
 
 
590
                        if (r->type != IPTCC_R_JUMP)
 
591
                                continue;
 
592
 
 
593
                        t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
 
594
                        c = iptcc_find_chain_by_offset(h, t->verdict);
 
595
                        if (!c)
 
596
                                return -1;
 
597
                        r->jump = c;
 
598
                        c->references++;
 
599
                }
 
600
        }
 
601
 
 
602
        /* FIXME: sort chains */
 
603
 
 
604
        return 1;
 
605
}
 
606
 
 
607
 
 
608
/**********************************************************************
 
609
 * RULESET COMPILATION (cache -> blob)
 
610
 **********************************************************************/
 
611
 
 
612
/* Convenience structures */
 
613
struct iptcb_chain_start{
 
614
        STRUCT_ENTRY e;
 
615
        struct ipt_error_target name;
 
616
};
 
617
#define IPTCB_CHAIN_START_SIZE  (sizeof(STRUCT_ENTRY) +                 \
 
618
                                 ALIGN(sizeof(struct ipt_error_target)))
 
619
 
 
620
struct iptcb_chain_foot {
 
621
        STRUCT_ENTRY e;
 
622
        STRUCT_STANDARD_TARGET target;
 
623
};
 
624
#define IPTCB_CHAIN_FOOT_SIZE   (sizeof(STRUCT_ENTRY) +                 \
 
625
                                 ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
 
626
 
 
627
struct iptcb_chain_error {
 
628
        STRUCT_ENTRY entry;
 
629
        struct ipt_error_target target;
 
630
};
 
631
#define IPTCB_CHAIN_ERROR_SIZE  (sizeof(STRUCT_ENTRY) +                 \
 
632
                                 ALIGN(sizeof(struct ipt_error_target)))
 
633
 
 
634
 
 
635
 
 
636
/* compile rule from cache into blob */
 
637
static inline int iptcc_compile_rule (TC_HANDLE_T h, STRUCT_REPLACE *repl, struct rule_head *r)
 
638
{
 
639
        /* handle jumps */
 
640
        if (r->type == IPTCC_R_JUMP) {
 
641
                STRUCT_STANDARD_TARGET *t;
 
642
                t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
 
643
                /* memset for memcmp convenience on delete/replace */
 
644
                memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
 
645
                strcpy(t->target.u.user.name, STANDARD_TARGET);
 
646
                /* Jumps can only happen to builtin chains, so we
 
647
                 * can safely assume that they always have a header */
 
648
                t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE;
 
649
        } else if (r->type == IPTCC_R_FALLTHROUGH) {
 
650
                STRUCT_STANDARD_TARGET *t;
 
651
                t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
 
652
                t->verdict = r->offset + r->size;
 
653
        }
 
654
        
 
655
        /* copy entry from cache to blob */
 
656
        memcpy((char *)repl->entries+r->offset, r->entry, r->size);
 
657
 
 
658
        return 1;
 
659
}
 
660
 
 
661
/* compile chain from cache into blob */
 
662
static int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain_head *c)
 
663
{
 
664
        int ret;
 
665
        struct rule_head *r;
 
666
        struct iptcb_chain_start *head;
 
667
        struct iptcb_chain_foot *foot;
 
668
 
 
669
        /* only user-defined chains have heaer */
 
670
        if (!iptcc_is_builtin(c)) {
 
671
                /* put chain header in place */
 
672
                head = (void *)repl->entries + c->head_offset;
 
673
                head->e.target_offset = sizeof(STRUCT_ENTRY);
 
674
                head->e.next_offset = IPTCB_CHAIN_START_SIZE;
 
675
                strcpy(head->name.t.u.user.name, ERROR_TARGET);
 
676
                head->name.t.u.target_size = 
 
677
                                ALIGN(sizeof(struct ipt_error_target));
 
678
                strcpy(head->name.error, c->name);
 
679
        } else {
 
680
                repl->hook_entry[c->hooknum-1] = c->head_offset;        
 
681
                repl->underflow[c->hooknum-1] = c->foot_offset;
 
682
        }
 
683
 
 
684
        /* iterate over rules */
 
685
        list_for_each_entry(r, &c->rules, list) {
 
686
                ret = iptcc_compile_rule(h, repl, r);
 
687
                if (ret < 0)
 
688
                        return ret;
 
689
        }
 
690
 
 
691
        /* put chain footer in place */
 
692
        foot = (void *)repl->entries + c->foot_offset;
 
693
        foot->e.target_offset = sizeof(STRUCT_ENTRY);
 
694
        foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE;
 
695
        strcpy(foot->target.target.u.user.name, STANDARD_TARGET);
 
696
        foot->target.target.u.target_size =
 
697
                                ALIGN(sizeof(STRUCT_STANDARD_TARGET));
 
698
        /* builtin targets have verdict, others return */
 
699
        if (iptcc_is_builtin(c))
 
700
                foot->target.verdict = c->verdict;
 
701
        else
 
702
                foot->target.verdict = RETURN;
 
703
        /* set policy-counters */
 
704
        memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
 
705
 
 
706
        return 0;
 
707
}
 
708
 
 
709
/* calculate offset and number for every rule in the cache */
 
710
static int iptcc_compile_chain_offsets(TC_HANDLE_T h, struct chain_head *c,
 
711
                                       unsigned int *offset, unsigned int *num)
 
712
{
 
713
        struct rule_head *r;
 
714
 
 
715
        c->head_offset = *offset;
 
716
        DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset);
 
717
 
 
718
        if (!iptcc_is_builtin(c))  {
 
719
                /* Chain has header */
 
720
                *offset += sizeof(STRUCT_ENTRY) 
 
721
                             + ALIGN(sizeof(struct ipt_error_target));
 
722
                (*num)++;
 
723
        }
 
724
 
 
725
        list_for_each_entry(r, &c->rules, list) {
 
726
                DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num);
 
727
                r->offset = *offset;
 
728
                r->index = *num;
 
729
                *offset += r->size;
 
730
                (*num)++;
 
731
        }
 
732
 
 
733
        DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num, 
 
734
                *offset, *num);
 
735
        c->foot_offset = *offset;
 
736
        c->foot_index = *num;
 
737
        *offset += sizeof(STRUCT_ENTRY)
 
738
                   + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
 
739
        (*num)++;
 
740
 
 
741
        return 1;
 
742
}
 
743
 
 
744
/* put the pieces back together again */
 
745
static int iptcc_compile_table_prep(TC_HANDLE_T h, unsigned int *size)
 
746
{
 
747
        struct chain_head *c;
 
748
        unsigned int offset = 0, num = 0;
 
749
        int ret = 0;
 
750
 
 
751
        /* First pass: calculate offset for every rule */
 
752
        list_for_each_entry(c, &h->chains, list) {
 
753
                ret = iptcc_compile_chain_offsets(h, c, &offset, &num);
 
754
                if (ret < 0)
 
755
                        return ret;
 
756
        }
 
757
 
 
758
        /* Append one error rule at end of chain */
 
759
        num++;
 
760
        offset += sizeof(STRUCT_ENTRY)
 
761
                  + ALIGN(sizeof(struct ipt_error_target));
 
762
 
 
763
        /* ruleset size is now in offset */
 
764
        *size = offset;
 
765
        return num;
 
766
}
 
767
 
 
768
static int iptcc_compile_table(TC_HANDLE_T h, STRUCT_REPLACE *repl)
 
769
{
 
770
        struct chain_head *c;
 
771
        struct iptcb_chain_error *error;
 
772
 
 
773
        /* Second pass: copy from cache to offsets, fill in jumps */
 
774
        list_for_each_entry(c, &h->chains, list) {
 
775
                int ret = iptcc_compile_chain(h, repl, c);
 
776
                if (ret < 0)
 
777
                        return ret;
 
778
        }
 
779
 
 
780
        /* Append error rule at end of chain */
 
781
        error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE;
 
782
        error->entry.target_offset = sizeof(STRUCT_ENTRY);
 
783
        error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE;
 
784
        error->target.t.u.user.target_size = 
 
785
                ALIGN(sizeof(struct ipt_error_target));
 
786
        strcpy((char *)&error->target.t.u.user.name, ERROR_TARGET);
 
787
        strcpy((char *)&error->target.error, "ERROR");
 
788
 
 
789
        return 1;
 
790
}
 
791
 
 
792
/**********************************************************************
 
793
 * EXTERNAL API (operates on cache only)
 
794
 **********************************************************************/
 
795
 
 
796
/* Allocate handle of given size */
 
797
static TC_HANDLE_T
 
798
alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
 
799
{
 
800
        size_t len;
 
801
        TC_HANDLE_T h;
 
802
 
 
803
        len = sizeof(STRUCT_TC_HANDLE) + size;
 
804
 
 
805
        h = malloc(sizeof(STRUCT_TC_HANDLE));
 
806
        if (!h) {
 
807
                errno = ENOMEM;
 
808
                return NULL;
 
809
        }
 
810
        memset(h, 0, sizeof(*h));
 
811
        INIT_LIST_HEAD(&h->chains);
 
812
        strcpy(h->info.name, tablename);
 
813
 
 
814
        h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size);
 
815
        if (!h->entries)
 
816
                goto out_free_handle;
 
817
 
 
818
        strcpy(h->entries->name, tablename);
 
819
        h->entries->size = size;
 
820
 
 
821
        return h;
 
822
 
 
823
out_free_handle:
 
824
        free(h);
 
825
 
 
826
        return NULL;
 
827
}
 
828
 
 
829
 
 
830
TC_HANDLE_T
 
831
TC_INIT(const char *tablename)
 
832
{
 
833
        TC_HANDLE_T h;
 
834
        STRUCT_GETINFO info;
 
835
        unsigned int tmp;
 
836
        socklen_t s;
 
837
 
 
838
        iptc_fn = TC_INIT;
 
839
 
 
840
        if (strlen(tablename) >= TABLE_MAXNAMELEN) {
 
841
                errno = EINVAL;
 
842
                return NULL;
 
843
        }
 
844
        
 
845
        if (sockfd_use == 0) {
 
846
                sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
 
847
                if (sockfd < 0)
 
848
                        return NULL;
 
849
        }
 
850
        sockfd_use++;
 
851
 
 
852
        s = sizeof(info);
 
853
 
 
854
        strcpy(info.name, tablename);
 
855
        if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) {
 
856
                if (--sockfd_use == 0) {
 
857
                        close(sockfd);
 
858
                        sockfd = -1;
 
859
                }
 
860
                return NULL;
 
861
        }
 
862
 
 
863
        DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
 
864
                info.valid_hooks, info.num_entries, info.size);
 
865
 
 
866
        if ((h = alloc_handle(info.name, info.size, info.num_entries))
 
867
            == NULL) {
 
868
                if (--sockfd_use == 0) {
 
869
                        close(sockfd);
 
870
                        sockfd = -1;
 
871
                }
 
872
                return NULL;
 
873
        }
 
874
 
 
875
        /* Initialize current state */
 
876
        h->info = info;
 
877
 
 
878
        h->entries->size = h->info.size;
 
879
 
 
880
        tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
 
881
 
 
882
        if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
 
883
                       &tmp) < 0)
 
884
                goto error;
 
885
 
 
886
#ifdef IPTC_DEBUG2
 
887
        {
 
888
                int fd = open("/tmp/libiptc-so_get_entries.blob", 
 
889
                                O_CREAT|O_WRONLY);
 
890
                if (fd >= 0) {
 
891
                        write(fd, h->entries, tmp);
 
892
                        close(fd);
 
893
                }
 
894
        }
 
895
#endif
 
896
 
 
897
        if (parse_table(h) < 0)
 
898
                goto error;
 
899
 
 
900
        CHECK(h);
 
901
        return h;
 
902
error:
 
903
        TC_FREE(&h);
 
904
        return NULL;
 
905
}
 
906
 
 
907
void
 
908
TC_FREE(TC_HANDLE_T *h)
 
909
{
 
910
        struct chain_head *c, *tmp;
 
911
 
 
912
        iptc_fn = TC_FREE;
 
913
        if (--sockfd_use == 0) {
 
914
                close(sockfd);
 
915
                sockfd = -1;
 
916
        }
 
917
 
 
918
        list_for_each_entry_safe(c, tmp, &(*h)->chains, list) {
 
919
                struct rule_head *r, *rtmp;
 
920
 
 
921
                list_for_each_entry_safe(r, rtmp, &c->rules, list) {
 
922
                        free(r);
 
923
                }
 
924
 
 
925
                free(c);
 
926
        }
 
927
 
 
928
        free((*h)->entries);
 
929
        free(*h);
 
930
 
 
931
        *h = NULL;
 
932
}
 
933
 
 
934
static inline int
 
935
print_match(const STRUCT_ENTRY_MATCH *m)
 
936
{
 
937
        printf("Match name: `%s'\n", m->u.user.name);
 
938
        return 0;
 
939
}
 
940
 
 
941
static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
 
942
 
 
943
void
 
944
TC_DUMP_ENTRIES(const TC_HANDLE_T handle)
 
945
{
 
946
        iptc_fn = TC_DUMP_ENTRIES;
 
947
        CHECK(handle);
 
948
 
 
949
        printf("libiptc v%s. %u bytes.\n",
 
950
               IPTABLES_VERSION, handle->entries->size);
 
951
        printf("Table `%s'\n", handle->info.name);
 
952
        printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
 
953
               handle->info.hook_entry[HOOK_PRE_ROUTING],
 
954
               handle->info.hook_entry[HOOK_LOCAL_IN],
 
955
               handle->info.hook_entry[HOOK_FORWARD],
 
956
               handle->info.hook_entry[HOOK_LOCAL_OUT],
 
957
               handle->info.hook_entry[HOOK_POST_ROUTING]);
 
958
        printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
 
959
               handle->info.underflow[HOOK_PRE_ROUTING],
 
960
               handle->info.underflow[HOOK_LOCAL_IN],
 
961
               handle->info.underflow[HOOK_FORWARD],
 
962
               handle->info.underflow[HOOK_LOCAL_OUT],
 
963
               handle->info.underflow[HOOK_POST_ROUTING]);
 
964
 
 
965
        ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size,
 
966
                      dump_entry, handle);
 
967
}
 
968
 
 
969
/* Does this chain exist? */
 
970
int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
 
971
{
 
972
        iptc_fn = TC_IS_CHAIN;
 
973
        return iptcc_find_label(chain, handle) != NULL;
 
974
}
 
975
 
 
976
static void iptcc_chain_iterator_advance(TC_HANDLE_T handle)
 
977
{
 
978
        struct chain_head *c = handle->chain_iterator_cur;
 
979
 
 
980
        if (c->list.next == &handle->chains)
 
981
                handle->chain_iterator_cur = NULL;
 
982
        else
 
983
                handle->chain_iterator_cur = 
 
984
                        list_entry(c->list.next, struct chain_head, list);
 
985
}
 
986
 
 
987
/* Iterator functions to run through the chains. */
 
988
const char *
 
989
TC_FIRST_CHAIN(TC_HANDLE_T *handle)
 
990
{
 
991
        struct chain_head *c = list_entry((*handle)->chains.next,
 
992
                                          struct chain_head, list);
 
993
 
 
994
        iptc_fn = TC_FIRST_CHAIN;
 
995
 
 
996
 
 
997
        if (list_empty(&(*handle)->chains)) {
 
998
                DEBUGP(": no chains\n");
 
999
                return NULL;
 
1000
        }
 
1001
 
 
1002
        (*handle)->chain_iterator_cur = c;
 
1003
        iptcc_chain_iterator_advance(*handle);
 
1004
 
 
1005
        DEBUGP(": returning `%s'\n", c->name);
 
1006
        return c->name;
 
1007
}
 
1008
 
 
1009
/* Iterator functions to run through the chains.  Returns NULL at end. */
 
1010
const char *
 
1011
TC_NEXT_CHAIN(TC_HANDLE_T *handle)
 
1012
{
 
1013
        struct chain_head *c = (*handle)->chain_iterator_cur;
 
1014
 
 
1015
        iptc_fn = TC_NEXT_CHAIN;
 
1016
 
 
1017
        if (!c) {
 
1018
                DEBUGP(": no more chains\n");
 
1019
                return NULL;
 
1020
        }
 
1021
 
 
1022
        iptcc_chain_iterator_advance(*handle);
 
1023
        
 
1024
        DEBUGP(": returning `%s'\n", c->name);
 
1025
        return c->name;
 
1026
}
 
1027
 
 
1028
/* Get first rule in the given chain: NULL for empty chain. */
 
1029
const STRUCT_ENTRY *
 
1030
TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
 
1031
{
 
1032
        struct chain_head *c;
 
1033
        struct rule_head *r;
 
1034
 
 
1035
        iptc_fn = TC_FIRST_RULE;
 
1036
 
 
1037
        DEBUGP("first rule(%s): ", chain);
 
1038
 
 
1039
        c = iptcc_find_label(chain, *handle);
 
1040
        if (!c) {
 
1041
                errno = ENOENT;
 
1042
                return NULL;
 
1043
        }
 
1044
 
 
1045
        /* Empty chain: single return/policy rule */
 
1046
        if (list_empty(&c->rules)) {
 
1047
                DEBUGP_C("no rules, returning NULL\n");
 
1048
                return NULL;
 
1049
        }
 
1050
 
 
1051
        r = list_entry(c->rules.next, struct rule_head, list);
 
1052
        (*handle)->rule_iterator_cur = r;
 
1053
        DEBUGP_C("%p\n", r);
 
1054
 
 
1055
        return r->entry;
 
1056
}
 
1057
 
 
1058
/* Returns NULL when rules run out. */
 
1059
const STRUCT_ENTRY *
 
1060
TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
 
1061
{
 
1062
        struct rule_head *r;
 
1063
 
 
1064
        iptc_fn = TC_NEXT_RULE;
 
1065
        DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
 
1066
 
 
1067
        if (!(*handle)->rule_iterator_cur) {
 
1068
                DEBUGP_C("returning NULL\n");
 
1069
                return NULL;
 
1070
        }
 
1071
        
 
1072
        r = list_entry((*handle)->rule_iterator_cur->list.next, 
 
1073
                        struct rule_head, list);
 
1074
 
 
1075
        iptc_fn = TC_NEXT_RULE;
 
1076
 
 
1077
        DEBUGP_C("next=%p, head=%p...", &r->list, 
 
1078
                &(*handle)->rule_iterator_cur->chain->rules);
 
1079
 
 
1080
        if (&r->list == &(*handle)->rule_iterator_cur->chain->rules) {
 
1081
                (*handle)->rule_iterator_cur = NULL;
 
1082
                DEBUGP_C("finished, returning NULL\n");
 
1083
                return NULL;
 
1084
        }
 
1085
 
 
1086
        (*handle)->rule_iterator_cur = r;
 
1087
 
 
1088
        /* NOTE: prev is without any influence ! */
 
1089
        DEBUGP_C("returning rule %p\n", r);
 
1090
        return r->entry;
 
1091
}
 
1092
 
 
1093
/* How many rules in this chain? */
 
1094
unsigned int
 
1095
TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
 
1096
{
 
1097
        struct chain_head *c;
 
1098
        iptc_fn = TC_NUM_RULES;
 
1099
        CHECK(*handle);
 
1100
 
 
1101
        c = iptcc_find_label(chain, *handle);
 
1102
        if (!c) {
 
1103
                errno = ENOENT;
 
1104
                return (unsigned int)-1;
 
1105
        }
 
1106
        
 
1107
        return c->num_rules;
 
1108
}
 
1109
 
 
1110
const STRUCT_ENTRY *TC_GET_RULE(const char *chain,
 
1111
                                unsigned int n,
 
1112
                                TC_HANDLE_T *handle)
 
1113
{
 
1114
        struct chain_head *c;
 
1115
        struct rule_head *r;
 
1116
        
 
1117
        iptc_fn = TC_GET_RULE;
 
1118
 
 
1119
        CHECK(*handle);
 
1120
 
 
1121
        c = iptcc_find_label(chain, *handle);
 
1122
        if (!c) {
 
1123
                errno = ENOENT;
 
1124
                return NULL;
 
1125
        }
 
1126
 
 
1127
        r = iptcc_get_rule_num(c, n);
 
1128
        if (!r)
 
1129
                return NULL;
 
1130
        return r->entry;
 
1131
}
 
1132
 
 
1133
/* Returns a pointer to the target name of this position. */
 
1134
static const char *standard_target_map(int verdict)
 
1135
{
 
1136
        switch (verdict) {
 
1137
                case RETURN:
 
1138
                        return LABEL_RETURN;
 
1139
                        break;
 
1140
                case -NF_ACCEPT-1:
 
1141
                        return LABEL_ACCEPT;
 
1142
                        break;
 
1143
                case -NF_DROP-1:
 
1144
                        return LABEL_DROP;
 
1145
                        break;
 
1146
                case -NF_QUEUE-1:
 
1147
                        return LABEL_QUEUE;
 
1148
                        break;
 
1149
                default:
 
1150
                        fprintf(stderr, "ERROR: %d not a valid target)\n",
 
1151
                                verdict);
 
1152
                        abort();
 
1153
                        break;
 
1154
        }
 
1155
        /* not reached */
 
1156
        return NULL;
 
1157
}
 
1158
 
 
1159
/* Returns a pointer to the target name of this position. */
 
1160
const char *TC_GET_TARGET(const STRUCT_ENTRY *ce,
 
1161
                          TC_HANDLE_T *handle)
 
1162
{
 
1163
        STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
 
1164
        struct rule_head *r = container_of(e, struct rule_head, entry[0]);
 
1165
 
 
1166
        iptc_fn = TC_GET_TARGET;
 
1167
 
 
1168
        switch(r->type) {
 
1169
                int spos;
 
1170
                case IPTCC_R_FALLTHROUGH:
 
1171
                        return "";
 
1172
                        break;
 
1173
                case IPTCC_R_JUMP:
 
1174
                        DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name);
 
1175
                        return r->jump->name;
 
1176
                        break;
 
1177
                case IPTCC_R_STANDARD:
 
1178
                        spos = *(int *)GET_TARGET(e)->data;
 
1179
                        DEBUGP("r=%p, spos=%d'\n", r, spos);
 
1180
                        return standard_target_map(spos);
 
1181
                        break;
 
1182
                case IPTCC_R_MODULE:
 
1183
                        return GET_TARGET(e)->u.user.name;
 
1184
                        break;
 
1185
        }
 
1186
        return NULL;
 
1187
}
 
1188
/* Is this a built-in chain?  Actually returns hook + 1. */
 
1189
int
 
1190
TC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
 
1191
{
 
1192
        struct chain_head *c;
 
1193
        
 
1194
        iptc_fn = TC_BUILTIN;
 
1195
 
 
1196
        c = iptcc_find_label(chain, handle);
 
1197
        if (!c) {
 
1198
                errno = ENOENT;
 
1199
                return 0;
 
1200
        }
 
1201
 
 
1202
        return iptcc_is_builtin(c);
 
1203
}
 
1204
 
 
1205
/* Get the policy of a given built-in chain */
 
1206
const char *
 
1207
TC_GET_POLICY(const char *chain,
 
1208
              STRUCT_COUNTERS *counters,
 
1209
              TC_HANDLE_T *handle)
 
1210
{
 
1211
        struct chain_head *c;
 
1212
 
 
1213
        iptc_fn = TC_GET_POLICY;
 
1214
 
 
1215
        DEBUGP("called for chain %s\n", chain);
 
1216
 
 
1217
        c = iptcc_find_label(chain, *handle);
 
1218
        if (!c) {
 
1219
                errno = ENOENT;
 
1220
                return NULL;
 
1221
        }
 
1222
 
 
1223
        if (!iptcc_is_builtin(c))
 
1224
                return NULL;
 
1225
 
 
1226
        *counters = c->counters;
 
1227
 
 
1228
        return standard_target_map(c->verdict);
 
1229
}
 
1230
 
 
1231
static int
 
1232
iptcc_standard_map(struct rule_head *r, int verdict)
 
1233
{
 
1234
        STRUCT_ENTRY *e = r->entry;
 
1235
        STRUCT_STANDARD_TARGET *t;
 
1236
 
 
1237
        t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
 
1238
 
 
1239
        if (t->target.u.target_size
 
1240
            != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
 
1241
                errno = EINVAL;
 
1242
                return 0;
 
1243
        }
 
1244
        /* memset for memcmp convenience on delete/replace */
 
1245
        memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
 
1246
        strcpy(t->target.u.user.name, STANDARD_TARGET);
 
1247
        t->verdict = verdict;
 
1248
 
 
1249
        r->type = IPTCC_R_STANDARD;
 
1250
 
 
1251
        return 1;
 
1252
}
 
1253
 
 
1254
static int
 
1255
iptcc_map_target(const TC_HANDLE_T handle,
 
1256
           struct rule_head *r)
 
1257
{
 
1258
        STRUCT_ENTRY *e = r->entry;
 
1259
        STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
 
1260
 
 
1261
        /* Maybe it's empty (=> fall through) */
 
1262
        if (strcmp(t->u.user.name, "") == 0) {
 
1263
                r->type = IPTCC_R_FALLTHROUGH;
 
1264
                return 1;
 
1265
        }
 
1266
        /* Maybe it's a standard target name... */
 
1267
        else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
 
1268
                return iptcc_standard_map(r, -NF_ACCEPT - 1);
 
1269
        else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
 
1270
                return iptcc_standard_map(r, -NF_DROP - 1);
 
1271
        else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
 
1272
                return iptcc_standard_map(r, -NF_QUEUE - 1);
 
1273
        else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
 
1274
                return iptcc_standard_map(r, RETURN);
 
1275
        else if (TC_BUILTIN(t->u.user.name, handle)) {
 
1276
                /* Can't jump to builtins. */
 
1277
                errno = EINVAL;
 
1278
                return 0;
 
1279
        } else {
 
1280
                /* Maybe it's an existing chain name. */
 
1281
                struct chain_head *c;
 
1282
                DEBUGP("trying to find chain `%s': ", t->u.user.name);
 
1283
 
 
1284
                c = iptcc_find_label(t->u.user.name, handle);
 
1285
                if (c) {
 
1286
                        DEBUGP_C("found!\n");
 
1287
                        r->type = IPTCC_R_JUMP;
 
1288
                        r->jump = c;
 
1289
                        c->references++;
 
1290
                        return 1;
 
1291
                }
 
1292
                DEBUGP_C("not found :(\n");
 
1293
        }
 
1294
 
 
1295
        /* Must be a module?  If not, kernel will reject... */
 
1296
        /* memset to all 0 for your memcmp convenience: don't clear version */
 
1297
        memset(t->u.user.name + strlen(t->u.user.name),
 
1298
               0,
 
1299
               FUNCTION_MAXNAMELEN - 1 - strlen(t->u.user.name));
 
1300
        r->type = IPTCC_R_MODULE;
 
1301
        set_changed(handle);
 
1302
        return 1;
 
1303
}
 
1304
 
 
1305
/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
 
1306
int
 
1307
TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
 
1308
                const STRUCT_ENTRY *e,
 
1309
                unsigned int rulenum,
 
1310
                TC_HANDLE_T *handle)
 
1311
{
 
1312
        struct chain_head *c;
 
1313
        struct rule_head *r;
 
1314
        struct list_head *prev;
 
1315
 
 
1316
        iptc_fn = TC_INSERT_ENTRY;
 
1317
 
 
1318
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1319
                errno = ENOENT;
 
1320
                return 0;
 
1321
        }
 
1322
 
 
1323
        /* first rulenum index = 0
 
1324
           first c->num_rules index = 1 */
 
1325
        if (rulenum > c->num_rules) {
 
1326
                errno = E2BIG;
 
1327
                return 0;
 
1328
        }
 
1329
 
 
1330
        /* If we are inserting at the end just take advantage of the
 
1331
           double linked list, insert will happen before the entry
 
1332
           prev points to. */
 
1333
        if (rulenum == c->num_rules) {
 
1334
                prev = &c->rules;
 
1335
        } else if (rulenum + 1 <= c->num_rules/2) {
 
1336
                r = iptcc_get_rule_num(c, rulenum + 1);
 
1337
                prev = &r->list;
 
1338
        } else {
 
1339
                r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
 
1340
                prev = &r->list;
 
1341
        }
 
1342
 
 
1343
        if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
 
1344
                errno = ENOMEM;
 
1345
                return 0;
 
1346
        }
 
1347
 
 
1348
        memcpy(r->entry, e, e->next_offset);
 
1349
        r->counter_map.maptype = COUNTER_MAP_SET;
 
1350
 
 
1351
        if (!iptcc_map_target(*handle, r)) {
 
1352
                free(r);
 
1353
                return 0;
 
1354
        }
 
1355
 
 
1356
        list_add_tail(&r->list, prev);
 
1357
        c->num_rules++;
 
1358
 
 
1359
        set_changed(*handle);
 
1360
 
 
1361
        return 1;
 
1362
}
 
1363
 
 
1364
/* Atomically replace rule `rulenum' in `chain' with `fw'. */
 
1365
int
 
1366
TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
 
1367
                 const STRUCT_ENTRY *e,
 
1368
                 unsigned int rulenum,
 
1369
                 TC_HANDLE_T *handle)
 
1370
{
 
1371
        struct chain_head *c;
 
1372
        struct rule_head *r, *old;
 
1373
 
 
1374
        iptc_fn = TC_REPLACE_ENTRY;
 
1375
 
 
1376
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1377
                errno = ENOENT;
 
1378
                return 0;
 
1379
        }
 
1380
 
 
1381
        if (rulenum >= c->num_rules) {
 
1382
                errno = E2BIG;
 
1383
                return 0;
 
1384
        }
 
1385
 
 
1386
        /* Take advantage of the double linked list if possible. */
 
1387
        if (rulenum + 1 <= c->num_rules/2) {
 
1388
                old = iptcc_get_rule_num(c, rulenum + 1);
 
1389
        } else {
 
1390
                old = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
 
1391
        }
 
1392
 
 
1393
        if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
 
1394
                errno = ENOMEM;
 
1395
                return 0;
 
1396
        }
 
1397
 
 
1398
        memcpy(r->entry, e, e->next_offset);
 
1399
        r->counter_map.maptype = COUNTER_MAP_SET;
 
1400
 
 
1401
        if (!iptcc_map_target(*handle, r)) {
 
1402
                free(r);
 
1403
                return 0;
 
1404
        }
 
1405
 
 
1406
        list_add(&r->list, &old->list);
 
1407
        iptcc_delete_rule(old);
 
1408
 
 
1409
        set_changed(*handle);
 
1410
 
 
1411
        return 1;
 
1412
}
 
1413
 
 
1414
/* Append entry `fw' to chain `chain'.  Equivalent to insert with
 
1415
   rulenum = length of chain. */
 
1416
int
 
1417
TC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
 
1418
                const STRUCT_ENTRY *e,
 
1419
                TC_HANDLE_T *handle)
 
1420
{
 
1421
        struct chain_head *c;
 
1422
        struct rule_head *r;
 
1423
 
 
1424
        iptc_fn = TC_APPEND_ENTRY;
 
1425
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1426
                DEBUGP("unable to find chain `%s'\n", chain);
 
1427
                errno = ENOENT;
 
1428
                return 0;
 
1429
        }
 
1430
 
 
1431
        if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
 
1432
                DEBUGP("unable to allocate rule for chain `%s'\n", chain);
 
1433
                errno = ENOMEM;
 
1434
                return 0;
 
1435
        }
 
1436
 
 
1437
        memcpy(r->entry, e, e->next_offset);
 
1438
        r->counter_map.maptype = COUNTER_MAP_SET;
 
1439
 
 
1440
        if (!iptcc_map_target(*handle, r)) {
 
1441
                DEBUGP("unable to map target of rule for chain `%s'\n", chain);
 
1442
                free(r);
 
1443
                return 0;
 
1444
        }
 
1445
 
 
1446
        list_add_tail(&r->list, &c->rules);
 
1447
        c->num_rules++;
 
1448
 
 
1449
        set_changed(*handle);
 
1450
 
 
1451
        return 1;
 
1452
}
 
1453
 
 
1454
static inline int
 
1455
match_different(const STRUCT_ENTRY_MATCH *a,
 
1456
                const unsigned char *a_elems,
 
1457
                const unsigned char *b_elems,
 
1458
                unsigned char **maskptr)
 
1459
{
 
1460
        const STRUCT_ENTRY_MATCH *b;
 
1461
        unsigned int i;
 
1462
 
 
1463
        /* Offset of b is the same as a. */
 
1464
        b = (void *)b_elems + ((unsigned char *)a - a_elems);
 
1465
 
 
1466
        if (a->u.match_size != b->u.match_size)
 
1467
                return 1;
 
1468
 
 
1469
        if (strcmp(a->u.user.name, b->u.user.name) != 0)
 
1470
                return 1;
 
1471
 
 
1472
        *maskptr += ALIGN(sizeof(*a));
 
1473
 
 
1474
        for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
 
1475
                if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
 
1476
                        return 1;
 
1477
        *maskptr += i;
 
1478
        return 0;
 
1479
}
 
1480
 
 
1481
static inline int
 
1482
target_same(struct rule_head *a, struct rule_head *b,const unsigned char *mask)
 
1483
{
 
1484
        unsigned int i;
 
1485
        STRUCT_ENTRY_TARGET *ta, *tb;
 
1486
 
 
1487
        if (a->type != b->type)
 
1488
                return 0;
 
1489
 
 
1490
        ta = GET_TARGET(a->entry);
 
1491
        tb = GET_TARGET(b->entry);
 
1492
 
 
1493
        switch (a->type) {
 
1494
        case IPTCC_R_FALLTHROUGH:
 
1495
                return 1;
 
1496
        case IPTCC_R_JUMP:
 
1497
                return a->jump == b->jump;
 
1498
        case IPTCC_R_STANDARD:
 
1499
                return ((STRUCT_STANDARD_TARGET *)ta)->verdict
 
1500
                        == ((STRUCT_STANDARD_TARGET *)tb)->verdict;
 
1501
        case IPTCC_R_MODULE:
 
1502
                if (ta->u.target_size != tb->u.target_size)
 
1503
                        return 0;
 
1504
                if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
 
1505
                        return 0;
 
1506
 
 
1507
                for (i = 0; i < ta->u.target_size - sizeof(*ta); i++)
 
1508
                        if (((ta->data[i] ^ tb->data[i]) & mask[i]) != 0)
 
1509
                                return 0;
 
1510
                return 1;
 
1511
        default:
 
1512
                fprintf(stderr, "ERROR: bad type %i\n", a->type);
 
1513
                abort();
 
1514
        }
 
1515
}
 
1516
 
 
1517
static unsigned char *
 
1518
is_same(const STRUCT_ENTRY *a,
 
1519
        const STRUCT_ENTRY *b,
 
1520
        unsigned char *matchmask);
 
1521
 
 
1522
/* Delete the first rule in `chain' which matches `fw'. */
 
1523
int
 
1524
TC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
 
1525
                const STRUCT_ENTRY *origfw,
 
1526
                unsigned char *matchmask,
 
1527
                TC_HANDLE_T *handle)
 
1528
{
 
1529
        struct chain_head *c;
 
1530
        struct rule_head *r, *i;
 
1531
 
 
1532
        iptc_fn = TC_DELETE_ENTRY;
 
1533
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1534
                errno = ENOENT;
 
1535
                return 0;
 
1536
        }
 
1537
 
 
1538
        /* Create a rule_head from origfw. */
 
1539
        r = iptcc_alloc_rule(c, origfw->next_offset);
 
1540
        if (!r) {
 
1541
                errno = ENOMEM;
 
1542
                return 0;
 
1543
        }
 
1544
 
 
1545
        memcpy(r->entry, origfw, origfw->next_offset);
 
1546
        r->counter_map.maptype = COUNTER_MAP_NOMAP;
 
1547
        if (!iptcc_map_target(*handle, r)) {
 
1548
                DEBUGP("unable to map target of rule for chain `%s'\n", chain);
 
1549
                free(r);
 
1550
                return 0;
 
1551
        } else {
 
1552
                /* iptcc_map_target increment target chain references
 
1553
                 * since this is a fake rule only used for matching
 
1554
                 * the chain references count is decremented again. 
 
1555
                 */
 
1556
                if (r->type == IPTCC_R_JUMP
 
1557
                    && r->jump)
 
1558
                        r->jump->references--;
 
1559
        }
 
1560
 
 
1561
        list_for_each_entry(i, &c->rules, list) {
 
1562
                unsigned char *mask;
 
1563
 
 
1564
                mask = is_same(r->entry, i->entry, matchmask);
 
1565
                if (!mask)
 
1566
                        continue;
 
1567
 
 
1568
                if (!target_same(r, i, mask))
 
1569
                        continue;
 
1570
 
 
1571
                /* If we are about to delete the rule that is the
 
1572
                 * current iterator, move rule iterator back.  next
 
1573
                 * pointer will then point to real next node */
 
1574
                if (i == (*handle)->rule_iterator_cur) {
 
1575
                        (*handle)->rule_iterator_cur = 
 
1576
                                list_entry((*handle)->rule_iterator_cur->list.prev,
 
1577
                                           struct rule_head, list);
 
1578
                }
 
1579
 
 
1580
                c->num_rules--;
 
1581
                iptcc_delete_rule(i);
 
1582
 
 
1583
                set_changed(*handle);
 
1584
                free(r);
 
1585
                return 1;
 
1586
        }
 
1587
 
 
1588
        free(r);
 
1589
        errno = ENOENT;
 
1590
        return 0;
 
1591
}
 
1592
 
 
1593
 
 
1594
/* Delete the rule in position `rulenum' in `chain'. */
 
1595
int
 
1596
TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
 
1597
                    unsigned int rulenum,
 
1598
                    TC_HANDLE_T *handle)
 
1599
{
 
1600
        struct chain_head *c;
 
1601
        struct rule_head *r;
 
1602
 
 
1603
        iptc_fn = TC_DELETE_NUM_ENTRY;
 
1604
 
 
1605
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1606
                errno = ENOENT;
 
1607
                return 0;
 
1608
        }
 
1609
 
 
1610
        if (rulenum >= c->num_rules) {
 
1611
                errno = E2BIG;
 
1612
                return 0;
 
1613
        }
 
1614
 
 
1615
        /* Take advantage of the double linked list if possible. */
 
1616
        if (rulenum + 1 <= c->num_rules/2) {
 
1617
                r = iptcc_get_rule_num(c, rulenum + 1);
 
1618
        } else {
 
1619
                r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
 
1620
        }
 
1621
 
 
1622
        /* If we are about to delete the rule that is the current
 
1623
         * iterator, move rule iterator back.  next pointer will then
 
1624
         * point to real next node */
 
1625
        if (r == (*handle)->rule_iterator_cur) {
 
1626
                (*handle)->rule_iterator_cur = 
 
1627
                        list_entry((*handle)->rule_iterator_cur->list.prev,
 
1628
                                   struct rule_head, list);
 
1629
        }
 
1630
 
 
1631
        c->num_rules--;
 
1632
        iptcc_delete_rule(r);
 
1633
 
 
1634
        set_changed(*handle);
 
1635
 
 
1636
        return 1;
 
1637
}
 
1638
 
 
1639
/* Check the packet `fw' on chain `chain'.  Returns the verdict, or
 
1640
   NULL and sets errno. */
 
1641
const char *
 
1642
TC_CHECK_PACKET(const IPT_CHAINLABEL chain,
 
1643
                STRUCT_ENTRY *entry,
 
1644
                TC_HANDLE_T *handle)
 
1645
{
 
1646
        iptc_fn = TC_CHECK_PACKET;
 
1647
        errno = ENOSYS;
 
1648
        return NULL;
 
1649
}
 
1650
 
 
1651
/* Flushes the entries in the given chain (ie. empties chain). */
 
1652
int
 
1653
TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
 
1654
{
 
1655
        struct chain_head *c;
 
1656
        struct rule_head *r, *tmp;
 
1657
 
 
1658
        iptc_fn = TC_FLUSH_ENTRIES;
 
1659
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1660
                errno = ENOENT;
 
1661
                return 0;
 
1662
        }
 
1663
 
 
1664
        list_for_each_entry_safe(r, tmp, &c->rules, list) {
 
1665
                iptcc_delete_rule(r);
 
1666
        }
 
1667
 
 
1668
        c->num_rules = 0;
 
1669
 
 
1670
        set_changed(*handle);
 
1671
 
 
1672
        return 1;
 
1673
}
 
1674
 
 
1675
/* Zeroes the counters in a chain. */
 
1676
int
 
1677
TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
 
1678
{
 
1679
        struct chain_head *c;
 
1680
        struct rule_head *r;
 
1681
 
 
1682
        iptc_fn = TC_ZERO_ENTRIES;
 
1683
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1684
                errno = ENOENT;
 
1685
                return 0;
 
1686
        }
 
1687
 
 
1688
        if (c->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
 
1689
                c->counter_map.maptype = COUNTER_MAP_ZEROED;
 
1690
 
 
1691
        list_for_each_entry(r, &c->rules, list) {
 
1692
                if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
 
1693
                        r->counter_map.maptype = COUNTER_MAP_ZEROED;
 
1694
        }
 
1695
 
 
1696
        set_changed(*handle);
 
1697
 
 
1698
        return 1;
 
1699
}
 
1700
 
 
1701
STRUCT_COUNTERS *
 
1702
TC_READ_COUNTER(const IPT_CHAINLABEL chain,
 
1703
                unsigned int rulenum,
 
1704
                TC_HANDLE_T *handle)
 
1705
{
 
1706
        struct chain_head *c;
 
1707
        struct rule_head *r;
 
1708
 
 
1709
        iptc_fn = TC_READ_COUNTER;
 
1710
        CHECK(*handle);
 
1711
 
 
1712
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1713
                errno = ENOENT;
 
1714
                return NULL;
 
1715
        }
 
1716
 
 
1717
        if (!(r = iptcc_get_rule_num(c, rulenum))) {
 
1718
                errno = E2BIG;
 
1719
                return NULL;
 
1720
        }
 
1721
 
 
1722
        return &r->entry[0].counters;
 
1723
}
 
1724
 
 
1725
int
 
1726
TC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
 
1727
                unsigned int rulenum,
 
1728
                TC_HANDLE_T *handle)
 
1729
{
 
1730
        struct chain_head *c;
 
1731
        struct rule_head *r;
 
1732
        
 
1733
        iptc_fn = TC_ZERO_COUNTER;
 
1734
        CHECK(*handle);
 
1735
 
 
1736
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1737
                errno = ENOENT;
 
1738
                return 0;
 
1739
        }
 
1740
 
 
1741
        if (!(r = iptcc_get_rule_num(c, rulenum))) {
 
1742
                errno = E2BIG;
 
1743
                return 0;
 
1744
        }
 
1745
 
 
1746
        if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
 
1747
                r->counter_map.maptype = COUNTER_MAP_ZEROED;
 
1748
 
 
1749
        set_changed(*handle);
 
1750
 
 
1751
        return 1;
 
1752
}
 
1753
 
 
1754
int 
 
1755
TC_SET_COUNTER(const IPT_CHAINLABEL chain,
 
1756
               unsigned int rulenum,
 
1757
               STRUCT_COUNTERS *counters,
 
1758
               TC_HANDLE_T *handle)
 
1759
{
 
1760
        struct chain_head *c;
 
1761
        struct rule_head *r;
 
1762
        STRUCT_ENTRY *e;
 
1763
 
 
1764
        iptc_fn = TC_SET_COUNTER;
 
1765
        CHECK(*handle);
 
1766
 
 
1767
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1768
                errno = ENOENT;
 
1769
                return 0;
 
1770
        }
 
1771
 
 
1772
        if (!(r = iptcc_get_rule_num(c, rulenum))) {
 
1773
                errno = E2BIG;
 
1774
                return 0;
 
1775
        }
 
1776
 
 
1777
        e = r->entry;
 
1778
        r->counter_map.maptype = COUNTER_MAP_SET;
 
1779
 
 
1780
        memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
 
1781
 
 
1782
        set_changed(*handle);
 
1783
 
 
1784
        return 1;
 
1785
}
 
1786
 
 
1787
/* Creates a new chain. */
 
1788
/* To create a chain, create two rules: error node and unconditional
 
1789
 * return. */
 
1790
int
 
1791
TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
 
1792
{
 
1793
        static struct chain_head *c;
 
1794
 
 
1795
        iptc_fn = TC_CREATE_CHAIN;
 
1796
 
 
1797
        /* find_label doesn't cover built-in targets: DROP, ACCEPT,
 
1798
           QUEUE, RETURN. */
 
1799
        if (iptcc_find_label(chain, *handle)
 
1800
            || strcmp(chain, LABEL_DROP) == 0
 
1801
            || strcmp(chain, LABEL_ACCEPT) == 0
 
1802
            || strcmp(chain, LABEL_QUEUE) == 0
 
1803
            || strcmp(chain, LABEL_RETURN) == 0) {
 
1804
                DEBUGP("Chain `%s' already exists\n", chain);
 
1805
                errno = EEXIST;
 
1806
                return 0;
 
1807
        }
 
1808
 
 
1809
        if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
 
1810
                DEBUGP("Chain name `%s' too long\n", chain);
 
1811
                errno = EINVAL;
 
1812
                return 0;
 
1813
        }
 
1814
 
 
1815
        c = iptcc_alloc_chain_head(chain, 0);
 
1816
        if (!c) {
 
1817
                DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
 
1818
                errno = ENOMEM;
 
1819
                return 0;
 
1820
 
 
1821
        }
 
1822
 
 
1823
        DEBUGP("Creating chain `%s'\n", chain);
 
1824
        iptc_insert_chain(*handle, c); /* Insert sorted */
 
1825
 
 
1826
        set_changed(*handle);
 
1827
 
 
1828
        return 1;
 
1829
}
 
1830
 
 
1831
/* Get the number of references to this chain. */
 
1832
int
 
1833
TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
 
1834
                  TC_HANDLE_T *handle)
 
1835
{
 
1836
        struct chain_head *c;
 
1837
 
 
1838
        iptc_fn = TC_GET_REFERENCES;
 
1839
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1840
                errno = ENOENT;
 
1841
                return 0;
 
1842
        }
 
1843
 
 
1844
        *ref = c->references;
 
1845
 
 
1846
        return 1;
 
1847
}
 
1848
 
 
1849
/* Deletes a chain. */
 
1850
int
 
1851
TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
 
1852
{
 
1853
        unsigned int references;
 
1854
        struct chain_head *c;
 
1855
 
 
1856
        iptc_fn = TC_DELETE_CHAIN;
 
1857
 
 
1858
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1859
                DEBUGP("cannot find chain `%s'\n", chain);
 
1860
                errno = ENOENT;
 
1861
                return 0;
 
1862
        }
 
1863
 
 
1864
        if (TC_BUILTIN(chain, *handle)) {
 
1865
                DEBUGP("cannot remove builtin chain `%s'\n", chain);
 
1866
                errno = EINVAL;
 
1867
                return 0;
 
1868
        }
 
1869
 
 
1870
        if (!TC_GET_REFERENCES(&references, chain, handle)) {
 
1871
                DEBUGP("cannot get references on chain `%s'\n", chain);
 
1872
                return 0;
 
1873
        }
 
1874
 
 
1875
        if (references > 0) {
 
1876
                DEBUGP("chain `%s' still has references\n", chain);
 
1877
                errno = EMLINK;
 
1878
                return 0;
 
1879
        }
 
1880
 
 
1881
        if (c->num_rules) {
 
1882
                DEBUGP("chain `%s' is not empty\n", chain);
 
1883
                errno = ENOTEMPTY;
 
1884
                return 0;
 
1885
        }
 
1886
 
 
1887
        /* If we are about to delete the chain that is the current
 
1888
         * iterator, move chain iterator firward. */
 
1889
        if (c == (*handle)->chain_iterator_cur)
 
1890
                iptcc_chain_iterator_advance(*handle);
 
1891
 
 
1892
        list_del(&c->list);
 
1893
        free(c);
 
1894
 
 
1895
        DEBUGP("chain `%s' deleted\n", chain);
 
1896
 
 
1897
        set_changed(*handle);
 
1898
 
 
1899
        return 1;
 
1900
}
 
1901
 
 
1902
/* Renames a chain. */
 
1903
int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
 
1904
                    const IPT_CHAINLABEL newname,
 
1905
                    TC_HANDLE_T *handle)
 
1906
{
 
1907
        struct chain_head *c;
 
1908
        iptc_fn = TC_RENAME_CHAIN;
 
1909
 
 
1910
        /* find_label doesn't cover built-in targets: DROP, ACCEPT,
 
1911
           QUEUE, RETURN. */
 
1912
        if (iptcc_find_label(newname, *handle)
 
1913
            || strcmp(newname, LABEL_DROP) == 0
 
1914
            || strcmp(newname, LABEL_ACCEPT) == 0
 
1915
            || strcmp(newname, LABEL_QUEUE) == 0
 
1916
            || strcmp(newname, LABEL_RETURN) == 0) {
 
1917
                errno = EEXIST;
 
1918
                return 0;
 
1919
        }
 
1920
 
 
1921
        if (!(c = iptcc_find_label(oldname, *handle))
 
1922
            || TC_BUILTIN(oldname, *handle)) {
 
1923
                errno = ENOENT;
 
1924
                return 0;
 
1925
        }
 
1926
 
 
1927
        if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
 
1928
                errno = EINVAL;
 
1929
                return 0;
 
1930
        }
 
1931
 
 
1932
        strncpy(c->name, newname, sizeof(IPT_CHAINLABEL));
 
1933
        
 
1934
        set_changed(*handle);
 
1935
 
 
1936
        return 1;
 
1937
}
 
1938
 
 
1939
/* Sets the policy on a built-in chain. */
 
1940
int
 
1941
TC_SET_POLICY(const IPT_CHAINLABEL chain,
 
1942
              const IPT_CHAINLABEL policy,
 
1943
              STRUCT_COUNTERS *counters,
 
1944
              TC_HANDLE_T *handle)
 
1945
{
 
1946
        struct chain_head *c;
 
1947
 
 
1948
        iptc_fn = TC_SET_POLICY;
 
1949
 
 
1950
        if (!(c = iptcc_find_label(chain, *handle))) {
 
1951
                DEBUGP("cannot find chain `%s'\n", chain);
 
1952
                errno = ENOENT;
 
1953
                return 0;
 
1954
        }
 
1955
 
 
1956
        if (!iptcc_is_builtin(c)) {
 
1957
                DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain);
 
1958
                errno = ENOENT;
 
1959
                return 0;
 
1960
        }
 
1961
 
 
1962
        if (strcmp(policy, LABEL_ACCEPT) == 0)
 
1963
                c->verdict = -NF_ACCEPT - 1;
 
1964
        else if (strcmp(policy, LABEL_DROP) == 0)
 
1965
                c->verdict = -NF_DROP - 1;
 
1966
        else {
 
1967
                errno = EINVAL;
 
1968
                return 0;
 
1969
        }
 
1970
 
 
1971
        if (counters) {
 
1972
                /* set byte and packet counters */
 
1973
                memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS));
 
1974
                c->counter_map.maptype = COUNTER_MAP_SET;
 
1975
        } else {
 
1976
                c->counter_map.maptype = COUNTER_MAP_NOMAP;
 
1977
        }
 
1978
 
 
1979
        set_changed(*handle);
 
1980
 
 
1981
        return 1;
 
1982
}
 
1983
 
 
1984
/* Without this, on gcc 2.7.2.3, we get:
 
1985
   libiptc.c: In function `TC_COMMIT':
 
1986
   libiptc.c:833: fixed or forbidden register was spilled.
 
1987
   This may be due to a compiler bug or to impossible asm
 
1988
   statements or clauses.
 
1989
*/
 
1990
static void
 
1991
subtract_counters(STRUCT_COUNTERS *answer,
 
1992
                  const STRUCT_COUNTERS *a,
 
1993
                  const STRUCT_COUNTERS *b)
 
1994
{
 
1995
        answer->pcnt = a->pcnt - b->pcnt;
 
1996
        answer->bcnt = a->bcnt - b->bcnt;
 
1997
}
 
1998
 
 
1999
 
 
2000
static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters,
 
2001
                           unsigned int index)
 
2002
{
 
2003
        newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0});
 
2004
        DEBUGP_C("NOMAP => zero\n");
 
2005
}
 
2006
 
 
2007
static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
 
2008
                                STRUCT_REPLACE *repl,
 
2009
                                unsigned int index,
 
2010
                                unsigned int mappos)
 
2011
{
 
2012
        /* Original read: X.
 
2013
         * Atomic read on replacement: X + Y.
 
2014
         * Currently in kernel: Z.
 
2015
         * Want in kernel: X + Y + Z.
 
2016
         * => Add in X + Y
 
2017
         * => Add in replacement read.
 
2018
         */
 
2019
        newcounters->counters[index] = repl->counters[mappos];
 
2020
        DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
 
2021
}
 
2022
 
 
2023
static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
 
2024
                                STRUCT_REPLACE *repl,
 
2025
                                unsigned int index,
 
2026
                                unsigned int mappos,
 
2027
                                STRUCT_COUNTERS *counters)
 
2028
{
 
2029
        /* Original read: X.
 
2030
         * Atomic read on replacement: X + Y.
 
2031
         * Currently in kernel: Z.
 
2032
         * Want in kernel: Y + Z.
 
2033
         * => Add in Y.
 
2034
         * => Add in (replacement read - original read).
 
2035
         */
 
2036
        subtract_counters(&newcounters->counters[index],
 
2037
                          &repl->counters[mappos],
 
2038
                          counters);
 
2039
        DEBUGP_C("ZEROED => mappos %u\n", mappos);
 
2040
}
 
2041
 
 
2042
static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
 
2043
                             unsigned int index,
 
2044
                             STRUCT_COUNTERS *counters)
 
2045
{
 
2046
        /* Want to set counter (iptables-restore) */
 
2047
 
 
2048
        memcpy(&newcounters->counters[index], counters,
 
2049
                sizeof(STRUCT_COUNTERS));
 
2050
 
 
2051
        DEBUGP_C("SET\n");
 
2052
}
 
2053
 
 
2054
 
 
2055
int
 
2056
TC_COMMIT(TC_HANDLE_T *handle)
 
2057
{
 
2058
        /* Replace, then map back the counters. */
 
2059
        STRUCT_REPLACE *repl;
 
2060
        STRUCT_COUNTERS_INFO *newcounters;
 
2061
        struct chain_head *c;
 
2062
        int ret;
 
2063
        size_t counterlen;
 
2064
        int new_number;
 
2065
        unsigned int new_size;
 
2066
 
 
2067
        iptc_fn = TC_COMMIT;
 
2068
        CHECK(*handle);
 
2069
 
 
2070
        /* Don't commit if nothing changed. */
 
2071
        if (!(*handle)->changed)
 
2072
                goto finished;
 
2073
 
 
2074
        new_number = iptcc_compile_table_prep(*handle, &new_size);
 
2075
        if (new_number < 0) {
 
2076
                errno = ENOMEM;
 
2077
                goto out_zero;
 
2078
        }
 
2079
 
 
2080
        repl = malloc(sizeof(*repl) + new_size);
 
2081
        if (!repl) {
 
2082
                errno = ENOMEM;
 
2083
                goto out_zero;
 
2084
        }
 
2085
        memset(repl, 0, sizeof(*repl) + new_size);
 
2086
 
 
2087
#if 0
 
2088
        TC_DUMP_ENTRIES(*handle);
 
2089
#endif
 
2090
 
 
2091
        counterlen = sizeof(STRUCT_COUNTERS_INFO)
 
2092
                        + sizeof(STRUCT_COUNTERS) * new_number;
 
2093
 
 
2094
        /* These are the old counters we will get from kernel */
 
2095
        repl->counters = malloc(sizeof(STRUCT_COUNTERS)
 
2096
                                * (*handle)->info.num_entries);
 
2097
        if (!repl->counters) {
 
2098
                errno = ENOMEM;
 
2099
                goto out_free_repl;
 
2100
        }
 
2101
        /* These are the counters we're going to put back, later. */
 
2102
        newcounters = malloc(counterlen);
 
2103
        if (!newcounters) {
 
2104
                errno = ENOMEM;
 
2105
                goto out_free_repl_counters;
 
2106
        }
 
2107
        memset(newcounters, 0, counterlen);
 
2108
 
 
2109
        strcpy(repl->name, (*handle)->info.name);
 
2110
        repl->num_entries = new_number;
 
2111
        repl->size = new_size;
 
2112
 
 
2113
        repl->num_counters = (*handle)->info.num_entries;
 
2114
        repl->valid_hooks = (*handle)->info.valid_hooks;
 
2115
 
 
2116
        DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
 
2117
                repl->num_entries, repl->size, repl->num_counters);
 
2118
 
 
2119
        ret = iptcc_compile_table(*handle, repl);
 
2120
        if (ret < 0) {
 
2121
                errno = ret;
 
2122
                goto out_free_newcounters;
 
2123
        }
 
2124
 
 
2125
 
 
2126
#ifdef IPTC_DEBUG2
 
2127
        {
 
2128
                int fd = open("/tmp/libiptc-so_set_replace.blob", 
 
2129
                                O_CREAT|O_WRONLY);
 
2130
                if (fd >= 0) {
 
2131
                        write(fd, repl, sizeof(*repl) + repl->size);
 
2132
                        close(fd);
 
2133
                }
 
2134
        }
 
2135
#endif
 
2136
 
 
2137
        ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
 
2138
                         sizeof(*repl) + repl->size);
 
2139
        if (ret < 0)
 
2140
                goto out_free_newcounters;
 
2141
 
 
2142
        /* Put counters back. */
 
2143
        strcpy(newcounters->name, (*handle)->info.name);
 
2144
        newcounters->num_counters = new_number;
 
2145
 
 
2146
        list_for_each_entry(c, &(*handle)->chains, list) {
 
2147
                struct rule_head *r;
 
2148
 
 
2149
                /* Builtin chains have their own counters */
 
2150
                if (iptcc_is_builtin(c)) {
 
2151
                        DEBUGP("counter for chain-index %u: ", c->foot_index);
 
2152
                        switch(c->counter_map.maptype) {
 
2153
                        case COUNTER_MAP_NOMAP:
 
2154
                                counters_nomap(newcounters, c->foot_index);
 
2155
                                break;
 
2156
                        case COUNTER_MAP_NORMAL_MAP:
 
2157
                                counters_normal_map(newcounters, repl,
 
2158
                                                    c->foot_index, 
 
2159
                                                    c->counter_map.mappos);
 
2160
                                break;
 
2161
                        case COUNTER_MAP_ZEROED:
 
2162
                                counters_map_zeroed(newcounters, repl,
 
2163
                                                    c->foot_index, 
 
2164
                                                    c->counter_map.mappos,
 
2165
                                                    &c->counters);
 
2166
                                break;
 
2167
                        case COUNTER_MAP_SET:
 
2168
                                counters_map_set(newcounters, c->foot_index,
 
2169
                                                 &c->counters);
 
2170
                                break;
 
2171
                        }
 
2172
                }
 
2173
 
 
2174
                list_for_each_entry(r, &c->rules, list) {
 
2175
                        DEBUGP("counter for index %u: ", r->index);
 
2176
                        switch (r->counter_map.maptype) {
 
2177
                        case COUNTER_MAP_NOMAP:
 
2178
                                counters_nomap(newcounters, r->index);
 
2179
                                break;
 
2180
 
 
2181
                        case COUNTER_MAP_NORMAL_MAP:
 
2182
                                counters_normal_map(newcounters, repl,
 
2183
                                                    r->index, 
 
2184
                                                    r->counter_map.mappos);
 
2185
                                break;
 
2186
 
 
2187
                        case COUNTER_MAP_ZEROED:
 
2188
                                counters_map_zeroed(newcounters, repl,
 
2189
                                                    r->index,
 
2190
                                                    r->counter_map.mappos,
 
2191
                                                    &r->entry->counters);
 
2192
                                break;
 
2193
 
 
2194
                        case COUNTER_MAP_SET:
 
2195
                                counters_map_set(newcounters, r->index,
 
2196
                                                 &r->entry->counters);
 
2197
                                break;
 
2198
                        }
 
2199
                }
 
2200
        }
 
2201
 
 
2202
#ifdef IPTC_DEBUG2
 
2203
        {
 
2204
                int fd = open("/tmp/libiptc-so_set_add_counters.blob", 
 
2205
                                O_CREAT|O_WRONLY);
 
2206
                if (fd >= 0) {
 
2207
                        write(fd, newcounters, counterlen);
 
2208
                        close(fd);
 
2209
                }
 
2210
        }
 
2211
#endif
 
2212
 
 
2213
        ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
 
2214
                         newcounters, counterlen);
 
2215
        if (ret < 0)
 
2216
                goto out_free_newcounters;
 
2217
 
 
2218
        free(repl->counters);
 
2219
        free(repl);
 
2220
        free(newcounters);
 
2221
 
 
2222
finished:
 
2223
        TC_FREE(handle);
 
2224
        return 1;
 
2225
 
 
2226
out_free_newcounters:
 
2227
        free(newcounters);
 
2228
out_free_repl_counters:
 
2229
        free(repl->counters);
 
2230
out_free_repl:
 
2231
        free(repl);
 
2232
out_zero:
 
2233
        return 0;
 
2234
}
 
2235
 
 
2236
/* Get raw socket. */
 
2237
int
 
2238
TC_GET_RAW_SOCKET(void)
 
2239
{
 
2240
        return sockfd;
 
2241
}
 
2242
 
 
2243
/* Translates errno numbers into more human-readable form than strerror. */
 
2244
const char *
 
2245
TC_STRERROR(int err)
 
2246
{
 
2247
        unsigned int i;
 
2248
        struct table_struct {
 
2249
                void *fn;
 
2250
                int err;
 
2251
                const char *message;
 
2252
        } table [] =
 
2253
          { { TC_INIT, EPERM, "Permission denied (you must be root)" },
 
2254
            { TC_INIT, EINVAL, "Module is wrong version" },
 
2255
            { TC_INIT, ENOENT, 
 
2256
                    "Table does not exist (do you need to insmod?)" },
 
2257
            { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
 
2258
            { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
 
2259
            { TC_DELETE_CHAIN, EMLINK,
 
2260
              "Can't delete chain with references left" },
 
2261
            { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
 
2262
            { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
 
2263
            { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
 
2264
            { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
 
2265
            { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
 
2266
            { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
 
2267
            { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
 
2268
            { TC_INSERT_ENTRY, EINVAL, "Target problem" },
 
2269
            /* EINVAL for CHECK probably means bad interface. */
 
2270
            { TC_CHECK_PACKET, EINVAL,
 
2271
              "Bad arguments (does that interface exist?)" },
 
2272
            { TC_CHECK_PACKET, ENOSYS,
 
2273
              "Checking will most likely never get implemented" },
 
2274
            /* ENOENT for DELETE probably means no matching rule */
 
2275
            { TC_DELETE_ENTRY, ENOENT,
 
2276
              "Bad rule (does a matching rule exist in that chain?)" },
 
2277
            { TC_SET_POLICY, ENOENT,
 
2278
              "Bad built-in chain name" },
 
2279
            { TC_SET_POLICY, EINVAL,
 
2280
              "Bad policy name" },
 
2281
 
 
2282
            { NULL, 0, "Incompatible with this kernel" },
 
2283
            { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
 
2284
            { NULL, ENOSYS, "Will be implemented real soon.  I promise ;)" },
 
2285
            { NULL, ENOMEM, "Memory allocation problem" },
 
2286
            { NULL, ENOENT, "No chain/target/match by that name" },
 
2287
          };
 
2288
 
 
2289
        for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
 
2290
                if ((!table[i].fn || table[i].fn == iptc_fn)
 
2291
                    && table[i].err == err)
 
2292
                        return table[i].message;
 
2293
        }
 
2294
 
 
2295
        return strerror(err);
 
2296
}