blob: 0a29a690e5a413136cdeb38fd246fc3e5e317518 [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
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +010012 * 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
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +010020 * up after a ruleset change.
Harald Welteaae69be2004-08-29 23:32:14 +000021 * 2004-Aug-18: Harald Welte <laforge@netfilter.org>:
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +010022 * - further performance work: total reimplementation of libiptc.
Harald Welteaae69be2004-08-29 23:32:14 +000023 * - 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/)
Jesper Dangaard Brouerc9477d02009-03-23 14:27:44 +010026 *
27 * 2008-Jan+Jul: Jesper Dangaard Brouer <hawk@comx.dk>
28 * - performance work: speedup chain list "name" searching.
29 * - performance work: speedup initial ruleset parsing.
30 * - sponsored by ComX Networks A/S (http://www.comx.dk/)
Harald Welte3ea8f402003-06-23 18:25:59 +000031 */
Harald Welte15920d12004-05-16 09:05:07 +000032#include <sys/types.h>
33#include <sys/socket.h>
Stefan Tomanekd59b9db2011-03-08 22:42:51 +010034#include <stdbool.h>
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020035#include <xtables.h>
Stephane Ouellette7cd00282004-05-14 08:21:06 +000036
Harald Welteaae69be2004-08-29 23:32:14 +000037#include "linux_list.h"
38
39//#define IPTC_DEBUG2 1
40
41#ifdef IPTC_DEBUG2
42#include <fcntl.h>
43#define DEBUGP(x, args...) fprintf(stderr, "%s: " x, __FUNCTION__, ## args)
44#define DEBUGP_C(x, args...) fprintf(stderr, x, ## args)
45#else
46#define DEBUGP(x, args...)
47#define DEBUGP_C(x, args...)
48#endif
49
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +000050#ifdef DEBUG
51#define debug(x, args...) fprintf(stderr, x, ## args)
52#else
53#define debug(x, args...)
54#endif
55
Marc Bouchere6869a82000-03-20 06:03:29 +000056static void *iptc_fn = NULL;
57
Patrick McHardy0b639362007-09-08 16:00:01 +000058static const char *hooknames[] = {
59 [HOOK_PRE_ROUTING] = "PREROUTING",
60 [HOOK_LOCAL_IN] = "INPUT",
61 [HOOK_FORWARD] = "FORWARD",
62 [HOOK_LOCAL_OUT] = "OUTPUT",
63 [HOOK_POST_ROUTING] = "POSTROUTING",
Marc Bouchere6869a82000-03-20 06:03:29 +000064};
65
Harald Welteaae69be2004-08-29 23:32:14 +000066/* Convenience structures */
Harald Welteaae69be2004-08-29 23:32:14 +000067struct chain_head;
68struct rule_head;
69
Marc Bouchere6869a82000-03-20 06:03:29 +000070struct counter_map
71{
72 enum {
73 COUNTER_MAP_NOMAP,
74 COUNTER_MAP_NORMAL_MAP,
Harald Welte1cef74d2001-01-05 15:22:59 +000075 COUNTER_MAP_ZEROED,
76 COUNTER_MAP_SET
Marc Bouchere6869a82000-03-20 06:03:29 +000077 } maptype;
78 unsigned int mappos;
79};
80
Harald Welteaae69be2004-08-29 23:32:14 +000081enum iptcc_rule_type {
82 IPTCC_R_STANDARD, /* standard target (ACCEPT, ...) */
83 IPTCC_R_MODULE, /* extension module (SNAT, ...) */
84 IPTCC_R_FALLTHROUGH, /* fallthrough rule */
85 IPTCC_R_JUMP, /* jump to other chain */
Marc Bouchere6869a82000-03-20 06:03:29 +000086};
87
Harald Welteaae69be2004-08-29 23:32:14 +000088struct rule_head
Rusty Russell30fd6e52000-04-23 09:16:06 +000089{
Harald Welteaae69be2004-08-29 23:32:14 +000090 struct list_head list;
91 struct chain_head *chain;
92 struct counter_map counter_map;
93
94 unsigned int index; /* index (needed for counter_map) */
95 unsigned int offset; /* offset in rule blob */
96
97 enum iptcc_rule_type type;
98 struct chain_head *jump; /* jump target, if IPTCC_R_JUMP */
99
100 unsigned int size; /* size of entry data */
101 STRUCT_ENTRY entry[0];
102};
103
104struct chain_head
105{
106 struct list_head list;
Rusty Russell79dee072000-05-02 16:45:16 +0000107 char name[TABLE_MAXNAMELEN];
Harald Welteaae69be2004-08-29 23:32:14 +0000108 unsigned int hooknum; /* hook number+1 if builtin */
109 unsigned int references; /* how many jumps reference us */
110 int verdict; /* verdict if builtin */
111
112 STRUCT_COUNTERS counters; /* per-chain counters */
113 struct counter_map counter_map;
114
115 unsigned int num_rules; /* number of rules in list */
116 struct list_head rules; /* list of rules */
117
118 unsigned int index; /* index (needed for jump resolval) */
119 unsigned int head_offset; /* offset in rule blob */
120 unsigned int foot_index; /* index (needed for counter_map) */
121 unsigned int foot_offset; /* offset in rule blob */
Rusty Russell30fd6e52000-04-23 09:16:06 +0000122};
123
Rusty Russell79dee072000-05-02 16:45:16 +0000124STRUCT_TC_HANDLE
Marc Bouchere6869a82000-03-20 06:03:29 +0000125{
Jan Engelhardt175f4512008-11-10 17:25:55 +0100126 int sockfd;
Harald Welteaae69be2004-08-29 23:32:14 +0000127 int changed; /* Have changes been made? */
128
129 struct list_head chains;
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +0100130
Harald Welteaae69be2004-08-29 23:32:14 +0000131 struct chain_head *chain_iterator_cur;
132 struct rule_head *rule_iterator_cur;
133
Jesper Dangaard Brouer48bde402008-01-15 17:06:48 +0000134 unsigned int num_chains; /* number of user defined chains */
135
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000136 struct chain_head **chain_index; /* array for fast chain list access*/
137 unsigned int chain_index_sz;/* size of chain index array */
138
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200139 int sorted_offsets; /* if chains are received sorted from kernel,
140 * then the offsets are also sorted. Says if its
141 * possible to bsearch offsets using chain_index.
142 */
143
Rusty Russell79dee072000-05-02 16:45:16 +0000144 STRUCT_GETINFO info;
Harald Welteaae69be2004-08-29 23:32:14 +0000145 STRUCT_GET_ENTRIES *entries;
Marc Bouchere6869a82000-03-20 06:03:29 +0000146};
147
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200148enum bsearch_type {
149 BSEARCH_NAME, /* Binary search after chain name */
150 BSEARCH_OFFSET, /* Binary search based on offset */
151};
152
Harald Welteaae69be2004-08-29 23:32:14 +0000153/* allocate a new chain head for the cache */
154static struct chain_head *iptcc_alloc_chain_head(const char *name, int hooknum)
155{
156 struct chain_head *c = malloc(sizeof(*c));
157 if (!c)
158 return NULL;
159 memset(c, 0, sizeof(*c));
160
161 strncpy(c->name, name, TABLE_MAXNAMELEN);
162 c->hooknum = hooknum;
163 INIT_LIST_HEAD(&c->rules);
164
165 return c;
166}
167
168/* allocate and initialize a new rule for the cache */
169static struct rule_head *iptcc_alloc_rule(struct chain_head *c, unsigned int size)
170{
171 struct rule_head *r = malloc(sizeof(*r)+size);
172 if (!r)
173 return NULL;
174 memset(r, 0, sizeof(*r));
175
176 r->chain = c;
177 r->size = size;
178
179 return r;
180}
181
182/* notify us that the ruleset has been modified by the user */
Jesper Dangaard Brouer91093982008-01-15 17:01:58 +0000183static inline void
Jan Engelhardtfd187312008-11-10 16:59:27 +0100184set_changed(struct xtc_handle *h)
Rusty Russell175f6412000-03-24 09:32:20 +0000185{
Rusty Russell175f6412000-03-24 09:32:20 +0000186 h->changed = 1;
187}
188
Harald Welte380ba5f2002-02-13 16:19:55 +0000189#ifdef IPTC_DEBUG
Jan Engelhardtfd187312008-11-10 16:59:27 +0100190static void do_check(struct xtc_handle *h, unsigned int line);
Rusty Russell849779c2000-04-23 15:51:51 +0000191#define CHECK(h) do { if (!getenv("IPTC_NO_CHECK")) do_check((h), __LINE__); } while(0)
Rusty Russell30fd6e52000-04-23 09:16:06 +0000192#else
193#define CHECK(h)
194#endif
Marc Bouchere6869a82000-03-20 06:03:29 +0000195
Harald Welteaae69be2004-08-29 23:32:14 +0000196
197/**********************************************************************
198 * iptc blob utility functions (iptcb_*)
199 **********************************************************************/
200
Marc Bouchere6869a82000-03-20 06:03:29 +0000201static inline int
Harald Welteaae69be2004-08-29 23:32:14 +0000202iptcb_get_number(const STRUCT_ENTRY *i,
Rusty Russell79dee072000-05-02 16:45:16 +0000203 const STRUCT_ENTRY *seek,
Marc Bouchere6869a82000-03-20 06:03:29 +0000204 unsigned int *pos)
205{
206 if (i == seek)
207 return 1;
208 (*pos)++;
209 return 0;
210}
211
Marc Bouchere6869a82000-03-20 06:03:29 +0000212static inline int
Harald Welteaae69be2004-08-29 23:32:14 +0000213iptcb_get_entry_n(STRUCT_ENTRY *i,
Marc Bouchere6869a82000-03-20 06:03:29 +0000214 unsigned int number,
215 unsigned int *pos,
Rusty Russell79dee072000-05-02 16:45:16 +0000216 STRUCT_ENTRY **pe)
Marc Bouchere6869a82000-03-20 06:03:29 +0000217{
218 if (*pos == number) {
219 *pe = i;
220 return 1;
221 }
222 (*pos)++;
223 return 0;
224}
225
Harald Welteaae69be2004-08-29 23:32:14 +0000226static inline STRUCT_ENTRY *
Jan Engelhardtfd187312008-11-10 16:59:27 +0100227iptcb_get_entry(struct xtc_handle *h, unsigned int offset)
Harald Welteaae69be2004-08-29 23:32:14 +0000228{
229 return (STRUCT_ENTRY *)((char *)h->entries->entrytable + offset);
230}
231
232static unsigned int
Jan Engelhardtfd187312008-11-10 16:59:27 +0100233iptcb_entry2index(struct xtc_handle *const h, const STRUCT_ENTRY *seek)
Marc Bouchere6869a82000-03-20 06:03:29 +0000234{
235 unsigned int pos = 0;
Marc Bouchere6869a82000-03-20 06:03:29 +0000236
Harald Welteaae69be2004-08-29 23:32:14 +0000237 if (ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
238 iptcb_get_number, seek, &pos) == 0) {
239 fprintf(stderr, "ERROR: offset %u not an entry!\n",
240 (unsigned int)((char *)seek - (char *)h->entries->entrytable));
241 abort();
242 }
243 return pos;
Marc Bouchere6869a82000-03-20 06:03:29 +0000244}
245
Harald Welte0113fe72004-01-06 19:04:02 +0000246static inline STRUCT_ENTRY *
Jan Engelhardtfd187312008-11-10 16:59:27 +0100247iptcb_offset2entry(struct xtc_handle *h, unsigned int offset)
Harald Welte0113fe72004-01-06 19:04:02 +0000248{
Harald Welteaae69be2004-08-29 23:32:14 +0000249 return (STRUCT_ENTRY *) ((void *)h->entries->entrytable+offset);
Harald Welte0113fe72004-01-06 19:04:02 +0000250}
251
Harald Welteaae69be2004-08-29 23:32:14 +0000252
Harald Welte0113fe72004-01-06 19:04:02 +0000253static inline unsigned long
Jan Engelhardtfd187312008-11-10 16:59:27 +0100254iptcb_entry2offset(struct xtc_handle *const h, const STRUCT_ENTRY *e)
Harald Welte0113fe72004-01-06 19:04:02 +0000255{
Harald Welteaae69be2004-08-29 23:32:14 +0000256 return (void *)e - (void *)h->entries->entrytable;
Harald Welte3ea8f402003-06-23 18:25:59 +0000257}
258
259static inline unsigned int
Jan Engelhardtfd187312008-11-10 16:59:27 +0100260iptcb_offset2index(struct xtc_handle *const h, unsigned int offset)
Harald Welte3ea8f402003-06-23 18:25:59 +0000261{
Harald Welteaae69be2004-08-29 23:32:14 +0000262 return iptcb_entry2index(h, iptcb_offset2entry(h, offset));
263}
264
265/* Returns 0 if not hook entry, else hooknumber + 1 */
266static inline unsigned int
Jan Engelhardtfd187312008-11-10 16:59:27 +0100267iptcb_ent_is_hook_entry(STRUCT_ENTRY *e, struct xtc_handle *h)
Harald Welteaae69be2004-08-29 23:32:14 +0000268{
269 unsigned int i;
270
271 for (i = 0; i < NUMHOOKS; i++) {
272 if ((h->info.valid_hooks & (1 << i))
273 && iptcb_get_entry(h, h->info.hook_entry[i]) == e)
274 return i+1;
275 }
276 return 0;
Harald Welte3ea8f402003-06-23 18:25:59 +0000277}
278
279
Harald Welteaae69be2004-08-29 23:32:14 +0000280/**********************************************************************
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000281 * Chain index (cache utility) functions
282 **********************************************************************
283 * The chain index is an array with pointers into the chain list, with
284 * CHAIN_INDEX_BUCKET_LEN spacing. This facilitates the ability to
285 * speedup chain list searching, by find a more optimal starting
286 * points when searching the linked list.
287 *
288 * The starting point can be found fast by using a binary search of
289 * the chain index. Thus, reducing the previous search complexity of
290 * O(n) to O(log(n/k) + k) where k is CHAIN_INDEX_BUCKET_LEN.
291 *
292 * A nice property of the chain index, is that the "bucket" list
293 * length is max CHAIN_INDEX_BUCKET_LEN (when just build, inserts will
294 * change this). Oppose to hashing, where the "bucket" list length can
295 * vary a lot.
296 */
297#ifndef CHAIN_INDEX_BUCKET_LEN
298#define CHAIN_INDEX_BUCKET_LEN 40
299#endif
300
301/* Another nice property of the chain index is that inserting/creating
302 * chains in chain list don't change the correctness of the chain
303 * index, it only causes longer lists in the buckets.
304 *
305 * To mitigate the performance penalty of longer bucket lists and the
306 * penalty of rebuilding, the chain index is rebuild only when
307 * CHAIN_INDEX_INSERT_MAX chains has been added.
308 */
309#ifndef CHAIN_INDEX_INSERT_MAX
310#define CHAIN_INDEX_INSERT_MAX 355
311#endif
312
313static inline unsigned int iptcc_is_builtin(struct chain_head *c);
314
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000315/* Use binary search in the chain index array, to find a chain_head
316 * pointer closest to the place of the searched name element.
317 *
318 * Notes that, binary search (obviously) requires that the chain list
319 * is sorted by name.
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200320 *
321 * The not so obvious: The chain index array, is actually both sorted
322 * by name and offset, at the same time!. This is only true because,
323 * chain are stored sorted in the kernel (as we pushed it in sorted).
324 *
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000325 */
326static struct list_head *
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200327__iptcc_bsearch_chain_index(const char *name, unsigned int offset,
Jan Engelhardtfd187312008-11-10 16:59:27 +0100328 unsigned int *idx, struct xtc_handle *handle,
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200329 enum bsearch_type type)
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000330{
331 unsigned int pos, end;
332 int res;
333
334 struct list_head *list_pos;
335 list_pos=&handle->chains;
336
337 /* Check for empty array, e.g. no user defined chains */
338 if (handle->chain_index_sz == 0) {
339 debug("WARNING: handle->chain_index_sz == 0\n");
340 return list_pos;
341 }
342
343 /* Init */
344 end = handle->chain_index_sz;
345 pos = end / 2;
346
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200347 debug("bsearch Find chain:%s (pos:%d end:%d) (offset:%d)\n",
348 name, pos, end, offset);
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000349
350 /* Loop */
351 loop:
352 if (!handle->chain_index[pos]) {
353 fprintf(stderr, "ERROR: NULL pointer chain_index[%d]\n", pos);
354 return &handle->chains; /* Be safe, return orig start pos */
355 }
356
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200357 debug("bsearch Index[%d] name:%s ",
358 pos, handle->chain_index[pos]->name);
359
360 /* Support for different compare functions */
361 switch (type) {
362 case BSEARCH_NAME:
363 res = strcmp(name, handle->chain_index[pos]->name);
364 break;
365 case BSEARCH_OFFSET:
366 debug("head_offset:[%d] foot_offset:[%d] ",
367 handle->chain_index[pos]->head_offset,
368 handle->chain_index[pos]->foot_offset);
369 res = offset - handle->chain_index[pos]->head_offset;
370 break;
371 default:
372 fprintf(stderr, "ERROR: %d not a valid bsearch type\n",
373 type);
374 abort();
375 break;
376 }
377 debug("res:%d ", res);
378
379
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000380 list_pos = &handle->chain_index[pos]->list;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100381 *idx = pos;
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000382
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000383 if (res == 0) { /* Found element, by direct hit */
384 debug("[found] Direct hit pos:%d end:%d\n", pos, end);
385 return list_pos;
386 } else if (res < 0) { /* Too far, jump back */
387 end = pos;
388 pos = pos / 2;
389
390 /* Exit case: First element of array */
391 if (end == 0) {
392 debug("[found] Reached first array elem (end%d)\n",end);
393 return list_pos;
394 }
395 debug("jump back to pos:%d (end:%d)\n", pos, end);
396 goto loop;
Jiri Popelka96d0d012011-06-10 15:25:55 +0200397 } else { /* res > 0; Not far enough, jump forward */
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000398
399 /* Exit case: Last element of array */
400 if (pos == handle->chain_index_sz-1) {
401 debug("[found] Last array elem (end:%d)\n", end);
402 return list_pos;
403 }
404
405 /* Exit case: Next index less, thus elem in this list section */
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200406 switch (type) {
407 case BSEARCH_NAME:
408 res = strcmp(name, handle->chain_index[pos+1]->name);
409 break;
410 case BSEARCH_OFFSET:
411 res = offset - handle->chain_index[pos+1]->head_offset;
412 break;
413 }
414
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000415 if (res < 0) {
416 debug("[found] closest list (end:%d)\n", end);
417 return list_pos;
418 }
419
420 pos = (pos+end)/2;
421 debug("jump forward to pos:%d (end:%d)\n", pos, end);
422 goto loop;
423 }
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000424}
425
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200426/* Wrapper for string chain name based bsearch */
427static struct list_head *
428iptcc_bsearch_chain_index(const char *name, unsigned int *idx,
Jan Engelhardtfd187312008-11-10 16:59:27 +0100429 struct xtc_handle *handle)
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200430{
431 return __iptcc_bsearch_chain_index(name, 0, idx, handle, BSEARCH_NAME);
432}
433
434
435/* Wrapper for offset chain based bsearch */
436static struct list_head *
437iptcc_bsearch_chain_offset(unsigned int offset, unsigned int *idx,
Jan Engelhardtfd187312008-11-10 16:59:27 +0100438 struct xtc_handle *handle)
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200439{
440 struct list_head *pos;
441
442 /* If chains were not received sorted from kernel, then the
443 * offset bsearch is not possible.
444 */
445 if (!handle->sorted_offsets)
446 pos = handle->chains.next;
447 else
448 pos = __iptcc_bsearch_chain_index(NULL, offset, idx, handle,
449 BSEARCH_OFFSET);
450 return pos;
451}
452
453
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000454#ifdef DEBUG
455/* Trivial linear search of chain index. Function used for verifying
456 the output of bsearch function */
457static struct list_head *
Jan Engelhardtfd187312008-11-10 16:59:27 +0100458iptcc_linearly_search_chain_index(const char *name, struct xtc_handle *handle)
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000459{
460 unsigned int i=0;
461 int res=0;
462
463 struct list_head *list_pos;
464 list_pos = &handle->chains;
465
466 if (handle->chain_index_sz)
467 list_pos = &handle->chain_index[0]->list;
468
469 /* Linearly walk of chain index array */
470
471 for (i=0; i < handle->chain_index_sz; i++) {
472 if (handle->chain_index[i]) {
473 res = strcmp(handle->chain_index[i]->name, name);
474 if (res > 0)
475 break; // One step too far
476 list_pos = &handle->chain_index[i]->list;
477 if (res == 0)
478 break; // Direct hit
479 }
480 }
481
482 return list_pos;
483}
484#endif
485
Jan Engelhardtfd187312008-11-10 16:59:27 +0100486static int iptcc_chain_index_alloc(struct xtc_handle *h)
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000487{
488 unsigned int list_length = CHAIN_INDEX_BUCKET_LEN;
489 unsigned int array_elems;
490 unsigned int array_mem;
491
492 /* Allocate memory for the chain index array */
493 array_elems = (h->num_chains / list_length) +
494 (h->num_chains % list_length ? 1 : 0);
495 array_mem = sizeof(h->chain_index) * array_elems;
496
497 debug("Alloc Chain index, elems:%d mem:%d bytes\n",
498 array_elems, array_mem);
499
500 h->chain_index = malloc(array_mem);
Jan Engelhardt0eee3002008-11-26 17:18:08 +0100501 if (h->chain_index == NULL && array_mem > 0) {
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000502 h->chain_index_sz = 0;
503 return -ENOMEM;
504 }
505 memset(h->chain_index, 0, array_mem);
506 h->chain_index_sz = array_elems;
507
508 return 1;
509}
510
Jan Engelhardtfd187312008-11-10 16:59:27 +0100511static void iptcc_chain_index_free(struct xtc_handle *h)
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000512{
513 h->chain_index_sz = 0;
514 free(h->chain_index);
515}
516
517
518#ifdef DEBUG
Jan Engelhardtfd187312008-11-10 16:59:27 +0100519static void iptcc_chain_index_dump(struct xtc_handle *h)
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000520{
521 unsigned int i = 0;
522
523 /* Dump: contents of chain index array */
524 for (i=0; i < h->chain_index_sz; i++) {
525 if (h->chain_index[i]) {
526 fprintf(stderr, "Chain index[%d].name: %s\n",
527 i, h->chain_index[i]->name);
528 }
529 }
530}
531#endif
532
533/* Build the chain index */
Jan Engelhardtfd187312008-11-10 16:59:27 +0100534static int iptcc_chain_index_build(struct xtc_handle *h)
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000535{
536 unsigned int list_length = CHAIN_INDEX_BUCKET_LEN;
537 unsigned int chains = 0;
538 unsigned int cindex = 0;
539 struct chain_head *c;
540
541 /* Build up the chain index array here */
542 debug("Building chain index\n");
543
544 debug("Number of user defined chains:%d bucket_sz:%d array_sz:%d\n",
545 h->num_chains, list_length, h->chain_index_sz);
546
547 if (h->chain_index_sz == 0)
548 return 0;
549
550 list_for_each_entry(c, &h->chains, list) {
551
552 /* Issue: The index array needs to start after the
553 * builtin chains, as they are not sorted */
554 if (!iptcc_is_builtin(c)) {
555 cindex=chains / list_length;
556
557 /* Safe guard, break out on array limit, this
558 * is useful if chains are added and array is
559 * rebuild, without realloc of memory. */
560 if (cindex >= h->chain_index_sz)
561 break;
562
563 if ((chains % list_length)== 0) {
564 debug("\nIndex[%d] Chains:", cindex);
565 h->chain_index[cindex] = c;
566 }
567 chains++;
568 }
569 debug("%s, ", c->name);
570 }
571 debug("\n");
572
573 return 1;
574}
575
Jan Engelhardtfd187312008-11-10 16:59:27 +0100576static int iptcc_chain_index_rebuild(struct xtc_handle *h)
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000577{
578 debug("REBUILD chain index array\n");
579 iptcc_chain_index_free(h);
580 if ((iptcc_chain_index_alloc(h)) < 0)
581 return -ENOMEM;
582 iptcc_chain_index_build(h);
583 return 1;
584}
585
586/* Delete chain (pointer) from index array. Removing an element from
587 * the chain list only affects the chain index array, if the chain
588 * index points-to/uses that list pointer.
589 *
590 * There are different strategies, the simple and safe is to rebuild
591 * the chain index every time. The more advanced is to update the
592 * array index to point to the next element, but that requires some
593 * house keeping and boundry checks. The advanced is implemented, as
594 * the simple approach behaves badly when all chains are deleted
595 * because list_for_each processing will always hit the first chain
596 * index, thus causing a rebuild for every chain.
597 */
Jan Engelhardtfd187312008-11-10 16:59:27 +0100598static int iptcc_chain_index_delete_chain(struct chain_head *c, struct xtc_handle *h)
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000599{
Jan Engelhardt7d91a2a2011-05-30 01:39:54 +0200600 struct list_head *index_ptr, *next;
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000601 struct chain_head *c2;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100602 unsigned int idx, idx2;
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000603
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100604 index_ptr = iptcc_bsearch_chain_index(c->name, &idx, h);
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000605
606 debug("Del chain[%s] c->list:%p index_ptr:%p\n",
607 c->name, &c->list, index_ptr);
608
609 /* Save the next pointer */
610 next = c->list.next;
611 list_del(&c->list);
612
613 if (index_ptr == &c->list) { /* Chain used as index ptr */
614
615 /* See if its possible to avoid a rebuild, by shifting
616 * to next pointer. Its possible if the next pointer
617 * is located in the same index bucket.
618 */
619 c2 = list_entry(next, struct chain_head, list);
Jan Engelhardt7d91a2a2011-05-30 01:39:54 +0200620 iptcc_bsearch_chain_index(c2->name, &idx2, h);
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100621 if (idx != idx2) {
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000622 /* Rebuild needed */
623 return iptcc_chain_index_rebuild(h);
624 } else {
625 /* Avoiding rebuild */
626 debug("Update cindex[%d] with next ptr name:[%s]\n",
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100627 idx, c2->name);
628 h->chain_index[idx]=c2;
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000629 return 0;
630 }
631 }
632 return 0;
633}
634
635
636/**********************************************************************
Harald Welteaae69be2004-08-29 23:32:14 +0000637 * iptc cache utility functions (iptcc_*)
638 **********************************************************************/
Harald Welte0113fe72004-01-06 19:04:02 +0000639
Harald Welteaae69be2004-08-29 23:32:14 +0000640/* Is the given chain builtin (1) or user-defined (0) */
Jesper Dangaard Brouer91093982008-01-15 17:01:58 +0000641static inline unsigned int iptcc_is_builtin(struct chain_head *c)
Harald Welteaae69be2004-08-29 23:32:14 +0000642{
643 return (c->hooknum ? 1 : 0);
644}
645
646/* Get a specific rule within a chain */
647static struct rule_head *iptcc_get_rule_num(struct chain_head *c,
648 unsigned int rulenum)
649{
650 struct rule_head *r;
651 unsigned int num = 0;
652
653 list_for_each_entry(r, &c->rules, list) {
654 num++;
655 if (num == rulenum)
656 return r;
657 }
658 return NULL;
659}
660
Martin Josefssona5616dc2004-10-24 22:27:31 +0000661/* Get a specific rule within a chain backwards */
662static struct rule_head *iptcc_get_rule_num_reverse(struct chain_head *c,
663 unsigned int rulenum)
664{
665 struct rule_head *r;
666 unsigned int num = 0;
667
668 list_for_each_entry_reverse(r, &c->rules, list) {
669 num++;
670 if (num == rulenum)
671 return r;
672 }
673 return NULL;
674}
675
Harald Welteaae69be2004-08-29 23:32:14 +0000676/* Returns chain head if found, otherwise NULL. */
677static struct chain_head *
Jan Engelhardtfd187312008-11-10 16:59:27 +0100678iptcc_find_chain_by_offset(struct xtc_handle *handle, unsigned int offset)
Harald Welteaae69be2004-08-29 23:32:14 +0000679{
680 struct list_head *pos;
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200681 struct list_head *list_start_pos;
682 unsigned int i;
Harald Welteaae69be2004-08-29 23:32:14 +0000683
684 if (list_empty(&handle->chains))
685 return NULL;
686
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200687 /* Find a smart place to start the search */
688 list_start_pos = iptcc_bsearch_chain_offset(offset, &i, handle);
689
690 /* Note that iptcc_bsearch_chain_offset() skips builtin
691 * chains, but this function is only used for finding jump
692 * targets, and a buildin chain is not a valid jump target */
693
694 debug("Offset:[%u] starting search at index:[%u]\n", offset, i);
695// list_for_each(pos, &handle->chains) {
696 list_for_each(pos, list_start_pos->prev) {
Harald Welteaae69be2004-08-29 23:32:14 +0000697 struct chain_head *c = list_entry(pos, struct chain_head, list);
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200698 debug(".");
699 if (offset >= c->head_offset && offset <= c->foot_offset) {
700 debug("Offset search found chain:[%s]\n", c->name);
Harald Welteaae69be2004-08-29 23:32:14 +0000701 return c;
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200702 }
Harald Welte0113fe72004-01-06 19:04:02 +0000703 }
704
Harald Welteaae69be2004-08-29 23:32:14 +0000705 return NULL;
Harald Welte0113fe72004-01-06 19:04:02 +0000706}
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000707
Harald Welteaae69be2004-08-29 23:32:14 +0000708/* Returns chain head if found, otherwise NULL. */
709static struct chain_head *
Jan Engelhardtfd187312008-11-10 16:59:27 +0100710iptcc_find_label(const char *name, struct xtc_handle *handle)
Harald Welteaae69be2004-08-29 23:32:14 +0000711{
712 struct list_head *pos;
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000713 struct list_head *list_start_pos;
714 unsigned int i=0;
715 int res;
Harald Welteaae69be2004-08-29 23:32:14 +0000716
717 if (list_empty(&handle->chains))
718 return NULL;
719
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000720 /* First look at builtin chains */
Harald Welteaae69be2004-08-29 23:32:14 +0000721 list_for_each(pos, &handle->chains) {
722 struct chain_head *c = list_entry(pos, struct chain_head, list);
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000723 if (!iptcc_is_builtin(c))
724 break;
Harald Welteaae69be2004-08-29 23:32:14 +0000725 if (!strcmp(c->name, name))
726 return c;
727 }
728
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000729 /* Find a smart place to start the search via chain index */
730 //list_start_pos = iptcc_linearly_search_chain_index(name, handle);
731 list_start_pos = iptcc_bsearch_chain_index(name, &i, handle);
732
733 /* Handel if bsearch bails out early */
734 if (list_start_pos == &handle->chains) {
735 list_start_pos = pos;
736 }
737#ifdef DEBUG
738 else {
739 /* Verify result of bsearch against linearly index search */
740 struct list_head *test_pos;
741 struct chain_head *test_c, *tmp_c;
742 test_pos = iptcc_linearly_search_chain_index(name, handle);
743 if (list_start_pos != test_pos) {
744 debug("BUG in chain_index search\n");
745 test_c=list_entry(test_pos, struct chain_head,list);
746 tmp_c =list_entry(list_start_pos,struct chain_head,list);
747 debug("Verify search found:\n");
748 debug(" Chain:%s\n", test_c->name);
749 debug("BSearch found:\n");
750 debug(" Chain:%s\n", tmp_c->name);
751 exit(42);
752 }
753 }
754#endif
755
756 /* Initial/special case, no user defined chains */
757 if (handle->num_chains == 0)
758 return NULL;
759
760 /* Start searching through the chain list */
761 list_for_each(pos, list_start_pos->prev) {
762 struct chain_head *c = list_entry(pos, struct chain_head, list);
763 res = strcmp(c->name, name);
764 debug("List search name:%s == %s res:%d\n", name, c->name, res);
765 if (res==0)
766 return c;
767
768 /* We can stop earlier as we know list is sorted */
769 if (res>0 && !iptcc_is_builtin(c)) { /* Walked too far*/
770 debug(" Not in list, walked too far, sorted list\n");
771 return NULL;
772 }
773
774 /* Stop on wrap around, if list head is reached */
775 if (pos == &handle->chains) {
776 debug("Stop, list head reached\n");
777 return NULL;
778 }
779 }
780
781 debug("List search NOT found name:%s\n", name);
Harald Welteaae69be2004-08-29 23:32:14 +0000782 return NULL;
783}
784
785/* called when rule is to be removed from cache */
786static void iptcc_delete_rule(struct rule_head *r)
787{
788 DEBUGP("deleting rule %p (offset %u)\n", r, r->offset);
789 /* clean up reference count of called chain */
790 if (r->type == IPTCC_R_JUMP
791 && r->jump)
792 r->jump->references--;
793
794 list_del(&r->list);
795 free(r);
796}
797
798
799/**********************************************************************
800 * RULESET PARSER (blob -> cache)
801 **********************************************************************/
802
Harald Welteaae69be2004-08-29 23:32:14 +0000803/* Delete policy rule of previous chain, since cache doesn't contain
804 * chain policy rules.
805 * WARNING: This function has ugly design and relies on a lot of context, only
806 * to be called from specific places within the parser */
Jan Engelhardtfd187312008-11-10 16:59:27 +0100807static int __iptcc_p_del_policy(struct xtc_handle *h, unsigned int num)
Harald Welteaae69be2004-08-29 23:32:14 +0000808{
Jan Engelhardt51651b62009-10-23 23:35:49 +0200809 const unsigned char *data;
810
Harald Welteaae69be2004-08-29 23:32:14 +0000811 if (h->chain_iterator_cur) {
812 /* policy rule is last rule */
813 struct rule_head *pr = (struct rule_head *)
814 h->chain_iterator_cur->rules.prev;
815
816 /* save verdict */
Jan Engelhardt51651b62009-10-23 23:35:49 +0200817 data = GET_TARGET(pr->entry)->data;
818 h->chain_iterator_cur->verdict = *(const int *)data;
Harald Welteaae69be2004-08-29 23:32:14 +0000819
820 /* save counter and counter_map information */
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +0100821 h->chain_iterator_cur->counter_map.maptype =
Jan Engelhardt7c4d6682009-10-26 18:43:54 +0100822 COUNTER_MAP_ZEROED;
Harald Welteaae69be2004-08-29 23:32:14 +0000823 h->chain_iterator_cur->counter_map.mappos = num-1;
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +0100824 memcpy(&h->chain_iterator_cur->counters, &pr->entry->counters,
Harald Welteaae69be2004-08-29 23:32:14 +0000825 sizeof(h->chain_iterator_cur->counters));
826
827 /* foot_offset points to verdict rule */
828 h->chain_iterator_cur->foot_index = num;
829 h->chain_iterator_cur->foot_offset = pr->offset;
830
831 /* delete rule from cache */
832 iptcc_delete_rule(pr);
Martin Josefsson8d1b38a2004-09-22 21:00:19 +0000833 h->chain_iterator_cur->num_rules--;
Harald Welteaae69be2004-08-29 23:32:14 +0000834
835 return 1;
836 }
837 return 0;
838}
839
Harald Welteec30b6c2005-02-01 16:45:56 +0000840/* alphabetically insert a chain into the list */
Christoph Paasch7cd15e32009-03-23 13:50:11 +0100841static void iptc_insert_chain(struct xtc_handle *h, struct chain_head *c)
Harald Welteec30b6c2005-02-01 16:45:56 +0000842{
843 struct chain_head *tmp;
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000844 struct list_head *list_start_pos;
845 unsigned int i=1;
846
847 /* Find a smart place to start the insert search */
848 list_start_pos = iptcc_bsearch_chain_index(c->name, &i, h);
849
850 /* Handle the case, where chain.name is smaller than index[0] */
851 if (i==0 && strcmp(c->name, h->chain_index[0]->name) <= 0) {
852 h->chain_index[0] = c; /* Update chain index head */
853 list_start_pos = h->chains.next;
854 debug("Update chain_index[0] with %s\n", c->name);
855 }
856
857 /* Handel if bsearch bails out early */
858 if (list_start_pos == &h->chains) {
859 list_start_pos = h->chains.next;
860 }
Harald Welteec30b6c2005-02-01 16:45:56 +0000861
Olaf Rempel9d3ed772005-03-04 23:08:30 +0000862 /* sort only user defined chains */
863 if (!c->hooknum) {
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000864 list_for_each_entry(tmp, list_start_pos->prev, list) {
Robert de Barthfeca0572005-07-31 07:04:59 +0000865 if (!tmp->hooknum && strcmp(c->name, tmp->name) <= 0) {
Olaf Rempel9d3ed772005-03-04 23:08:30 +0000866 list_add(&c->list, tmp->list.prev);
867 return;
868 }
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +0000869
870 /* Stop if list head is reached */
871 if (&tmp->list == &h->chains) {
872 debug("Insert, list head reached add to tail\n");
873 break;
874 }
Harald Welteec30b6c2005-02-01 16:45:56 +0000875 }
876 }
877
878 /* survived till end of list: add at tail */
879 list_add_tail(&c->list, &h->chains);
880}
881
Harald Welteaae69be2004-08-29 23:32:14 +0000882/* Another ugly helper function split out of cache_add_entry to make it less
883 * spaghetti code */
Jan Engelhardtfd187312008-11-10 16:59:27 +0100884static void __iptcc_p_add_chain(struct xtc_handle *h, struct chain_head *c,
Harald Welteaae69be2004-08-29 23:32:14 +0000885 unsigned int offset, unsigned int *num)
886{
Jesper Dangaard Brouer13364512007-12-12 15:20:42 +0000887 struct list_head *tail = h->chains.prev;
888 struct chain_head *ctail;
889
Harald Welteaae69be2004-08-29 23:32:14 +0000890 __iptcc_p_del_policy(h, *num);
891
892 c->head_offset = offset;
893 c->index = *num;
894
Jesper Dangaard Brouer13364512007-12-12 15:20:42 +0000895 /* Chains from kernel are already sorted, as they are inserted
896 * sorted. But there exists an issue when shifting to 1.4.0
897 * from an older version, as old versions allow last created
898 * chain to be unsorted.
899 */
900 if (iptcc_is_builtin(c)) /* Only user defined chains are sorted*/
901 list_add_tail(&c->list, &h->chains);
902 else {
903 ctail = list_entry(tail, struct chain_head, list);
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200904
Jesper Dangaard Brouer526d3e12008-07-03 20:29:34 +0200905 if (strcmp(c->name, ctail->name) > 0 ||
906 iptcc_is_builtin(ctail))
Jesper Dangaard Brouer13364512007-12-12 15:20:42 +0000907 list_add_tail(&c->list, &h->chains);/* Already sorted*/
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200908 else {
Jesper Dangaard Brouer13364512007-12-12 15:20:42 +0000909 iptc_insert_chain(h, c);/* Was not sorted */
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +0200910
911 /* Notice, if chains were not received sorted
912 * from kernel, then an offset bsearch is no
913 * longer valid.
914 */
915 h->sorted_offsets = 0;
916
917 debug("NOTICE: chain:[%s] was NOT sorted(ctail:%s)\n",
918 c->name, ctail->name);
919 }
Jesper Dangaard Brouer13364512007-12-12 15:20:42 +0000920 }
Jesper Dangaard Brouerd8cb7872007-11-28 08:40:26 +0000921
Harald Welteaae69be2004-08-29 23:32:14 +0000922 h->chain_iterator_cur = c;
923}
924
925/* main parser function: add an entry from the blob to the cache */
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +0100926static int cache_add_entry(STRUCT_ENTRY *e,
927 struct xtc_handle *h,
Harald Welteaae69be2004-08-29 23:32:14 +0000928 STRUCT_ENTRY **prev,
929 unsigned int *num)
930{
931 unsigned int builtin;
932 unsigned int offset = (char *)e - (char *)h->entries->entrytable;
933
934 DEBUGP("entering...");
935
936 /* Last entry ("policy rule"). End it.*/
937 if (iptcb_entry2offset(h,e) + e->next_offset == h->entries->size) {
938 /* This is the ERROR node at the end of the chain */
939 DEBUGP_C("%u:%u: end of table:\n", *num, offset);
940
941 __iptcc_p_del_policy(h, *num);
942
943 h->chain_iterator_cur = NULL;
944 goto out_inc;
945 }
946
947 /* We know this is the start of a new chain if it's an ERROR
948 * target, or a hook entry point */
949
950 if (strcmp(GET_TARGET(e)->u.user.name, ERROR_TARGET) == 0) {
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +0100951 struct chain_head *c =
Harald Welteaae69be2004-08-29 23:32:14 +0000952 iptcc_alloc_chain_head((const char *)GET_TARGET(e)->data, 0);
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +0100953 DEBUGP_C("%u:%u:new userdefined chain %s: %p\n", *num, offset,
Harald Welteaae69be2004-08-29 23:32:14 +0000954 (char *)c->name, c);
955 if (!c) {
956 errno = -ENOMEM;
957 return -1;
958 }
Jesper Dangaard Brouer48bde402008-01-15 17:06:48 +0000959 h->num_chains++; /* New user defined chain */
Harald Welteaae69be2004-08-29 23:32:14 +0000960
961 __iptcc_p_add_chain(h, c, offset, num);
962
963 } else if ((builtin = iptcb_ent_is_hook_entry(e, h)) != 0) {
964 struct chain_head *c =
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +0100965 iptcc_alloc_chain_head((char *)hooknames[builtin-1],
Harald Welteaae69be2004-08-29 23:32:14 +0000966 builtin);
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +0100967 DEBUGP_C("%u:%u new builtin chain: %p (rules=%p)\n",
Harald Welteaae69be2004-08-29 23:32:14 +0000968 *num, offset, c, &c->rules);
969 if (!c) {
970 errno = -ENOMEM;
971 return -1;
972 }
973
974 c->hooknum = builtin;
975
976 __iptcc_p_add_chain(h, c, offset, num);
977
978 /* FIXME: this is ugly. */
979 goto new_rule;
980 } else {
981 /* has to be normal rule */
982 struct rule_head *r;
983new_rule:
984
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +0100985 if (!(r = iptcc_alloc_rule(h->chain_iterator_cur,
Harald Welteaae69be2004-08-29 23:32:14 +0000986 e->next_offset))) {
987 errno = ENOMEM;
988 return -1;
989 }
990 DEBUGP_C("%u:%u normal rule: %p: ", *num, offset, r);
991
992 r->index = *num;
993 r->offset = offset;
994 memcpy(r->entry, e, e->next_offset);
995 r->counter_map.maptype = COUNTER_MAP_NORMAL_MAP;
996 r->counter_map.mappos = r->index;
997
998 /* handling of jumps, etc. */
999 if (!strcmp(GET_TARGET(e)->u.user.name, STANDARD_TARGET)) {
1000 STRUCT_STANDARD_TARGET *t;
1001
1002 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
1003 if (t->target.u.target_size
1004 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
1005 errno = EINVAL;
1006 return -1;
1007 }
1008
1009 if (t->verdict < 0) {
1010 DEBUGP_C("standard, verdict=%d\n", t->verdict);
1011 r->type = IPTCC_R_STANDARD;
1012 } else if (t->verdict == r->offset+e->next_offset) {
1013 DEBUGP_C("fallthrough\n");
1014 r->type = IPTCC_R_FALLTHROUGH;
1015 } else {
1016 DEBUGP_C("jump, target=%u\n", t->verdict);
1017 r->type = IPTCC_R_JUMP;
1018 /* Jump target fixup has to be deferred
1019 * until second pass, since we migh not
1020 * yet have parsed the target */
1021 }
Martin Josefsson52c38022004-09-22 19:39:40 +00001022 } else {
1023 DEBUGP_C("module, target=%s\n", GET_TARGET(e)->u.user.name);
1024 r->type = IPTCC_R_MODULE;
Harald Welteaae69be2004-08-29 23:32:14 +00001025 }
1026
1027 list_add_tail(&r->list, &h->chain_iterator_cur->rules);
Martin Josefsson8d1b38a2004-09-22 21:00:19 +00001028 h->chain_iterator_cur->num_rules++;
Harald Welteaae69be2004-08-29 23:32:14 +00001029 }
1030out_inc:
1031 (*num)++;
1032 return 0;
1033}
1034
1035
1036/* parse an iptables blob into it's pieces */
Jan Engelhardtfd187312008-11-10 16:59:27 +01001037static int parse_table(struct xtc_handle *h)
Harald Welteaae69be2004-08-29 23:32:14 +00001038{
1039 STRUCT_ENTRY *prev;
1040 unsigned int num = 0;
1041 struct chain_head *c;
1042
Jesper Dangaard Brouer4bae3f12008-07-03 20:31:42 +02001043 /* Assume that chains offsets are sorted, this verified during
1044 parsing of ruleset (in __iptcc_p_add_chain())*/
1045 h->sorted_offsets = 1;
1046
Harald Welteaae69be2004-08-29 23:32:14 +00001047 /* First pass: over ruleset blob */
1048 ENTRY_ITERATE(h->entries->entrytable, h->entries->size,
1049 cache_add_entry, h, &prev, &num);
1050
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +00001051 /* Build the chain index, used for chain list search speedup */
1052 if ((iptcc_chain_index_alloc(h)) < 0)
1053 return -ENOMEM;
1054 iptcc_chain_index_build(h);
1055
Harald Welteaae69be2004-08-29 23:32:14 +00001056 /* Second pass: fixup parsed data from first pass */
1057 list_for_each_entry(c, &h->chains, list) {
1058 struct rule_head *r;
1059 list_for_each_entry(r, &c->rules, list) {
Jan Engelhardtdbb77542008-02-11 00:33:30 +01001060 struct chain_head *lc;
Harald Welteaae69be2004-08-29 23:32:14 +00001061 STRUCT_STANDARD_TARGET *t;
1062
1063 if (r->type != IPTCC_R_JUMP)
1064 continue;
1065
1066 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
Jan Engelhardtdbb77542008-02-11 00:33:30 +01001067 lc = iptcc_find_chain_by_offset(h, t->verdict);
1068 if (!lc)
Harald Welteaae69be2004-08-29 23:32:14 +00001069 return -1;
Jan Engelhardtdbb77542008-02-11 00:33:30 +01001070 r->jump = lc;
1071 lc->references++;
Harald Welteaae69be2004-08-29 23:32:14 +00001072 }
1073 }
1074
Harald Welteaae69be2004-08-29 23:32:14 +00001075 return 1;
1076}
1077
1078
1079/**********************************************************************
1080 * RULESET COMPILATION (cache -> blob)
1081 **********************************************************************/
1082
1083/* Convenience structures */
1084struct iptcb_chain_start{
1085 STRUCT_ENTRY e;
Jan Engelhardt9cf67de2011-09-11 17:24:26 +02001086 struct xt_error_target name;
Harald Welteaae69be2004-08-29 23:32:14 +00001087};
1088#define IPTCB_CHAIN_START_SIZE (sizeof(STRUCT_ENTRY) + \
Jan Engelhardt9cf67de2011-09-11 17:24:26 +02001089 ALIGN(sizeof(struct xt_error_target)))
Harald Welteaae69be2004-08-29 23:32:14 +00001090
1091struct iptcb_chain_foot {
1092 STRUCT_ENTRY e;
1093 STRUCT_STANDARD_TARGET target;
1094};
1095#define IPTCB_CHAIN_FOOT_SIZE (sizeof(STRUCT_ENTRY) + \
1096 ALIGN(sizeof(STRUCT_STANDARD_TARGET)))
1097
1098struct iptcb_chain_error {
1099 STRUCT_ENTRY entry;
Jan Engelhardt9cf67de2011-09-11 17:24:26 +02001100 struct xt_error_target target;
Harald Welteaae69be2004-08-29 23:32:14 +00001101};
1102#define IPTCB_CHAIN_ERROR_SIZE (sizeof(STRUCT_ENTRY) + \
Jan Engelhardt9cf67de2011-09-11 17:24:26 +02001103 ALIGN(sizeof(struct xt_error_target)))
Harald Welteaae69be2004-08-29 23:32:14 +00001104
1105
1106
1107/* compile rule from cache into blob */
Jan Engelhardtfd187312008-11-10 16:59:27 +01001108static inline int iptcc_compile_rule (struct xtc_handle *h, STRUCT_REPLACE *repl, struct rule_head *r)
Harald Welteaae69be2004-08-29 23:32:14 +00001109{
1110 /* handle jumps */
1111 if (r->type == IPTCC_R_JUMP) {
1112 STRUCT_STANDARD_TARGET *t;
1113 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
1114 /* memset for memcmp convenience on delete/replace */
1115 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
1116 strcpy(t->target.u.user.name, STANDARD_TARGET);
1117 /* Jumps can only happen to builtin chains, so we
1118 * can safely assume that they always have a header */
1119 t->verdict = r->jump->head_offset + IPTCB_CHAIN_START_SIZE;
1120 } else if (r->type == IPTCC_R_FALLTHROUGH) {
1121 STRUCT_STANDARD_TARGET *t;
1122 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(r->entry);
1123 t->verdict = r->offset + r->size;
1124 }
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001125
Harald Welteaae69be2004-08-29 23:32:14 +00001126 /* copy entry from cache to blob */
1127 memcpy((char *)repl->entries+r->offset, r->entry, r->size);
1128
1129 return 1;
1130}
1131
1132/* compile chain from cache into blob */
Jan Engelhardtfd187312008-11-10 16:59:27 +01001133static int iptcc_compile_chain(struct xtc_handle *h, STRUCT_REPLACE *repl, struct chain_head *c)
Harald Welteaae69be2004-08-29 23:32:14 +00001134{
1135 int ret;
1136 struct rule_head *r;
1137 struct iptcb_chain_start *head;
1138 struct iptcb_chain_foot *foot;
1139
1140 /* only user-defined chains have heaer */
1141 if (!iptcc_is_builtin(c)) {
1142 /* put chain header in place */
1143 head = (void *)repl->entries + c->head_offset;
1144 head->e.target_offset = sizeof(STRUCT_ENTRY);
1145 head->e.next_offset = IPTCB_CHAIN_START_SIZE;
Jan Engelhardt9cf67de2011-09-11 17:24:26 +02001146 strcpy(head->name.target.u.user.name, ERROR_TARGET);
1147 head->name.target.u.target_size =
1148 ALIGN(sizeof(struct xt_error_target));
1149 strcpy(head->name.errorname, c->name);
Harald Welteaae69be2004-08-29 23:32:14 +00001150 } else {
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001151 repl->hook_entry[c->hooknum-1] = c->head_offset;
Harald Welteaae69be2004-08-29 23:32:14 +00001152 repl->underflow[c->hooknum-1] = c->foot_offset;
1153 }
1154
1155 /* iterate over rules */
1156 list_for_each_entry(r, &c->rules, list) {
1157 ret = iptcc_compile_rule(h, repl, r);
1158 if (ret < 0)
1159 return ret;
1160 }
1161
1162 /* put chain footer in place */
1163 foot = (void *)repl->entries + c->foot_offset;
1164 foot->e.target_offset = sizeof(STRUCT_ENTRY);
1165 foot->e.next_offset = IPTCB_CHAIN_FOOT_SIZE;
1166 strcpy(foot->target.target.u.user.name, STANDARD_TARGET);
1167 foot->target.target.u.target_size =
1168 ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1169 /* builtin targets have verdict, others return */
1170 if (iptcc_is_builtin(c))
1171 foot->target.verdict = c->verdict;
1172 else
1173 foot->target.verdict = RETURN;
1174 /* set policy-counters */
1175 memcpy(&foot->e.counters, &c->counters, sizeof(STRUCT_COUNTERS));
1176
1177 return 0;
1178}
1179
1180/* calculate offset and number for every rule in the cache */
Jan Engelhardtfd187312008-11-10 16:59:27 +01001181static int iptcc_compile_chain_offsets(struct xtc_handle *h, struct chain_head *c,
Harald Welteefa8fc22005-07-19 22:03:49 +00001182 unsigned int *offset, unsigned int *num)
Harald Welteaae69be2004-08-29 23:32:14 +00001183{
1184 struct rule_head *r;
1185
1186 c->head_offset = *offset;
1187 DEBUGP("%s: chain_head %u, offset=%u\n", c->name, *num, *offset);
1188
1189 if (!iptcc_is_builtin(c)) {
1190 /* Chain has header */
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001191 *offset += sizeof(STRUCT_ENTRY)
Jan Engelhardt9cf67de2011-09-11 17:24:26 +02001192 + ALIGN(sizeof(struct xt_error_target));
Harald Welteaae69be2004-08-29 23:32:14 +00001193 (*num)++;
1194 }
1195
1196 list_for_each_entry(r, &c->rules, list) {
1197 DEBUGP("rule %u, offset=%u, index=%u\n", *num, *offset, *num);
1198 r->offset = *offset;
1199 r->index = *num;
1200 *offset += r->size;
1201 (*num)++;
1202 }
1203
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001204 DEBUGP("%s; chain_foot %u, offset=%u, index=%u\n", c->name, *num,
Harald Welteaae69be2004-08-29 23:32:14 +00001205 *offset, *num);
1206 c->foot_offset = *offset;
1207 c->foot_index = *num;
1208 *offset += sizeof(STRUCT_ENTRY)
1209 + ALIGN(sizeof(STRUCT_STANDARD_TARGET));
1210 (*num)++;
1211
1212 return 1;
1213}
1214
1215/* put the pieces back together again */
Jan Engelhardtfd187312008-11-10 16:59:27 +01001216static int iptcc_compile_table_prep(struct xtc_handle *h, unsigned int *size)
Harald Welteaae69be2004-08-29 23:32:14 +00001217{
1218 struct chain_head *c;
1219 unsigned int offset = 0, num = 0;
1220 int ret = 0;
1221
1222 /* First pass: calculate offset for every rule */
1223 list_for_each_entry(c, &h->chains, list) {
1224 ret = iptcc_compile_chain_offsets(h, c, &offset, &num);
1225 if (ret < 0)
1226 return ret;
1227 }
1228
1229 /* Append one error rule at end of chain */
1230 num++;
1231 offset += sizeof(STRUCT_ENTRY)
Jan Engelhardt9cf67de2011-09-11 17:24:26 +02001232 + ALIGN(sizeof(struct xt_error_target));
Harald Welteaae69be2004-08-29 23:32:14 +00001233
1234 /* ruleset size is now in offset */
1235 *size = offset;
1236 return num;
1237}
1238
Jan Engelhardtfd187312008-11-10 16:59:27 +01001239static int iptcc_compile_table(struct xtc_handle *h, STRUCT_REPLACE *repl)
Harald Welteaae69be2004-08-29 23:32:14 +00001240{
1241 struct chain_head *c;
1242 struct iptcb_chain_error *error;
1243
1244 /* Second pass: copy from cache to offsets, fill in jumps */
1245 list_for_each_entry(c, &h->chains, list) {
1246 int ret = iptcc_compile_chain(h, repl, c);
1247 if (ret < 0)
1248 return ret;
1249 }
1250
1251 /* Append error rule at end of chain */
1252 error = (void *)repl->entries + repl->size - IPTCB_CHAIN_ERROR_SIZE;
1253 error->entry.target_offset = sizeof(STRUCT_ENTRY);
1254 error->entry.next_offset = IPTCB_CHAIN_ERROR_SIZE;
Jan Engelhardt9cf67de2011-09-11 17:24:26 +02001255 error->target.target.u.user.target_size =
1256 ALIGN(sizeof(struct xt_error_target));
1257 strcpy((char *)&error->target.target.u.user.name, ERROR_TARGET);
1258 strcpy((char *)&error->target.errorname, "ERROR");
Harald Welteaae69be2004-08-29 23:32:14 +00001259
1260 return 1;
1261}
1262
1263/**********************************************************************
1264 * EXTERNAL API (operates on cache only)
1265 **********************************************************************/
Marc Bouchere6869a82000-03-20 06:03:29 +00001266
1267/* Allocate handle of given size */
Jan Engelhardtfd187312008-11-10 16:59:27 +01001268static struct xtc_handle *
Harald Welte0113fe72004-01-06 19:04:02 +00001269alloc_handle(const char *tablename, unsigned int size, unsigned int num_rules)
Marc Bouchere6869a82000-03-20 06:03:29 +00001270{
Jan Engelhardtfd187312008-11-10 16:59:27 +01001271 struct xtc_handle *h;
Marc Bouchere6869a82000-03-20 06:03:29 +00001272
Harald Welteaae69be2004-08-29 23:32:14 +00001273 h = malloc(sizeof(STRUCT_TC_HANDLE));
1274 if (!h) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001275 errno = ENOMEM;
1276 return NULL;
1277 }
Harald Welteaae69be2004-08-29 23:32:14 +00001278 memset(h, 0, sizeof(*h));
1279 INIT_LIST_HEAD(&h->chains);
Marc Bouchere6869a82000-03-20 06:03:29 +00001280 strcpy(h->info.name, tablename);
Harald Welteaae69be2004-08-29 23:32:14 +00001281
Harald Welte0371c0c2004-09-19 21:00:12 +00001282 h->entries = malloc(sizeof(STRUCT_GET_ENTRIES) + size);
Harald Welteaae69be2004-08-29 23:32:14 +00001283 if (!h->entries)
1284 goto out_free_handle;
1285
1286 strcpy(h->entries->name, tablename);
Harald Welte0371c0c2004-09-19 21:00:12 +00001287 h->entries->size = size;
Marc Bouchere6869a82000-03-20 06:03:29 +00001288
1289 return h;
Harald Welteaae69be2004-08-29 23:32:14 +00001290
1291out_free_handle:
1292 free(h);
1293
1294 return NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +00001295}
1296
Harald Welteaae69be2004-08-29 23:32:14 +00001297
Jan Engelhardtfd187312008-11-10 16:59:27 +01001298struct xtc_handle *
Rusty Russell79dee072000-05-02 16:45:16 +00001299TC_INIT(const char *tablename)
Marc Bouchere6869a82000-03-20 06:03:29 +00001300{
Jan Engelhardtfd187312008-11-10 16:59:27 +01001301 struct xtc_handle *h;
Rusty Russell79dee072000-05-02 16:45:16 +00001302 STRUCT_GETINFO info;
Harald Welteefa8fc22005-07-19 22:03:49 +00001303 unsigned int tmp;
Marc Bouchere6869a82000-03-20 06:03:29 +00001304 socklen_t s;
Jan Engelhardt175f4512008-11-10 17:25:55 +01001305 int sockfd;
Marc Bouchere6869a82000-03-20 06:03:29 +00001306
Rusty Russell79dee072000-05-02 16:45:16 +00001307 iptc_fn = TC_INIT;
Marc Bouchere6869a82000-03-20 06:03:29 +00001308
Martin Josefsson841e4ae2003-05-02 15:30:11 +00001309 if (strlen(tablename) >= TABLE_MAXNAMELEN) {
1310 errno = EINVAL;
1311 return NULL;
1312 }
Jan Engelhardt175f4512008-11-10 17:25:55 +01001313
1314 sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
1315 if (sockfd < 0)
1316 return NULL;
1317
Patrick McHardy2f932052008-04-02 14:01:53 +02001318retry:
Marc Bouchere6869a82000-03-20 06:03:29 +00001319 s = sizeof(info);
Martin Josefsson841e4ae2003-05-02 15:30:11 +00001320
Marc Bouchere6869a82000-03-20 06:03:29 +00001321 strcpy(info.name, tablename);
Derrik Pates664c0a32005-02-01 13:28:14 +00001322 if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) < 0) {
Jan Engelhardt175f4512008-11-10 17:25:55 +01001323 close(sockfd);
Marc Bouchere6869a82000-03-20 06:03:29 +00001324 return NULL;
Derrik Pates664c0a32005-02-01 13:28:14 +00001325 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001326
Harald Welteaae69be2004-08-29 23:32:14 +00001327 DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
1328 info.valid_hooks, info.num_entries, info.size);
1329
Harald Welte0113fe72004-01-06 19:04:02 +00001330 if ((h = alloc_handle(info.name, info.size, info.num_entries))
Martin Josefsson841e4ae2003-05-02 15:30:11 +00001331 == NULL) {
Jan Engelhardt175f4512008-11-10 17:25:55 +01001332 close(sockfd);
Marc Bouchere6869a82000-03-20 06:03:29 +00001333 return NULL;
Martin Josefsson841e4ae2003-05-02 15:30:11 +00001334 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001335
Marc Bouchere6869a82000-03-20 06:03:29 +00001336 /* Initialize current state */
Jan Engelhardt175f4512008-11-10 17:25:55 +01001337 h->sockfd = sockfd;
Marc Bouchere6869a82000-03-20 06:03:29 +00001338 h->info = info;
Harald Welte0113fe72004-01-06 19:04:02 +00001339
Harald Welteaae69be2004-08-29 23:32:14 +00001340 h->entries->size = h->info.size;
Marc Bouchere6869a82000-03-20 06:03:29 +00001341
Rusty Russell79dee072000-05-02 16:45:16 +00001342 tmp = sizeof(STRUCT_GET_ENTRIES) + h->info.size;
Marc Bouchere6869a82000-03-20 06:03:29 +00001343
Jan Engelhardt175f4512008-11-10 17:25:55 +01001344 if (getsockopt(h->sockfd, TC_IPPROTO, SO_GET_ENTRIES, h->entries,
Harald Welteaae69be2004-08-29 23:32:14 +00001345 &tmp) < 0)
1346 goto error;
1347
1348#ifdef IPTC_DEBUG2
1349 {
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001350 int fd = open("/tmp/libiptc-so_get_entries.blob",
Harald Welteaae69be2004-08-29 23:32:14 +00001351 O_CREAT|O_WRONLY);
1352 if (fd >= 0) {
1353 write(fd, h->entries, tmp);
1354 close(fd);
1355 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001356 }
Harald Welteaae69be2004-08-29 23:32:14 +00001357#endif
1358
1359 if (parse_table(h) < 0)
1360 goto error;
Rusty Russell7e53bf92000-03-20 07:03:28 +00001361
Marc Bouchere6869a82000-03-20 06:03:29 +00001362 CHECK(h);
1363 return h;
Harald Welteaae69be2004-08-29 23:32:14 +00001364error:
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001365 TC_FREE(h);
Patrick McHardy2f932052008-04-02 14:01:53 +02001366 /* A different process changed the ruleset size, retry */
1367 if (errno == EAGAIN)
1368 goto retry;
Harald Welteaae69be2004-08-29 23:32:14 +00001369 return NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +00001370}
1371
Martin Josefsson841e4ae2003-05-02 15:30:11 +00001372void
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001373TC_FREE(struct xtc_handle *h)
Martin Josefsson841e4ae2003-05-02 15:30:11 +00001374{
Harald Welteaae69be2004-08-29 23:32:14 +00001375 struct chain_head *c, *tmp;
1376
Derrik Pates664c0a32005-02-01 13:28:14 +00001377 iptc_fn = TC_FREE;
Jan Engelhardt175f4512008-11-10 17:25:55 +01001378 close(h->sockfd);
Harald Welteaae69be2004-08-29 23:32:14 +00001379
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001380 list_for_each_entry_safe(c, tmp, &h->chains, list) {
Harald Welteaae69be2004-08-29 23:32:14 +00001381 struct rule_head *r, *rtmp;
1382
1383 list_for_each_entry_safe(r, rtmp, &c->rules, list) {
1384 free(r);
1385 }
1386
1387 free(c);
1388 }
1389
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001390 iptcc_chain_index_free(h);
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +00001391
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001392 free(h->entries);
1393 free(h);
Martin Josefsson841e4ae2003-05-02 15:30:11 +00001394}
1395
Marc Bouchere6869a82000-03-20 06:03:29 +00001396static inline int
Rusty Russell79dee072000-05-02 16:45:16 +00001397print_match(const STRUCT_ENTRY_MATCH *m)
Marc Bouchere6869a82000-03-20 06:03:29 +00001398{
Rusty Russell228e98d2000-04-27 10:28:06 +00001399 printf("Match name: `%s'\n", m->u.user.name);
Marc Bouchere6869a82000-03-20 06:03:29 +00001400 return 0;
1401}
1402
Jan Engelhardtfd187312008-11-10 16:59:27 +01001403static int dump_entry(STRUCT_ENTRY *e, struct xtc_handle *const handle);
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001404
Marc Bouchere6869a82000-03-20 06:03:29 +00001405void
Jan Engelhardtfd187312008-11-10 16:59:27 +01001406TC_DUMP_ENTRIES(struct xtc_handle *const handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001407{
Derrik Pates664c0a32005-02-01 13:28:14 +00001408 iptc_fn = TC_DUMP_ENTRIES;
Marc Bouchere6869a82000-03-20 06:03:29 +00001409 CHECK(handle);
Patrick McHardy97fb2f12007-09-08 16:52:25 +00001410
Rusty Russelle45c7132004-12-16 13:21:44 +00001411 printf("libiptc v%s. %u bytes.\n",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +02001412 XTABLES_VERSION, handle->entries->size);
Marc Bouchere6869a82000-03-20 06:03:29 +00001413 printf("Table `%s'\n", handle->info.name);
Jan Engelhardtd73af642008-11-10 17:07:31 +01001414 printf("Hooks: pre/in/fwd/out/post = %x/%x/%x/%x/%x\n",
Rusty Russell67088e72000-05-10 01:18:57 +00001415 handle->info.hook_entry[HOOK_PRE_ROUTING],
1416 handle->info.hook_entry[HOOK_LOCAL_IN],
1417 handle->info.hook_entry[HOOK_FORWARD],
1418 handle->info.hook_entry[HOOK_LOCAL_OUT],
1419 handle->info.hook_entry[HOOK_POST_ROUTING]);
Jan Engelhardtd73af642008-11-10 17:07:31 +01001420 printf("Underflows: pre/in/fwd/out/post = %x/%x/%x/%x/%x\n",
Rusty Russell67088e72000-05-10 01:18:57 +00001421 handle->info.underflow[HOOK_PRE_ROUTING],
1422 handle->info.underflow[HOOK_LOCAL_IN],
1423 handle->info.underflow[HOOK_FORWARD],
1424 handle->info.underflow[HOOK_LOCAL_OUT],
1425 handle->info.underflow[HOOK_POST_ROUTING]);
Marc Bouchere6869a82000-03-20 06:03:29 +00001426
Harald Welteaae69be2004-08-29 23:32:14 +00001427 ENTRY_ITERATE(handle->entries->entrytable, handle->entries->size,
Rusty Russell79dee072000-05-02 16:45:16 +00001428 dump_entry, handle);
Harald Welte0113fe72004-01-06 19:04:02 +00001429}
Rusty Russell30fd6e52000-04-23 09:16:06 +00001430
Marc Bouchere6869a82000-03-20 06:03:29 +00001431/* Does this chain exist? */
Jan Engelhardtfd187312008-11-10 16:59:27 +01001432int TC_IS_CHAIN(const char *chain, struct xtc_handle *const handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001433{
Derrik Pates664c0a32005-02-01 13:28:14 +00001434 iptc_fn = TC_IS_CHAIN;
Harald Welteaae69be2004-08-29 23:32:14 +00001435 return iptcc_find_label(chain, handle) != NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +00001436}
1437
Jan Engelhardtfd187312008-11-10 16:59:27 +01001438static void iptcc_chain_iterator_advance(struct xtc_handle *handle)
Harald Welteaae69be2004-08-29 23:32:14 +00001439{
1440 struct chain_head *c = handle->chain_iterator_cur;
1441
1442 if (c->list.next == &handle->chains)
1443 handle->chain_iterator_cur = NULL;
1444 else
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001445 handle->chain_iterator_cur =
Harald Welteaae69be2004-08-29 23:32:14 +00001446 list_entry(c->list.next, struct chain_head, list);
1447}
Marc Bouchere6869a82000-03-20 06:03:29 +00001448
Rusty Russell30fd6e52000-04-23 09:16:06 +00001449/* Iterator functions to run through the chains. */
Marc Bouchere6869a82000-03-20 06:03:29 +00001450const char *
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001451TC_FIRST_CHAIN(struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001452{
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001453 struct chain_head *c = list_entry(handle->chains.next,
Harald Welteaae69be2004-08-29 23:32:14 +00001454 struct chain_head, list);
1455
1456 iptc_fn = TC_FIRST_CHAIN;
1457
1458
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001459 if (list_empty(&handle->chains)) {
Harald Welteaae69be2004-08-29 23:32:14 +00001460 DEBUGP(": no chains\n");
Harald Welte0113fe72004-01-06 19:04:02 +00001461 return NULL;
Harald Welteaae69be2004-08-29 23:32:14 +00001462 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001463
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001464 handle->chain_iterator_cur = c;
1465 iptcc_chain_iterator_advance(handle);
Harald Welte0113fe72004-01-06 19:04:02 +00001466
Harald Welteaae69be2004-08-29 23:32:14 +00001467 DEBUGP(": returning `%s'\n", c->name);
1468 return c->name;
Marc Bouchere6869a82000-03-20 06:03:29 +00001469}
1470
Rusty Russell30fd6e52000-04-23 09:16:06 +00001471/* Iterator functions to run through the chains. Returns NULL at end. */
1472const char *
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001473TC_NEXT_CHAIN(struct xtc_handle *handle)
Rusty Russell30fd6e52000-04-23 09:16:06 +00001474{
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001475 struct chain_head *c = handle->chain_iterator_cur;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001476
Harald Welteaae69be2004-08-29 23:32:14 +00001477 iptc_fn = TC_NEXT_CHAIN;
1478
1479 if (!c) {
1480 DEBUGP(": no more chains\n");
Rusty Russell30fd6e52000-04-23 09:16:06 +00001481 return NULL;
Harald Welteaae69be2004-08-29 23:32:14 +00001482 }
Rusty Russell30fd6e52000-04-23 09:16:06 +00001483
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001484 iptcc_chain_iterator_advance(handle);
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001485
Harald Welteaae69be2004-08-29 23:32:14 +00001486 DEBUGP(": returning `%s'\n", c->name);
1487 return c->name;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001488}
1489
1490/* Get first rule in the given chain: NULL for empty chain. */
Rusty Russell79dee072000-05-02 16:45:16 +00001491const STRUCT_ENTRY *
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001492TC_FIRST_RULE(const char *chain, struct xtc_handle *handle)
Rusty Russell30fd6e52000-04-23 09:16:06 +00001493{
Harald Welteaae69be2004-08-29 23:32:14 +00001494 struct chain_head *c;
1495 struct rule_head *r;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001496
Harald Welteaae69be2004-08-29 23:32:14 +00001497 iptc_fn = TC_FIRST_RULE;
1498
1499 DEBUGP("first rule(%s): ", chain);
1500
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001501 c = iptcc_find_label(chain, handle);
Rusty Russell30fd6e52000-04-23 09:16:06 +00001502 if (!c) {
1503 errno = ENOENT;
1504 return NULL;
1505 }
1506
1507 /* Empty chain: single return/policy rule */
Harald Welteaae69be2004-08-29 23:32:14 +00001508 if (list_empty(&c->rules)) {
1509 DEBUGP_C("no rules, returning NULL\n");
Rusty Russell30fd6e52000-04-23 09:16:06 +00001510 return NULL;
Harald Welteaae69be2004-08-29 23:32:14 +00001511 }
Rusty Russell30fd6e52000-04-23 09:16:06 +00001512
Harald Welteaae69be2004-08-29 23:32:14 +00001513 r = list_entry(c->rules.next, struct rule_head, list);
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001514 handle->rule_iterator_cur = r;
Harald Welteaae69be2004-08-29 23:32:14 +00001515 DEBUGP_C("%p\n", r);
1516
1517 return r->entry;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001518}
1519
1520/* Returns NULL when rules run out. */
Rusty Russell79dee072000-05-02 16:45:16 +00001521const STRUCT_ENTRY *
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001522TC_NEXT_RULE(const STRUCT_ENTRY *prev, struct xtc_handle *handle)
Rusty Russell30fd6e52000-04-23 09:16:06 +00001523{
Harald Welteaae69be2004-08-29 23:32:14 +00001524 struct rule_head *r;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001525
Derrik Pates664c0a32005-02-01 13:28:14 +00001526 iptc_fn = TC_NEXT_RULE;
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001527 DEBUGP("rule_iterator_cur=%p...", handle->rule_iterator_cur);
Harald Welteaae69be2004-08-29 23:32:14 +00001528
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001529 if (handle->rule_iterator_cur == NULL) {
Harald Welteaae69be2004-08-29 23:32:14 +00001530 DEBUGP_C("returning NULL\n");
1531 return NULL;
1532 }
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001533
1534 r = list_entry(handle->rule_iterator_cur->list.next,
Harald Welteaae69be2004-08-29 23:32:14 +00001535 struct rule_head, list);
1536
1537 iptc_fn = TC_NEXT_RULE;
1538
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001539 DEBUGP_C("next=%p, head=%p...", &r->list,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001540 &handle->rule_iterator_cur->chain->rules);
Harald Welteaae69be2004-08-29 23:32:14 +00001541
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001542 if (&r->list == &handle->rule_iterator_cur->chain->rules) {
1543 handle->rule_iterator_cur = NULL;
Harald Welteaae69be2004-08-29 23:32:14 +00001544 DEBUGP_C("finished, returning NULL\n");
1545 return NULL;
1546 }
1547
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001548 handle->rule_iterator_cur = r;
Harald Welteaae69be2004-08-29 23:32:14 +00001549
1550 /* NOTE: prev is without any influence ! */
1551 DEBUGP_C("returning rule %p\n", r);
1552 return r->entry;
Rusty Russell30fd6e52000-04-23 09:16:06 +00001553}
1554
Marc Bouchere6869a82000-03-20 06:03:29 +00001555/* Returns a pointer to the target name of this position. */
Jan Engelhardt33690a12008-02-11 00:54:00 +01001556static const char *standard_target_map(int verdict)
Marc Bouchere6869a82000-03-20 06:03:29 +00001557{
Harald Welteaae69be2004-08-29 23:32:14 +00001558 switch (verdict) {
1559 case RETURN:
1560 return LABEL_RETURN;
1561 break;
1562 case -NF_ACCEPT-1:
1563 return LABEL_ACCEPT;
1564 break;
1565 case -NF_DROP-1:
1566 return LABEL_DROP;
1567 break;
1568 case -NF_QUEUE-1:
1569 return LABEL_QUEUE;
1570 break;
1571 default:
1572 fprintf(stderr, "ERROR: %d not a valid target)\n",
1573 verdict);
1574 abort();
1575 break;
1576 }
1577 /* not reached */
1578 return NULL;
Marc Bouchere6869a82000-03-20 06:03:29 +00001579}
1580
Harald Welteaae69be2004-08-29 23:32:14 +00001581/* Returns a pointer to the target name of this position. */
1582const char *TC_GET_TARGET(const STRUCT_ENTRY *ce,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001583 struct xtc_handle *handle)
Harald Welteaae69be2004-08-29 23:32:14 +00001584{
1585 STRUCT_ENTRY *e = (STRUCT_ENTRY *)ce;
Rusty Russelle45c7132004-12-16 13:21:44 +00001586 struct rule_head *r = container_of(e, struct rule_head, entry[0]);
Jan Engelhardt51651b62009-10-23 23:35:49 +02001587 const unsigned char *data;
Harald Welteaae69be2004-08-29 23:32:14 +00001588
1589 iptc_fn = TC_GET_TARGET;
1590
1591 switch(r->type) {
1592 int spos;
1593 case IPTCC_R_FALLTHROUGH:
1594 return "";
1595 break;
1596 case IPTCC_R_JUMP:
1597 DEBUGP("r=%p, jump=%p, name=`%s'\n", r, r->jump, r->jump->name);
1598 return r->jump->name;
1599 break;
1600 case IPTCC_R_STANDARD:
Jan Engelhardt51651b62009-10-23 23:35:49 +02001601 data = GET_TARGET(e)->data;
1602 spos = *(const int *)data;
Harald Welteaae69be2004-08-29 23:32:14 +00001603 DEBUGP("r=%p, spos=%d'\n", r, spos);
1604 return standard_target_map(spos);
1605 break;
1606 case IPTCC_R_MODULE:
1607 return GET_TARGET(e)->u.user.name;
1608 break;
1609 }
1610 return NULL;
1611}
Marc Bouchere6869a82000-03-20 06:03:29 +00001612/* Is this a built-in chain? Actually returns hook + 1. */
1613int
Jan Engelhardtfd187312008-11-10 16:59:27 +01001614TC_BUILTIN(const char *chain, struct xtc_handle *const handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001615{
Harald Welteaae69be2004-08-29 23:32:14 +00001616 struct chain_head *c;
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001617
Harald Welteaae69be2004-08-29 23:32:14 +00001618 iptc_fn = TC_BUILTIN;
Marc Bouchere6869a82000-03-20 06:03:29 +00001619
Harald Welteaae69be2004-08-29 23:32:14 +00001620 c = iptcc_find_label(chain, handle);
1621 if (!c) {
1622 errno = ENOENT;
Martin Josefssonb0f3d2d2004-09-23 18:23:20 +00001623 return 0;
Marc Bouchere6869a82000-03-20 06:03:29 +00001624 }
Harald Welteaae69be2004-08-29 23:32:14 +00001625
1626 return iptcc_is_builtin(c);
Marc Bouchere6869a82000-03-20 06:03:29 +00001627}
1628
1629/* Get the policy of a given built-in chain */
1630const char *
Rusty Russell79dee072000-05-02 16:45:16 +00001631TC_GET_POLICY(const char *chain,
1632 STRUCT_COUNTERS *counters,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001633 struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001634{
Harald Welteaae69be2004-08-29 23:32:14 +00001635 struct chain_head *c;
Marc Bouchere6869a82000-03-20 06:03:29 +00001636
Harald Welteaae69be2004-08-29 23:32:14 +00001637 iptc_fn = TC_GET_POLICY;
1638
1639 DEBUGP("called for chain %s\n", chain);
1640
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001641 c = iptcc_find_label(chain, handle);
Harald Welteaae69be2004-08-29 23:32:14 +00001642 if (!c) {
1643 errno = ENOENT;
1644 return NULL;
1645 }
1646
1647 if (!iptcc_is_builtin(c))
Marc Bouchere6869a82000-03-20 06:03:29 +00001648 return NULL;
1649
Harald Welteaae69be2004-08-29 23:32:14 +00001650 *counters = c->counters;
Marc Bouchere6869a82000-03-20 06:03:29 +00001651
Harald Welteaae69be2004-08-29 23:32:14 +00001652 return standard_target_map(c->verdict);
Harald Welte0113fe72004-01-06 19:04:02 +00001653}
1654
1655static int
Harald Welteaae69be2004-08-29 23:32:14 +00001656iptcc_standard_map(struct rule_head *r, int verdict)
Harald Welte0113fe72004-01-06 19:04:02 +00001657{
Harald Welteaae69be2004-08-29 23:32:14 +00001658 STRUCT_ENTRY *e = r->entry;
Rusty Russell79dee072000-05-02 16:45:16 +00001659 STRUCT_STANDARD_TARGET *t;
Marc Bouchere6869a82000-03-20 06:03:29 +00001660
Rusty Russell79dee072000-05-02 16:45:16 +00001661 t = (STRUCT_STANDARD_TARGET *)GET_TARGET(e);
Marc Bouchere6869a82000-03-20 06:03:29 +00001662
Rusty Russell67088e72000-05-10 01:18:57 +00001663 if (t->target.u.target_size
Philip Blundell8c700902000-05-15 02:17:52 +00001664 != ALIGN(sizeof(STRUCT_STANDARD_TARGET))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001665 errno = EINVAL;
1666 return 0;
1667 }
1668 /* memset for memcmp convenience on delete/replace */
Rusty Russell79dee072000-05-02 16:45:16 +00001669 memset(t->target.u.user.name, 0, FUNCTION_MAXNAMELEN);
1670 strcpy(t->target.u.user.name, STANDARD_TARGET);
Marc Bouchere6869a82000-03-20 06:03:29 +00001671 t->verdict = verdict;
1672
Harald Welteaae69be2004-08-29 23:32:14 +00001673 r->type = IPTCC_R_STANDARD;
1674
Marc Bouchere6869a82000-03-20 06:03:29 +00001675 return 1;
1676}
Rusty Russell7e53bf92000-03-20 07:03:28 +00001677
Marc Bouchere6869a82000-03-20 06:03:29 +00001678static int
Jan Engelhardtfd187312008-11-10 16:59:27 +01001679iptcc_map_target(struct xtc_handle *const handle,
Harald Welteaae69be2004-08-29 23:32:14 +00001680 struct rule_head *r)
Marc Bouchere6869a82000-03-20 06:03:29 +00001681{
Harald Welteaae69be2004-08-29 23:32:14 +00001682 STRUCT_ENTRY *e = r->entry;
Harald Welte0113fe72004-01-06 19:04:02 +00001683 STRUCT_ENTRY_TARGET *t = GET_TARGET(e);
Marc Bouchere6869a82000-03-20 06:03:29 +00001684
Marc Bouchere6869a82000-03-20 06:03:29 +00001685 /* Maybe it's empty (=> fall through) */
Harald Welteaae69be2004-08-29 23:32:14 +00001686 if (strcmp(t->u.user.name, "") == 0) {
1687 r->type = IPTCC_R_FALLTHROUGH;
1688 return 1;
1689 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001690 /* Maybe it's a standard target name... */
Rusty Russell79dee072000-05-02 16:45:16 +00001691 else if (strcmp(t->u.user.name, LABEL_ACCEPT) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00001692 return iptcc_standard_map(r, -NF_ACCEPT - 1);
Rusty Russell79dee072000-05-02 16:45:16 +00001693 else if (strcmp(t->u.user.name, LABEL_DROP) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00001694 return iptcc_standard_map(r, -NF_DROP - 1);
Rusty Russell67088e72000-05-10 01:18:57 +00001695 else if (strcmp(t->u.user.name, LABEL_QUEUE) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00001696 return iptcc_standard_map(r, -NF_QUEUE - 1);
Rusty Russell79dee072000-05-02 16:45:16 +00001697 else if (strcmp(t->u.user.name, LABEL_RETURN) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00001698 return iptcc_standard_map(r, RETURN);
Rusty Russell79dee072000-05-02 16:45:16 +00001699 else if (TC_BUILTIN(t->u.user.name, handle)) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001700 /* Can't jump to builtins. */
1701 errno = EINVAL;
1702 return 0;
1703 } else {
1704 /* Maybe it's an existing chain name. */
Harald Welteaae69be2004-08-29 23:32:14 +00001705 struct chain_head *c;
1706 DEBUGP("trying to find chain `%s': ", t->u.user.name);
Marc Bouchere6869a82000-03-20 06:03:29 +00001707
Harald Welteaae69be2004-08-29 23:32:14 +00001708 c = iptcc_find_label(t->u.user.name, handle);
1709 if (c) {
1710 DEBUGP_C("found!\n");
1711 r->type = IPTCC_R_JUMP;
1712 r->jump = c;
1713 c->references++;
1714 return 1;
1715 }
1716 DEBUGP_C("not found :(\n");
Marc Bouchere6869a82000-03-20 06:03:29 +00001717 }
1718
1719 /* Must be a module? If not, kernel will reject... */
Rusty Russell3aef54d2005-01-03 03:48:40 +00001720 /* memset to all 0 for your memcmp convenience: don't clear version */
Rusty Russell228e98d2000-04-27 10:28:06 +00001721 memset(t->u.user.name + strlen(t->u.user.name),
Marc Bouchere6869a82000-03-20 06:03:29 +00001722 0,
Rusty Russell3aef54d2005-01-03 03:48:40 +00001723 FUNCTION_MAXNAMELEN - 1 - strlen(t->u.user.name));
Rusty Russell733e54b2004-12-16 14:22:23 +00001724 r->type = IPTCC_R_MODULE;
Harald Welteaae69be2004-08-29 23:32:14 +00001725 set_changed(handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00001726 return 1;
1727}
1728
Harald Welte0113fe72004-01-06 19:04:02 +00001729/* Insert the entry `fw' in chain `chain' into position `rulenum'. */
Marc Bouchere6869a82000-03-20 06:03:29 +00001730int
Rusty Russell79dee072000-05-02 16:45:16 +00001731TC_INSERT_ENTRY(const IPT_CHAINLABEL chain,
1732 const STRUCT_ENTRY *e,
1733 unsigned int rulenum,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001734 struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001735{
Harald Welteaae69be2004-08-29 23:32:14 +00001736 struct chain_head *c;
Martin Josefssoneb066cc2004-09-22 21:04:07 +00001737 struct rule_head *r;
1738 struct list_head *prev;
Marc Bouchere6869a82000-03-20 06:03:29 +00001739
Rusty Russell79dee072000-05-02 16:45:16 +00001740 iptc_fn = TC_INSERT_ENTRY;
Harald Welteaae69be2004-08-29 23:32:14 +00001741
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001742 if (!(c = iptcc_find_label(chain, handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001743 errno = ENOENT;
1744 return 0;
1745 }
1746
Martin Josefssoneb066cc2004-09-22 21:04:07 +00001747 /* first rulenum index = 0
1748 first c->num_rules index = 1 */
1749 if (rulenum > c->num_rules) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001750 errno = E2BIG;
1751 return 0;
1752 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001753
Martin Josefsson631f3612004-09-23 19:25:06 +00001754 /* If we are inserting at the end just take advantage of the
1755 double linked list, insert will happen before the entry
1756 prev points to. */
1757 if (rulenum == c->num_rules) {
Martin Josefssoneb066cc2004-09-22 21:04:07 +00001758 prev = &c->rules;
Martin Josefssona5616dc2004-10-24 22:27:31 +00001759 } else if (rulenum + 1 <= c->num_rules/2) {
Martin Josefsson631f3612004-09-23 19:25:06 +00001760 r = iptcc_get_rule_num(c, rulenum + 1);
Martin Josefssona5616dc2004-10-24 22:27:31 +00001761 prev = &r->list;
1762 } else {
1763 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
Martin Josefsson631f3612004-09-23 19:25:06 +00001764 prev = &r->list;
1765 }
Martin Josefssoneb066cc2004-09-22 21:04:07 +00001766
Harald Welteaae69be2004-08-29 23:32:14 +00001767 if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1768 errno = ENOMEM;
Harald Welte0113fe72004-01-06 19:04:02 +00001769 return 0;
Harald Welteaae69be2004-08-29 23:32:14 +00001770 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001771
Harald Welteaae69be2004-08-29 23:32:14 +00001772 memcpy(r->entry, e, e->next_offset);
1773 r->counter_map.maptype = COUNTER_MAP_SET;
1774
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001775 if (!iptcc_map_target(handle, r)) {
Harald Welteaae69be2004-08-29 23:32:14 +00001776 free(r);
1777 return 0;
1778 }
1779
Martin Josefssoneb066cc2004-09-22 21:04:07 +00001780 list_add_tail(&r->list, prev);
Harald Welteaae69be2004-08-29 23:32:14 +00001781 c->num_rules++;
1782
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001783 set_changed(handle);
Harald Welteaae69be2004-08-29 23:32:14 +00001784
1785 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001786}
1787
1788/* Atomically replace rule `rulenum' in `chain' with `fw'. */
1789int
Rusty Russell79dee072000-05-02 16:45:16 +00001790TC_REPLACE_ENTRY(const IPT_CHAINLABEL chain,
1791 const STRUCT_ENTRY *e,
1792 unsigned int rulenum,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001793 struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001794{
Harald Welteaae69be2004-08-29 23:32:14 +00001795 struct chain_head *c;
1796 struct rule_head *r, *old;
Marc Bouchere6869a82000-03-20 06:03:29 +00001797
Rusty Russell79dee072000-05-02 16:45:16 +00001798 iptc_fn = TC_REPLACE_ENTRY;
Marc Bouchere6869a82000-03-20 06:03:29 +00001799
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001800 if (!(c = iptcc_find_label(chain, handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001801 errno = ENOENT;
1802 return 0;
1803 }
1804
Martin Josefsson0f9b8b12004-12-18 17:18:49 +00001805 if (rulenum >= c->num_rules) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001806 errno = E2BIG;
1807 return 0;
1808 }
1809
Martin Josefsson0f9b8b12004-12-18 17:18:49 +00001810 /* Take advantage of the double linked list if possible. */
1811 if (rulenum + 1 <= c->num_rules/2) {
1812 old = iptcc_get_rule_num(c, rulenum + 1);
1813 } else {
1814 old = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
1815 }
1816
Harald Welteaae69be2004-08-29 23:32:14 +00001817 if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1818 errno = ENOMEM;
Marc Bouchere6869a82000-03-20 06:03:29 +00001819 return 0;
Harald Welteaae69be2004-08-29 23:32:14 +00001820 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001821
Harald Welteaae69be2004-08-29 23:32:14 +00001822 memcpy(r->entry, e, e->next_offset);
1823 r->counter_map.maptype = COUNTER_MAP_SET;
1824
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001825 if (!iptcc_map_target(handle, r)) {
Harald Welteaae69be2004-08-29 23:32:14 +00001826 free(r);
Harald Welte0113fe72004-01-06 19:04:02 +00001827 return 0;
Harald Welteaae69be2004-08-29 23:32:14 +00001828 }
Harald Welte0113fe72004-01-06 19:04:02 +00001829
Harald Welteaae69be2004-08-29 23:32:14 +00001830 list_add(&r->list, &old->list);
1831 iptcc_delete_rule(old);
1832
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001833 set_changed(handle);
Harald Welteaae69be2004-08-29 23:32:14 +00001834
1835 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001836}
1837
Harald Welte0113fe72004-01-06 19:04:02 +00001838/* Append entry `fw' to chain `chain'. Equivalent to insert with
Marc Bouchere6869a82000-03-20 06:03:29 +00001839 rulenum = length of chain. */
1840int
Rusty Russell79dee072000-05-02 16:45:16 +00001841TC_APPEND_ENTRY(const IPT_CHAINLABEL chain,
1842 const STRUCT_ENTRY *e,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001843 struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00001844{
Harald Welteaae69be2004-08-29 23:32:14 +00001845 struct chain_head *c;
1846 struct rule_head *r;
Marc Bouchere6869a82000-03-20 06:03:29 +00001847
Rusty Russell79dee072000-05-02 16:45:16 +00001848 iptc_fn = TC_APPEND_ENTRY;
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001849 if (!(c = iptcc_find_label(chain, handle))) {
Harald Welteaae69be2004-08-29 23:32:14 +00001850 DEBUGP("unable to find chain `%s'\n", chain);
Marc Bouchere6869a82000-03-20 06:03:29 +00001851 errno = ENOENT;
1852 return 0;
1853 }
1854
Harald Welteaae69be2004-08-29 23:32:14 +00001855 if (!(r = iptcc_alloc_rule(c, e->next_offset))) {
1856 DEBUGP("unable to allocate rule for chain `%s'\n", chain);
1857 errno = ENOMEM;
Harald Welte0113fe72004-01-06 19:04:02 +00001858 return 0;
Harald Welteaae69be2004-08-29 23:32:14 +00001859 }
Harald Welte0113fe72004-01-06 19:04:02 +00001860
Harald Welteaae69be2004-08-29 23:32:14 +00001861 memcpy(r->entry, e, e->next_offset);
1862 r->counter_map.maptype = COUNTER_MAP_SET;
1863
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001864 if (!iptcc_map_target(handle, r)) {
Martin Josefsson12009532004-09-23 18:24:29 +00001865 DEBUGP("unable to map target of rule for chain `%s'\n", chain);
Harald Welteaae69be2004-08-29 23:32:14 +00001866 free(r);
1867 return 0;
1868 }
1869
1870 list_add_tail(&r->list, &c->rules);
1871 c->num_rules++;
1872
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001873 set_changed(handle);
Harald Welteaae69be2004-08-29 23:32:14 +00001874
1875 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00001876}
1877
1878static inline int
Rusty Russell79dee072000-05-02 16:45:16 +00001879match_different(const STRUCT_ENTRY_MATCH *a,
Rusty Russelledf14cf2000-04-19 11:26:44 +00001880 const unsigned char *a_elems,
1881 const unsigned char *b_elems,
1882 unsigned char **maskptr)
Marc Bouchere6869a82000-03-20 06:03:29 +00001883{
Rusty Russell79dee072000-05-02 16:45:16 +00001884 const STRUCT_ENTRY_MATCH *b;
Rusty Russelledf14cf2000-04-19 11:26:44 +00001885 unsigned int i;
Marc Bouchere6869a82000-03-20 06:03:29 +00001886
1887 /* Offset of b is the same as a. */
Rusty Russell30fd6e52000-04-23 09:16:06 +00001888 b = (void *)b_elems + ((unsigned char *)a - a_elems);
Marc Bouchere6869a82000-03-20 06:03:29 +00001889
Rusty Russell228e98d2000-04-27 10:28:06 +00001890 if (a->u.match_size != b->u.match_size)
Marc Bouchere6869a82000-03-20 06:03:29 +00001891 return 1;
1892
Rusty Russell228e98d2000-04-27 10:28:06 +00001893 if (strcmp(a->u.user.name, b->u.user.name) != 0)
Marc Bouchere6869a82000-03-20 06:03:29 +00001894 return 1;
1895
Rusty Russell73ef09b2000-07-03 10:24:04 +00001896 *maskptr += ALIGN(sizeof(*a));
Rusty Russelledf14cf2000-04-19 11:26:44 +00001897
Rusty Russell73ef09b2000-07-03 10:24:04 +00001898 for (i = 0; i < a->u.match_size - ALIGN(sizeof(*a)); i++)
Rusty Russelledf14cf2000-04-19 11:26:44 +00001899 if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0)
Rusty Russell90e712a2000-03-29 04:19:26 +00001900 return 1;
Rusty Russelledf14cf2000-04-19 11:26:44 +00001901 *maskptr += i;
1902 return 0;
1903}
1904
1905static inline int
Rusty Russell733e54b2004-12-16 14:22:23 +00001906target_same(struct rule_head *a, struct rule_head *b,const unsigned char *mask)
Rusty Russelledf14cf2000-04-19 11:26:44 +00001907{
1908 unsigned int i;
Rusty Russell733e54b2004-12-16 14:22:23 +00001909 STRUCT_ENTRY_TARGET *ta, *tb;
Marc Bouchere6869a82000-03-20 06:03:29 +00001910
Rusty Russell733e54b2004-12-16 14:22:23 +00001911 if (a->type != b->type)
1912 return 0;
1913
1914 ta = GET_TARGET(a->entry);
1915 tb = GET_TARGET(b->entry);
1916
1917 switch (a->type) {
1918 case IPTCC_R_FALLTHROUGH:
1919 return 1;
1920 case IPTCC_R_JUMP:
1921 return a->jump == b->jump;
1922 case IPTCC_R_STANDARD:
1923 return ((STRUCT_STANDARD_TARGET *)ta)->verdict
1924 == ((STRUCT_STANDARD_TARGET *)tb)->verdict;
1925 case IPTCC_R_MODULE:
1926 if (ta->u.target_size != tb->u.target_size)
1927 return 0;
1928 if (strcmp(ta->u.user.name, tb->u.user.name) != 0)
1929 return 0;
1930
1931 for (i = 0; i < ta->u.target_size - sizeof(*ta); i++)
Rusty Russelldaade442004-12-29 11:14:52 +00001932 if (((ta->data[i] ^ tb->data[i]) & mask[i]) != 0)
Rusty Russell733e54b2004-12-16 14:22:23 +00001933 return 0;
1934 return 1;
1935 default:
1936 fprintf(stderr, "ERROR: bad type %i\n", a->type);
1937 abort();
1938 }
Marc Bouchere6869a82000-03-20 06:03:29 +00001939}
1940
Rusty Russell733e54b2004-12-16 14:22:23 +00001941static unsigned char *
Rusty Russell79dee072000-05-02 16:45:16 +00001942is_same(const STRUCT_ENTRY *a,
1943 const STRUCT_ENTRY *b,
1944 unsigned char *matchmask);
Marc Bouchere6869a82000-03-20 06:03:29 +00001945
Stefan Tomanekd59b9db2011-03-08 22:42:51 +01001946
1947/* find the first rule in `chain' which matches `fw' and remove it unless dry_run is set */
1948static int delete_entry(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw,
1949 unsigned char *matchmask, struct xtc_handle *handle,
1950 bool dry_run)
Marc Bouchere6869a82000-03-20 06:03:29 +00001951{
Harald Welteaae69be2004-08-29 23:32:14 +00001952 struct chain_head *c;
Rusty Russelle45c7132004-12-16 13:21:44 +00001953 struct rule_head *r, *i;
Marc Bouchere6869a82000-03-20 06:03:29 +00001954
Rusty Russell79dee072000-05-02 16:45:16 +00001955 iptc_fn = TC_DELETE_ENTRY;
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001956 if (!(c = iptcc_find_label(chain, handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00001957 errno = ENOENT;
1958 return 0;
1959 }
1960
Rusty Russelle45c7132004-12-16 13:21:44 +00001961 /* Create a rule_head from origfw. */
1962 r = iptcc_alloc_rule(c, origfw->next_offset);
1963 if (!r) {
Harald Welte0113fe72004-01-06 19:04:02 +00001964 errno = ENOMEM;
1965 return 0;
1966 }
1967
Rusty Russelle45c7132004-12-16 13:21:44 +00001968 memcpy(r->entry, origfw, origfw->next_offset);
1969 r->counter_map.maptype = COUNTER_MAP_NOMAP;
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01001970 if (!iptcc_map_target(handle, r)) {
Rusty Russelle45c7132004-12-16 13:21:44 +00001971 DEBUGP("unable to map target of rule for chain `%s'\n", chain);
1972 free(r);
1973 return 0;
Patrick McHardyJesper Brouer04a1e4c2006-07-25 01:50:48 +00001974 } else {
1975 /* iptcc_map_target increment target chain references
1976 * since this is a fake rule only used for matching
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01001977 * the chain references count is decremented again.
Patrick McHardyJesper Brouer04a1e4c2006-07-25 01:50:48 +00001978 */
1979 if (r->type == IPTCC_R_JUMP
1980 && r->jump)
1981 r->jump->references--;
Rusty Russelle45c7132004-12-16 13:21:44 +00001982 }
Harald Welte0113fe72004-01-06 19:04:02 +00001983
Rusty Russelle45c7132004-12-16 13:21:44 +00001984 list_for_each_entry(i, &c->rules, list) {
Rusty Russell733e54b2004-12-16 14:22:23 +00001985 unsigned char *mask;
Harald Weltefe537072004-08-30 20:28:53 +00001986
Rusty Russell733e54b2004-12-16 14:22:23 +00001987 mask = is_same(r->entry, i->entry, matchmask);
1988 if (!mask)
1989 continue;
Martin Josefsson2a5dbbb2004-09-22 21:37:41 +00001990
Rusty Russell733e54b2004-12-16 14:22:23 +00001991 if (!target_same(r, i, mask))
1992 continue;
1993
Stefan Tomanekd59b9db2011-03-08 22:42:51 +01001994 /* if we are just doing a dry run, we simply skip the rest */
1995 if (dry_run)
1996 return 1;
1997
Rusty Russell733e54b2004-12-16 14:22:23 +00001998 /* If we are about to delete the rule that is the
1999 * current iterator, move rule iterator back. next
2000 * pointer will then point to real next node */
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002001 if (i == handle->rule_iterator_cur) {
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01002002 handle->rule_iterator_cur =
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002003 list_entry(handle->rule_iterator_cur->list.prev,
Rusty Russell733e54b2004-12-16 14:22:23 +00002004 struct rule_head, list);
Marc Bouchere6869a82000-03-20 06:03:29 +00002005 }
Rusty Russell733e54b2004-12-16 14:22:23 +00002006
2007 c->num_rules--;
2008 iptcc_delete_rule(i);
2009
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002010 set_changed(handle);
Rusty Russell733e54b2004-12-16 14:22:23 +00002011 free(r);
2012 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00002013 }
2014
Rusty Russelle45c7132004-12-16 13:21:44 +00002015 free(r);
Marc Bouchere6869a82000-03-20 06:03:29 +00002016 errno = ENOENT;
2017 return 0;
Rusty Russell7e53bf92000-03-20 07:03:28 +00002018}
Harald Welteaae69be2004-08-29 23:32:14 +00002019
Stefan Tomanekd59b9db2011-03-08 22:42:51 +01002020/* check whether a specified rule is present */
2021int TC_CHECK_ENTRY(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw,
2022 unsigned char *matchmask, struct xtc_handle *handle)
2023{
2024 /* do a dry-run delete to find out whether a matching rule exists */
2025 return delete_entry(chain, origfw, matchmask, handle, true);
2026}
2027
2028/* Delete the first rule in `chain' which matches `fw'. */
2029int TC_DELETE_ENTRY(const IPT_CHAINLABEL chain, const STRUCT_ENTRY *origfw,
2030 unsigned char *matchmask, struct xtc_handle *handle)
2031{
2032 return delete_entry(chain, origfw, matchmask, handle, false);
2033}
Marc Bouchere6869a82000-03-20 06:03:29 +00002034
2035/* Delete the rule in position `rulenum' in `chain'. */
2036int
Rusty Russell79dee072000-05-02 16:45:16 +00002037TC_DELETE_NUM_ENTRY(const IPT_CHAINLABEL chain,
2038 unsigned int rulenum,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002039 struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00002040{
Harald Welteaae69be2004-08-29 23:32:14 +00002041 struct chain_head *c;
2042 struct rule_head *r;
Marc Bouchere6869a82000-03-20 06:03:29 +00002043
Rusty Russell79dee072000-05-02 16:45:16 +00002044 iptc_fn = TC_DELETE_NUM_ENTRY;
Harald Welteaae69be2004-08-29 23:32:14 +00002045
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002046 if (!(c = iptcc_find_label(chain, handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002047 errno = ENOENT;
2048 return 0;
2049 }
2050
Martin Josefssona5616dc2004-10-24 22:27:31 +00002051 if (rulenum >= c->num_rules) {
Martin Josefsson631f3612004-09-23 19:25:06 +00002052 errno = E2BIG;
2053 return 0;
2054 }
2055
2056 /* Take advantage of the double linked list if possible. */
Martin Josefssona5616dc2004-10-24 22:27:31 +00002057 if (rulenum + 1 <= c->num_rules/2) {
2058 r = iptcc_get_rule_num(c, rulenum + 1);
2059 } else {
2060 r = iptcc_get_rule_num_reverse(c, c->num_rules - rulenum);
Marc Bouchere6869a82000-03-20 06:03:29 +00002061 }
2062
Harald Welteaae69be2004-08-29 23:32:14 +00002063 /* If we are about to delete the rule that is the current
2064 * iterator, move rule iterator back. next pointer will then
2065 * point to real next node */
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002066 if (r == handle->rule_iterator_cur) {
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01002067 handle->rule_iterator_cur =
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002068 list_entry(handle->rule_iterator_cur->list.prev,
Harald Welteaae69be2004-08-29 23:32:14 +00002069 struct rule_head, list);
Harald Welte0113fe72004-01-06 19:04:02 +00002070 }
Marc Bouchere6869a82000-03-20 06:03:29 +00002071
Harald Welteaae69be2004-08-29 23:32:14 +00002072 c->num_rules--;
2073 iptcc_delete_rule(r);
2074
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002075 set_changed(handle);
Martin Josefsson2a5dbbb2004-09-22 21:37:41 +00002076
Harald Welteaae69be2004-08-29 23:32:14 +00002077 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00002078}
2079
Marc Bouchere6869a82000-03-20 06:03:29 +00002080/* Flushes the entries in the given chain (ie. empties chain). */
2081int
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002082TC_FLUSH_ENTRIES(const IPT_CHAINLABEL chain, struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00002083{
Harald Welteaae69be2004-08-29 23:32:14 +00002084 struct chain_head *c;
2085 struct rule_head *r, *tmp;
Marc Bouchere6869a82000-03-20 06:03:29 +00002086
Harald Welte0113fe72004-01-06 19:04:02 +00002087 iptc_fn = TC_FLUSH_ENTRIES;
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002088 if (!(c = iptcc_find_label(chain, handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002089 errno = ENOENT;
2090 return 0;
2091 }
Marc Bouchere6869a82000-03-20 06:03:29 +00002092
Harald Welteaae69be2004-08-29 23:32:14 +00002093 list_for_each_entry_safe(r, tmp, &c->rules, list) {
2094 iptcc_delete_rule(r);
2095 }
2096
2097 c->num_rules = 0;
2098
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002099 set_changed(handle);
Harald Welteaae69be2004-08-29 23:32:14 +00002100
2101 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00002102}
2103
2104/* Zeroes the counters in a chain. */
2105int
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002106TC_ZERO_ENTRIES(const IPT_CHAINLABEL chain, struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00002107{
Harald Welteaae69be2004-08-29 23:32:14 +00002108 struct chain_head *c;
2109 struct rule_head *r;
Rusty Russell7e53bf92000-03-20 07:03:28 +00002110
Derrik Pates664c0a32005-02-01 13:28:14 +00002111 iptc_fn = TC_ZERO_ENTRIES;
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002112 if (!(c = iptcc_find_label(chain, handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002113 errno = ENOENT;
2114 return 0;
2115 }
Marc Bouchere6869a82000-03-20 06:03:29 +00002116
Andy Gaye5bd1d72006-08-22 02:56:41 +00002117 if (c->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
2118 c->counter_map.maptype = COUNTER_MAP_ZEROED;
2119
Harald Welteaae69be2004-08-29 23:32:14 +00002120 list_for_each_entry(r, &c->rules, list) {
2121 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
2122 r->counter_map.maptype = COUNTER_MAP_ZEROED;
Marc Bouchere6869a82000-03-20 06:03:29 +00002123 }
Harald Welteaae69be2004-08-29 23:32:14 +00002124
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002125 set_changed(handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00002126
Marc Bouchere6869a82000-03-20 06:03:29 +00002127 return 1;
2128}
2129
Harald Welte1cef74d2001-01-05 15:22:59 +00002130STRUCT_COUNTERS *
2131TC_READ_COUNTER(const IPT_CHAINLABEL chain,
2132 unsigned int rulenum,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002133 struct xtc_handle *handle)
Harald Welte1cef74d2001-01-05 15:22:59 +00002134{
Harald Welteaae69be2004-08-29 23:32:14 +00002135 struct chain_head *c;
2136 struct rule_head *r;
Harald Welte1cef74d2001-01-05 15:22:59 +00002137
2138 iptc_fn = TC_READ_COUNTER;
2139 CHECK(*handle);
2140
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002141 if (!(c = iptcc_find_label(chain, handle))) {
Harald Welte1cef74d2001-01-05 15:22:59 +00002142 errno = ENOENT;
2143 return NULL;
2144 }
2145
Harald Welteaae69be2004-08-29 23:32:14 +00002146 if (!(r = iptcc_get_rule_num(c, rulenum))) {
Harald Welte0113fe72004-01-06 19:04:02 +00002147 errno = E2BIG;
2148 return NULL;
2149 }
2150
Harald Welteaae69be2004-08-29 23:32:14 +00002151 return &r->entry[0].counters;
Harald Welte1cef74d2001-01-05 15:22:59 +00002152}
2153
2154int
2155TC_ZERO_COUNTER(const IPT_CHAINLABEL chain,
2156 unsigned int rulenum,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002157 struct xtc_handle *handle)
Harald Welte1cef74d2001-01-05 15:22:59 +00002158{
Harald Welteaae69be2004-08-29 23:32:14 +00002159 struct chain_head *c;
2160 struct rule_head *r;
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01002161
Harald Welte1cef74d2001-01-05 15:22:59 +00002162 iptc_fn = TC_ZERO_COUNTER;
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002163 CHECK(handle);
Harald Welte1cef74d2001-01-05 15:22:59 +00002164
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002165 if (!(c = iptcc_find_label(chain, handle))) {
Harald Welte1cef74d2001-01-05 15:22:59 +00002166 errno = ENOENT;
2167 return 0;
2168 }
2169
Harald Welteaae69be2004-08-29 23:32:14 +00002170 if (!(r = iptcc_get_rule_num(c, rulenum))) {
Harald Welte0113fe72004-01-06 19:04:02 +00002171 errno = E2BIG;
2172 return 0;
2173 }
2174
Harald Welteaae69be2004-08-29 23:32:14 +00002175 if (r->counter_map.maptype == COUNTER_MAP_NORMAL_MAP)
2176 r->counter_map.maptype = COUNTER_MAP_ZEROED;
Harald Welte1cef74d2001-01-05 15:22:59 +00002177
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002178 set_changed(handle);
Harald Welte1cef74d2001-01-05 15:22:59 +00002179
2180 return 1;
2181}
2182
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01002183int
Harald Welte1cef74d2001-01-05 15:22:59 +00002184TC_SET_COUNTER(const IPT_CHAINLABEL chain,
2185 unsigned int rulenum,
2186 STRUCT_COUNTERS *counters,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002187 struct xtc_handle *handle)
Harald Welte1cef74d2001-01-05 15:22:59 +00002188{
Harald Welteaae69be2004-08-29 23:32:14 +00002189 struct chain_head *c;
2190 struct rule_head *r;
Harald Welte1cef74d2001-01-05 15:22:59 +00002191 STRUCT_ENTRY *e;
Harald Welte1cef74d2001-01-05 15:22:59 +00002192
2193 iptc_fn = TC_SET_COUNTER;
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002194 CHECK(handle);
Harald Welte1cef74d2001-01-05 15:22:59 +00002195
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002196 if (!(c = iptcc_find_label(chain, handle))) {
Harald Welte1cef74d2001-01-05 15:22:59 +00002197 errno = ENOENT;
2198 return 0;
2199 }
Harald Welte0113fe72004-01-06 19:04:02 +00002200
Harald Welteaae69be2004-08-29 23:32:14 +00002201 if (!(r = iptcc_get_rule_num(c, rulenum))) {
Harald Welte0113fe72004-01-06 19:04:02 +00002202 errno = E2BIG;
2203 return 0;
2204 }
2205
Harald Welteaae69be2004-08-29 23:32:14 +00002206 e = r->entry;
2207 r->counter_map.maptype = COUNTER_MAP_SET;
Harald Welte0113fe72004-01-06 19:04:02 +00002208
2209 memcpy(&e->counters, counters, sizeof(STRUCT_COUNTERS));
Harald Welte1cef74d2001-01-05 15:22:59 +00002210
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002211 set_changed(handle);
Harald Welte1cef74d2001-01-05 15:22:59 +00002212
2213 return 1;
2214}
2215
Marc Bouchere6869a82000-03-20 06:03:29 +00002216/* Creates a new chain. */
2217/* To create a chain, create two rules: error node and unconditional
2218 * return. */
2219int
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002220TC_CREATE_CHAIN(const IPT_CHAINLABEL chain, struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00002221{
Harald Welteaae69be2004-08-29 23:32:14 +00002222 static struct chain_head *c;
Patrick McHardy1f23d3c2008-06-07 15:04:34 +02002223 int capacity;
2224 int exceeded;
Marc Bouchere6869a82000-03-20 06:03:29 +00002225
Rusty Russell79dee072000-05-02 16:45:16 +00002226 iptc_fn = TC_CREATE_CHAIN;
Marc Bouchere6869a82000-03-20 06:03:29 +00002227
2228 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
2229 QUEUE, RETURN. */
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002230 if (iptcc_find_label(chain, handle)
Rusty Russell79dee072000-05-02 16:45:16 +00002231 || strcmp(chain, LABEL_DROP) == 0
2232 || strcmp(chain, LABEL_ACCEPT) == 0
Rusty Russell67088e72000-05-10 01:18:57 +00002233 || strcmp(chain, LABEL_QUEUE) == 0
Rusty Russell79dee072000-05-02 16:45:16 +00002234 || strcmp(chain, LABEL_RETURN) == 0) {
Harald Welteaae69be2004-08-29 23:32:14 +00002235 DEBUGP("Chain `%s' already exists\n", chain);
Marc Bouchere6869a82000-03-20 06:03:29 +00002236 errno = EEXIST;
2237 return 0;
2238 }
2239
Rusty Russell79dee072000-05-02 16:45:16 +00002240 if (strlen(chain)+1 > sizeof(IPT_CHAINLABEL)) {
Harald Welteaae69be2004-08-29 23:32:14 +00002241 DEBUGP("Chain name `%s' too long\n", chain);
Marc Bouchere6869a82000-03-20 06:03:29 +00002242 errno = EINVAL;
2243 return 0;
2244 }
2245
Harald Welteaae69be2004-08-29 23:32:14 +00002246 c = iptcc_alloc_chain_head(chain, 0);
2247 if (!c) {
2248 DEBUGP("Cannot allocate memory for chain `%s'\n", chain);
2249 errno = ENOMEM;
2250 return 0;
Marc Bouchere6869a82000-03-20 06:03:29 +00002251
Harald Welteaae69be2004-08-29 23:32:14 +00002252 }
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002253 handle->num_chains++; /* New user defined chain */
Marc Bouchere6869a82000-03-20 06:03:29 +00002254
Harald Welteaae69be2004-08-29 23:32:14 +00002255 DEBUGP("Creating chain `%s'\n", chain);
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002256 iptc_insert_chain(handle, c); /* Insert sorted */
Harald Welte0113fe72004-01-06 19:04:02 +00002257
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +00002258 /* Inserting chains don't change the correctness of the chain
2259 * index (except if its smaller than index[0], but that
2260 * handled by iptc_insert_chain). It only causes longer lists
2261 * in the buckets. Thus, only rebuild chain index when the
2262 * capacity is exceed with CHAIN_INDEX_INSERT_MAX chains.
2263 */
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002264 capacity = handle->chain_index_sz * CHAIN_INDEX_BUCKET_LEN;
2265 exceeded = handle->num_chains - capacity;
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +00002266 if (exceeded > CHAIN_INDEX_INSERT_MAX) {
2267 debug("Capacity(%d) exceeded(%d) rebuild (chains:%d)\n",
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002268 capacity, exceeded, handle->num_chains);
2269 iptcc_chain_index_rebuild(handle);
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +00002270 }
2271
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002272 set_changed(handle);
Harald Welte0113fe72004-01-06 19:04:02 +00002273
Harald Welteaae69be2004-08-29 23:32:14 +00002274 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00002275}
2276
2277/* Get the number of references to this chain. */
2278int
Rusty Russell79dee072000-05-02 16:45:16 +00002279TC_GET_REFERENCES(unsigned int *ref, const IPT_CHAINLABEL chain,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002280 struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00002281{
Harald Welteaae69be2004-08-29 23:32:14 +00002282 struct chain_head *c;
Marc Bouchere6869a82000-03-20 06:03:29 +00002283
Derrik Pates664c0a32005-02-01 13:28:14 +00002284 iptc_fn = TC_GET_REFERENCES;
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002285 if (!(c = iptcc_find_label(chain, handle))) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002286 errno = ENOENT;
2287 return 0;
2288 }
2289
Harald Welteaae69be2004-08-29 23:32:14 +00002290 *ref = c->references;
2291
Marc Bouchere6869a82000-03-20 06:03:29 +00002292 return 1;
2293}
2294
2295/* Deletes a chain. */
2296int
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002297TC_DELETE_CHAIN(const IPT_CHAINLABEL chain, struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00002298{
Marc Bouchere6869a82000-03-20 06:03:29 +00002299 unsigned int references;
Harald Welteaae69be2004-08-29 23:32:14 +00002300 struct chain_head *c;
Rusty Russell7e53bf92000-03-20 07:03:28 +00002301
Rusty Russell79dee072000-05-02 16:45:16 +00002302 iptc_fn = TC_DELETE_CHAIN;
Marc Bouchere6869a82000-03-20 06:03:29 +00002303
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002304 if (!(c = iptcc_find_label(chain, handle))) {
Harald Welteaae69be2004-08-29 23:32:14 +00002305 DEBUGP("cannot find chain `%s'\n", chain);
Marc Bouchere6869a82000-03-20 06:03:29 +00002306 errno = ENOENT;
2307 return 0;
2308 }
2309
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002310 if (TC_BUILTIN(chain, handle)) {
Harald Welteaae69be2004-08-29 23:32:14 +00002311 DEBUGP("cannot remove builtin chain `%s'\n", chain);
2312 errno = EINVAL;
2313 return 0;
2314 }
2315
2316 if (!TC_GET_REFERENCES(&references, chain, handle)) {
2317 DEBUGP("cannot get references on chain `%s'\n", chain);
2318 return 0;
2319 }
2320
2321 if (references > 0) {
2322 DEBUGP("chain `%s' still has references\n", chain);
2323 errno = EMLINK;
2324 return 0;
2325 }
2326
2327 if (c->num_rules) {
2328 DEBUGP("chain `%s' is not empty\n", chain);
Marc Bouchere6869a82000-03-20 06:03:29 +00002329 errno = ENOTEMPTY;
2330 return 0;
2331 }
2332
Harald Welteaae69be2004-08-29 23:32:14 +00002333 /* If we are about to delete the chain that is the current
Jesper Dangaard Brouer48bde402008-01-15 17:06:48 +00002334 * iterator, move chain iterator forward. */
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002335 if (c == handle->chain_iterator_cur)
2336 iptcc_chain_iterator_advance(handle);
Harald Welte0113fe72004-01-06 19:04:02 +00002337
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002338 handle->num_chains--; /* One user defined chain deleted */
Jesper Dangaard Brouer48bde402008-01-15 17:06:48 +00002339
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +00002340 //list_del(&c->list); /* Done in iptcc_chain_index_delete_chain() */
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002341 iptcc_chain_index_delete_chain(c, handle);
Jesper Dangaard Brouer01444da2008-01-15 17:18:15 +00002342 free(c);
2343
Harald Welteaae69be2004-08-29 23:32:14 +00002344 DEBUGP("chain `%s' deleted\n", chain);
2345
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002346 set_changed(handle);
Harald Welteaae69be2004-08-29 23:32:14 +00002347
2348 return 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00002349}
2350
2351/* Renames a chain. */
Rusty Russell79dee072000-05-02 16:45:16 +00002352int TC_RENAME_CHAIN(const IPT_CHAINLABEL oldname,
2353 const IPT_CHAINLABEL newname,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002354 struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00002355{
Harald Welteaae69be2004-08-29 23:32:14 +00002356 struct chain_head *c;
Rusty Russell79dee072000-05-02 16:45:16 +00002357 iptc_fn = TC_RENAME_CHAIN;
Marc Bouchere6869a82000-03-20 06:03:29 +00002358
Harald Welte1de80462000-10-30 12:00:27 +00002359 /* find_label doesn't cover built-in targets: DROP, ACCEPT,
2360 QUEUE, RETURN. */
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002361 if (iptcc_find_label(newname, handle)
Rusty Russell79dee072000-05-02 16:45:16 +00002362 || strcmp(newname, LABEL_DROP) == 0
2363 || strcmp(newname, LABEL_ACCEPT) == 0
Harald Welte1de80462000-10-30 12:00:27 +00002364 || strcmp(newname, LABEL_QUEUE) == 0
Rusty Russell79dee072000-05-02 16:45:16 +00002365 || strcmp(newname, LABEL_RETURN) == 0) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002366 errno = EEXIST;
2367 return 0;
2368 }
2369
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002370 if (!(c = iptcc_find_label(oldname, handle))
2371 || TC_BUILTIN(oldname, handle)) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002372 errno = ENOENT;
2373 return 0;
2374 }
2375
Rusty Russell79dee072000-05-02 16:45:16 +00002376 if (strlen(newname)+1 > sizeof(IPT_CHAINLABEL)) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002377 errno = EINVAL;
2378 return 0;
2379 }
2380
Jesper Dangaard Brouer64ff47c2009-03-23 14:25:49 +01002381 /* This only unlinks "c" from the list, thus no free(c) */
2382 iptcc_chain_index_delete_chain(c, handle);
2383
2384 /* Change the name of the chain */
Harald Welteaae69be2004-08-29 23:32:14 +00002385 strncpy(c->name, newname, sizeof(IPT_CHAINLABEL));
Jesper Dangaard Brouer64ff47c2009-03-23 14:25:49 +01002386
2387 /* Insert sorted into to list again */
2388 iptc_insert_chain(handle, c);
2389
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002390 set_changed(handle);
Harald Welte0113fe72004-01-06 19:04:02 +00002391
Marc Bouchere6869a82000-03-20 06:03:29 +00002392 return 1;
2393}
2394
2395/* Sets the policy on a built-in chain. */
2396int
Rusty Russell79dee072000-05-02 16:45:16 +00002397TC_SET_POLICY(const IPT_CHAINLABEL chain,
2398 const IPT_CHAINLABEL policy,
Harald Welte1cef74d2001-01-05 15:22:59 +00002399 STRUCT_COUNTERS *counters,
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002400 struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00002401{
Harald Welteaae69be2004-08-29 23:32:14 +00002402 struct chain_head *c;
Marc Bouchere6869a82000-03-20 06:03:29 +00002403
Rusty Russell79dee072000-05-02 16:45:16 +00002404 iptc_fn = TC_SET_POLICY;
Marc Bouchere6869a82000-03-20 06:03:29 +00002405
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002406 if (!(c = iptcc_find_label(chain, handle))) {
Harald Welteaae69be2004-08-29 23:32:14 +00002407 DEBUGP("cannot find chain `%s'\n", chain);
2408 errno = ENOENT;
Marc Bouchere6869a82000-03-20 06:03:29 +00002409 return 0;
2410 }
2411
Harald Welteaae69be2004-08-29 23:32:14 +00002412 if (!iptcc_is_builtin(c)) {
2413 DEBUGP("cannot set policy of userdefinedchain `%s'\n", chain);
2414 errno = ENOENT;
2415 return 0;
2416 }
Marc Bouchere6869a82000-03-20 06:03:29 +00002417
Rusty Russell79dee072000-05-02 16:45:16 +00002418 if (strcmp(policy, LABEL_ACCEPT) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00002419 c->verdict = -NF_ACCEPT - 1;
Rusty Russell79dee072000-05-02 16:45:16 +00002420 else if (strcmp(policy, LABEL_DROP) == 0)
Harald Welteaae69be2004-08-29 23:32:14 +00002421 c->verdict = -NF_DROP - 1;
Marc Bouchere6869a82000-03-20 06:03:29 +00002422 else {
2423 errno = EINVAL;
2424 return 0;
2425 }
Harald Welte1cef74d2001-01-05 15:22:59 +00002426
Harald Welte1cef74d2001-01-05 15:22:59 +00002427 if (counters) {
2428 /* set byte and packet counters */
Harald Welteaae69be2004-08-29 23:32:14 +00002429 memcpy(&c->counters, counters, sizeof(STRUCT_COUNTERS));
2430 c->counter_map.maptype = COUNTER_MAP_SET;
Harald Welte1cef74d2001-01-05 15:22:59 +00002431 } else {
Harald Welteaae69be2004-08-29 23:32:14 +00002432 c->counter_map.maptype = COUNTER_MAP_NOMAP;
Harald Welte1cef74d2001-01-05 15:22:59 +00002433 }
2434
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002435 set_changed(handle);
Marc Bouchere6869a82000-03-20 06:03:29 +00002436
Marc Bouchere6869a82000-03-20 06:03:29 +00002437 return 1;
2438}
2439
2440/* Without this, on gcc 2.7.2.3, we get:
Rusty Russell79dee072000-05-02 16:45:16 +00002441 libiptc.c: In function `TC_COMMIT':
Marc Bouchere6869a82000-03-20 06:03:29 +00002442 libiptc.c:833: fixed or forbidden register was spilled.
2443 This may be due to a compiler bug or to impossible asm
2444 statements or clauses.
2445*/
2446static void
Rusty Russell79dee072000-05-02 16:45:16 +00002447subtract_counters(STRUCT_COUNTERS *answer,
2448 const STRUCT_COUNTERS *a,
2449 const STRUCT_COUNTERS *b)
Marc Bouchere6869a82000-03-20 06:03:29 +00002450{
2451 answer->pcnt = a->pcnt - b->pcnt;
2452 answer->bcnt = a->bcnt - b->bcnt;
2453}
2454
Harald Welteaae69be2004-08-29 23:32:14 +00002455
Jan Engelhardtdbb77542008-02-11 00:33:30 +01002456static void counters_nomap(STRUCT_COUNTERS_INFO *newcounters, unsigned int idx)
Harald Welteaae69be2004-08-29 23:32:14 +00002457{
Jan Engelhardtdbb77542008-02-11 00:33:30 +01002458 newcounters->counters[idx] = ((STRUCT_COUNTERS) { 0, 0});
Harald Welteaae69be2004-08-29 23:32:14 +00002459 DEBUGP_C("NOMAP => zero\n");
2460}
2461
2462static void counters_normal_map(STRUCT_COUNTERS_INFO *newcounters,
Jan Engelhardtdbb77542008-02-11 00:33:30 +01002463 STRUCT_REPLACE *repl, unsigned int idx,
Harald Welteaae69be2004-08-29 23:32:14 +00002464 unsigned int mappos)
2465{
2466 /* Original read: X.
2467 * Atomic read on replacement: X + Y.
2468 * Currently in kernel: Z.
2469 * Want in kernel: X + Y + Z.
2470 * => Add in X + Y
2471 * => Add in replacement read.
2472 */
Jan Engelhardtdbb77542008-02-11 00:33:30 +01002473 newcounters->counters[idx] = repl->counters[mappos];
Harald Welteaae69be2004-08-29 23:32:14 +00002474 DEBUGP_C("NORMAL_MAP => mappos %u \n", mappos);
2475}
2476
2477static void counters_map_zeroed(STRUCT_COUNTERS_INFO *newcounters,
Jan Engelhardtdbb77542008-02-11 00:33:30 +01002478 STRUCT_REPLACE *repl, unsigned int idx,
2479 unsigned int mappos, STRUCT_COUNTERS *counters)
Harald Welteaae69be2004-08-29 23:32:14 +00002480{
2481 /* Original read: X.
2482 * Atomic read on replacement: X + Y.
2483 * Currently in kernel: Z.
2484 * Want in kernel: Y + Z.
2485 * => Add in Y.
2486 * => Add in (replacement read - original read).
2487 */
Jan Engelhardtdbb77542008-02-11 00:33:30 +01002488 subtract_counters(&newcounters->counters[idx],
Harald Welteaae69be2004-08-29 23:32:14 +00002489 &repl->counters[mappos],
2490 counters);
2491 DEBUGP_C("ZEROED => mappos %u\n", mappos);
2492}
2493
2494static void counters_map_set(STRUCT_COUNTERS_INFO *newcounters,
Jan Engelhardtdbb77542008-02-11 00:33:30 +01002495 unsigned int idx, STRUCT_COUNTERS *counters)
Harald Welteaae69be2004-08-29 23:32:14 +00002496{
2497 /* Want to set counter (iptables-restore) */
2498
Jan Engelhardtdbb77542008-02-11 00:33:30 +01002499 memcpy(&newcounters->counters[idx], counters,
Harald Welteaae69be2004-08-29 23:32:14 +00002500 sizeof(STRUCT_COUNTERS));
2501
2502 DEBUGP_C("SET\n");
2503}
2504
2505
Marc Bouchere6869a82000-03-20 06:03:29 +00002506int
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002507TC_COMMIT(struct xtc_handle *handle)
Marc Bouchere6869a82000-03-20 06:03:29 +00002508{
2509 /* Replace, then map back the counters. */
Rusty Russell79dee072000-05-02 16:45:16 +00002510 STRUCT_REPLACE *repl;
2511 STRUCT_COUNTERS_INFO *newcounters;
Harald Welteaae69be2004-08-29 23:32:14 +00002512 struct chain_head *c;
2513 int ret;
Martin Josefsson841e4ae2003-05-02 15:30:11 +00002514 size_t counterlen;
Harald Welteaae69be2004-08-29 23:32:14 +00002515 int new_number;
2516 unsigned int new_size;
Marc Bouchere6869a82000-03-20 06:03:29 +00002517
Derrik Pates664c0a32005-02-01 13:28:14 +00002518 iptc_fn = TC_COMMIT;
Marc Bouchere6869a82000-03-20 06:03:29 +00002519 CHECK(*handle);
Martin Josefsson841e4ae2003-05-02 15:30:11 +00002520
Marc Bouchere6869a82000-03-20 06:03:29 +00002521 /* Don't commit if nothing changed. */
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002522 if (!handle->changed)
Marc Bouchere6869a82000-03-20 06:03:29 +00002523 goto finished;
2524
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002525 new_number = iptcc_compile_table_prep(handle, &new_size);
Harald Welteaae69be2004-08-29 23:32:14 +00002526 if (new_number < 0) {
2527 errno = ENOMEM;
Harald Welted6ba6f52005-11-12 10:39:40 +00002528 goto out_zero;
Harald Welteaae69be2004-08-29 23:32:14 +00002529 }
2530
2531 repl = malloc(sizeof(*repl) + new_size);
Marc Bouchere6869a82000-03-20 06:03:29 +00002532 if (!repl) {
2533 errno = ENOMEM;
Harald Welted6ba6f52005-11-12 10:39:40 +00002534 goto out_zero;
Marc Bouchere6869a82000-03-20 06:03:29 +00002535 }
Martin Josefssonad3b4f92004-09-22 22:04:07 +00002536 memset(repl, 0, sizeof(*repl) + new_size);
Harald Welteaae69be2004-08-29 23:32:14 +00002537
Rusty Russelle45c7132004-12-16 13:21:44 +00002538#if 0
2539 TC_DUMP_ENTRIES(*handle);
2540#endif
2541
Harald Welteaae69be2004-08-29 23:32:14 +00002542 counterlen = sizeof(STRUCT_COUNTERS_INFO)
2543 + sizeof(STRUCT_COUNTERS) * new_number;
Marc Bouchere6869a82000-03-20 06:03:29 +00002544
2545 /* These are the old counters we will get from kernel */
Rusty Russell79dee072000-05-02 16:45:16 +00002546 repl->counters = malloc(sizeof(STRUCT_COUNTERS)
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002547 * handle->info.num_entries);
Marc Bouchere6869a82000-03-20 06:03:29 +00002548 if (!repl->counters) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002549 errno = ENOMEM;
Harald Welted6ba6f52005-11-12 10:39:40 +00002550 goto out_free_repl;
Marc Bouchere6869a82000-03-20 06:03:29 +00002551 }
Marc Bouchere6869a82000-03-20 06:03:29 +00002552 /* These are the counters we're going to put back, later. */
2553 newcounters = malloc(counterlen);
2554 if (!newcounters) {
Marc Bouchere6869a82000-03-20 06:03:29 +00002555 errno = ENOMEM;
Harald Welted6ba6f52005-11-12 10:39:40 +00002556 goto out_free_repl_counters;
Marc Bouchere6869a82000-03-20 06:03:29 +00002557 }
Harald Welteaae69be2004-08-29 23:32:14 +00002558 memset(newcounters, 0, counterlen);
Marc Bouchere6869a82000-03-20 06:03:29 +00002559
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002560 strcpy(repl->name, handle->info.name);
Harald Welteaae69be2004-08-29 23:32:14 +00002561 repl->num_entries = new_number;
2562 repl->size = new_size;
2563
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002564 repl->num_counters = handle->info.num_entries;
2565 repl->valid_hooks = handle->info.valid_hooks;
Harald Welteaae69be2004-08-29 23:32:14 +00002566
2567 DEBUGP("num_entries=%u, size=%u, num_counters=%u\n",
2568 repl->num_entries, repl->size, repl->num_counters);
2569
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002570 ret = iptcc_compile_table(handle, repl);
Harald Welteaae69be2004-08-29 23:32:14 +00002571 if (ret < 0) {
2572 errno = ret;
Harald Welted6ba6f52005-11-12 10:39:40 +00002573 goto out_free_newcounters;
Harald Welteaae69be2004-08-29 23:32:14 +00002574 }
2575
2576
2577#ifdef IPTC_DEBUG2
2578 {
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01002579 int fd = open("/tmp/libiptc-so_set_replace.blob",
Harald Welteaae69be2004-08-29 23:32:14 +00002580 O_CREAT|O_WRONLY);
2581 if (fd >= 0) {
2582 write(fd, repl, sizeof(*repl) + repl->size);
2583 close(fd);
2584 }
2585 }
2586#endif
Marc Bouchere6869a82000-03-20 06:03:29 +00002587
Jan Engelhardt175f4512008-11-10 17:25:55 +01002588 ret = setsockopt(handle->sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
Harald Welted6ba6f52005-11-12 10:39:40 +00002589 sizeof(*repl) + repl->size);
Patrick McHardye0865ad2006-04-22 02:08:56 +00002590 if (ret < 0)
Harald Welted6ba6f52005-11-12 10:39:40 +00002591 goto out_free_newcounters;
Marc Bouchere6869a82000-03-20 06:03:29 +00002592
2593 /* Put counters back. */
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002594 strcpy(newcounters->name, handle->info.name);
Harald Welteaae69be2004-08-29 23:32:14 +00002595 newcounters->num_counters = new_number;
Marc Bouchere6869a82000-03-20 06:03:29 +00002596
Jan Engelhardt1c9015b2008-11-10 17:00:41 +01002597 list_for_each_entry(c, &handle->chains, list) {
Harald Welteaae69be2004-08-29 23:32:14 +00002598 struct rule_head *r;
Marc Bouchere6869a82000-03-20 06:03:29 +00002599
Harald Welteaae69be2004-08-29 23:32:14 +00002600 /* Builtin chains have their own counters */
2601 if (iptcc_is_builtin(c)) {
2602 DEBUGP("counter for chain-index %u: ", c->foot_index);
2603 switch(c->counter_map.maptype) {
2604 case COUNTER_MAP_NOMAP:
2605 counters_nomap(newcounters, c->foot_index);
2606 break;
2607 case COUNTER_MAP_NORMAL_MAP:
2608 counters_normal_map(newcounters, repl,
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01002609 c->foot_index,
Harald Welteaae69be2004-08-29 23:32:14 +00002610 c->counter_map.mappos);
2611 break;
2612 case COUNTER_MAP_ZEROED:
2613 counters_map_zeroed(newcounters, repl,
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01002614 c->foot_index,
Harald Welteaae69be2004-08-29 23:32:14 +00002615 c->counter_map.mappos,
2616 &c->counters);
2617 break;
2618 case COUNTER_MAP_SET:
2619 counters_map_set(newcounters, c->foot_index,
2620 &c->counters);
2621 break;
2622 }
2623 }
Harald Welte1cef74d2001-01-05 15:22:59 +00002624
Harald Welteaae69be2004-08-29 23:32:14 +00002625 list_for_each_entry(r, &c->rules, list) {
2626 DEBUGP("counter for index %u: ", r->index);
2627 switch (r->counter_map.maptype) {
2628 case COUNTER_MAP_NOMAP:
2629 counters_nomap(newcounters, r->index);
2630 break;
Harald Welte1cef74d2001-01-05 15:22:59 +00002631
Harald Welteaae69be2004-08-29 23:32:14 +00002632 case COUNTER_MAP_NORMAL_MAP:
2633 counters_normal_map(newcounters, repl,
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01002634 r->index,
Harald Welteaae69be2004-08-29 23:32:14 +00002635 r->counter_map.mappos);
2636 break;
Harald Welte1cef74d2001-01-05 15:22:59 +00002637
Harald Welteaae69be2004-08-29 23:32:14 +00002638 case COUNTER_MAP_ZEROED:
2639 counters_map_zeroed(newcounters, repl,
2640 r->index,
2641 r->counter_map.mappos,
2642 &r->entry->counters);
2643 break;
2644
2645 case COUNTER_MAP_SET:
2646 counters_map_set(newcounters, r->index,
2647 &r->entry->counters);
2648 break;
2649 }
Marc Bouchere6869a82000-03-20 06:03:29 +00002650 }
2651 }
Rusty Russell62527ce2000-09-04 09:45:54 +00002652
Harald Welteaae69be2004-08-29 23:32:14 +00002653#ifdef IPTC_DEBUG2
2654 {
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01002655 int fd = open("/tmp/libiptc-so_set_add_counters.blob",
Harald Welteaae69be2004-08-29 23:32:14 +00002656 O_CREAT|O_WRONLY);
2657 if (fd >= 0) {
2658 write(fd, newcounters, counterlen);
2659 close(fd);
2660 }
2661 }
2662#endif
2663
Jan Engelhardt175f4512008-11-10 17:25:55 +01002664 ret = setsockopt(handle->sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
Harald Welted6ba6f52005-11-12 10:39:40 +00002665 newcounters, counterlen);
Patrick McHardye0865ad2006-04-22 02:08:56 +00002666 if (ret < 0)
Harald Welted6ba6f52005-11-12 10:39:40 +00002667 goto out_free_newcounters;
Marc Bouchere6869a82000-03-20 06:03:29 +00002668
2669 free(repl->counters);
2670 free(repl);
2671 free(newcounters);
2672
Harald Welted6ba6f52005-11-12 10:39:40 +00002673finished:
Marc Bouchere6869a82000-03-20 06:03:29 +00002674 return 1;
Harald Welted6ba6f52005-11-12 10:39:40 +00002675
2676out_free_newcounters:
2677 free(newcounters);
2678out_free_repl_counters:
2679 free(repl->counters);
2680out_free_repl:
2681 free(repl);
2682out_zero:
2683 return 0;
Marc Bouchere6869a82000-03-20 06:03:29 +00002684}
2685
Marc Bouchere6869a82000-03-20 06:03:29 +00002686/* Translates errno numbers into more human-readable form than strerror. */
2687const char *
Rusty Russell79dee072000-05-02 16:45:16 +00002688TC_STRERROR(int err)
Marc Bouchere6869a82000-03-20 06:03:29 +00002689{
2690 unsigned int i;
2691 struct table_struct {
2692 void *fn;
2693 int err;
2694 const char *message;
2695 } table [] =
Harald Welte4ccfa632001-07-30 15:12:43 +00002696 { { TC_INIT, EPERM, "Permission denied (you must be root)" },
Rusty Russell79dee072000-05-02 16:45:16 +00002697 { TC_INIT, EINVAL, "Module is wrong version" },
Jesper Dangaard Brouera9fe5b32009-03-23 14:26:56 +01002698 { TC_INIT, ENOENT,
Harald Welte4ccfa632001-07-30 15:12:43 +00002699 "Table does not exist (do you need to insmod?)" },
Rusty Russell79dee072000-05-02 16:45:16 +00002700 { TC_DELETE_CHAIN, ENOTEMPTY, "Chain is not empty" },
2701 { TC_DELETE_CHAIN, EINVAL, "Can't delete built-in chain" },
2702 { TC_DELETE_CHAIN, EMLINK,
Marc Bouchere6869a82000-03-20 06:03:29 +00002703 "Can't delete chain with references left" },
Rusty Russell79dee072000-05-02 16:45:16 +00002704 { TC_CREATE_CHAIN, EEXIST, "Chain already exists" },
2705 { TC_INSERT_ENTRY, E2BIG, "Index of insertion too big" },
2706 { TC_REPLACE_ENTRY, E2BIG, "Index of replacement too big" },
2707 { TC_DELETE_NUM_ENTRY, E2BIG, "Index of deletion too big" },
Harald Welte1cef74d2001-01-05 15:22:59 +00002708 { TC_READ_COUNTER, E2BIG, "Index of counter too big" },
2709 { TC_ZERO_COUNTER, E2BIG, "Index of counter too big" },
Rusty Russell79dee072000-05-02 16:45:16 +00002710 { TC_INSERT_ENTRY, ELOOP, "Loop found in table" },
2711 { TC_INSERT_ENTRY, EINVAL, "Target problem" },
Marc Bouchere6869a82000-03-20 06:03:29 +00002712 /* ENOENT for DELETE probably means no matching rule */
Rusty Russell79dee072000-05-02 16:45:16 +00002713 { TC_DELETE_ENTRY, ENOENT,
Marc Boucherc8264992000-04-22 22:34:44 +00002714 "Bad rule (does a matching rule exist in that chain?)" },
Rusty Russell79dee072000-05-02 16:45:16 +00002715 { TC_SET_POLICY, ENOENT,
Marc Boucherc8264992000-04-22 22:34:44 +00002716 "Bad built-in chain name" },
Rusty Russell79dee072000-05-02 16:45:16 +00002717 { TC_SET_POLICY, EINVAL,
Marc Boucherc8264992000-04-22 22:34:44 +00002718 "Bad policy name" },
Harald Welte4ccfa632001-07-30 15:12:43 +00002719
2720 { NULL, 0, "Incompatible with this kernel" },
2721 { NULL, ENOPROTOOPT, "iptables who? (do you need to insmod?)" },
2722 { NULL, ENOSYS, "Will be implemented real soon. I promise ;)" },
2723 { NULL, ENOMEM, "Memory allocation problem" },
2724 { NULL, ENOENT, "No chain/target/match by that name" },
Marc Bouchere6869a82000-03-20 06:03:29 +00002725 };
2726
2727 for (i = 0; i < sizeof(table)/sizeof(struct table_struct); i++) {
2728 if ((!table[i].fn || table[i].fn == iptc_fn)
2729 && table[i].err == err)
2730 return table[i].message;
2731 }
2732
2733 return strerror(err);
2734}