blob: b4d865e6af3cae194d61c872f5a4d8e9145df545 [file] [log] [blame]
Martin Josefsson0f9b8b12004-12-18 17:18:49 +00001/* Library which manipulates firewall rules. Version $Revision$ */
Marc Bouchere6869a82000-03-20 06:03:29 +00002
3/* Architecture of firewall rules is as follows:
4 *
5 * Chains go INPUT, FORWARD, OUTPUT then user chains.
6 * Each user chain starts with an ERROR node.
7 * Every chain ends with an unconditional jump: a RETURN for user chains,
8 * and a POLICY for built-ins.
9 */
10
Harald Welte3ea8f402003-06-23 18:25:59 +000011/* (C) 1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
12 * COPYING for details).
Harald Welteaae69be2004-08-29 23:32:14 +000013 * (C) 2000-2004 by the Netfilter Core Team <coreteam@netfilter.org>
Harald Welte3ea8f402003-06-23 18:25:59 +000014 *
Harald Weltefbc85232003-06-24 17:37:21 +000015 * 2003-Jun-20: Harald Welte <laforge@netfilter.org>:
Harald Welte3ea8f402003-06-23 18:25:59 +000016 * - Reimplementation of chain cache to use offsets instead of entries
Harald Weltefbc85232003-06-24 17:37:21 +000017 * 2003-Jun-23: Harald Welte <laforge@netfilter.org>:
Harald Welte0113fe72004-01-06 19:04:02 +000018 * - performance optimization, sponsored by Astaro AG (http://www.astaro.com/)
Harald Weltefbc85232003-06-24 17:37:21 +000019 * don't rebuild the chain cache after every operation, instead fix it
20 * up after a ruleset change.
Harald Welteaae69be2004-08-29 23:32:14 +000021 * 2004-Aug-18: Harald Welte <laforge@netfilter.org>:
22 * - futher performance work: total reimplementation of libiptc.
23 * - libiptc now has a real internal (linked-list) represntation of the
24 * ruleset and a parser/compiler from/to this internal representation
25 * - again sponsored by Astaro AG (http://www.astaro.com/)
Harald Welte3ea8f402003-06-23 18:25:59 +000026 */
Harald Welte15920d12004-05-16 09:05:07 +000027#include <sys/types.h>
28#include <sys/socket.h>
Stephane Ouellette7cd00282004-05-14 08:21:06 +000029
Harald Welteaae69be2004-08-29 23:32:14 +000030#include "linux_list.h"
31
32//#define IPTC_DEBUG2 1
33
34#ifdef IPTC_DEBUG2
35#include <fcntl.h>
36#define DEBUGP(x, args...) fprintf(stderr, "%s: " x, __FUNCTION__, ## args)
37#define DEBUGP_C(x, args...) fprintf(stderr, x, ## args)
38#else
39#define DEBUGP(x, args...)
40#define DEBUGP_C(x, args...)
41#endif
42
Marc Bouchere6869a82000-03-20 06:03:29 +000043#ifndef IPT_LIB_DIR
44#define IPT_LIB_DIR "/usr/local/lib/iptables"
45#endif
46
47static int sockfd = -1;
Derrik Pates664c0a32005-02-01 13:28:14 +000048static int sockfd_use = 0;
Marc Bouchere6869a82000-03-20 06:03:29 +000049static void *iptc_fn = NULL;
50
Patrick McHardy0b639362007-09-08 16:00:01 +000051static const char *hooknames[] = {
52 [HOOK_PRE_ROUTING] = "PREROUTING",
53 [HOOK_LOCAL_IN] = "INPUT",
54 [HOOK_FORWARD] = "FORWARD",
55 [HOOK_LOCAL_OUT] = "OUTPUT",
56 [HOOK_POST_ROUTING] = "POSTROUTING",
Rusty Russell10758b72000-09-14 07:37:33 +000057#ifdef HOOK_DROPPING
Patrick McHardy0b639362007-09-08 16:00:01 +000058 [HOOK_DROPPING] = "DROPPING"
Rusty Russell10758b72000-09-14 07:37:33 +000059#endif
Marc Bouchere6869a82000-03-20 06:03:29 +000060};
61
Harald Welteaae69be2004-08-29 23:32:14 +000062/* Convenience structures */
63struct ipt_error_target
64{
65 STRUCT_ENTRY_TARGET t;
66 char error[TABLE_MAXNAMELEN];
67};
68
69struct chain_head;
70struct rule_head;
71
Marc Bouchere6869a82000-03-20 06:03:29 +000072struct counter_map
73{
74 enum {
75 COUNTER_MAP_NOMAP,
76 COUNTER_MAP_NORMAL_MAP,
Harald Welte1cef74d2001-01-05 15:22:59 +000077 COUNTER_MAP_ZEROED,
78 COUNTER_MAP_SET
Marc Bouchere6869a82000-03-20 06:03:29 +000079 } maptype;
80 unsigned int mappos;
81};
82
Harald Welteaae69be2004-08-29 23:32:14 +000083enum iptcc_rule_type {
84 IPTCC_R_STANDARD, /* standard target (ACCEPT, ...) */
85 IPTCC_R_MODULE, /* extension module (SNAT, ...) */
86 IPTCC_R_FALLTHROUGH, /* fallthrough rule */
87 IPTCC_R_JUMP, /* jump to other chain */
Marc Bouchere6869a82000-03-20 06:03:29 +000088};
89
Harald Welteaae69be2004-08-29 23:32:14 +000090struct rule_head
Rusty Russell30fd6e52000-04-23 09:16:06 +000091{
Harald Welteaae69be2004-08-29 23:32:14 +000092 struct list_head list;
93 struct chain_head *chain;
94 struct counter_map counter_map;
95
96 unsigned int index; /* index (needed for counter_map) */
97 unsigned int offset; /* offset in rule blob */
98
99 enum iptcc_rule_type type;
100 struct chain_head *jump; /* jump target, if IPTCC_R_JUMP */
101
102 unsigned int size; /* size of entry data */
103 STRUCT_ENTRY entry[0];
104};
105
106struct chain_head
107{
108 struct list_head list;
Rusty Russell79dee072000-05-02 16:45:16 +0000109 char name[TABLE_MAXNAMELEN];
Harald Welteaae69be2004-08-29 23:32:14 +0000110 unsigned int hooknum; /* hook number+1 if builtin */
111 unsigned int references; /* how many jumps reference us */
112 int verdict; /* verdict if builtin */
113
114 STRUCT_COUNTERS counters; /* per-chain counters */
115 struct counter_map counter_map;
116
117 unsigned int num_rules; /* number of rules in list */
118 struct list_head rules; /* list of rules */
119
120 unsigned int index; /* index (needed for jump resolval) */
121 unsigned int head_offset; /* offset in rule blob */
122 unsigned int foot_index; /* index (needed for counter_map) */
123 unsigned int foot_offset; /* offset in rule blob */
Rusty Russell30fd6e52000-04-23 09:16:06 +0000124};
125
Rusty Russell79dee072000-05-02 16:45:16 +0000126STRUCT_TC_HANDLE
Marc Bouchere6869a82000-03-20 06:03:29 +0000127{
Harald Welteaae69be2004-08-29 23:32:14 +0000128 int changed; /* Have changes been made? */
129
130 struct list_head chains;
131
132 struct chain_head *chain_iterator_cur;
133 struct rule_head *rule_iterator_cur;
134
Jesper Dangaard Brouer48bde402008-01-15 17:06:48 +0000135 unsigned int num_chains; /* number of user defined chains */
136
Rusty Russell79dee072000-05-02 16:45:16 +0000137 STRUCT_GETINFO info;
Harald Welteaae69be2004-08-29 23:32:14 +0000138 STRUCT_GET_ENTRIES *entries;
Marc Bouchere6869a82000-03-20 06:03:29 +0000139};
140
Harald Welteaae69be2004-08-29 23:32:14 +0000141/* allocate a new chain head for the cache */
142static struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
143{
144 struct chain_head *c = malloc(sizeof(*c));
145 if (!c)
146 return NULL;
147 memset(c, 0, sizeof(*c));
148
149 strncpy(c->name, name, TABLE_MAXNAMELEN);
150 c->hooknum = hooknum;
151 INIT_LIST_HEAD(&c->rules);
152
153 return c;
154}
155
156/* allocate and initialize a new rule for the cache */
157static struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int size)
158{
159 struct rule_head *r = malloc(sizeof(*r)+size);
160 if (!r)
161 return NULL;
162 memset(r, 0, sizeof(*r));
163
164 r->chain = c;
165 r->size = size;
166
167 return r;
168}
169
170/* notify us that the ruleset has been modified by the user */
Jesper Dangaard Brouer91093982008-01-15 17:01:58 +0000171static inline void
Rusty Russell79dee072000-05-02 16:45:16 +0000172set_changed(TC_HANDLE_T h)
Rusty Russell175f6412000-03-24 09:32:20 +0000173{
Rusty Russell175f6412000-03-24 09:32:20 +0000174 h->changed = 1;
175}
176
Harald Welte380ba5f2002-02-13 16:19:55 +0000177#ifdef IPTC_DEBUG
Rusty Russell79dee072000-05-02 16:45:16 +0000178static void do_check(TC_HANDLE_T h, unsigned int line);
Rusty Russell849779c2000-04-23 15:51:51 +0000179#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
Rusty Russell30fd6e52000-04-23 09:16:06 +0000180#else
181#define CHECK(h)
182#endif
Marc Bouchere6869a82000-03-20 06:03:29 +0000183
Harald Welteaae69be2004-08-29 23:32:14 +0000184
185/**********************************************************************
186 * iptc blob utility functions (iptcb_*)
187 **********************************************************************/
188
Marc Bouchere6869a82000-03-20 06:03:29 +0000189static inline int
Harald Welteaae69be2004-08-29 23:32:14 +0000190iptcb_get_number(const STRUCT_ENTRY *i,
Rusty Russell79dee072000-05-02 16:45:16 +0000191 const STRUCT_ENTRY *seek,
Marc Bouchere6869a82000-03-20 06:03:29 +0000192 unsigned int *pos)
193{
194 if (i == seek)
195 return 1;
196 (*pos)++;
197 return 0;
198}
199
Marc Bouchere6869a82000-03-20 06:03:29 +0000200static inline int
Harald Welteaae69be2004-08-29 23:32:14 +0000201iptcb_get_entry_n(STRUCT_ENTRY *i,
Marc Bouchere6869a82000-03-20 06:03:29 +0000202 unsigned int number,
203 unsigned int *pos,
Rusty Russell79dee072000-05-02 16:45:16 +0000204 STRUCT_ENTRY **pe)
Marc Bouchere6869a82000-03-20 06:03:29 +0000205{
206 if (*pos == number) {
207 *pe = i;
208 return 1;
209 }
210 (*pos)++;
211 return 0;
212}
213
Harald Welteaae69be2004-08-29 23:32:14 +0000214static inline STRUCT_ENTRY *
215iptcb_get_entry(TC_HANDLE_T h, unsigned int offset)
216{
217 return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset);
218}
219
220static unsigned int
221iptcb_entry2index(const TC_HANDLE_T h, const STRUCT_ENTRY *seek)
Marc Bouchere6869a82000-03-20 06:03:29 +0000222{
223 unsigned int pos = 0;
Marc Bouchere6869a82000-03-20 06:03:29 +0000224
Harald Welteaae69be2004-08-29 23:32:14 +0000225 if (ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
226 iptcb_get_number, seek, &pos) == 0) {
227 fprintf(stderr, "ERROR: offset %u not an entry!\n",
228 (unsigned int)((char *)seek - (char *)h->entries->entrytable));
229 abort();
230 }
231 return pos;
Marc Bouchere6869a82000-03-20 06:03:29 +0000232}
233
Harald Welte0113fe72004-01-06 19:04:02 +0000234static inline STRUCT_ENTRY *
Harald Welteaae69be2004-08-29 23:32:14 +0000235iptcb_offset2entry(TC_HANDLE_T h, unsigned int offset)
Harald Welte0113fe72004-01-06 19:04:02 +0000236{
Harald Welteaae69be2004-08-29 23:32:14 +0000237 return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset);
Harald Welte0113fe72004-01-06 19:04:02 +0000238}
239
Harald Welteaae69be2004-08-29 23:32:14 +0000240
Harald Welte0113fe72004-01-06 19:04:02 +0000241static inline unsigned long
Harald Welteaae69be2004-08-29 23:32:14 +0000242iptcb_entry2offset(const TC_HANDLE_T h, const STRUCT_ENTRY *e)
Harald Welte0113fe72004-01-06 19:04:02 +0000243{
Harald Welteaae69be2004-08-29 23:32:14 +0000244 return (void *)e - (void *)h->entries->entrytable;
Harald Welte3ea8f402003-06-23 18:25:59 +0000245}
246
247static inline unsigned int
Harald Welteaae69be2004-08-29 23:32:14 +0000248iptcb_offset2index(const TC_HANDLE_T h, unsigned int offset)
Harald Welte3ea8f402003-06-23 18:25:59 +0000249{
Harald Welteaae69be2004-08-29 23:32:14 +0000250 return iptcb_entry2index(h, iptcb_offset2entry(h, offset));
251}
252
253/* Returns 0 if not hook entry, else hooknumber + 1 */
254static inline unsigned int
255iptcb_ent_is_hook_entry(STRUCT_ENTRY *e, TC_HANDLE_T h)
256{
257 unsigned int i;
258
259 for (i = 0; i < NUMHOOKS; i++) {
260 if ((h->info.valid_hooks & (1 << i))
261 && iptcb_get_entry(h, h->info.hook_entry[i]) == e)
262 return i+1;
263 }
264 return 0;
Harald Welte3ea8f402003-06-23 18:25:59 +0000265}
266
267
Harald Welteaae69be2004-08-29 23:32:14 +0000268/**********************************************************************
269 * iptc cache utility functions (iptcc_*)
270 **********************************************************************/
Harald Welte0113fe72004-01-06 19:04:02 +0000271
Harald Welteaae69be2004-08-29 23:32:14 +0000272/* Is the given chain builtin (1) or user-defined (0) */
Jesper Dangaard Brouer91093982008-01-15 17:01:58 +0000273static inline unsigned int iptcc_is_builtin(struct chain_head *c)
Harald Welteaae69be2004-08-29 23:32:14 +0000274{
275 return (c->hooknum ? 1 : 0);
276}
277
278/* Get a specific rule within a chain */
279static struct rule_head *iptcc_get_rule_num(struct chain_head *c,
280 unsigned int rulenum)
281{
282 struct rule_head *r;
283 unsigned int num = 0;
284
285 list_for_each_entry(r, &c->rules, list) {
286 num++;
287 if (num == rulenum)
288 return r;
289 }
290 return NULL;
291}
292
Martin Josefssona5616dc2004-10-24 22:27:31 +0000293/* Get a specific rule within a chain backwards */
294static struct rule_head *iptcc_get_rule_num_reverse(struct chain_head *c,
295 unsigned int rulenum)
296{
297 struct rule_head *r;
298 unsigned int num = 0;
299
300 list_for_each_entry_reverse(r, &c->rules, list) {
301 num++;
302 if (num == rulenum)
303 return r;
304 }
305 return NULL;
306}
307
Harald Welteaae69be2004-08-29 23:32:14 +0000308/* Returns chain head if found, otherwise NULL. */
309static struct chain_head *
310iptcc_find_chain_by_offset(TC_HANDLE_T handle, unsigned int offset)
311{
312 struct list_head *pos;
313
314 if (list_empty(&handle->chains))
315 return NULL;
316
317 list_for_each(pos, &handle->chains) {
318 struct chain_head *c = list_entry(pos, struct chain_head, list);
319 if (offset >= c->head_offset && offset <= c->foot_offset)
320 return c;
Harald Welte0113fe72004-01-06 19:04:02 +0000321 }
322
Harald Welteaae69be2004-08-29 23:32:14 +0000323 return NULL;
Harald Welte0113fe72004-01-06 19:04:02 +0000324}
Harald Welteaae69be2004-08-29 23:32:14 +0000325/* Returns chain head if found, otherwise NULL. */
326static struct chain_head *
327iptcc_find_label(const char *name, TC_HANDLE_T handle)
328{
329 struct list_head *pos;
330
331 if (list_empty(&handle->chains))
332 return NULL;
333
334 list_for_each(pos, &handle->chains) {
335 struct chain_head *c = list_entry(pos, struct chain_head, list);
336 if (!strcmp(c->name, name))
337 return c;
338 }
339
340 return NULL;
341}
342
343/* called when rule is to be removed from cache */
344static void iptcc_delete_rule(struct rule_head *r)
345{
346 DEBUGP("deleting rule %p (offset %u)\n", r, r->offset);
347 /* clean up reference count of called chain */
348 if (r->type == IPTCC_R_JUMP
349 && r->jump)
350 r->jump->references--;
351
352 list_del(&r->list);
353 free(r);
354}
355
356
357/**********************************************************************
358 * RULESET PARSER (blob -> cache)
359 **********************************************************************/
360
Harald Welteaae69be2004-08-29 23:32:14 +0000361/* Delete policy rule of previous chain, since cache doesn't contain
362 * chain policy rules.
363 * WARNING: This function has ugly design and relies on a lot of context, only
364 * to be called from specific places within the parser */
365static int __iptcc_p_del_policy(TC_HANDLE_T h, unsigned int num)
366{
367 if (h->chain_iterator_cur) {
368 /* policy rule is last rule */
369 struct rule_head *pr = (struct rule_head *)
370 h->chain_iterator_cur->rules.prev;
371
372 /* save verdict */
373 h->chain_iterator_cur->verdict =
374 *(int *)GET_TARGET(pr->entry)->data;
375
376 /* save counter and counter_map information */
377 h->chain_iterator_cur->counter_map.maptype =
378 COUNTER_MAP_NORMAL_MAP;
379 h->chain_iterator_cur->counter_map.mappos = num-1;
380 memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters,
381 sizeof(h->chain_iterator_cur->counters));
382
383 /* foot_offset points to verdict rule */
384 h->chain_iterator_cur->foot_index = num;
385 h->chain_iterator_cur->foot_offset = pr->offset;
386
387 /* delete rule from cache */
388 iptcc_delete_rule(pr);
Martin Josefsson8d1b38a2004-09-22 21:00:19 +0000389 h->chain_iterator_cur->num_rules--;
Harald Welteaae69be2004-08-29 23:32:14 +0000390
391 return 1;
392 }
393 return 0;
394}
395
Harald Welteec30b6c2005-02-01 16:45:56 +0000396/* alphabetically insert a chain into the list */
397static inline void iptc_insert_chain(TC_HANDLE_T h, struct chain_head *c)
398{
399 struct chain_head *tmp;
400
Olaf Rempel9d3ed772005-03-04 23:08:30 +0000401 /* sort only user defined chains */
402 if (!c->hooknum) {
403 list_for_each_entry(tmp, &h->chains, list) {
Robert de Barthfeca0572005-07-31 07:04:59 +0000404 if (!tmp->hooknum && strcmp(c->name, tmp->name) <= 0) {
Olaf Rempel9d3ed772005-03-04 23:08:30 +0000405 list_add(&c->list, tmp->list.prev);
406 return;
407 }
Harald Welteec30b6c2005-02-01 16:45:56 +0000408 }
409 }
410
411 /* survived till end of list: add at tail */
412 list_add_tail(&c->list, &h->chains);
413}
414
Harald Welteaae69be2004-08-29 23:32:14 +0000415/* Another ugly helper function split out of cache_add_entry to make it less
416 * spaghetti code */
417static void __iptcc_p_add_chain(TC_HANDLE_T h, struct chain_head *c,
418 unsigned int offset, unsigned int *num)
419{
Jesper Dangaard Brouer13364512007-12-12 15:20:42 +0000420 struct list_head *tail = h->chains.prev;
421 struct chain_head *ctail;
422
Harald Welteaae69be2004-08-29 23:32:14 +0000423 __iptcc_p_del_policy(h, *num);
424
425 c->head_offset = offset;
426 c->index = *num;
427
Jesper Dangaard Brouer13364512007-12-12 15:20:42 +0000428 /* Chains from kernel are already sorted, as they are inserted
429 * sorted. But there exists an issue when shifting to 1.4.0
430 * from an older version, as old versions allow last created
431 * chain to be unsorted.
432 */
433 if (iptcc_is_builtin(c)) /* Only user defined chains are sorted*/
434 list_add_tail(&c->list, &h->chains);
435 else {
436 ctail = list_entry(tail, struct chain_head, list);
437 if (strcmp(c->name, ctail->name) > 0)
438 list_add_tail(&c->list, &h->chains);/* Already sorted*/
439 else
440 iptc_insert_chain(h, c);/* Was not sorted */
441 }
Jesper Dangaard Brouerd8cb7872007-11-28 08:40:26 +0000442
Harald Welteaae69be2004-08-29 23:32:14 +0000443 h->chain_iterator_cur = c;
444}
445
446/* main parser function: add an entry from the blob to the cache */
447static int cache_add_entry(STRUCT_ENTRY *e,
448 TC_HANDLE_T h,
449 STRUCT_ENTRY **prev,
450 unsigned int *num)
451{
452 unsigned int builtin;
453 unsigned int offset = (char *)e - (char *)h->entries->entrytable;
454
455 DEBUGP("entering...");
456
457 /* Last entry ("policy rule"). End it.*/
458 if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) {
459 /* This is the ERROR node at the end of the chain */
460 DEBUGP_C("%u:%u: end of table:\n", *num, offset);
461
462 __iptcc_p_del_policy(h, *num);
463
464 h->chain_iterator_cur = NULL;
465 goto out_inc;
466 }
467
468 /* We know this is the start of a new chain if it's an ERROR
469 * target, or a hook entry point */
470
471 if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
472 struct chain_head *c =
473 iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0);
474 DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset,
475 (char *)c->name, c);
476 if (!c) {
477 errno = -ENOMEM;
478 return -1;
479 }
Jesper Dangaard Brouer48bde402008-01-15 17:06:48 +0000480 h->num_chains++; /* New user defined chain */
Harald Welteaae69be2004-08-29 23:32:14 +0000481
482 __iptcc_p_add_chain(h, c, offset, num);
483
484 } else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) {
485 struct chain_head *c =
486 iptcc_alloc_chain_head((char *)hooknames[builtin-1],
487 builtin);
488 DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
489 *num, offset, c, &c->rules);
490 if (!c) {
491 errno = -ENOMEM;
492 return -1;
493 }
494
495 c->hooknum = builtin;
496
497 __iptcc_p_add_chain(h, c, offset, num);
498
499 /* FIXME: this is ugly. */
500 goto new_rule;
501 } else {
502 /* has to be normal rule */
503 struct rule_head *r;
504new_rule:
505
506 if (!(r = iptcc_alloc_rule(h->chain_iterator_cur,
507 e->next_offset))) {
508 errno = ENOMEM;
509 return -1;
510 }
511 DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
512
513 r->index = *num;
514 r->offset = offset;
515 memcpy(r->entry, e, e->next_offset);
516 r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP;
517 r->counter_map.mappos = r->index;
518
519 /* handling of jumps, etc. */
520 if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) {
521 STRUCT_STANDARD_TARGET *t;
522
523 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
524 if (t->target.u.target_size
525 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
526 errno = EINVAL;
527 return -1;
528 }
529
530 if (t->verdict < 0) {
531 DEBUGP_C("standard, verdict=%d\n", t->verdict);
532 r->type = IPTCC_R_STANDARD;
533 } else if (t->verdict == r->offset+e->next_offset) {
534 DEBUGP_C("fallthrough\n");
535 r->type = IPTCC_R_FALLTHROUGH;
536 } else {
537 DEBUGP_C("jump, target=%u\n", t->verdict);
538 r->type = IPTCC_R_JUMP;
539 /* Jump target fixup has to be deferred
540 * until second pass, since we migh not
541 * yet have parsed the target */
542 }
Martin Josefsson52c38022004-09-22 19:39:40 +0000543 } else {
544 DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name);
545 r->type = IPTCC_R_MODULE;
Harald Welteaae69be2004-08-29 23:32:14 +0000546 }
547
548 list_add_tail(&r->list, &h->chain_iterator_cur->rules);
Martin Josefsson8d1b38a2004-09-22 21:00:19 +0000549 h->chain_iterator_cur->num_rules++;
Harald Welteaae69be2004-08-29 23:32:14 +0000550 }
551out_inc:
552 (*num)++;
553 return 0;
554}
555
556
557/* parse an iptables blob into it's pieces */
558static int parse_table(TC_HANDLE_T h)
559{
560 STRUCT_ENTRY *prev;
561 unsigned int num = 0;
562 struct chain_head *c;
563
564 /* First pass: over ruleset blob */
565 ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
566 cache_add_entry, h, &prev, &num);
567
568 /* Second pass: fixup parsed data from first pass */
569 list_for_each_entry(c, &h->chains, list) {
570 struct rule_head *r;
571 list_for_each_entry(r, &c->rules, list) {
572 struct chain_head *c;
573 STRUCT_STANDARD_TARGET *t;
574
575 if (r->type != IPTCC_R_JUMP)
576 continue;
577
578 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
579 c = iptcc_find_chain_by_offset(h, t->verdict);
580 if (!c)
581 return -1;
582 r->jump = c;
583 c->references++;
584 }
585 }
586
587 /* FIXME: sort chains */
588
589 return 1;
590}
591
592
593/**********************************************************************
594 * RULESET COMPILATION (cache -> blob)
595 **********************************************************************/
596
597/* Convenience structures */
598struct iptcb_chain_start{
599 STRUCT_ENTRY e;
600 struct ipt_error_target name;
601};
602#define IPTCB_CHAIN_START_SIZE (sizeof(STRUCT_ENTRY) + \
603 ALIGN(sizeof(struct ipt_error_target)))
604
605struct iptcb_chain_foot {
606 STRUCT_ENTRY e;
607 STRUCT_STANDARD_TARGET target;
608};
609#define IPTCB_CHAIN_FOOT_SIZE (sizeof(STRUCT_ENTRY) + \
610 ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
611
612struct iptcb_chain_error {
613 STRUCT_ENTRY entry;
614 struct ipt_error_target target;
615};
616#define IPTCB_CHAIN_ERROR_SIZE (sizeof(STRUCT_ENTRY) + \
617 ALIGN(sizeof(struct ipt_error_target)))
618
619
620
621/* compile rule from cache into blob */
622static inline int iptcc_compile_rule (TC_HANDLE_T h, STRUCT_REPLACE *repl, struct rule_head *r)
623{
624 /* handle jumps */
625 if (r->type == IPTCC_R_JUMP) {
626 STRUCT_STANDARD_TARGET *t;
627 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
628 /* memset for memcmp convenience on delete/replace */
629 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
630 strcpy(t->target.u.user.name, STANDARD_TARGET);
631 /* Jumps can only happen to builtin chains, so we
632 * can safely assume that they always have a header */
633 t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE;
634 } else if (r->type == IPTCC_R_FALLTHROUGH) {
635 STRUCT_STANDARD_TARGET *t;
636 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
637 t->verdict = r->offset + r->size;
638 }
639
640 /* copy entry from cache to blob */
641 memcpy((char *)repl->entries+r->offset, r->entry, r->size);
642
643 return 1;
644}
645
646/* compile chain from cache into blob */
647static int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain_head *c)
648{
649 int ret;
650 struct rule_head *r;
651 struct iptcb_chain_start *head;
652 struct iptcb_chain_foot *foot;
653
654 /* only user-defined chains have heaer */
655 if (!iptcc_is_builtin(c)) {
656 /* put chain header in place */
657 head = (void *)repl->entries + c->head_offset;
658 head->e.target_offset = sizeof(STRUCT_ENTRY);
659 head->e.next_offset = IPTCB_CHAIN_START_SIZE;
660 strcpy(head->name.t.u.user.name, ERROR_TARGET);
661 head->name.t.u.target_size =
662 ALIGN(sizeof(struct ipt_error_target));
663 strcpy(head->name.error, c->name);
664 } else {
665 repl->hook_entry[c->hooknum-1] = c->head_offset;
666 repl->underflow[c->hooknum-1] = c->foot_offset;
667 }
668
669 /* iterate over rules */
670 list_for_each_entry(r, &c->rules, list) {
671 ret = iptcc_compile_rule(h, repl, r);
672 if (ret < 0)
673 return ret;
674 }
675
676 /* put chain footer in place */
677 foot = (void *)repl->entries + c->foot_offset;
678 foot->e.target_offset = sizeof(STRUCT_ENTRY);
679 foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE;
680 strcpy(foot->target.target.u.user.name, STANDARD_TARGET);
681 foot->target.target.u.target_size =
682 ALIGN(sizeof(STRUCT_STANDARD_TARGET));
683 /* builtin targets have verdict, others return */
684 if (iptcc_is_builtin(c))
685 foot->target.verdict = c->verdict;
686 else
687 foot->target.verdict = RETURN;
688 /* set policy-counters */
689 memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
690
691 return 0;
692}
693
694/* calculate offset and number for every rule in the cache */
695static int iptcc_compile_chain_offsets(TC_HANDLE_T h, struct chain_head *c,
Harald Welteefa8fc22005-07-19 22:03:49 +0000696 unsigned int *offset, unsigned int *num)
Harald Welteaae69be2004-08-29 23:32:14 +0000697{
698 struct rule_head *r;
699
700 c->head_offset = *offset;
701 DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset);
702
703 if (!iptcc_is_builtin(c)) {
704 /* Chain has header */
705 *offset += sizeof(STRUCT_ENTRY)
706 + ALIGN(sizeof(struct ipt_error_target));
707 (*num)++;
708 }
709
710 list_for_each_entry(r, &c->rules, list) {
711 DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num);
712 r->offset = *offset;
713 r->index = *num;
714 *offset += r->size;
715 (*num)++;
716 }
717
718 DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num,
719 *offset, *num);
720 c->foot_offset = *offset;
721 c->foot_index = *num;
722 *offset += sizeof(STRUCT_ENTRY)
723 + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
724 (*num)++;
725
726 return 1;
727}
728
729/* put the pieces back together again */
730static int iptcc_compile_table_prep(TC_HANDLE_T h, unsigned int *size)
731{
732 struct chain_head *c;
733 unsigned int offset = 0, num = 0;
734 int ret = 0;
735
736 /* First pass: calculate offset for every rule */
737 list_for_each_entry(c, &h->chains, list) {
738 ret = iptcc_compile_chain_offsets(h, c, &offset, &num);
739 if (ret < 0)
740 return ret;
741 }
742
743 /* Append one error rule at end of chain */
744 num++;
745 offset += sizeof(STRUCT_ENTRY)
746 + ALIGN(sizeof(struct ipt_error_target));
747
748 /* ruleset size is now in offset */
749 *size = offset;
750 return num;
751}
752
753static int iptcc_compile_table(TC_HANDLE_T h, STRUCT_REPLACE *repl)
754{
755 struct chain_head *c;
756 struct iptcb_chain_error *error;
757
758 /* Second pass: copy from cache to offsets, fill in jumps */
759 list_for_each_entry(c, &h->chains, list) {
760 int ret = iptcc_compile_chain(h, repl, c);
761 if (ret < 0)
762 return ret;
763 }
764
765 /* Append error rule at end of chain */
766 error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE;
767 error->entry.target_offset = sizeof(STRUCT_ENTRY);
768 error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE;
769 error->target.t.u.user.target_size =
770 ALIGN(sizeof(struct ipt_error_target));
771 strcpy((char *)&error->target.t.u.user.name, ERROR_TARGET);
772 strcpy((char *)&error->target.error, "ERROR");
773
774 return 1;
775}
776
777/**********************************************************************
778 * EXTERNAL API (operates on cache only)
779 **********************************************************************/
Marc Bouchere6869a82000-03-20 06:03:29 +0000780
781/* Allocate handle of given size */
Rusty Russell79dee072000-05-02 16:45:16 +0000782static TC_HANDLE_T
Harald Welte0113fe72004-01-06 19:04:02 +0000783alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
Marc Bouchere6869a82000-03-20 06:03:29 +0000784{
785 size_t len;
Rusty Russell79dee072000-05-02 16:45:16 +0000786 TC_HANDLE_T h;
Marc Bouchere6869a82000-03-20 06:03:29 +0000787
Harald Welteaae69be2004-08-29 23:32:14 +0000788 len = sizeof(STRUCT_TC_HANDLE) + size;
Marc Bouchere6869a82000-03-20 06:03:29 +0000789
Harald Welteaae69be2004-08-29 23:32:14 +0000790 h = malloc(sizeof(STRUCT_TC_HANDLE));
791 if (!h) {
Marc Bouchere6869a82000-03-20 06:03:29 +0000792 errno = ENOMEM;
793 return NULL;
794 }
Harald Welteaae69be2004-08-29 23:32:14 +0000795 memset(h, 0, sizeof(*h));
796 INIT_LIST_HEAD(&h->chains);
Marc Bouchere6869a82000-03-20 06:03:29 +0000797 strcpy(h->info.name, tablename);
Harald Welteaae69be2004-08-29 23:32:14 +0000798
Harald Welte0371c0c2004-09-19 21:00:12 +0000799 h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size);
Harald Welteaae69be2004-08-29 23:32:14 +0000800 if (!h->entries)
801 goto out_free_handle;
802
803 strcpy(h->entries->name, tablename);
Harald Welte0371c0c2004-09-19 21:00:12 +0000804 h->entries->size = size;
Marc Bouchere6869a82000-03-20 06:03:29 +0000805
806 return h;
Harald Welteaae69be2004-08-29 23:32:14 +0000807
808out_free_handle:
809 free(h);
810
811 return NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +0000812}
813
Harald Welteaae69be2004-08-29 23:32:14 +0000814
Rusty Russell79dee072000-05-02 16:45:16 +0000815TC_HANDLE_T
816TC_INIT(const char *tablename)
Marc Bouchere6869a82000-03-20 06:03:29 +0000817{
Rusty Russell79dee072000-05-02 16:45:16 +0000818 TC_HANDLE_T h;
819 STRUCT_GETINFO info;
Harald Welteefa8fc22005-07-19 22:03:49 +0000820 unsigned int tmp;
Marc Bouchere6869a82000-03-20 06:03:29 +0000821 socklen_t s;
822
Rusty Russell79dee072000-05-02 16:45:16 +0000823 iptc_fn = TC_INIT;
Marc Bouchere6869a82000-03-20 06:03:29 +0000824
Martin Josefsson841e4ae2003-05-02 15:30:11 +0000825 if (strlen(tablename) >= TABLE_MAXNAMELEN) {
826 errno = EINVAL;
827 return NULL;
828 }
829
Derrik Pates664c0a32005-02-01 13:28:14 +0000830 if (sockfd_use == 0) {
831 sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
832 if (sockfd < 0)
833 return NULL;
834 }
835 sockfd_use++;
Marc Bouchere6869a82000-03-20 06:03:29 +0000836
837 s = sizeof(info);
Martin Josefsson841e4ae2003-05-02 15:30:11 +0000838
Marc Bouchere6869a82000-03-20 06:03:29 +0000839 strcpy(info.name, tablename);
Derrik Pates664c0a32005-02-01 13:28:14 +0000840 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) {
841 if (--sockfd_use == 0) {
842 close(sockfd);
843 sockfd = -1;
844 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000845 return NULL;
Derrik Pates664c0a32005-02-01 13:28:14 +0000846 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000847
Harald Welteaae69be2004-08-29 23:32:14 +0000848 DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
849 info.valid_hooks, info.num_entries, info.size);
850
Harald Welte0113fe72004-01-06 19:04:02 +0000851 if ((h = alloc_handle(info.name, info.size, info.num_entries))
Martin Josefsson841e4ae2003-05-02 15:30:11 +0000852 == NULL) {
Derrik Pates664c0a32005-02-01 13:28:14 +0000853 if (--sockfd_use == 0) {
854 close(sockfd);
855 sockfd = -1;
856 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000857 return NULL;
Martin Josefsson841e4ae2003-05-02 15:30:11 +0000858 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000859
Marc Bouchere6869a82000-03-20 06:03:29 +0000860 /* Initialize current state */
861 h->info = info;
Harald Welte0113fe72004-01-06 19:04:02 +0000862
Harald Welteaae69be2004-08-29 23:32:14 +0000863 h->entries->size = h->info.size;
Marc Bouchere6869a82000-03-20 06:03:29 +0000864
Rusty Russell79dee072000-05-02 16:45:16 +0000865 tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
Marc Bouchere6869a82000-03-20 06:03:29 +0000866
Harald Welteaae69be2004-08-29 23:32:14 +0000867 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
868 &tmp) < 0)
869 goto error;
870
871#ifdef IPTC_DEBUG2
872 {
873 int fd = open("/tmp/libiptc-so_get_entries.blob",
874 O_CREAT|O_WRONLY);
875 if (fd >= 0) {
876 write(fd, h->entries, tmp);
877 close(fd);
878 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000879 }
Harald Welteaae69be2004-08-29 23:32:14 +0000880#endif
881
882 if (parse_table(h) < 0)
883 goto error;
Rusty Russell7e53bf92000-03-20 07:03:28 +0000884
Marc Bouchere6869a82000-03-20 06:03:29 +0000885 CHECK(h);
886 return h;
Harald Welteaae69be2004-08-29 23:32:14 +0000887error:
888 TC_FREE(&h);
889 return NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +0000890}
891
Martin Josefsson841e4ae2003-05-02 15:30:11 +0000892void
893TC_FREE(TC_HANDLE_T *h)
894{
Harald Welteaae69be2004-08-29 23:32:14 +0000895 struct chain_head *c, *tmp;
896
Derrik Pates664c0a32005-02-01 13:28:14 +0000897 iptc_fn = TC_FREE;
898 if (--sockfd_use == 0) {
899 close(sockfd);
900 sockfd = -1;
901 }
Harald Welteaae69be2004-08-29 23:32:14 +0000902
903 list_for_each_entry_safe(c, tmp, &(*h)->chains, list) {
904 struct rule_head *r, *rtmp;
905
906 list_for_each_entry_safe(r, rtmp, &c->rules, list) {
907 free(r);
908 }
909
910 free(c);
911 }
912
913 free((*h)->entries);
Martin Josefsson841e4ae2003-05-02 15:30:11 +0000914 free(*h);
Harald Welteaae69be2004-08-29 23:32:14 +0000915
Martin Josefsson841e4ae2003-05-02 15:30:11 +0000916 *h = NULL;
917}
918
Marc Bouchere6869a82000-03-20 06:03:29 +0000919static inline int
Rusty Russell79dee072000-05-02 16:45:16 +0000920print_match(const STRUCT_ENTRY_MATCH *m)
Marc Bouchere6869a82000-03-20 06:03:29 +0000921{
Rusty Russell228e98d2000-04-27 10:28:06 +0000922 printf("Match name: `%s'\n", m->u.user.name);
Marc Bouchere6869a82000-03-20 06:03:29 +0000923 return 0;
924}
925
Rusty Russell79dee072000-05-02 16:45:16 +0000926static int dump_entry(STRUCT_ENTRY *e, const TC_HANDLE_T handle);
927
Marc Bouchere6869a82000-03-20 06:03:29 +0000928void
Rusty Russell79dee072000-05-02 16:45:16 +0000929TC_DUMP_ENTRIES(const TC_HANDLE_T handle)
Marc Bouchere6869a82000-03-20 06:03:29 +0000930{
Derrik Pates664c0a32005-02-01 13:28:14 +0000931 iptc_fn = TC_DUMP_ENTRIES;
Marc Bouchere6869a82000-03-20 06:03:29 +0000932 CHECK(handle);
Patrick McHardy97fb2f12007-09-08 16:52:25 +0000933
Rusty Russelle45c7132004-12-16 13:21:44 +0000934 printf("libiptc v%s. %u bytes.\n",
935 IPTABLES_VERSION, handle->entries->size);
Marc Bouchere6869a82000-03-20 06:03:29 +0000936 printf("Table `%s'\n", handle->info.name);
937 printf("Hooks: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
Rusty Russell67088e72000-05-10 01:18:57 +0000938 handle->info.hook_entry[HOOK_PRE_ROUTING],
939 handle->info.hook_entry[HOOK_LOCAL_IN],
940 handle->info.hook_entry[HOOK_FORWARD],
941 handle->info.hook_entry[HOOK_LOCAL_OUT],
942 handle->info.hook_entry[HOOK_POST_ROUTING]);
Marc Bouchere6869a82000-03-20 06:03:29 +0000943 printf("Underflows: pre/in/fwd/out/post = %u/%u/%u/%u/%u\n",
Rusty Russell67088e72000-05-10 01:18:57 +0000944 handle->info.underflow[HOOK_PRE_ROUTING],
945 handle->info.underflow[HOOK_LOCAL_IN],
946 handle->info.underflow[HOOK_FORWARD],
947 handle->info.underflow[HOOK_LOCAL_OUT],
948 handle->info.underflow[HOOK_POST_ROUTING]);
Marc Bouchere6869a82000-03-20 06:03:29 +0000949
Harald Welteaae69be2004-08-29 23:32:14 +0000950 ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size,
Rusty Russell79dee072000-05-02 16:45:16 +0000951 dump_entry, handle);
Harald Welte0113fe72004-01-06 19:04:02 +0000952}
Rusty Russell30fd6e52000-04-23 09:16:06 +0000953
Marc Bouchere6869a82000-03-20 06:03:29 +0000954/* Does this chain exist? */
Rusty Russell79dee072000-05-02 16:45:16 +0000955int TC_IS_CHAIN(const char *chain, const TC_HANDLE_T handle)
Marc Bouchere6869a82000-03-20 06:03:29 +0000956{
Derrik Pates664c0a32005-02-01 13:28:14 +0000957 iptc_fn = TC_IS_CHAIN;
Harald Welteaae69be2004-08-29 23:32:14 +0000958 return iptcc_find_label(chain, handle) != NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +0000959}
960
Harald Welteaae69be2004-08-29 23:32:14 +0000961static void iptcc_chain_iterator_advance(TC_HANDLE_T handle)
962{
963 struct chain_head *c = handle->chain_iterator_cur;
964
965 if (c->list.next == &handle->chains)
966 handle->chain_iterator_cur = NULL;
967 else
968 handle->chain_iterator_cur =
969 list_entry(c->list.next, struct chain_head, list);
970}
Marc Bouchere6869a82000-03-20 06:03:29 +0000971
Rusty Russell30fd6e52000-04-23 09:16:06 +0000972/* Iterator functions to run through the chains. */
Marc Bouchere6869a82000-03-20 06:03:29 +0000973const char *
Philip Blundell8c700902000-05-15 02:17:52 +0000974TC_FIRST_CHAIN(TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +0000975{
Harald Welteaae69be2004-08-29 23:32:14 +0000976 struct chain_head *c = list_entry((*handle)->chains.next,
977 struct chain_head, list);
978
979 iptc_fn = TC_FIRST_CHAIN;
980
981
982 if (list_empty(&(*handle)->chains)) {
983 DEBUGP(": no chains\n");
Harald Welte0113fe72004-01-06 19:04:02 +0000984 return NULL;
Harald Welteaae69be2004-08-29 23:32:14 +0000985 }
Marc Bouchere6869a82000-03-20 06:03:29 +0000986
Harald Welteaae69be2004-08-29 23:32:14 +0000987 (*handle)->chain_iterator_cur = c;
988 iptcc_chain_iterator_advance(*handle);
Harald Welte0113fe72004-01-06 19:04:02 +0000989
Harald Welteaae69be2004-08-29 23:32:14 +0000990 DEBUGP(": returning `%s'\n", c->name);
991 return c->name;
Marc Bouchere6869a82000-03-20 06:03:29 +0000992}
993
Rusty Russell30fd6e52000-04-23 09:16:06 +0000994/* Iterator functions to run through the chains. Returns NULL at end. */
995const char *
Rusty Russell79dee072000-05-02 16:45:16 +0000996TC_NEXT_CHAIN(TC_HANDLE_T *handle)
Rusty Russell30fd6e52000-04-23 09:16:06 +0000997{
Harald Welteaae69be2004-08-29 23:32:14 +0000998 struct chain_head *c = (*handle)->chain_iterator_cur;
Rusty Russell30fd6e52000-04-23 09:16:06 +0000999
Harald Welteaae69be2004-08-29 23:32:14 +00001000 iptc_fn = TC_NEXT_CHAIN;
1001
1002 if (!c) {
1003 DEBUGP(": no more chains\n");
Rusty Russell30fd6e52000-04-23 09:16:06 +00001004 return NULL;
Harald Welteaae69be2004-08-29 23:32:14 +00001005 }
Rusty Russell30fd6e52000-04-23 09:16:06 +00001006
Harald Welteaae69be2004-08-29 23:32:14 +00001007 iptcc_chain_iterator_advance(*handle);
1008
1009 DEBUGP(": returning `%s'\n", c->name);
1010 return c->name;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001011}
1012
1013/* Get first rule in the given chain: NULL for empty chain. */
Rusty Russell79dee072000-05-02 16:45:16 +00001014const STRUCT_ENTRY *
Philip Blundell8c700902000-05-15 02:17:52 +00001015TC_FIRST_RULE(const char *chain, TC_HANDLE_T *handle)
Rusty Russell30fd6e52000-04-23 09:16:06 +00001016{
Harald Welteaae69be2004-08-29 23:32:14 +00001017 struct chain_head *c;
1018 struct rule_head *r;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001019
Harald Welteaae69be2004-08-29 23:32:14 +00001020 iptc_fn = TC_FIRST_RULE;
1021
1022 DEBUGP("first rule(%s): ", chain);
1023
1024 c = iptcc_find_label(chain, *handle);
Rusty Russell30fd6e52000-04-23 09:16:06 +00001025 if (!c) {
1026 errno = ENOENT;
1027 return NULL;
1028 }
1029
1030 /* Empty chain: single return/policy rule */
Harald Welteaae69be2004-08-29 23:32:14 +00001031 if (list_empty(&c->rules)) {
1032 DEBUGP_C("no rules, returning NULL\n");
Rusty Russell30fd6e52000-04-23 09:16:06 +00001033 return NULL;
Harald Welteaae69be2004-08-29 23:32:14 +00001034 }
Rusty Russell30fd6e52000-04-23 09:16:06 +00001035
Harald Welteaae69be2004-08-29 23:32:14 +00001036 r = list_entry(c->rules.next, struct rule_head, list);
1037 (*handle)->rule_iterator_cur = r;
1038 DEBUGP_C("%p\n", r);
1039
1040 return r->entry;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001041}
1042
1043/* Returns NULL when rules run out. */
Rusty Russell79dee072000-05-02 16:45:16 +00001044const STRUCT_ENTRY *
Philip Blundell8c700902000-05-15 02:17:52 +00001045TC_NEXT_RULE(const STRUCT_ENTRY *prev, TC_HANDLE_T *handle)
Rusty Russell30fd6e52000-04-23 09:16:06 +00001046{
Harald Welteaae69be2004-08-29 23:32:14 +00001047 struct rule_head *r;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001048
Derrik Pates664c0a32005-02-01 13:28:14 +00001049 iptc_fn = TC_NEXT_RULE;
Harald Welteaae69be2004-08-29 23:32:14 +00001050 DEBUGP("rule_iterator_cur=%p...", (*handle)->rule_iterator_cur);
1051
1052 if (!(*handle)->rule_iterator_cur) {
1053 DEBUGP_C("returning NULL\n");
1054 return NULL;
1055 }
1056
1057 r = list_entry((*handle)->rule_iterator_cur->list.next,
1058 struct rule_head, list);
1059
1060 iptc_fn = TC_NEXT_RULE;
1061
1062 DEBUGP_C("next=%p, head=%p...", &r->list,
1063 &(*handle)->rule_iterator_cur->chain->rules);
1064
1065 if (&r->list == &(*handle)->rule_iterator_cur->chain->rules) {
1066 (*handle)->rule_iterator_cur = NULL;
1067 DEBUGP_C("finished, returning NULL\n");
1068 return NULL;
1069 }
1070
1071 (*handle)->rule_iterator_cur = r;
1072
1073 /* NOTE: prev is without any influence ! */
1074 DEBUGP_C("returning rule %p\n", r);
1075 return r->entry;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001076}
1077
Marc Bouchere6869a82000-03-20 06:03:29 +00001078/* How many rules in this chain? */
1079unsigned int
Rusty Russell79dee072000-05-02 16:45:16 +00001080TC_NUM_RULES(const char *chain, TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001081{
Harald Welteaae69be2004-08-29 23:32:14 +00001082 struct chain_head *c;
1083 iptc_fn = TC_NUM_RULES;
Marc Bouchere6869a82000-03-20 06:03:29 +00001084 CHECK(*handle);
Harald Welteaae69be2004-08-29 23:32:14 +00001085
1086 c = iptcc_find_label(chain, *handle);
1087 if (!c) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001088 errno = ENOENT;
1089 return (unsigned int)-1;
1090 }
Harald Welteaae69be2004-08-29 23:32:14 +00001091
1092 return c->num_rules;
Marc Bouchere6869a82000-03-20 06:03:29 +00001093}
1094
Rusty Russell79dee072000-05-02 16:45:16 +00001095const STRUCT_ENTRY *TC_GET_RULE(const char *chain,
1096 unsigned int n,
1097 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001098{
Harald Welteaae69be2004-08-29 23:32:14 +00001099 struct chain_head *c;
1100 struct rule_head *r;
1101
1102 iptc_fn = TC_GET_RULE;
Marc Bouchere6869a82000-03-20 06:03:29 +00001103
1104 CHECK(*handle);
Harald Welteaae69be2004-08-29 23:32:14 +00001105
1106 c = iptcc_find_label(chain, *handle);
1107 if (!c) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001108 errno = ENOENT;
1109 return NULL;
1110 }
1111
Harald Welteaae69be2004-08-29 23:32:14 +00001112 r = iptcc_get_rule_num(c, n);
1113 if (!r)
1114 return NULL;
1115 return r->entry;
Marc Bouchere6869a82000-03-20 06:03:29 +00001116}
1117
1118/* Returns a pointer to the target name of this position. */
Harald Welteaae69be2004-08-29 23:32:14 +00001119const char *standard_target_map(int verdict)
Marc Bouchere6869a82000-03-20 06:03:29 +00001120{
Harald Welteaae69be2004-08-29 23:32:14 +00001121 switch (verdict) {
1122 case RETURN:
1123 return LABEL_RETURN;
1124 break;
1125 case -NF_ACCEPT-1:
1126 return LABEL_ACCEPT;
1127 break;
1128 case -NF_DROP-1:
1129 return LABEL_DROP;
1130 break;
1131 case -NF_QUEUE-1:
1132 return LABEL_QUEUE;
1133 break;
1134 default:
1135 fprintf(stderr, "ERROR: %d not a valid target)\n",
1136 verdict);
1137 abort();
1138 break;
1139 }
1140 /* not reached */
1141 return NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +00001142}
1143
Harald Welteaae69be2004-08-29 23:32:14 +00001144/* Returns a pointer to the target name of this position. */
1145const char *TC_GET_TARGET(const STRUCT_ENTRY *ce,
1146 TC_HANDLE_T *handle)
1147{
1148 STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
Rusty Russelle45c7132004-12-16 13:21:44 +00001149 struct rule_head *r = container_of(e, struct rule_head, entry[0]);
Harald Welteaae69be2004-08-29 23:32:14 +00001150
1151 iptc_fn = TC_GET_TARGET;
1152
1153 switch(r->type) {
1154 int spos;
1155 case IPTCC_R_FALLTHROUGH:
1156 return "";
1157 break;
1158 case IPTCC_R_JUMP:
1159 DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name);
1160 return r->jump->name;
1161 break;
1162 case IPTCC_R_STANDARD:
1163 spos = *(int *)GET_TARGET(e)->data;
1164 DEBUGP("r=%p, spos=%d'\n", r, spos);
1165 return standard_target_map(spos);
1166 break;
1167 case IPTCC_R_MODULE:
1168 return GET_TARGET(e)->u.user.name;
1169 break;
1170 }
1171 return NULL;
1172}
Marc Bouchere6869a82000-03-20 06:03:29 +00001173/* Is this a built-in chain? Actually returns hook + 1. */
1174int
Rusty Russell79dee072000-05-02 16:45:16 +00001175TC_BUILTIN(const char *chain, const TC_HANDLE_T handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001176{
Harald Welteaae69be2004-08-29 23:32:14 +00001177 struct chain_head *c;
1178
1179 iptc_fn = TC_BUILTIN;
Marc Bouchere6869a82000-03-20 06:03:29 +00001180
Harald Welteaae69be2004-08-29 23:32:14 +00001181 c = iptcc_find_label(chain, handle);
1182 if (!c) {
1183 errno = ENOENT;
Martin Josefssonb0f3d2d2004-09-23 18:23:20 +00001184 return 0;
Marc Bouchere6869a82000-03-20 06:03:29 +00001185 }
Harald Welteaae69be2004-08-29 23:32:14 +00001186
1187 return iptcc_is_builtin(c);
Marc Bouchere6869a82000-03-20 06:03:29 +00001188}
1189
1190/* Get the policy of a given built-in chain */
1191const char *
Rusty Russell79dee072000-05-02 16:45:16 +00001192TC_GET_POLICY(const char *chain,
1193 STRUCT_COUNTERS *counters,
1194 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001195{
Harald Welteaae69be2004-08-29 23:32:14 +00001196 struct chain_head *c;
Marc Bouchere6869a82000-03-20 06:03:29 +00001197
Harald Welteaae69be2004-08-29 23:32:14 +00001198 iptc_fn = TC_GET_POLICY;
1199
1200 DEBUGP("called for chain %s\n", chain);
1201
1202 c = iptcc_find_label(chain, *handle);
1203 if (!c) {
1204 errno = ENOENT;
1205 return NULL;
1206 }
1207
1208 if (!iptcc_is_builtin(c))
Marc Bouchere6869a82000-03-20 06:03:29 +00001209 return NULL;
1210
Harald Welteaae69be2004-08-29 23:32:14 +00001211 *counters = c->counters;
Marc Bouchere6869a82000-03-20 06:03:29 +00001212
Harald Welteaae69be2004-08-29 23:32:14 +00001213 return standard_target_map(c->verdict);
Harald Welte0113fe72004-01-06 19:04:02 +00001214}
1215
1216static int
Harald Welteaae69be2004-08-29 23:32:14 +00001217iptcc_standard_map(struct rule_head *r, int verdict)
Harald Welte0113fe72004-01-06 19:04:02 +00001218{
Harald Welteaae69be2004-08-29 23:32:14 +00001219 STRUCT_ENTRY *e = r->entry;
Rusty Russell79dee072000-05-02 16:45:16 +00001220 STRUCT_STANDARD_TARGET *t;
Marc Bouchere6869a82000-03-20 06:03:29 +00001221
Rusty Russell79dee072000-05-02 16:45:16 +00001222 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
Marc Bouchere6869a82000-03-20 06:03:29 +00001223
Rusty Russell67088e72000-05-10 01:18:57 +00001224 if (t->target.u.target_size
Philip Blundell8c700902000-05-15 02:17:52 +00001225 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001226 errno = EINVAL;
1227 return 0;
1228 }
1229 /* memset for memcmp convenience on delete/replace */
Rusty Russell79dee072000-05-02 16:45:16 +00001230 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
1231 strcpy(t->target.u.user.name, STANDARD_TARGET);
Marc Bouchere6869a82000-03-20 06:03:29 +00001232 t->verdict = verdict;
1233
Harald Welteaae69be2004-08-29 23:32:14 +00001234 r->type = IPTCC_R_STANDARD;
1235
Marc Bouchere6869a82000-03-20 06:03:29 +00001236 return 1;
1237}
Rusty Russell7e53bf92000-03-20 07:03:28 +00001238
Marc Bouchere6869a82000-03-20 06:03:29 +00001239static int
Harald Welteaae69be2004-08-29 23:32:14 +00001240iptcc_map_target(const TC_HANDLE_T handle,
1241 struct rule_head *r)
Marc Bouchere6869a82000-03-20 06:03:29 +00001242{
Harald Welteaae69be2004-08-29 23:32:14 +00001243 STRUCT_ENTRY *e = r->entry;
Harald Welte0113fe72004-01-06 19:04:02 +00001244 STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
Marc Bouchere6869a82000-03-20 06:03:29 +00001245
Marc Bouchere6869a82000-03-20 06:03:29 +00001246 /* Maybe it's empty (=> fall through) */
Harald Welteaae69be2004-08-29 23:32:14 +00001247 if (strcmp(t->u.user.name, "") == 0) {
1248 r->type = IPTCC_R_FALLTHROUGH;
1249 return 1;
1250 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001251 /* Maybe it's a standard target name... */
Rusty Russell79dee072000-05-02 16:45:16 +00001252 else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00001253 return iptcc_standard_map(r, -NF_ACCEPT - 1);
Rusty Russell79dee072000-05-02 16:45:16 +00001254 else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00001255 return iptcc_standard_map(r, -NF_DROP - 1);
Rusty Russell67088e72000-05-10 01:18:57 +00001256 else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00001257 return iptcc_standard_map(r, -NF_QUEUE - 1);
Rusty Russell79dee072000-05-02 16:45:16 +00001258 else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00001259 return iptcc_standard_map(r, RETURN);
Rusty Russell79dee072000-05-02 16:45:16 +00001260 else if (TC_BUILTIN(t->u.user.name, handle)) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001261 /* Can't jump to builtins. */
1262 errno = EINVAL;
1263 return 0;
1264 } else {
1265 /* Maybe it's an existing chain name. */
Harald Welteaae69be2004-08-29 23:32:14 +00001266 struct chain_head *c;
1267 DEBUGP("trying to find chain `%s': ", t->u.user.name);
Marc Bouchere6869a82000-03-20 06:03:29 +00001268
Harald Welteaae69be2004-08-29 23:32:14 +00001269 c = iptcc_find_label(t->u.user.name, handle);
1270 if (c) {
1271 DEBUGP_C("found!\n");
1272 r->type = IPTCC_R_JUMP;
1273 r->jump = c;
1274 c->references++;
1275 return 1;
1276 }
1277 DEBUGP_C("not found :(\n");
Marc Bouchere6869a82000-03-20 06:03:29 +00001278 }
1279
1280 /* Must be a module? If not, kernel will reject... */
Rusty Russell3aef54d2005-01-03 03:48:40 +00001281 /* memset to all 0 for your memcmp convenience: don't clear version */
Rusty Russell228e98d2000-04-27 10:28:06 +00001282 memset(t->u.user.name + strlen(t->u.user.name),
Marc Bouchere6869a82000-03-20 06:03:29 +00001283 0,
Rusty Russell3aef54d2005-01-03 03:48:40 +00001284 FUNCTION_MAXNAMELEN - 1 - strlen(t->u.user.name));
Rusty Russell733e54b2004-12-16 14:22:23 +00001285 r->type = IPTCC_R_MODULE;
Harald Welteaae69be2004-08-29 23:32:14 +00001286 set_changed(handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00001287 return 1;
1288}
1289
Harald Welte0113fe72004-01-06 19:04:02 +00001290/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
Marc Bouchere6869a82000-03-20 06:03:29 +00001291int
Rusty Russell79dee072000-05-02 16:45:16 +00001292TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
1293 const STRUCT_ENTRY *e,
1294 unsigned int rulenum,
1295 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001296{
Harald Welteaae69be2004-08-29 23:32:14 +00001297 struct chain_head *c;
Martin Josefssoneb066cc2004-09-22 21:04:07 +00001298 struct rule_head *r;
1299 struct list_head *prev;
Marc Bouchere6869a82000-03-20 06:03:29 +00001300
Rusty Russell79dee072000-05-02 16:45:16 +00001301 iptc_fn = TC_INSERT_ENTRY;
Harald Welteaae69be2004-08-29 23:32:14 +00001302
1303 if (!(c = iptcc_find_label(chain, *handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001304 errno = ENOENT;
1305 return 0;
1306 }
1307
Martin Josefssoneb066cc2004-09-22 21:04:07 +00001308 /* first rulenum index = 0
1309 first c->num_rules index = 1 */
1310 if (rulenum > c->num_rules) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001311 errno = E2BIG;
1312 return 0;
1313 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001314
Martin Josefsson631f3612004-09-23 19:25:06 +00001315 /* If we are inserting at the end just take advantage of the
1316 double linked list, insert will happen before the entry
1317 prev points to. */
1318 if (rulenum == c->num_rules) {
Martin Josefssoneb066cc2004-09-22 21:04:07 +00001319 prev = &c->rules;
Martin Josefssona5616dc2004-10-24 22:27:31 +00001320 } else if (rulenum + 1 <= c->num_rules/2) {
Martin Josefsson631f3612004-09-23 19:25:06 +00001321 r = iptcc_get_rule_num(c, rulenum + 1);
Martin Josefssona5616dc2004-10-24 22:27:31 +00001322 prev = &r->list;
1323 } else {
1324 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
Martin Josefsson631f3612004-09-23 19:25:06 +00001325 prev = &r->list;
1326 }
Martin Josefssoneb066cc2004-09-22 21:04:07 +00001327
Harald Welteaae69be2004-08-29 23:32:14 +00001328 if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1329 errno = ENOMEM;
Harald Welte0113fe72004-01-06 19:04:02 +00001330 return 0;
Harald Welteaae69be2004-08-29 23:32:14 +00001331 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001332
Harald Welteaae69be2004-08-29 23:32:14 +00001333 memcpy(r->entry, e, e->next_offset);
1334 r->counter_map.maptype = COUNTER_MAP_SET;
1335
1336 if (!iptcc_map_target(*handle, r)) {
1337 free(r);
1338 return 0;
1339 }
1340
Martin Josefssoneb066cc2004-09-22 21:04:07 +00001341 list_add_tail(&r->list, prev);
Harald Welteaae69be2004-08-29 23:32:14 +00001342 c->num_rules++;
1343
1344 set_changed(*handle);
1345
1346 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001347}
1348
1349/* Atomically replace rule `rulenum' in `chain' with `fw'. */
1350int
Rusty Russell79dee072000-05-02 16:45:16 +00001351TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
1352 const STRUCT_ENTRY *e,
1353 unsigned int rulenum,
1354 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001355{
Harald Welteaae69be2004-08-29 23:32:14 +00001356 struct chain_head *c;
1357 struct rule_head *r, *old;
Marc Bouchere6869a82000-03-20 06:03:29 +00001358
Rusty Russell79dee072000-05-02 16:45:16 +00001359 iptc_fn = TC_REPLACE_ENTRY;
Marc Bouchere6869a82000-03-20 06:03:29 +00001360
Harald Welteaae69be2004-08-29 23:32:14 +00001361 if (!(c = iptcc_find_label(chain, *handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001362 errno = ENOENT;
1363 return 0;
1364 }
1365
Martin Josefsson0f9b8b12004-12-18 17:18:49 +00001366 if (rulenum >= c->num_rules) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001367 errno = E2BIG;
1368 return 0;
1369 }
1370
Martin Josefsson0f9b8b12004-12-18 17:18:49 +00001371 /* Take advantage of the double linked list if possible. */
1372 if (rulenum + 1 <= c->num_rules/2) {
1373 old = iptcc_get_rule_num(c, rulenum + 1);
1374 } else {
1375 old = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
1376 }
1377
Harald Welteaae69be2004-08-29 23:32:14 +00001378 if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1379 errno = ENOMEM;
Marc Bouchere6869a82000-03-20 06:03:29 +00001380 return 0;
Harald Welteaae69be2004-08-29 23:32:14 +00001381 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001382
Harald Welteaae69be2004-08-29 23:32:14 +00001383 memcpy(r->entry, e, e->next_offset);
1384 r->counter_map.maptype = COUNTER_MAP_SET;
1385
1386 if (!iptcc_map_target(*handle, r)) {
1387 free(r);
Harald Welte0113fe72004-01-06 19:04:02 +00001388 return 0;
Harald Welteaae69be2004-08-29 23:32:14 +00001389 }
Harald Welte0113fe72004-01-06 19:04:02 +00001390
Harald Welteaae69be2004-08-29 23:32:14 +00001391 list_add(&r->list, &old->list);
1392 iptcc_delete_rule(old);
1393
1394 set_changed(*handle);
1395
1396 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001397}
1398
Harald Welte0113fe72004-01-06 19:04:02 +00001399/* Append entry `fw' to chain `chain'. Equivalent to insert with
Marc Bouchere6869a82000-03-20 06:03:29 +00001400 rulenum = length of chain. */
1401int
Rusty Russell79dee072000-05-02 16:45:16 +00001402TC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
1403 const STRUCT_ENTRY *e,
1404 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001405{
Harald Welteaae69be2004-08-29 23:32:14 +00001406 struct chain_head *c;
1407 struct rule_head *r;
Marc Bouchere6869a82000-03-20 06:03:29 +00001408
Rusty Russell79dee072000-05-02 16:45:16 +00001409 iptc_fn = TC_APPEND_ENTRY;
Harald Welteaae69be2004-08-29 23:32:14 +00001410 if (!(c = iptcc_find_label(chain, *handle))) {
1411 DEBUGP("unable to find chain `%s'\n", chain);
Marc Bouchere6869a82000-03-20 06:03:29 +00001412 errno = ENOENT;
1413 return 0;
1414 }
1415
Harald Welteaae69be2004-08-29 23:32:14 +00001416 if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1417 DEBUGP("unable to allocate rule for chain `%s'\n", chain);
1418 errno = ENOMEM;
Harald Welte0113fe72004-01-06 19:04:02 +00001419 return 0;
Harald Welteaae69be2004-08-29 23:32:14 +00001420 }
Harald Welte0113fe72004-01-06 19:04:02 +00001421
Harald Welteaae69be2004-08-29 23:32:14 +00001422 memcpy(r->entry, e, e->next_offset);
1423 r->counter_map.maptype = COUNTER_MAP_SET;
1424
1425 if (!iptcc_map_target(*handle, r)) {
Martin Josefsson12009532004-09-23 18:24:29 +00001426 DEBUGP("unable to map target of rule for chain `%s'\n", chain);
Harald Welteaae69be2004-08-29 23:32:14 +00001427 free(r);
1428 return 0;
1429 }
1430
1431 list_add_tail(&r->list, &c->rules);
1432 c->num_rules++;
1433
1434 set_changed(*handle);
1435
1436 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001437}
1438
1439static inline int
Rusty Russell79dee072000-05-02 16:45:16 +00001440match_different(const STRUCT_ENTRY_MATCH *a,
Rusty Russelledf14cf2000-04-19 11:26:44 +00001441 const unsigned char *a_elems,
1442 const unsigned char *b_elems,
1443 unsigned char **maskptr)
Marc Bouchere6869a82000-03-20 06:03:29 +00001444{
Rusty Russell79dee072000-05-02 16:45:16 +00001445 const STRUCT_ENTRY_MATCH *b;
Rusty Russelledf14cf2000-04-19 11:26:44 +00001446 unsigned int i;
Marc Bouchere6869a82000-03-20 06:03:29 +00001447
1448 /* Offset of b is the same as a. */
Rusty Russell30fd6e52000-04-23 09:16:06 +00001449 b = (void *)b_elems + ((unsigned char *)a - a_elems);
Marc Bouchere6869a82000-03-20 06:03:29 +00001450
Rusty Russell228e98d2000-04-27 10:28:06 +00001451 if (a->u.match_size != b->u.match_size)
Marc Bouchere6869a82000-03-20 06:03:29 +00001452 return 1;
1453
Rusty Russell228e98d2000-04-27 10:28:06 +00001454 if (strcmp(a->u.user.name, b->u.user.name) != 0)
Marc Bouchere6869a82000-03-20 06:03:29 +00001455 return 1;
1456
Rusty Russell73ef09b2000-07-03 10:24:04 +00001457 *maskptr += ALIGN(sizeof(*a));
Rusty Russelledf14cf2000-04-19 11:26:44 +00001458
Rusty Russell73ef09b2000-07-03 10:24:04 +00001459 for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
Rusty Russelledf14cf2000-04-19 11:26:44 +00001460 if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
Rusty Russell90e712a2000-03-29 04:19:26 +00001461 return 1;
Rusty Russelledf14cf2000-04-19 11:26:44 +00001462 *maskptr += i;
1463 return 0;
1464}
1465
1466static inline int
Rusty Russell733e54b2004-12-16 14:22:23 +00001467target_same(struct rule_head *a, struct rule_head *b,const unsigned char *mask)
Rusty Russelledf14cf2000-04-19 11:26:44 +00001468{
1469 unsigned int i;
Rusty Russell733e54b2004-12-16 14:22:23 +00001470 STRUCT_ENTRY_TARGET *ta, *tb;
Marc Bouchere6869a82000-03-20 06:03:29 +00001471
Rusty Russell733e54b2004-12-16 14:22:23 +00001472 if (a->type != b->type)
1473 return 0;
1474
1475 ta = GET_TARGET(a->entry);
1476 tb = GET_TARGET(b->entry);
1477
1478 switch (a->type) {
1479 case IPTCC_R_FALLTHROUGH:
1480 return 1;
1481 case IPTCC_R_JUMP:
1482 return a->jump == b->jump;
1483 case IPTCC_R_STANDARD:
1484 return ((STRUCT_STANDARD_TARGET *)ta)->verdict
1485 == ((STRUCT_STANDARD_TARGET *)tb)->verdict;
1486 case IPTCC_R_MODULE:
1487 if (ta->u.target_size != tb->u.target_size)
1488 return 0;
1489 if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
1490 return 0;
1491
1492 for (i = 0; i < ta->u.target_size - sizeof(*ta); i++)
Rusty Russelldaade442004-12-29 11:14:52 +00001493 if (((ta->data[i] ^ tb->data[i]) & mask[i]) != 0)
Rusty Russell733e54b2004-12-16 14:22:23 +00001494 return 0;
1495 return 1;
1496 default:
1497 fprintf(stderr, "ERROR: bad type %i\n", a->type);
1498 abort();
1499 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001500}
1501
Rusty Russell733e54b2004-12-16 14:22:23 +00001502static unsigned char *
Rusty Russell79dee072000-05-02 16:45:16 +00001503is_same(const STRUCT_ENTRY *a,
1504 const STRUCT_ENTRY *b,
1505 unsigned char *matchmask);
Marc Bouchere6869a82000-03-20 06:03:29 +00001506
Harald Welte0113fe72004-01-06 19:04:02 +00001507/* Delete the first rule in `chain' which matches `fw'. */
Marc Bouchere6869a82000-03-20 06:03:29 +00001508int
Rusty Russell79dee072000-05-02 16:45:16 +00001509TC_DELETE_ENTRY(const IPT_CHAINLABEL chain,
1510 const STRUCT_ENTRY *origfw,
1511 unsigned char *matchmask,
1512 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001513{
Harald Welteaae69be2004-08-29 23:32:14 +00001514 struct chain_head *c;
Rusty Russelle45c7132004-12-16 13:21:44 +00001515 struct rule_head *r, *i;
Marc Bouchere6869a82000-03-20 06:03:29 +00001516
Rusty Russell79dee072000-05-02 16:45:16 +00001517 iptc_fn = TC_DELETE_ENTRY;
Harald Welteaae69be2004-08-29 23:32:14 +00001518 if (!(c = iptcc_find_label(chain, *handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001519 errno = ENOENT;
1520 return 0;
1521 }
1522
Rusty Russelle45c7132004-12-16 13:21:44 +00001523 /* Create a rule_head from origfw. */
1524 r = iptcc_alloc_rule(c, origfw->next_offset);
1525 if (!r) {
Harald Welte0113fe72004-01-06 19:04:02 +00001526 errno = ENOMEM;
1527 return 0;
1528 }
1529
Rusty Russelle45c7132004-12-16 13:21:44 +00001530 memcpy(r->entry, origfw, origfw->next_offset);
1531 r->counter_map.maptype = COUNTER_MAP_NOMAP;
1532 if (!iptcc_map_target(*handle, r)) {
1533 DEBUGP("unable to map target of rule for chain `%s'\n", chain);
1534 free(r);
1535 return 0;
Patrick McHardyJesper Brouer04a1e4c2006-07-25 01:50:48 +00001536 } else {
1537 /* iptcc_map_target increment target chain references
1538 * since this is a fake rule only used for matching
1539 * the chain references count is decremented again.
1540 */
1541 if (r->type == IPTCC_R_JUMP
1542 && r->jump)
1543 r->jump->references--;
Rusty Russelle45c7132004-12-16 13:21:44 +00001544 }
Harald Welte0113fe72004-01-06 19:04:02 +00001545
Rusty Russelle45c7132004-12-16 13:21:44 +00001546 list_for_each_entry(i, &c->rules, list) {
Rusty Russell733e54b2004-12-16 14:22:23 +00001547 unsigned char *mask;
Harald Weltefe537072004-08-30 20:28:53 +00001548
Rusty Russell733e54b2004-12-16 14:22:23 +00001549 mask = is_same(r->entry, i->entry, matchmask);
1550 if (!mask)
1551 continue;
Martin Josefsson2a5dbbb2004-09-22 21:37:41 +00001552
Rusty Russell733e54b2004-12-16 14:22:23 +00001553 if (!target_same(r, i, mask))
1554 continue;
1555
1556 /* If we are about to delete the rule that is the
1557 * current iterator, move rule iterator back. next
1558 * pointer will then point to real next node */
1559 if (i == (*handle)->rule_iterator_cur) {
1560 (*handle)->rule_iterator_cur =
1561 list_entry((*handle)->rule_iterator_cur->list.prev,
1562 struct rule_head, list);
Marc Bouchere6869a82000-03-20 06:03:29 +00001563 }
Rusty Russell733e54b2004-12-16 14:22:23 +00001564
1565 c->num_rules--;
1566 iptcc_delete_rule(i);
1567
1568 set_changed(*handle);
1569 free(r);
1570 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001571 }
1572
Rusty Russelle45c7132004-12-16 13:21:44 +00001573 free(r);
Marc Bouchere6869a82000-03-20 06:03:29 +00001574 errno = ENOENT;
1575 return 0;
Rusty Russell7e53bf92000-03-20 07:03:28 +00001576}
Harald Welteaae69be2004-08-29 23:32:14 +00001577
Marc Bouchere6869a82000-03-20 06:03:29 +00001578
1579/* Delete the rule in position `rulenum' in `chain'. */
1580int
Rusty Russell79dee072000-05-02 16:45:16 +00001581TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
1582 unsigned int rulenum,
1583 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001584{
Harald Welteaae69be2004-08-29 23:32:14 +00001585 struct chain_head *c;
1586 struct rule_head *r;
Marc Bouchere6869a82000-03-20 06:03:29 +00001587
Rusty Russell79dee072000-05-02 16:45:16 +00001588 iptc_fn = TC_DELETE_NUM_ENTRY;
Harald Welteaae69be2004-08-29 23:32:14 +00001589
1590 if (!(c = iptcc_find_label(chain, *handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001591 errno = ENOENT;
1592 return 0;
1593 }
1594
Martin Josefssona5616dc2004-10-24 22:27:31 +00001595 if (rulenum >= c->num_rules) {
Martin Josefsson631f3612004-09-23 19:25:06 +00001596 errno = E2BIG;
1597 return 0;
1598 }
1599
1600 /* Take advantage of the double linked list if possible. */
Martin Josefssona5616dc2004-10-24 22:27:31 +00001601 if (rulenum + 1 <= c->num_rules/2) {
1602 r = iptcc_get_rule_num(c, rulenum + 1);
1603 } else {
1604 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
Marc Bouchere6869a82000-03-20 06:03:29 +00001605 }
1606
Harald Welteaae69be2004-08-29 23:32:14 +00001607 /* If we are about to delete the rule that is the current
1608 * iterator, move rule iterator back. next pointer will then
1609 * point to real next node */
1610 if (r == (*handle)->rule_iterator_cur) {
1611 (*handle)->rule_iterator_cur =
1612 list_entry((*handle)->rule_iterator_cur->list.prev,
1613 struct rule_head, list);
Harald Welte0113fe72004-01-06 19:04:02 +00001614 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001615
Harald Welteaae69be2004-08-29 23:32:14 +00001616 c->num_rules--;
1617 iptcc_delete_rule(r);
1618
Martin Josefsson2a5dbbb2004-09-22 21:37:41 +00001619 set_changed(*handle);
1620
Harald Welteaae69be2004-08-29 23:32:14 +00001621 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001622}
1623
1624/* Check the packet `fw' on chain `chain'. Returns the verdict, or
1625 NULL and sets errno. */
1626const char *
Rusty Russell79dee072000-05-02 16:45:16 +00001627TC_CHECK_PACKET(const IPT_CHAINLABEL chain,
1628 STRUCT_ENTRY *entry,
1629 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001630{
Derrik Pates664c0a32005-02-01 13:28:14 +00001631 iptc_fn = TC_CHECK_PACKET;
Marc Bouchere6869a82000-03-20 06:03:29 +00001632 errno = ENOSYS;
1633 return NULL;
1634}
1635
1636/* Flushes the entries in the given chain (ie. empties chain). */
1637int
Rusty Russell79dee072000-05-02 16:45:16 +00001638TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001639{
Harald Welteaae69be2004-08-29 23:32:14 +00001640 struct chain_head *c;
1641 struct rule_head *r, *tmp;
Marc Bouchere6869a82000-03-20 06:03:29 +00001642
Harald Welte0113fe72004-01-06 19:04:02 +00001643 iptc_fn = TC_FLUSH_ENTRIES;
Harald Welteaae69be2004-08-29 23:32:14 +00001644 if (!(c = iptcc_find_label(chain, *handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001645 errno = ENOENT;
1646 return 0;
1647 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001648
Harald Welteaae69be2004-08-29 23:32:14 +00001649 list_for_each_entry_safe(r, tmp, &c->rules, list) {
1650 iptcc_delete_rule(r);
1651 }
1652
1653 c->num_rules = 0;
1654
1655 set_changed(*handle);
1656
1657 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001658}
1659
1660/* Zeroes the counters in a chain. */
1661int
Rusty Russell79dee072000-05-02 16:45:16 +00001662TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001663{
Harald Welteaae69be2004-08-29 23:32:14 +00001664 struct chain_head *c;
1665 struct rule_head *r;
Rusty Russell7e53bf92000-03-20 07:03:28 +00001666
Derrik Pates664c0a32005-02-01 13:28:14 +00001667 iptc_fn = TC_ZERO_ENTRIES;
Harald Welteaae69be2004-08-29 23:32:14 +00001668 if (!(c = iptcc_find_label(chain, *handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001669 errno = ENOENT;
1670 return 0;
1671 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001672
Andy Gaye5bd1d72006-08-22 02:56:41 +00001673 if (c->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1674 c->counter_map.maptype = COUNTER_MAP_ZEROED;
1675
Harald Welteaae69be2004-08-29 23:32:14 +00001676 list_for_each_entry(r, &c->rules, list) {
1677 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1678 r->counter_map.maptype = COUNTER_MAP_ZEROED;
Marc Bouchere6869a82000-03-20 06:03:29 +00001679 }
Harald Welteaae69be2004-08-29 23:32:14 +00001680
Rusty Russell175f6412000-03-24 09:32:20 +00001681 set_changed(*handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00001682
Marc Bouchere6869a82000-03-20 06:03:29 +00001683 return 1;
1684}
1685
Harald Welte1cef74d2001-01-05 15:22:59 +00001686STRUCT_COUNTERS *
1687TC_READ_COUNTER(const IPT_CHAINLABEL chain,
1688 unsigned int rulenum,
1689 TC_HANDLE_T *handle)
1690{
Harald Welteaae69be2004-08-29 23:32:14 +00001691 struct chain_head *c;
1692 struct rule_head *r;
Harald Welte1cef74d2001-01-05 15:22:59 +00001693
1694 iptc_fn = TC_READ_COUNTER;
1695 CHECK(*handle);
1696
Harald Welteaae69be2004-08-29 23:32:14 +00001697 if (!(c = iptcc_find_label(chain, *handle))) {
Harald Welte1cef74d2001-01-05 15:22:59 +00001698 errno = ENOENT;
1699 return NULL;
1700 }
1701
Harald Welteaae69be2004-08-29 23:32:14 +00001702 if (!(r = iptcc_get_rule_num(c, rulenum))) {
Harald Welte0113fe72004-01-06 19:04:02 +00001703 errno = E2BIG;
1704 return NULL;
1705 }
1706
Harald Welteaae69be2004-08-29 23:32:14 +00001707 return &r->entry[0].counters;
Harald Welte1cef74d2001-01-05 15:22:59 +00001708}
1709
1710int
1711TC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
1712 unsigned int rulenum,
1713 TC_HANDLE_T *handle)
1714{
Harald Welteaae69be2004-08-29 23:32:14 +00001715 struct chain_head *c;
1716 struct rule_head *r;
Harald Welte1cef74d2001-01-05 15:22:59 +00001717
1718 iptc_fn = TC_ZERO_COUNTER;
1719 CHECK(*handle);
1720
Harald Welteaae69be2004-08-29 23:32:14 +00001721 if (!(c = iptcc_find_label(chain, *handle))) {
Harald Welte1cef74d2001-01-05 15:22:59 +00001722 errno = ENOENT;
1723 return 0;
1724 }
1725
Harald Welteaae69be2004-08-29 23:32:14 +00001726 if (!(r = iptcc_get_rule_num(c, rulenum))) {
Harald Welte0113fe72004-01-06 19:04:02 +00001727 errno = E2BIG;
1728 return 0;
1729 }
1730
Harald Welteaae69be2004-08-29 23:32:14 +00001731 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
1732 r->counter_map.maptype = COUNTER_MAP_ZEROED;
Harald Welte1cef74d2001-01-05 15:22:59 +00001733
1734 set_changed(*handle);
1735
1736 return 1;
1737}
1738
1739int
1740TC_SET_COUNTER(const IPT_CHAINLABEL chain,
1741 unsigned int rulenum,
1742 STRUCT_COUNTERS *counters,
1743 TC_HANDLE_T *handle)
1744{
Harald Welteaae69be2004-08-29 23:32:14 +00001745 struct chain_head *c;
1746 struct rule_head *r;
Harald Welte1cef74d2001-01-05 15:22:59 +00001747 STRUCT_ENTRY *e;
Harald Welte1cef74d2001-01-05 15:22:59 +00001748
1749 iptc_fn = TC_SET_COUNTER;
1750 CHECK(*handle);
1751
Harald Welteaae69be2004-08-29 23:32:14 +00001752 if (!(c = iptcc_find_label(chain, *handle))) {
Harald Welte1cef74d2001-01-05 15:22:59 +00001753 errno = ENOENT;
1754 return 0;
1755 }
Harald Welte0113fe72004-01-06 19:04:02 +00001756
Harald Welteaae69be2004-08-29 23:32:14 +00001757 if (!(r = iptcc_get_rule_num(c, rulenum))) {
Harald Welte0113fe72004-01-06 19:04:02 +00001758 errno = E2BIG;
1759 return 0;
1760 }
1761
Harald Welteaae69be2004-08-29 23:32:14 +00001762 e = r->entry;
1763 r->counter_map.maptype = COUNTER_MAP_SET;
Harald Welte0113fe72004-01-06 19:04:02 +00001764
1765 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
Harald Welte1cef74d2001-01-05 15:22:59 +00001766
1767 set_changed(*handle);
1768
1769 return 1;
1770}
1771
Marc Bouchere6869a82000-03-20 06:03:29 +00001772/* Creates a new chain. */
1773/* To create a chain, create two rules: error node and unconditional
1774 * return. */
1775int
Rusty Russell79dee072000-05-02 16:45:16 +00001776TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001777{
Harald Welteaae69be2004-08-29 23:32:14 +00001778 static struct chain_head *c;
Marc Bouchere6869a82000-03-20 06:03:29 +00001779
Rusty Russell79dee072000-05-02 16:45:16 +00001780 iptc_fn = TC_CREATE_CHAIN;
Marc Bouchere6869a82000-03-20 06:03:29 +00001781
1782 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
1783 QUEUE, RETURN. */
Harald Welteaae69be2004-08-29 23:32:14 +00001784 if (iptcc_find_label(chain, *handle)
Rusty Russell79dee072000-05-02 16:45:16 +00001785 || strcmp(chain, LABEL_DROP) == 0
1786 || strcmp(chain, LABEL_ACCEPT) == 0
Rusty Russell67088e72000-05-10 01:18:57 +00001787 || strcmp(chain, LABEL_QUEUE) == 0
Rusty Russell79dee072000-05-02 16:45:16 +00001788 || strcmp(chain, LABEL_RETURN) == 0) {
Harald Welteaae69be2004-08-29 23:32:14 +00001789 DEBUGP("Chain `%s' already exists\n", chain);
Marc Bouchere6869a82000-03-20 06:03:29 +00001790 errno = EEXIST;
1791 return 0;
1792 }
1793
Rusty Russell79dee072000-05-02 16:45:16 +00001794 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
Harald Welteaae69be2004-08-29 23:32:14 +00001795 DEBUGP("Chain name `%s' too long\n", chain);
Marc Bouchere6869a82000-03-20 06:03:29 +00001796 errno = EINVAL;
1797 return 0;
1798 }
1799
Harald Welteaae69be2004-08-29 23:32:14 +00001800 c = iptcc_alloc_chain_head(chain, 0);
1801 if (!c) {
1802 DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
1803 errno = ENOMEM;
1804 return 0;
Marc Bouchere6869a82000-03-20 06:03:29 +00001805
Harald Welteaae69be2004-08-29 23:32:14 +00001806 }
Jesper Dangaard Brouer48bde402008-01-15 17:06:48 +00001807 (*handle)->num_chains++; /* New user defined chain */
Marc Bouchere6869a82000-03-20 06:03:29 +00001808
Harald Welteaae69be2004-08-29 23:32:14 +00001809 DEBUGP("Creating chain `%s'\n", chain);
Jesper Dangaard Brouerd8cb7872007-11-28 08:40:26 +00001810 iptc_insert_chain(*handle, c); /* Insert sorted */
Harald Welte0113fe72004-01-06 19:04:02 +00001811
1812 set_changed(*handle);
1813
Harald Welteaae69be2004-08-29 23:32:14 +00001814 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001815}
1816
1817/* Get the number of references to this chain. */
1818int
Rusty Russell79dee072000-05-02 16:45:16 +00001819TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
1820 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001821{
Harald Welteaae69be2004-08-29 23:32:14 +00001822 struct chain_head *c;
Marc Bouchere6869a82000-03-20 06:03:29 +00001823
Derrik Pates664c0a32005-02-01 13:28:14 +00001824 iptc_fn = TC_GET_REFERENCES;
Harald Welteaae69be2004-08-29 23:32:14 +00001825 if (!(c = iptcc_find_label(chain, *handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001826 errno = ENOENT;
1827 return 0;
1828 }
1829
Harald Welteaae69be2004-08-29 23:32:14 +00001830 *ref = c->references;
1831
Marc Bouchere6869a82000-03-20 06:03:29 +00001832 return 1;
1833}
1834
1835/* Deletes a chain. */
1836int
Rusty Russell79dee072000-05-02 16:45:16 +00001837TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001838{
Marc Bouchere6869a82000-03-20 06:03:29 +00001839 unsigned int references;
Harald Welteaae69be2004-08-29 23:32:14 +00001840 struct chain_head *c;
Rusty Russell7e53bf92000-03-20 07:03:28 +00001841
Rusty Russell79dee072000-05-02 16:45:16 +00001842 iptc_fn = TC_DELETE_CHAIN;
Marc Bouchere6869a82000-03-20 06:03:29 +00001843
Harald Welteaae69be2004-08-29 23:32:14 +00001844 if (!(c = iptcc_find_label(chain, *handle))) {
1845 DEBUGP("cannot find chain `%s'\n", chain);
Marc Bouchere6869a82000-03-20 06:03:29 +00001846 errno = ENOENT;
1847 return 0;
1848 }
1849
Harald Welteaae69be2004-08-29 23:32:14 +00001850 if (TC_BUILTIN(chain, *handle)) {
1851 DEBUGP("cannot remove builtin chain `%s'\n", chain);
1852 errno = EINVAL;
1853 return 0;
1854 }
1855
1856 if (!TC_GET_REFERENCES(&references, chain, handle)) {
1857 DEBUGP("cannot get references on chain `%s'\n", chain);
1858 return 0;
1859 }
1860
1861 if (references > 0) {
1862 DEBUGP("chain `%s' still has references\n", chain);
1863 errno = EMLINK;
1864 return 0;
1865 }
1866
1867 if (c->num_rules) {
1868 DEBUGP("chain `%s' is not empty\n", chain);
Marc Bouchere6869a82000-03-20 06:03:29 +00001869 errno = ENOTEMPTY;
1870 return 0;
1871 }
1872
Harald Welteaae69be2004-08-29 23:32:14 +00001873 /* If we are about to delete the chain that is the current
Jesper Dangaard Brouer48bde402008-01-15 17:06:48 +00001874 * iterator, move chain iterator forward. */
Harald Welteaae69be2004-08-29 23:32:14 +00001875 if (c == (*handle)->chain_iterator_cur)
1876 iptcc_chain_iterator_advance(*handle);
Harald Welte0113fe72004-01-06 19:04:02 +00001877
Harald Welteaae69be2004-08-29 23:32:14 +00001878 list_del(&c->list);
1879 free(c);
Harald Welte0113fe72004-01-06 19:04:02 +00001880
Jesper Dangaard Brouer48bde402008-01-15 17:06:48 +00001881 (*handle)->num_chains--; /* One user defined chain deleted */
1882
Harald Welteaae69be2004-08-29 23:32:14 +00001883 DEBUGP("chain `%s' deleted\n", chain);
1884
1885 set_changed(*handle);
1886
1887 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001888}
1889
1890/* Renames a chain. */
Rusty Russell79dee072000-05-02 16:45:16 +00001891int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
1892 const IPT_CHAINLABEL newname,
1893 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001894{
Harald Welteaae69be2004-08-29 23:32:14 +00001895 struct chain_head *c;
Rusty Russell79dee072000-05-02 16:45:16 +00001896 iptc_fn = TC_RENAME_CHAIN;
Marc Bouchere6869a82000-03-20 06:03:29 +00001897
Harald Welte1de80462000-10-30 12:00:27 +00001898 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
1899 QUEUE, RETURN. */
Harald Welteaae69be2004-08-29 23:32:14 +00001900 if (iptcc_find_label(newname, *handle)
Rusty Russell79dee072000-05-02 16:45:16 +00001901 || strcmp(newname, LABEL_DROP) == 0
1902 || strcmp(newname, LABEL_ACCEPT) == 0
Harald Welte1de80462000-10-30 12:00:27 +00001903 || strcmp(newname, LABEL_QUEUE) == 0
Rusty Russell79dee072000-05-02 16:45:16 +00001904 || strcmp(newname, LABEL_RETURN) == 0) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001905 errno = EEXIST;
1906 return 0;
1907 }
1908
Harald Welteaae69be2004-08-29 23:32:14 +00001909 if (!(c = iptcc_find_label(oldname, *handle))
Rusty Russell79dee072000-05-02 16:45:16 +00001910 || TC_BUILTIN(oldname, *handle)) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001911 errno = ENOENT;
1912 return 0;
1913 }
1914
Rusty Russell79dee072000-05-02 16:45:16 +00001915 if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001916 errno = EINVAL;
1917 return 0;
1918 }
1919
Harald Welteaae69be2004-08-29 23:32:14 +00001920 strncpy(c->name, newname, sizeof(IPT_CHAINLABEL));
1921
Harald Welte0113fe72004-01-06 19:04:02 +00001922 set_changed(*handle);
1923
Marc Bouchere6869a82000-03-20 06:03:29 +00001924 return 1;
1925}
1926
1927/* Sets the policy on a built-in chain. */
1928int
Rusty Russell79dee072000-05-02 16:45:16 +00001929TC_SET_POLICY(const IPT_CHAINLABEL chain,
1930 const IPT_CHAINLABEL policy,
Harald Welte1cef74d2001-01-05 15:22:59 +00001931 STRUCT_COUNTERS *counters,
Rusty Russell79dee072000-05-02 16:45:16 +00001932 TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001933{
Harald Welteaae69be2004-08-29 23:32:14 +00001934 struct chain_head *c;
Marc Bouchere6869a82000-03-20 06:03:29 +00001935
Rusty Russell79dee072000-05-02 16:45:16 +00001936 iptc_fn = TC_SET_POLICY;
Marc Bouchere6869a82000-03-20 06:03:29 +00001937
Harald Welteaae69be2004-08-29 23:32:14 +00001938 if (!(c = iptcc_find_label(chain, *handle))) {
1939 DEBUGP("cannot find chain `%s'\n", chain);
1940 errno = ENOENT;
Marc Bouchere6869a82000-03-20 06:03:29 +00001941 return 0;
1942 }
1943
Harald Welteaae69be2004-08-29 23:32:14 +00001944 if (!iptcc_is_builtin(c)) {
1945 DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain);
1946 errno = ENOENT;
1947 return 0;
1948 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001949
Rusty Russell79dee072000-05-02 16:45:16 +00001950 if (strcmp(policy, LABEL_ACCEPT) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00001951 c->verdict = -NF_ACCEPT - 1;
Rusty Russell79dee072000-05-02 16:45:16 +00001952 else if (strcmp(policy, LABEL_DROP) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00001953 c->verdict = -NF_DROP - 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001954 else {
1955 errno = EINVAL;
1956 return 0;
1957 }
Harald Welte1cef74d2001-01-05 15:22:59 +00001958
Harald Welte1cef74d2001-01-05 15:22:59 +00001959 if (counters) {
1960 /* set byte and packet counters */
Harald Welteaae69be2004-08-29 23:32:14 +00001961 memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS));
1962 c->counter_map.maptype = COUNTER_MAP_SET;
Harald Welte1cef74d2001-01-05 15:22:59 +00001963 } else {
Harald Welteaae69be2004-08-29 23:32:14 +00001964 c->counter_map.maptype = COUNTER_MAP_NOMAP;
Harald Welte1cef74d2001-01-05 15:22:59 +00001965 }
1966
Rusty Russell175f6412000-03-24 09:32:20 +00001967 set_changed(*handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00001968
Marc Bouchere6869a82000-03-20 06:03:29 +00001969 return 1;
1970}
1971
1972/* Without this, on gcc 2.7.2.3, we get:
Rusty Russell79dee072000-05-02 16:45:16 +00001973 libiptc.c: In function `TC_COMMIT':
Marc Bouchere6869a82000-03-20 06:03:29 +00001974 libiptc.c:833: fixed or forbidden register was spilled.
1975 This may be due to a compiler bug or to impossible asm
1976 statements or clauses.
1977*/
1978static void
Rusty Russell79dee072000-05-02 16:45:16 +00001979subtract_counters(STRUCT_COUNTERS *answer,
1980 const STRUCT_COUNTERS *a,
1981 const STRUCT_COUNTERS *b)
Marc Bouchere6869a82000-03-20 06:03:29 +00001982{
1983 answer->pcnt = a->pcnt - b->pcnt;
1984 answer->bcnt = a->bcnt - b->bcnt;
1985}
1986
Harald Welteaae69be2004-08-29 23:32:14 +00001987
1988static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters,
1989 unsigned int index)
1990{
1991 newcounters->counters[index] = ((STRUCT_COUNTERS) { 0, 0});
1992 DEBUGP_C("NOMAP => zero\n");
1993}
1994
1995static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
1996 STRUCT_REPLACE *repl,
1997 unsigned int index,
1998 unsigned int mappos)
1999{
2000 /* Original read: X.
2001 * Atomic read on replacement: X + Y.
2002 * Currently in kernel: Z.
2003 * Want in kernel: X + Y + Z.
2004 * => Add in X + Y
2005 * => Add in replacement read.
2006 */
2007 newcounters->counters[index] = repl->counters[mappos];
2008 DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
2009}
2010
2011static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
2012 STRUCT_REPLACE *repl,
2013 unsigned int index,
2014 unsigned int mappos,
2015 STRUCT_COUNTERS *counters)
2016{
2017 /* Original read: X.
2018 * Atomic read on replacement: X + Y.
2019 * Currently in kernel: Z.
2020 * Want in kernel: Y + Z.
2021 * => Add in Y.
2022 * => Add in (replacement read - original read).
2023 */
2024 subtract_counters(&newcounters->counters[index],
2025 &repl->counters[mappos],
2026 counters);
2027 DEBUGP_C("ZEROED => mappos %u\n", mappos);
2028}
2029
2030static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
2031 unsigned int index,
2032 STRUCT_COUNTERS *counters)
2033{
2034 /* Want to set counter (iptables-restore) */
2035
2036 memcpy(&newcounters->counters[index], counters,
2037 sizeof(STRUCT_COUNTERS));
2038
2039 DEBUGP_C("SET\n");
2040}
2041
2042
Marc Bouchere6869a82000-03-20 06:03:29 +00002043int
Rusty Russell79dee072000-05-02 16:45:16 +00002044TC_COMMIT(TC_HANDLE_T *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00002045{
2046 /* Replace, then map back the counters. */
Rusty Russell79dee072000-05-02 16:45:16 +00002047 STRUCT_REPLACE *repl;
2048 STRUCT_COUNTERS_INFO *newcounters;
Harald Welteaae69be2004-08-29 23:32:14 +00002049 struct chain_head *c;
2050 int ret;
Martin Josefsson841e4ae2003-05-02 15:30:11 +00002051 size_t counterlen;
Harald Welteaae69be2004-08-29 23:32:14 +00002052 int new_number;
2053 unsigned int new_size;
Marc Bouchere6869a82000-03-20 06:03:29 +00002054
Derrik Pates664c0a32005-02-01 13:28:14 +00002055 iptc_fn = TC_COMMIT;
Marc Bouchere6869a82000-03-20 06:03:29 +00002056 CHECK(*handle);
Martin Josefsson841e4ae2003-05-02 15:30:11 +00002057
Marc Bouchere6869a82000-03-20 06:03:29 +00002058 /* Don't commit if nothing changed. */
2059 if (!(*handle)->changed)
2060 goto finished;
2061
Harald Welteaae69be2004-08-29 23:32:14 +00002062 new_number = iptcc_compile_table_prep(*handle, &new_size);
2063 if (new_number < 0) {
2064 errno = ENOMEM;
Harald Welted6ba6f52005-11-12 10:39:40 +00002065 goto out_zero;
Harald Welteaae69be2004-08-29 23:32:14 +00002066 }
2067
2068 repl = malloc(sizeof(*repl) + new_size);
Marc Bouchere6869a82000-03-20 06:03:29 +00002069 if (!repl) {
2070 errno = ENOMEM;
Harald Welted6ba6f52005-11-12 10:39:40 +00002071 goto out_zero;
Marc Bouchere6869a82000-03-20 06:03:29 +00002072 }
Martin Josefssonad3b4f92004-09-22 22:04:07 +00002073 memset(repl, 0, sizeof(*repl) + new_size);
Harald Welteaae69be2004-08-29 23:32:14 +00002074
Rusty Russelle45c7132004-12-16 13:21:44 +00002075#if 0
2076 TC_DUMP_ENTRIES(*handle);
2077#endif
2078
Harald Welteaae69be2004-08-29 23:32:14 +00002079 counterlen = sizeof(STRUCT_COUNTERS_INFO)
2080 + sizeof(STRUCT_COUNTERS) * new_number;
Marc Bouchere6869a82000-03-20 06:03:29 +00002081
2082 /* These are the old counters we will get from kernel */
Rusty Russell79dee072000-05-02 16:45:16 +00002083 repl->counters = malloc(sizeof(STRUCT_COUNTERS)
Marc Bouchere6869a82000-03-20 06:03:29 +00002084 * (*handle)->info.num_entries);
2085 if (!repl->counters) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002086 errno = ENOMEM;
Harald Welted6ba6f52005-11-12 10:39:40 +00002087 goto out_free_repl;
Marc Bouchere6869a82000-03-20 06:03:29 +00002088 }
Marc Bouchere6869a82000-03-20 06:03:29 +00002089 /* These are the counters we're going to put back, later. */
2090 newcounters = malloc(counterlen);
2091 if (!newcounters) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002092 errno = ENOMEM;
Harald Welted6ba6f52005-11-12 10:39:40 +00002093 goto out_free_repl_counters;
Marc Bouchere6869a82000-03-20 06:03:29 +00002094 }
Harald Welteaae69be2004-08-29 23:32:14 +00002095 memset(newcounters, 0, counterlen);
Marc Bouchere6869a82000-03-20 06:03:29 +00002096
2097 strcpy(repl->name, (*handle)->info.name);
Harald Welteaae69be2004-08-29 23:32:14 +00002098 repl->num_entries = new_number;
2099 repl->size = new_size;
2100
Marc Bouchere6869a82000-03-20 06:03:29 +00002101 repl->num_counters = (*handle)->info.num_entries;
2102 repl->valid_hooks = (*handle)->info.valid_hooks;
Harald Welteaae69be2004-08-29 23:32:14 +00002103
2104 DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
2105 repl->num_entries, repl->size, repl->num_counters);
2106
2107 ret = iptcc_compile_table(*handle, repl);
2108 if (ret < 0) {
2109 errno = ret;
Harald Welted6ba6f52005-11-12 10:39:40 +00002110 goto out_free_newcounters;
Harald Welteaae69be2004-08-29 23:32:14 +00002111 }
2112
2113
2114#ifdef IPTC_DEBUG2
2115 {
2116 int fd = open("/tmp/libiptc-so_set_replace.blob",
2117 O_CREAT|O_WRONLY);
2118 if (fd >= 0) {
2119 write(fd, repl, sizeof(*repl) + repl->size);
2120 close(fd);
2121 }
2122 }
2123#endif
Marc Bouchere6869a82000-03-20 06:03:29 +00002124
Harald Welted6ba6f52005-11-12 10:39:40 +00002125 ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
2126 sizeof(*repl) + repl->size);
Patrick McHardye0865ad2006-04-22 02:08:56 +00002127 if (ret < 0)
Harald Welted6ba6f52005-11-12 10:39:40 +00002128 goto out_free_newcounters;
Marc Bouchere6869a82000-03-20 06:03:29 +00002129
2130 /* Put counters back. */
2131 strcpy(newcounters->name, (*handle)->info.name);
Harald Welteaae69be2004-08-29 23:32:14 +00002132 newcounters->num_counters = new_number;
Marc Bouchere6869a82000-03-20 06:03:29 +00002133
Harald Welteaae69be2004-08-29 23:32:14 +00002134 list_for_each_entry(c, &(*handle)->chains, list) {
2135 struct rule_head *r;
Marc Bouchere6869a82000-03-20 06:03:29 +00002136
Harald Welteaae69be2004-08-29 23:32:14 +00002137 /* Builtin chains have their own counters */
2138 if (iptcc_is_builtin(c)) {
2139 DEBUGP("counter for chain-index %u: ", c->foot_index);
2140 switch(c->counter_map.maptype) {
2141 case COUNTER_MAP_NOMAP:
2142 counters_nomap(newcounters, c->foot_index);
2143 break;
2144 case COUNTER_MAP_NORMAL_MAP:
2145 counters_normal_map(newcounters, repl,
2146 c->foot_index,
2147 c->counter_map.mappos);
2148 break;
2149 case COUNTER_MAP_ZEROED:
2150 counters_map_zeroed(newcounters, repl,
2151 c->foot_index,
2152 c->counter_map.mappos,
2153 &c->counters);
2154 break;
2155 case COUNTER_MAP_SET:
2156 counters_map_set(newcounters, c->foot_index,
2157 &c->counters);
2158 break;
2159 }
2160 }
Harald Welte1cef74d2001-01-05 15:22:59 +00002161
Harald Welteaae69be2004-08-29 23:32:14 +00002162 list_for_each_entry(r, &c->rules, list) {
2163 DEBUGP("counter for index %u: ", r->index);
2164 switch (r->counter_map.maptype) {
2165 case COUNTER_MAP_NOMAP:
2166 counters_nomap(newcounters, r->index);
2167 break;
Harald Welte1cef74d2001-01-05 15:22:59 +00002168
Harald Welteaae69be2004-08-29 23:32:14 +00002169 case COUNTER_MAP_NORMAL_MAP:
2170 counters_normal_map(newcounters, repl,
2171 r->index,
2172 r->counter_map.mappos);
2173 break;
Harald Welte1cef74d2001-01-05 15:22:59 +00002174
Harald Welteaae69be2004-08-29 23:32:14 +00002175 case COUNTER_MAP_ZEROED:
2176 counters_map_zeroed(newcounters, repl,
2177 r->index,
2178 r->counter_map.mappos,
2179 &r->entry->counters);
2180 break;
2181
2182 case COUNTER_MAP_SET:
2183 counters_map_set(newcounters, r->index,
2184 &r->entry->counters);
2185 break;
2186 }
Marc Bouchere6869a82000-03-20 06:03:29 +00002187 }
2188 }
Rusty Russell62527ce2000-09-04 09:45:54 +00002189
Harald Welteaae69be2004-08-29 23:32:14 +00002190#ifdef IPTC_DEBUG2
2191 {
2192 int fd = open("/tmp/libiptc-so_set_add_counters.blob",
2193 O_CREAT|O_WRONLY);
2194 if (fd >= 0) {
2195 write(fd, newcounters, counterlen);
2196 close(fd);
2197 }
2198 }
2199#endif
2200
Harald Welted6ba6f52005-11-12 10:39:40 +00002201 ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
2202 newcounters, counterlen);
Patrick McHardye0865ad2006-04-22 02:08:56 +00002203 if (ret < 0)
Harald Welted6ba6f52005-11-12 10:39:40 +00002204 goto out_free_newcounters;
Marc Bouchere6869a82000-03-20 06:03:29 +00002205
2206 free(repl->counters);
2207 free(repl);
2208 free(newcounters);
2209
Harald Welted6ba6f52005-11-12 10:39:40 +00002210finished:
Martin Josefsson841e4ae2003-05-02 15:30:11 +00002211 TC_FREE(handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00002212 return 1;
Harald Welted6ba6f52005-11-12 10:39:40 +00002213
2214out_free_newcounters:
2215 free(newcounters);
2216out_free_repl_counters:
2217 free(repl->counters);
2218out_free_repl:
2219 free(repl);
2220out_zero:
2221 return 0;
Marc Bouchere6869a82000-03-20 06:03:29 +00002222}
2223
2224/* Get raw socket. */
2225int
Patrick McHardy0b639362007-09-08 16:00:01 +00002226TC_GET_RAW_SOCKET(void)
Marc Bouchere6869a82000-03-20 06:03:29 +00002227{
2228 return sockfd;
2229}
2230
2231/* Translates errno numbers into more human-readable form than strerror. */
2232const char *
Rusty Russell79dee072000-05-02 16:45:16 +00002233TC_STRERROR(int err)
Marc Bouchere6869a82000-03-20 06:03:29 +00002234{
2235 unsigned int i;
2236 struct table_struct {
2237 void *fn;
2238 int err;
2239 const char *message;
2240 } table [] =
Harald Welte4ccfa632001-07-30 15:12:43 +00002241 { { TC_INIT, EPERM, "Permission denied (you must be root)" },
Rusty Russell79dee072000-05-02 16:45:16 +00002242 { TC_INIT, EINVAL, "Module is wrong version" },
Harald Welte4ccfa632001-07-30 15:12:43 +00002243 { TC_INIT, ENOENT,
2244 "Table does not exist (do you need to insmod?)" },
Rusty Russell79dee072000-05-02 16:45:16 +00002245 { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
2246 { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
2247 { TC_DELETE_CHAIN, EMLINK,
Marc Bouchere6869a82000-03-20 06:03:29 +00002248 "Can't delete chain with references left" },
Rusty Russell79dee072000-05-02 16:45:16 +00002249 { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
2250 { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
2251 { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
2252 { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
Harald Welte1cef74d2001-01-05 15:22:59 +00002253 { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
2254 { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
Rusty Russell79dee072000-05-02 16:45:16 +00002255 { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
2256 { TC_INSERT_ENTRY, EINVAL, "Target problem" },
Marc Bouchere6869a82000-03-20 06:03:29 +00002257 /* EINVAL for CHECK probably means bad interface. */
Rusty Russell79dee072000-05-02 16:45:16 +00002258 { TC_CHECK_PACKET, EINVAL,
Marc Boucherc8264992000-04-22 22:34:44 +00002259 "Bad arguments (does that interface exist?)" },
Harald Welte4ccfa632001-07-30 15:12:43 +00002260 { TC_CHECK_PACKET, ENOSYS,
2261 "Checking will most likely never get implemented" },
Marc Bouchere6869a82000-03-20 06:03:29 +00002262 /* ENOENT for DELETE probably means no matching rule */
Rusty Russell79dee072000-05-02 16:45:16 +00002263 { TC_DELETE_ENTRY, ENOENT,
Marc Boucherc8264992000-04-22 22:34:44 +00002264 "Bad rule (does a matching rule exist in that chain?)" },
Rusty Russell79dee072000-05-02 16:45:16 +00002265 { TC_SET_POLICY, ENOENT,
Marc Boucherc8264992000-04-22 22:34:44 +00002266 "Bad built-in chain name" },
Rusty Russell79dee072000-05-02 16:45:16 +00002267 { TC_SET_POLICY, EINVAL,
Marc Boucherc8264992000-04-22 22:34:44 +00002268 "Bad policy name" },
Harald Welte4ccfa632001-07-30 15:12:43 +00002269
2270 { NULL, 0, "Incompatible with this kernel" },
2271 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
2272 { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" },
2273 { NULL, ENOMEM, "Memory allocation problem" },
2274 { NULL, ENOENT, "No chain/target/match by that name" },
Marc Bouchere6869a82000-03-20 06:03:29 +00002275 };
2276
2277 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
2278 if ((!table[i].fn || table[i].fn == iptc_fn)
2279 && table[i].err == err)
2280 return table[i].message;
2281 }
2282
2283 return strerror(err);
2284}